]> git.lizzy.rs Git - rust.git/commitdiff
Do not ICE when e.g. `call_mut()` is called on a closure whose kind is not yet known.
authorNiko Matsakis <niko@alum.mit.edu>
Sun, 1 Feb 2015 11:07:52 +0000 (06:07 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Sun, 1 Feb 2015 11:13:07 +0000 (06:13 -0500)
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs [new file with mode: 0644]

index 24e9f1c8720eef68e5ecca9b24bd04b6e10faf18..88455b3385a1e10a7fb98a855912850407850a46 100644 (file)
@@ -44,6 +44,9 @@ pub enum MethodError {
 
     // Multiple methods might apply.
     Ambiguity(Vec<CandidateSource>),
+
+    // 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,
     }
 }
 
index 8000776ad45f94227ba08143fda5d9857dec99ca..e9ea0921bc9e83dac2399e0d0c959c8c56e0e4a0 100644 (file)
@@ -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 @@ fn elaborate_bounds<F>(
 
     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 @@ fn assemble_extension_candidates_for_trait(&mut self,
                        .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 @@ fn assemble_extension_candidates_for_trait(&mut self,
         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 @@ fn assemble_closure_candidates(&mut self,
                                    trait_def_id: ast::DefId,
                                    method_ty: Rc<ty::Method<'tcx>>,
                                    method_index: uint)
+                                   -> Result<(),MethodError>
     {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
         let tcx = self.tcx();
@@ -586,7 +595,7 @@ fn assemble_closure_candidates(&mut self,
         } 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 @@ fn assemble_closure_candidates(&mut self,
             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 @@ fn assemble_closure_candidates(&mut self,
                 kind: ClosureCandidate(trait_def_id, method_index)
             });
         }
+
+        Ok(())
     }
 
     fn assemble_projection_candidates(&mut self,
@@ -735,11 +743,11 @@ fn pick(mut self) -> PickResult<'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 @@ fn pick(mut self) -> PickResult<'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<PickResult<'tcx>> {
@@ -895,7 +907,7 @@ fn consider_candidates(&self,
 
         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| {
index 3cf9a1a945668d624e1e8d12c65ab2a21d01366b..bd5060c940e5025505e5ec8d4fe9c0700f211c88 100644 (file)
@@ -22,6 +22,7 @@
 
 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,
index 268e61b994e14b4b2c18e5eb8434529fdd6502e9..c193e1ef48364814aa247428310927f3d0e9df24 100644 (file)
@@ -2695,7 +2695,8 @@ fn check_method_call<'a, 'tcx>(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 (file)
index 0000000..f993b8f
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
+}
+