about summary refs log tree commit diff
diff options
context:
space:
mode:
authorscalexm <martin.alex32@hotmail.fr>2017-08-03 13:50:06 +0200
committerscalexm <martin.alex32@hotmail.fr>2017-08-03 14:40:40 +0200
commit2e8e75f50f87dca154342790ba03401037a3c52e (patch)
treef5c257543f16895041d9a2f9b6681118721378fa
parentda12c4f8e543cecb3c3841bf4a099522950d3b70 (diff)
downloadrust-2e8e75f50f87dca154342790ba03401037a3c52e.tar.gz
rust-2e8e75f50f87dca154342790ba03401037a3c52e.zip
Tweak error message
-rw-r--r--src/librustc_typeck/check/method/confirm.rs8
-rw-r--r--src/librustc_typeck/check/method/mod.rs25
-rw-r--r--src/librustc_typeck/check/method/suggest.rs73
-rw-r--r--src/test/ui/issue-35976.rs (renamed from src/test/compile-fail/issue-35976.rs)6
-rw-r--r--src/test/ui/issue-35976.stderr11
5 files changed, 78 insertions, 45 deletions
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 0ab75ad622c..fd148062372 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -110,8 +110,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         self.unify_receivers(self_ty, method_sig.inputs()[0]);
 
         // Add any trait/regions obligations specified on the method's type parameters.
-        let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
-        self.add_obligations(method_ty, all_substs, &method_predicates);
+        // We won't add these if we encountered an illegal sized bound, so that we can use
+        // a custom error in that case.
+        if !rerun {
+            let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
+            self.add_obligations(method_ty, all_substs, &method_predicates);
+        }
 
         // Create the final `MethodCallee`.
         let callee = MethodCallee {
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f929a7ef49e..eda17ab02c4 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -60,6 +60,10 @@ pub enum MethodError<'tcx> {
 
     // Found an applicable method, but it is not visible.
     PrivateMatch(Def),
+
+    // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
+    // forgotten to import a trait.
+    IllegalSizedBound(Vec<DefId>),
 }
 
 // Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
@@ -112,6 +116,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Err(Ambiguity(..)) => true,
             Err(ClosureAmbiguity(..)) => true,
             Err(PrivateMatch(..)) => allow_private,
+            Err(IllegalSizedBound(..)) => true,
         }
     }
 
@@ -173,13 +178,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                         self_ty,
                                         call_expr,
                                         ProbeScope::AllTraits) {
+
+                    // If we find a different result the caller probably forgot to import a trait.
                     Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
-                    Err(MethodError::Ambiguity(ref sources)) => {
+                    Err(Ambiguity(ref sources)) => {
                         sources.iter()
                                .filter_map(|source| {
                                    match *source {
                                        // Note: this cannot come from an inherent impl,
-                                       // because the first probe succeeded.
+                                       // because the first probing succeeded.
                                        ImplSource(def) => self.tcx.trait_id_of_impl(def),
                                        TraitSource(_) => None,
                                    }
@@ -189,19 +196,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => Vec::new(),
                 };
 
-            // If we find a different result, the caller probably forgot to import a trait.
-            // We span an error with an appropriate help message.
-            if !candidates.is_empty() {
-                let error = MethodError::NoMatch(
-                    NoMatchData::new(Vec::new(), Vec::new(), candidates, probe::Mode::MethodCall)
-                );
-                self.report_method_error(span,
-                                         self_ty,
-                                         segment.name,
-                                         Some(self_expr),
-                                         error,
-                                         None);
-            }
+            return Err(IllegalSizedBound(candidates));
         }
 
         Ok(result.callee)
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 4faf71e0cc9..c480febdec6 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -315,7 +315,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let msg = format!("{} `{}` is private", def.kind_name(), item_name);
                 self.tcx.sess.span_err(span, &msg);
             }
+
+            MethodError::IllegalSizedBound(candidates) => {
+                let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
+                let mut err = self.sess().struct_span_err(span, &msg);
+                if !candidates.is_empty() {
+                    let help = format!("{an}other candidate{s} {were} found in the following \
+                                        trait{s}, perhaps add a `use` for {one_of_them}:",
+                                    an = if candidates.len() == 1 {"an" } else { "" },
+                                    s = if candidates.len() == 1 { "" } else { "s" },
+                                    were = if candidates.len() == 1 { "was" } else { "were" },
+                                    one_of_them = if candidates.len() == 1 {
+                                        "it"
+                                    } else {
+                                        "one_of_them"
+                                    });
+                    self.suggest_use_candidates(&mut err, help, candidates);
+                }
+                err.emit();
+            }
+        }
+    }
+
+    fn suggest_use_candidates(&self,
+                              err: &mut DiagnosticBuilder,
+                              mut msg: String,
+                              candidates: Vec<DefId>) {
+        let limit = if candidates.len() == 5 { 5 } else { 4 };
+        for (i, trait_did) in candidates.iter().take(limit).enumerate() {
+            msg.push_str(&format!("\ncandidate #{}: `use {};`",
+                                    i + 1,
+                                    self.tcx.item_path_str(*trait_did)));
+        }
+        if candidates.len() > limit {
+            msg.push_str(&format!("\nand {} others", candidates.len() - limit));
         }
+        err.note(&msg[..]);
     }
 
     fn suggest_traits_to_import(&self,
@@ -330,30 +365,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             candidates.sort();
             candidates.dedup();
             err.help("items from traits can only be used if the trait is in scope");
-            let mut msg = format!("the following {traits_are} implemented but not in scope, \
-                                   perhaps add a `use` for {one_of_them}:",
-                              traits_are = if candidates.len() == 1 {
-                                  "trait is"
-                              } else {
-                                  "traits are"
-                              },
-                              one_of_them = if candidates.len() == 1 {
-                                  "it"
-                              } else {
-                                  "one of them"
-                              });
-
-            let limit = if candidates.len() == 5 { 5 } else { 4 };
-            for (i, trait_did) in candidates.iter().take(limit).enumerate() {
-                msg.push_str(&format!("\ncandidate #{}: `use {};`",
-                                      i + 1,
-                                      self.tcx.item_path_str(*trait_did)));
-            }
-            if candidates.len() > limit {
-                msg.push_str(&format!("\nand {} others", candidates.len() - limit));
-            }
-            err.note(&msg[..]);
-
+            let msg = format!("the following {traits_are} implemented but not in scope, \
+                               perhaps add a `use` for {one_of_them}:",
+                            traits_are = if candidates.len() == 1 {
+                                "trait is"
+                            } else {
+                                "traits are"
+                            },
+                            one_of_them = if candidates.len() == 1 {
+                                "it"
+                            } else {
+                                "one of them"
+                            });
+
+            self.suggest_use_candidates(err, msg, candidates);
             return;
         }
 
diff --git a/src/test/compile-fail/issue-35976.rs b/src/test/ui/issue-35976.rs
index 194616c9443..169d7b55916 100644
--- a/src/test/compile-fail/issue-35976.rs
+++ b/src/test/ui/issue-35976.rs
@@ -22,10 +22,8 @@ mod private {
 
 fn bar(arg: Box<private::Future>) {
     arg.wait();
-    //~^ ERROR no method named `wait` found for type `std::boxed::Box<private::Future + 'static>`
-    //~| the following trait is implemented but not in scope
-    //~| ERROR the trait bound `private::Future + 'static: std::marker::Sized` is not satisfied
-    //~| `private::Future + 'static` does not have a constant size known at compile-time
+    //~^ ERROR the `wait` method cannot be invoked on a trait object
+    //~| another candidate was found in the following trait, perhaps add a `use` for it:
 }
 
 fn main() {
diff --git a/src/test/ui/issue-35976.stderr b/src/test/ui/issue-35976.stderr
new file mode 100644
index 00000000000..9fb67449734
--- /dev/null
+++ b/src/test/ui/issue-35976.stderr
@@ -0,0 +1,11 @@
+error: the `wait` method cannot be invoked on a trait object
+  --> $DIR/issue-35976.rs:24:9
+   |
+24 |     arg.wait();
+   |         ^^^^
+   |
+   = note: another candidate was found in the following trait, perhaps add a `use` for it:
+           candidate #1: `use private::Future;`
+
+error: aborting due to previous error
+