diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 24e9f1c8720ee..88455b3385a1e 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -44,6 +44,9 @@ pub enum MethodError { // Multiple methods might apply. Ambiguity(Vec), + + // Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind. + ClosureAmbiguity(/* DefId of fn trait */ ast::DefId), } // A pared down enum describing just the places from which a method @@ -65,9 +68,10 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> bool { match probe::probe(fcx, span, method_name, self_ty, call_expr_id) { - Ok(_) => true, - Err(NoMatch(_, _)) => false, - Err(Ambiguity(_)) => true, + Ok(..) => true, + Err(NoMatch(..)) => false, + Err(Ambiguity(..)) => true, + Err(ClosureAmbiguity(..)) => true, } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8000776ad45f9..e9ea0921bc9e8 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{MethodError,Ambiguity,NoMatch}; +use super::{MethodError}; use super::MethodIndex; use super::{CandidateSource,ImplSource,TraitSource}; use super::suggest; @@ -129,7 +129,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // take place in the `fcx.infcx().probe` below. let steps = match create_steps(fcx, span, self_ty) { Some(steps) => steps, - None => return Err(NoMatch(Vec::new(), Vec::new())), + None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())), }; // Create a list of simplified self types, if we can. @@ -158,7 +158,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (steps, opt_simplified_steps) = dummy.take().unwrap(); let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps); probe_cx.assemble_inherent_candidates(); - probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id); + try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id)); probe_cx.pick() }) } @@ -444,29 +444,34 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_id: ast::NodeId) + -> Result<(),MethodError> { let mut duplicates = HashSet::new(); let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id); for applicable_traits in opt_applicable_traits.into_iter() { for &trait_did in applicable_traits.iter() { if duplicates.insert(trait_did) { - self.assemble_extension_candidates_for_trait(trait_did); + try!(self.assemble_extension_candidates_for_trait(trait_did)); } } } + Ok(()) } - fn assemble_extension_candidates_for_all_traits(&mut self) { + fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(),MethodError> { let mut duplicates = HashSet::new(); for trait_info in suggest::all_traits(self.fcx.ccx) { if duplicates.insert(trait_info.def_id) { - self.assemble_extension_candidates_for_trait(trait_info.def_id) + try!(self.assemble_extension_candidates_for_trait(trait_info.def_id)); } } + Ok(()) } fn assemble_extension_candidates_for_trait(&mut self, - trait_def_id: ast::DefId) { + trait_def_id: ast::DefId) + -> Result<(),MethodError> + { debug!("assemble_extension_candidates_for_trait(trait_def_id={})", trait_def_id.repr(self.tcx())); @@ -478,26 +483,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { .position(|item| item.name() == self.method_name); let matching_index = match matching_index { Some(i) => i, - None => { return; } + None => { return Ok(()); } }; let method = match (&*trait_items)[matching_index].as_opt_method() { Some(m) => m, - None => { return; } + None => { return Ok(()); } }; // Check whether `trait_def_id` defines a method with suitable name: if !self.has_applicable_self(&*method) { debug!("method has inapplicable self"); - return self.record_static_candidate(TraitSource(trait_def_id)); + self.record_static_candidate(TraitSource(trait_def_id)); + return Ok(()); } self.assemble_extension_candidates_for_trait_impls(trait_def_id, method.clone(), matching_index); - self.assemble_closure_candidates(trait_def_id, - method.clone(), - matching_index); + try!(self.assemble_closure_candidates(trait_def_id, + method.clone(), + matching_index)); self.assemble_projection_candidates(trait_def_id, method.clone(), @@ -506,6 +512,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.assemble_where_clause_candidates(trait_def_id, method, matching_index); + + Ok(()) } fn assemble_extension_candidates_for_trait_impls(&mut self, @@ -576,6 +584,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { trait_def_id: ast::DefId, method_ty: Rc>, method_index: uint) + -> Result<(),MethodError> { // Check if this is one of the Fn,FnMut,FnOnce traits. let tcx = self.tcx(); @@ -586,7 +595,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() { ty::FnOnceClosureKind } else { - return; + return Ok(()); }; // Check if there is an unboxed-closure self-type in the list of receivers. @@ -602,10 +611,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let closure_kind = match closure_kinds.get(&closure_def_id) { Some(&k) => k, None => { - self.tcx().sess.span_bug( - self.span, - &format!("No entry for closure: {}", - closure_def_id.repr(self.tcx()))[]); + return Err(MethodError::ClosureAmbiguity(trait_def_id)); } }; @@ -630,6 +636,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { kind: ClosureCandidate(trait_def_id, method_index) }); } + + Ok(()) } fn assemble_projection_candidates(&mut self, @@ -735,11 +743,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let span = self.span; let tcx = self.tcx(); - self.assemble_extension_candidates_for_all_traits(); + try!(self.assemble_extension_candidates_for_all_traits()); let out_of_scope_traits = match self.pick_core() { Some(Ok(p)) => vec![p.method_ty.container.id()], - Some(Err(Ambiguity(v))) => v.into_iter().map(|source| { + Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| { match source { TraitSource(id) => id, ImplSource(impl_id) => { @@ -752,14 +760,18 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } } }).collect(), - Some(Err(NoMatch(_, others))) => { + Some(Err(MethodError::NoMatch(_, others))) => { assert!(others.is_empty()); vec![] } + Some(Err(MethodError::ClosureAmbiguity(..))) => { + // this error only occurs when assembling candidates + tcx.sess.span_bug(span, "encountered ClosureAmbiguity from pick_core"); + } None => vec![], }; -; - Err(NoMatch(static_candidates, out_of_scope_traits)) + + Err(MethodError::NoMatch(static_candidates, out_of_scope_traits)) } fn pick_core(&mut self) -> Option> { @@ -895,7 +907,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { if applicable_candidates.len() > 1 { let sources = probes.iter().map(|p| p.to_source()).collect(); - return Some(Err(Ambiguity(sources))); + return Some(Err(MethodError::Ambiguity(sources))); } applicable_candidates.pop().map(|probe| { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 3cf9a1a945668..bd5060c940e50 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -22,6 +22,7 @@ use util::ppaux::UserString; use syntax::{ast, ast_util}; use syntax::codemap::Span; +use syntax::print::pprust; use std::cell; use std::cmp::Ordering; @@ -32,6 +33,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, method_name: ast::Name, + callee_expr: &ast::Expr, error: MethodError) { match error { @@ -84,6 +86,18 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, report_candidates(fcx, span, method_name, sources); } + + MethodError::ClosureAmbiguity(trait_def_id) => { + fcx.sess().span_err( + span, + &*format!("the `{}` method from the `{}` trait cannot be explicitly \ + invoked on this closure as we have not yet inferred what \ + kind of closure it is; use overloaded call notation instead \ + (e.g., `{}()`)", + method_name.user_string(fcx.tcx()), + ty::item_path_str(fcx.tcx(), trait_def_id), + pprust::expr_to_string(callee_expr))); + } } fn report_candidates(fcx: &FnCtxt, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 268e61b994e14..c193e1ef48364 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2695,7 +2695,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, method_ty } Err(error) => { - method::report_error(fcx, method_name.span, expr_t, method_name.node.name, error); + method::report_error(fcx, method_name.span, expr_t, + method_name.node.name, rcvr, error); fcx.write_error(expr.id); fcx.tcx().types.err } diff --git a/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs b/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs new file mode 100644 index 0000000000000..f993b8fa8c4d1 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +fn main() { + let mut zero = || {}; + let () = zero.call_mut(()); + //~^ ERROR we have not yet inferred what kind of closure it is +} +