about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-10-29 16:49:01 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-12-10 12:02:18 -0800
commit12af2561e9936add8fab4b96ff206b00a5877efe (patch)
treeb5b5410af50110a0231f489451b3611ab6adf644 /src
parent7dbfb0a8ca4ab74ee3111e57a024f9e6257ce37c (diff)
downloadrust-12af2561e9936add8fab4b96ff206b00a5877efe.tar.gz
rust-12af2561e9936add8fab4b96ff206b00a5877efe.zip
Point at method call when type annotations are needed
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/error_reporting/need_type_info.rs59
-rw-r--r--src/librustc/traits/error_reporting.rs26
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs2
-rw-r--r--src/test/ui/associated-types/associated-types-overridden-binding.stderr17
-rw-r--r--src/test/ui/associated-types/associated-types-unconstrained.stderr6
-rw-r--r--src/test/ui/issues/issue-12028.stderr6
-rw-r--r--src/test/ui/issues/issue-65611.stderr5
-rw-r--r--src/test/ui/question-mark-type-infer.rs2
-rw-r--r--src/test/ui/question-mark-type-infer.stderr11
-rw-r--r--src/test/ui/span/issue-42234-unknown-receiver-type.rs4
-rw-r--r--src/test/ui/span/issue-42234-unknown-receiver-type.stderr7
-rw-r--r--src/test/ui/span/type-annotations-needed-expr.stderr5
13 files changed, 108 insertions, 44 deletions
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 32eecdf01a3..118fd186b1c 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -6,6 +6,7 @@ use crate::infer::type_variable::TypeVariableOriginKind;
 use crate::ty::{self, Ty, Infer, TyVar};
 use crate::ty::print::Print;
 use syntax::source_map::DesugaringKind;
+use syntax::symbol::kw;
 use syntax_pos::Span;
 use errors::{Applicability, DiagnosticBuilder};
 
@@ -19,6 +20,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
     found_arg_pattern: Option<&'tcx Pat>,
     found_ty: Option<Ty<'tcx>>,
     found_closure: Option<&'tcx ExprKind>,
+    found_method_call: Option<&'tcx ExprKind>,
 }
 
 impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
@@ -35,6 +37,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
             found_arg_pattern: None,
             found_ty: None,
             found_closure: None,
+            found_method_call: None,
         }
     }
 
@@ -93,11 +96,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
-        if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
-            &expr.kind,
-            self.node_matches_type(expr.hir_id),
-        ) {
-            self.found_closure = Some(&expr.kind);
+        if self.node_matches_type(expr.hir_id).is_some() {
+            match expr.kind {
+                ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
+                ExprKind::MethodCall(..) => self.found_method_call = Some(&expr.kind),
+                _ => {}
+            }
         }
         intravisit::walk_expr(self, expr);
     }
@@ -157,7 +161,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let ty_vars = self.type_variables.borrow();
             let var_origin = ty_vars.var_origin(ty_vid);
             if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
-                return (name.to_string(), Some(var_origin.span));
+                if name != kw::SelfUpper {
+                    return (name.to_string(), Some(var_origin.span));
+                }
             }
         }
 
@@ -175,6 +181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         body_id: Option<hir::BodyId>,
         span: Span,
         ty: Ty<'tcx>,
+        is_projection: bool,
     ) -> DiagnosticBuilder<'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
         let (name, name_sp) = self.extract_type_name(&ty, None);
@@ -210,6 +217,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             // 3 |     let _ = x.sum() as f64;
             //   |               ^^^ cannot infer type for `S`
             span
+        } else if let Some(ExprKind::MethodCall(_, call_span, _)) = local_visitor.found_method_call {
+            // Point at the call instead of the whole expression:
+            // error[E0284]: type annotations needed
+            //  --> file.rs:2:5
+            //   |
+            // 2 |     vec![Ok(2)].into_iter().collect()?;
+            //   |                             ^^^^^^^ cannot infer type
+            //   |
+            //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
+            if span.contains(*call_span) {
+                *call_span
+            } else {
+                span
+            }
         } else {
             span
         };
@@ -247,13 +268,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
         //   |         the type parameter `E` is specified
         // ```
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            err_span,
-            E0282,
-            "type annotations needed{}",
-            ty_msg,
-        );
+        let mut err = if is_projection {
+            struct_span_err!(self.tcx.sess, err_span, E0284, "type annotations needed{}", ty_msg)
+        } else {
+            struct_span_err!(self.tcx.sess, err_span, E0282, "type annotations needed{}", ty_msg)
+        };
 
         let suffix = match local_visitor.found_ty {
             Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => {
@@ -334,6 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 format!("consider giving this pattern {}", suffix)
             };
             err.span_label(pattern.span, msg);
+        } else if let Some(ExprKind::MethodCall(segment, ..)) = local_visitor.found_method_call {
+            if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(segment.ident.span) {
+                if segment.args.is_none() {
+                    err.span_suggestion(
+                        segment.ident.span,
+                        "consider specifying the type argument in the method call",
+                        // FIXME: we don't know how many type arguments should be set here.
+                        format!("{}::<_>", snippet),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+            }
         }
         // Instead of the following:
         // error[E0282]: type annotations needed
@@ -351,7 +382,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         //   |               ^^^ cannot infer type for `S`
         //   |
         //   = note: type must be known at this point
-        let span = name_sp.unwrap_or(span);
+        let span = name_sp.unwrap_or(err_span);
         if !err.span.span_labels().iter().any(|span_label| {
                 span_label.label.is_some() && span_label.span == span
             }) && local_visitor.found_arg_pattern.is_none()
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 35017d6330d..2b00861188e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1989,7 +1989,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     self.tcx.lang_items().sized_trait()
                     .map_or(false, |sized_id| sized_id == trait_ref.def_id())
                 {
-                    self.need_type_info_err(body_id, span, self_ty).emit();
+                    self.need_type_info_err(body_id, span, self_ty, false).emit();
                 } else {
                     let mut err = struct_span_err!(
                         self.tcx.sess,
@@ -2007,7 +2007,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if !ty.references_error() && !self.tcx.sess.has_errors() {
-                    self.need_type_info_err(body_id, span, ty).emit();
+                    let mut err = self.need_type_info_err(body_id, span, ty, false);
+                    self.note_obligation_cause(&mut err, obligation);
+                    err.emit();
                 }
             }
 
@@ -2018,21 +2020,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
                     // both must be type variables, or the other would've been instantiated
                     assert!(a.is_ty_var() && b.is_ty_var());
-                    self.need_type_info_err(body_id,
-                                            obligation.cause.span,
-                                            a).emit();
+                    let mut err = self.need_type_info_err(body_id, span, a, false);
+                    self.note_obligation_cause(&mut err, obligation);
+                    err.emit();
+                }
+            }
+            ty::Predicate::Projection(ref data) => {
+                let trait_ref = data.to_poly_trait_ref(self.tcx);
+                let self_ty = trait_ref.self_ty();
+                if predicate.references_error() {
+                    return;
                 }
+                let mut err = self.need_type_info_err(body_id, span, self_ty, true);
+                err.note(&format!("cannot resolve `{}`", predicate));
+                self.note_obligation_cause(&mut err, obligation);
+                err.emit();
             }
 
             _ => {
                 if !self.tcx.sess.has_errors() {
                     let mut err = struct_span_err!(
                         self.tcx.sess,
-                        obligation.cause.span,
+                        span,
                         E0284,
                         "type annotations needed: cannot resolve `{}`",
                         predicate,
                     );
+                    err.span_label(span, &format!("cannot resolve `{}`", predicate));
                     self.note_obligation_cause(&mut err, obligation);
                     err.emit();
                 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a956aba4f62..c8f1e025bae 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5359,7 +5359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.need_type_info_err((**self).body_id, sp, ty)
+                self.need_type_info_err((**self).body_id, sp, ty, false)
                     .note("type must be known at this point")
                     .emit();
             }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3113e9b241d..e5f1e2cc34c 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -717,7 +717,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
     fn report_error(&self, t: Ty<'tcx>) {
         if !self.tcx.sess.has_errors() {
             self.infcx
-                .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t)
+                .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, false)
                 .emit();
         }
     }
diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr
index 5ef1b23cbcd..dd6bde0c14d 100644
--- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr
+++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr
@@ -1,18 +1,23 @@
-error[E0284]: type annotations needed: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
+error[E0284]: type annotations needed
   --> $DIR/associated-types-overridden-binding.rs:4:1
    |
 LL | trait Foo: Iterator<Item = i32> {}
    | ------------------------------- required by `Foo`
 LL | trait Bar: Foo<Item = u32> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self`
+   |
+   = note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
 
-error[E0282]: type annotations needed
+error[E0284]: type annotations needed
   --> $DIR/associated-types-overridden-binding.rs:7:1
    |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   | ----------------------------------------- required by `I32Iterator`
 LL | trait U32Iterator = I32Iterator<Item = u32>;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self`
+   |
+   = note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0284.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr
index 4e9e54d3688..14ce4836f97 100644
--- a/src/test/ui/associated-types/associated-types-unconstrained.stderr
+++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr
@@ -1,8 +1,10 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _`
+error[E0284]: type annotations needed
   --> $DIR/associated-types-unconstrained.rs:14:20
    |
 LL |     let x: isize = Foo::bar();
-   |                    ^^^^^^^^
+   |                    ^^^^^^^^ cannot infer type
+   |
+   = note: cannot resolve `<_ as Foo>::A == _`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr
index ff92d01a69e..5f23b4f559f 100644
--- a/src/test/ui/issues/issue-12028.stderr
+++ b/src/test/ui/issues/issue-12028.stderr
@@ -1,8 +1,10 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
+error[E0284]: type annotations needed
   --> $DIR/issue-12028.rs:27:14
    |
 LL |         self.input_stream(&mut stream);
-   |              ^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^ cannot infer type for `H`
+   |
+   = note: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-65611.stderr b/src/test/ui/issues/issue-65611.stderr
index cb441c13c6b..905c5ae9461 100644
--- a/src/test/ui/issues/issue-65611.stderr
+++ b/src/test/ui/issues/issue-65611.stderr
@@ -2,7 +2,10 @@ error[E0282]: type annotations needed
   --> $DIR/issue-65611.rs:59:20
    |
 LL |     let x = buffer.last().unwrap().0.clone();
-   |                    ^^^^ cannot infer type for `T`
+   |                    ^^^^
+   |                    |
+   |                    cannot infer type for `T`
+   |                    help: consider specifying the type argument in the method call: `last::<_>`
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/question-mark-type-infer.rs b/src/test/ui/question-mark-type-infer.rs
index 95ee01a70ce..2ef8618192f 100644
--- a/src/test/ui/question-mark-type-infer.rs
+++ b/src/test/ui/question-mark-type-infer.rs
@@ -9,7 +9,7 @@ fn f(x: &i32) -> Result<i32, ()> {
 
 fn g() -> Result<Vec<i32>, ()> {
     let l = [1, 2, 3, 4];
-    l.iter().map(f).collect()? //~ ERROR type annotations needed: cannot resolve
+    l.iter().map(f).collect()? //~ ERROR type annotations needed
 }
 
 fn main() {
diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr
index 53a170e7d43..d32d9497645 100644
--- a/src/test/ui/question-mark-type-infer.stderr
+++ b/src/test/ui/question-mark-type-infer.stderr
@@ -1,8 +1,13 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as std::ops::Try>::Ok == _`
-  --> $DIR/question-mark-type-infer.rs:12:5
+error[E0284]: type annotations needed
+  --> $DIR/question-mark-type-infer.rs:12:21
    |
 LL |     l.iter().map(f).collect()?
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     ^^^^^^^
+   |                     |
+   |                     cannot infer type
+   |                     help: consider specifying the type argument in the method call: `collect::<_>`
+   |
+   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.rs b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
index 58138e21bc0..d3292bbecba 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.rs
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
@@ -9,8 +9,8 @@ fn shines_a_beacon_through_the_darkness() {
 }
 
 fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
-    data.iter() //~ ERROR type annotations needed
-        .sum::<_>()
+    data.iter()
+        .sum::<_>() //~ ERROR type annotations needed
         .to_string()
 }
 
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
index 30c9adb1dce..093a6f6f3eb 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
@@ -9,11 +9,10 @@ LL |     x.unwrap().method_that_could_exist_on_some_type();
    = note: type must be known at this point
 
 error[E0282]: type annotations needed
-  --> $DIR/issue-42234-unknown-receiver-type.rs:12:5
+  --> $DIR/issue-42234-unknown-receiver-type.rs:13:10
    |
-LL | /     data.iter()
-LL | |         .sum::<_>()
-   | |___________________^ cannot infer type
+LL |         .sum::<_>()
+   |          ^^^ cannot infer type
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr
index e32a542bb7a..1efb2720e0c 100644
--- a/src/test/ui/span/type-annotations-needed-expr.stderr
+++ b/src/test/ui/span/type-annotations-needed-expr.stderr
@@ -2,7 +2,10 @@ error[E0282]: type annotations needed
   --> $DIR/type-annotations-needed-expr.rs:2:39
    |
 LL |     let _ = (vec![1,2,3]).into_iter().sum() as f64;
-   |                                       ^^^ cannot infer type for `S`
+   |                                       ^^^
+   |                                       |
+   |                                       cannot infer type for `S`
+   |                                       help: consider specifying the type argument in the method call: `sum::<_>`
    |
    = note: type must be known at this point