From 12af2561e9936add8fab4b96ff206b00a5877efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 29 Oct 2019 16:49:01 -0700 Subject: [PATCH 01/12] Point at method call when type annotations are needed --- .../infer/error_reporting/need_type_info.rs | 59 ++++++++++++++----- src/librustc/traits/error_reporting.rs | 26 ++++++-- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/writeback.rs | 2 +- ...associated-types-overridden-binding.stderr | 17 ++++-- .../associated-types-unconstrained.stderr | 6 +- src/test/ui/issues/issue-12028.stderr | 6 +- src/test/ui/issues/issue-65611.stderr | 5 +- src/test/ui/question-mark-type-infer.rs | 2 +- src/test/ui/question-mark-type-infer.stderr | 11 +++- .../span/issue-42234-unknown-receiver-type.rs | 4 +- .../issue-42234-unknown-receiver-type.stderr | 7 +-- .../span/type-annotations-needed-expr.stderr | 5 +- 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 32eecdf01a31f..118fd186b1c8c 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>, 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, 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`, 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 35017d6330da3..2b00861188e82 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 a956aba4f62b9..c8f1e025baeb8 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 3113e9b241daa..e5f1e2cc34cee 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 5ef1b23cbcd21..dd6bde0c14d00 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 `::Item == i32` +error[E0284]: type annotations needed --> $DIR/associated-types-overridden-binding.rs:4:1 | LL | trait Foo: Iterator {} | ------------------------------- required by `Foo` LL | trait Bar: Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self` + | + = note: cannot resolve `::Item == i32` -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/associated-types-overridden-binding.rs:7:1 | +LL | trait I32Iterator = Iterator; + | ----------------------------------------- required by `I32Iterator` LL | trait U32Iterator = I32Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self` + | + = note: cannot resolve `::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 4e9e54d368805..14ce4836f97f8 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 ff92d01a69ed2..5f23b4f559fad 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 == ::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 == ::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 cb441c13c6b9e..905c5ae9461d0 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 95ee01a70cead..2ef8618192f6b 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 { fn g() -> Result, ()> { 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 53a170e7d431c..d32d94976451a 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 58138e21bc097..d3292bbecbaaa 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 30c9adb1dce72..093a6f6f3ebac 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 e32a542bb7a8c..1efb2720e0c55 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 From 252773af8ba86a644ccf3ff0b0cc06cc3857c7ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 29 Oct 2019 17:28:39 -0700 Subject: [PATCH 02/12] Deduplicate logic --- src/librustc/infer/error_reporting/mod.rs | 1 + .../infer/error_reporting/need_type_info.rs | 36 ++++++++-- src/librustc/traits/error_reporting.rs | 72 +++++++++---------- src/librustc_typeck/check/mod.rs | 3 +- src/librustc_typeck/check/writeback.rs | 3 +- src/test/ui/associated-const/issue-63496.rs | 4 +- .../ui/associated-const/issue-63496.stderr | 12 ++-- .../ui/associated-item/issue-48027.stderr | 6 +- src/test/ui/error-codes/E0283.stderr | 6 +- src/test/ui/issues/issue-21974.stderr | 6 +- src/test/ui/issues/issue-24424.rs | 2 +- src/test/ui/issues/issue-24424.stderr | 6 +- src/test/ui/issues/issue-29147.rs | 2 +- src/test/ui/issues/issue-29147.stderr | 6 +- src/test/ui/issues/issue-54954.stderr | 6 +- src/test/ui/issues/issue-58022.rs | 2 +- src/test/ui/issues/issue-58022.stderr | 6 +- ...ait-static-method-generic-inference.stderr | 6 +- src/test/ui/type/type-annotation-needed.rs | 2 + .../ui/type/type-annotation-needed.stderr | 6 +- .../ui/type/type-check/issue-40294.stderr | 6 +- 21 files changed, 121 insertions(+), 78 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 58c1498faa9de..c9d57706d55ea 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -70,6 +70,7 @@ use std::{cmp, fmt}; mod note; mod need_type_info; +pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 118fd186b1c8c..98134915b45d9 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -151,6 +151,25 @@ fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String { .unwrap_or_default() } +pub enum TypeAnnotationNeeded { + E0282, + E0283, + E0284, +} + +impl Into for TypeAnnotationNeeded { + fn into(self) -> errors::DiagnosticId { + syntax::diagnostic_used!(E0282); + syntax::diagnostic_used!(E0283); + syntax::diagnostic_used!(E0284); + errors::DiagnosticId::Error(match self { + Self::E0282 => "E0282".to_string(), + Self::E0283 => "E0283".to_string(), + Self::E0284 => "E0284".to_string(), + }) + } +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn extract_type_name( &self, @@ -181,7 +200,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { body_id: Option, span: Span, ty: Ty<'tcx>, - is_projection: bool, + error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); let (name, name_sp) = self.extract_type_name(&ty, None); @@ -217,7 +236,9 @@ 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 { + } 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 @@ -268,11 +289,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | consider giving `b` the explicit type `std::result::Result`, where // | the type parameter `E` is specified // ``` - 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 error_code = error_code.into(); + let mut err = self.tcx.sess.struct_span_err_with_code( + err_span, + &format!("type annotations needed{}", ty_msg), + error_code, + ); let suffix = match local_visitor.found_ty { Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2b00861188e82..6b9e413be133c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -22,6 +22,7 @@ use crate::hir; use crate::hir::Node; use crate::hir::def_id::DefId; use crate::infer::{self, InferCtxt}; +use crate::infer::error_reporting::TypeAnnotationNeeded::*; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::session::DiagnosticMessageId; use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; @@ -1951,7 +1952,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return; } - match predicate { + let mut err = match predicate { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); @@ -1985,45 +1986,35 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and dont add the obligations to // begin with in those cases. - if - self.tcx.lang_items().sized_trait() + if 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, false).emit(); - } else { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0283, - "type annotations needed: cannot resolve `{}`", - predicate, - ); - self.note_obligation_cause(&mut err, obligation); - err.emit(); + self.need_type_info_err(body_id, span, self_ty, E0282).emit(); + return; } + let mut err = self.need_type_info_err(body_id, span, self_ty, E0283); + err.note(&format!("cannot resolve `{}`", predicate)); + err } ty::Predicate::WellFormed(ty) => { // Same hacky approach as above to avoid deluging user // with error messages. - if !ty.references_error() && !self.tcx.sess.has_errors() { - let mut err = self.need_type_info_err(body_id, span, ty, false); - self.note_obligation_cause(&mut err, obligation); - err.emit(); + if ty.references_error() || self.tcx.sess.has_errors() { + return; } + self.need_type_info_err(body_id, span, ty, E0282) } ty::Predicate::Subtype(ref data) => { if data.references_error() || self.tcx.sess.has_errors() { // no need to overload user in such cases - } else { - 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()); - let mut err = self.need_type_info_err(body_id, span, a, false); - self.note_obligation_cause(&mut err, obligation); - err.emit(); + return } + 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, span, a, E0282) } ty::Predicate::Projection(ref data) => { let trait_ref = data.to_poly_trait_ref(self.tcx); @@ -2031,27 +2022,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if predicate.references_error() { return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, true); + let mut err = self.need_type_info_err(body_id, span, self_ty, E0284); err.note(&format!("cannot resolve `{}`", predicate)); - self.note_obligation_cause(&mut err, obligation); - err.emit(); + err } _ => { - if !self.tcx.sess.has_errors() { - let mut err = struct_span_err!( - self.tcx.sess, - 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(); + if self.tcx.sess.has_errors() { + return; } + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0284, + "type annotations needed: cannot resolve `{}`", + predicate, + ); + err.span_label(span, &format!("cannot resolve `{}`", predicate)); + err } - } + }; + self.note_obligation_cause(&mut err, obligation); + err.emit(); } /// Returns `true` if the trait predicate may apply for *some* assignment diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c8f1e025baeb8..43e7bbcf0c0dc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -103,6 +103,7 @@ use rustc_index::vec::Idx; use rustc_target::spec::abi::Abi; use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc::middle::region; use rustc::mir::interpret::{ConstValue, GlobalId}; @@ -5359,7 +5360,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, false) + self.need_type_info_err((**self).body_id, sp, ty, E0282) .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 e5f1e2cc34cee..35f25b322e053 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -8,6 +8,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::InferCtxt; +use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::{self, Ty, TyCtxt}; @@ -717,7 +718,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, false) + .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282) .emit(); } } diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-const/issue-63496.rs index 311c48b5e48c5..f9f663af5e265 100644 --- a/src/test/ui/associated-const/issue-63496.rs +++ b/src/test/ui/associated-const/issue-63496.rs @@ -2,8 +2,8 @@ trait A { const C: usize; fn f() -> ([u8; A::C], [u8; A::C]); - //~^ ERROR: type annotations needed: cannot resolve - //~| ERROR: type annotations needed: cannot resolve + //~^ ERROR: type annotations needed + //~| ERROR: type annotations needed } fn main() {} diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-const/issue-63496.stderr index 70bb12de1fb72..23916a3ba440c 100644 --- a/src/test/ui/associated-const/issue-63496.stderr +++ b/src/test/ui/associated-const/issue-63496.stderr @@ -1,20 +1,24 @@ -error[E0283]: type annotations needed: cannot resolve `_: A` +error[E0283]: type annotations needed --> $DIR/issue-63496.rs:4:21 | LL | const C: usize; | --------------- required by `A::C` LL | LL | fn f() -> ([u8; A::C], [u8; A::C]); - | ^^^^ + | ^^^^ cannot infer type + | + = note: cannot resolve `_: A` -error[E0283]: type annotations needed: cannot resolve `_: A` +error[E0283]: type annotations needed --> $DIR/issue-63496.rs:4:33 | LL | const C: usize; | --------------- required by `A::C` LL | LL | fn f() -> ([u8; A::C], [u8; A::C]); - | ^^^^ + | ^^^^ cannot infer type + | + = note: cannot resolve `_: A` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-item/issue-48027.stderr b/src/test/ui/associated-item/issue-48027.stderr index 562146a426d23..9c825d593d3e4 100644 --- a/src/test/ui/associated-item/issue-48027.stderr +++ b/src/test/ui/associated-item/issue-48027.stderr @@ -7,13 +7,15 @@ LL | const X: usize; LL | impl dyn Bar {} | ^^^^^^^ the trait `Bar` cannot be made into an object -error[E0283]: type annotations needed: cannot resolve `_: Bar` +error[E0283]: type annotations needed --> $DIR/issue-48027.rs:3:32 | LL | const X: usize; | --------------- required by `Bar::X` LL | fn return_n(&self) -> [u8; Bar::X]; - | ^^^^^^ + | ^^^^^^ cannot infer type + | + = note: cannot resolve `_: Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr index aba649d83ec01..ae5b7c3ae8f67 100644 --- a/src/test/ui/error-codes/E0283.stderr +++ b/src/test/ui/error-codes/E0283.stderr @@ -1,11 +1,13 @@ -error[E0283]: type annotations needed: cannot resolve `_: Generator` +error[E0283]: type annotations needed --> $DIR/E0283.rs:18:21 | LL | fn create() -> u32; | ------------------- required by `Generator::create` ... LL | let cont: u32 = Generator::create(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: cannot resolve `_: Generator` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr index 7ceb2bd23f6cd..4002c1eac2e2a 100644 --- a/src/test/ui/issues/issue-21974.stderr +++ b/src/test/ui/issues/issue-21974.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations needed: cannot resolve `&'a T: Foo` +error[E0283]: type annotations needed --> $DIR/issue-21974.rs:10:1 | LL | trait Foo { @@ -11,7 +11,9 @@ LL | | { LL | | x.foo(); LL | | y.foo(); LL | | } - | |_^ + | |_^ cannot infer type for `&'a T` + | + = note: cannot resolve `&'a T: Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24424.rs b/src/test/ui/issues/issue-24424.rs index 9b74cd1230e8a..22bf513afe891 100644 --- a/src/test/ui/issues/issue-24424.rs +++ b/src/test/ui/issues/issue-24424.rs @@ -2,6 +2,6 @@ trait Trait1<'l0, T0> {} trait Trait0<'l0> {} impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} -//~^ ERROR type annotations needed: cannot resolve `T0: Trait0<'l0>` +//~^ ERROR type annotations needed fn main() {} diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr index 8c539f7cedd19..87214f56a1b41 100644 --- a/src/test/ui/issues/issue-24424.stderr +++ b/src/test/ui/issues/issue-24424.stderr @@ -1,11 +1,13 @@ -error[E0283]: type annotations needed: cannot resolve `T0: Trait0<'l0>` +error[E0283]: type annotations needed --> $DIR/issue-24424.rs:4:1 | LL | trait Trait0<'l0> {} | ----------------- required by `Trait0` LL | LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `T0` + | + = note: cannot resolve `T0: Trait0<'l0>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-29147.rs b/src/test/ui/issues/issue-29147.rs index 7ec96b97eef07..271bc526033d4 100644 --- a/src/test/ui/issues/issue-29147.rs +++ b/src/test/ui/issues/issue-29147.rs @@ -18,5 +18,5 @@ impl Foo for S5 { fn xxx(&self) {} } impl Foo for S5 { fn xxx(&self) {} } fn main() { - let _ = >::xxx; //~ ERROR cannot resolve `S5<_>: Foo` + let _ = >::xxx; //~ ERROR type annotations needed } diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr index c9dd92fca7dc8..4de6a7c85146d 100644 --- a/src/test/ui/issues/issue-29147.stderr +++ b/src/test/ui/issues/issue-29147.stderr @@ -1,11 +1,13 @@ -error[E0283]: type annotations needed: cannot resolve `S5<_>: Foo` +error[E0283]: type annotations needed --> $DIR/issue-29147.rs:21:13 | LL | trait Foo { fn xxx(&self); } | -------------- required by `Foo::xxx` ... LL | let _ = >::xxx; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ cannot infer type for `S5<_>` + | + = note: cannot resolve `S5<_>: Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr index 56ccdaf7aac40..d99a5772e8a4c 100644 --- a/src/test/ui/issues/issue-54954.stderr +++ b/src/test/ui/issues/issue-54954.stderr @@ -4,14 +4,16 @@ error[E0379]: trait fns cannot be declared const LL | const fn const_val() -> usize { | ^^^^^ trait fns cannot be const -error[E0283]: type annotations needed: cannot resolve `_: Tt` +error[E0283]: type annotations needed --> $DIR/issue-54954.rs:3:24 | LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type ... LL | const fn const_val() -> usize { | --------- - required by this bound in `Tt::const_val` + | + = note: cannot resolve `_: Tt` error[E0080]: evaluation of constant value failed --> $DIR/issue-54954.rs:13:15 diff --git a/src/test/ui/issues/issue-58022.rs b/src/test/ui/issues/issue-58022.rs index 30527903ed0f2..e4b9b3b53a69e 100644 --- a/src/test/ui/issues/issue-58022.rs +++ b/src/test/ui/issues/issue-58022.rs @@ -2,7 +2,7 @@ pub trait Foo: Sized { const SIZE: usize; fn new(slice: &[u8; Foo::SIZE]) -> Self; - //~^ ERROR: type annotations needed: cannot resolve `_: Foo` + //~^ ERROR: type annotations needed } pub struct Bar(T); diff --git a/src/test/ui/issues/issue-58022.stderr b/src/test/ui/issues/issue-58022.stderr index a3e4cb6320240..ef0d66d7ad6d1 100644 --- a/src/test/ui/issues/issue-58022.stderr +++ b/src/test/ui/issues/issue-58022.stderr @@ -4,14 +4,16 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Foo LL | Foo(Box::new(*slice)) | ^^^ not a function, tuple struct or tuple variant -error[E0283]: type annotations needed: cannot resolve `_: Foo` +error[E0283]: type annotations needed --> $DIR/issue-58022.rs:4:25 | LL | const SIZE: usize; | ------------------ required by `Foo::SIZE` LL | LL | fn new(slice: &[u8; Foo::SIZE]) -> Self; - | ^^^^^^^^^ + | ^^^^^^^^^ cannot infer type + | + = note: cannot resolve `_: Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr index 22931c5ba32e9..f9718dac3547d 100644 --- a/src/test/ui/traits/trait-static-method-generic-inference.stderr +++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr @@ -1,11 +1,13 @@ -error[E0283]: type annotations needed: cannot resolve `_: base::HasNew` +error[E0283]: type annotations needed --> $DIR/trait-static-method-generic-inference.rs:24:25 | LL | fn new() -> T; | -------------- required by `base::HasNew::new` ... LL | let _f: base::Foo = base::HasNew::new(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: cannot resolve `_: base::HasNew` error: aborting due to previous error diff --git a/src/test/ui/type/type-annotation-needed.rs b/src/test/ui/type/type-annotation-needed.rs index 3b1521d5c028b..a420515be496d 100644 --- a/src/test/ui/type/type-annotation-needed.rs +++ b/src/test/ui/type/type-annotation-needed.rs @@ -5,4 +5,6 @@ fn foo>(x: i32) {} fn main() { foo(42); //~^ ERROR type annotations needed + //~| NOTE cannot infer type + //~| NOTE cannot resolve } diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 460bbe9dbc4f9..f30bbf6b7db5b 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -1,11 +1,13 @@ -error[E0283]: type annotations needed: cannot resolve `_: std::convert::Into` +error[E0283]: type annotations needed --> $DIR/type-annotation-needed.rs:6:5 | LL | fn foo>(x: i32) {} | --- ------------ required by this bound in `foo` ... LL | foo(42); - | ^^^ + | ^^^ cannot infer type for `T` + | + = note: cannot resolve `_: std::convert::Into` error: aborting due to previous error diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr index 508783aaf2b0e..f2bfd9ba54103 100644 --- a/src/test/ui/type/type-check/issue-40294.stderr +++ b/src/test/ui/type/type-check/issue-40294.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations needed: cannot resolve `&'a T: Foo` +error[E0283]: type annotations needed --> $DIR/issue-40294.rs:5:1 | LL | trait Foo: Sized { @@ -11,7 +11,9 @@ LL | | { LL | | x.foo(); LL | | y.foo(); LL | | } - | |_^ + | |_^ cannot infer type for `&'a T` + | + = note: cannot resolve `&'a T: Foo` error: aborting due to previous error From cca4b6d42ad984a28b9eb2dc3f62590cfc7ef421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 16 Nov 2019 12:39:45 -0800 Subject: [PATCH 03/12] Fix rebase --- src/librustc/traits/error_reporting.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 6b9e413be133c..963da85880350 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -22,7 +22,7 @@ use crate::hir; use crate::hir::Node; use crate::hir::def_id::DefId; use crate::infer::{self, InferCtxt}; -use crate::infer::error_reporting::TypeAnnotationNeeded::*; +use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::session::DiagnosticMessageId; use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; @@ -1989,10 +1989,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if 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, E0282).emit(); + self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, E0283); + let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); err.note(&format!("cannot resolve `{}`", predicate)); err } @@ -2003,7 +2003,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if ty.references_error() || self.tcx.sess.has_errors() { return; } - self.need_type_info_err(body_id, span, ty, E0282) + self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) } ty::Predicate::Subtype(ref data) => { @@ -2014,7 +2014,7 @@ 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, span, a, E0282) + self.need_type_info_err(body_id, span, a, ErrorCode::E0282) } ty::Predicate::Projection(ref data) => { let trait_ref = data.to_poly_trait_ref(self.tcx); @@ -2022,7 +2022,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if predicate.references_error() { return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, E0284); + let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); err.note(&format!("cannot resolve `{}`", predicate)); err } From 33b06362fa9207ec1beae209a39d974f6c471206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 09:01:06 -0800 Subject: [PATCH 04/12] Use the appropriate number of type arguments in suggestion --- .../infer/error_reporting/need_type_info.rs | 62 ++++++++++++++----- src/librustc/ty/context.rs | 19 ++++++ src/librustc_typeck/check/expr.rs | 21 +++++++ src/test/ui/issues/issue-65611.stderr | 8 +-- src/test/ui/question-mark-type-infer.stderr | 2 +- .../span/type-annotations-needed-expr.stderr | 2 +- 6 files changed, 93 insertions(+), 21 deletions(-) diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 98134915b45d9..c5133e8843225 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -20,7 +20,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> { found_arg_pattern: Option<&'tcx Pat>, found_ty: Option>, found_closure: Option<&'tcx ExprKind>, - found_method_call: Option<&'tcx ExprKind>, + found_method_call: Option<&'tcx Expr>, } impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { @@ -99,7 +99,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { 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), + ExprKind::MethodCall(..) => self.found_method_call = Some(&expr), _ => {} } } @@ -211,8 +211,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); let ty_vars = self.type_variables.borrow(); let getter = move |ty_vid| { - if let TypeVariableOriginKind::TypeParameterDefinition(name) = - ty_vars.var_origin(ty_vid).kind { + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind { return Some(name.to_string()); } None @@ -238,7 +238,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span } else if let Some( ExprKind::MethodCall(_, call_span, _), - ) = local_visitor.found_method_call { + ) = local_visitor.found_method_call.map(|e| &e.kind) { // Point at the call instead of the whole expression: // error[E0284]: type annotations needed // --> file.rs:2:5 @@ -375,16 +375,48 @@ 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, - ); + } else if let Some(e) = local_visitor.found_method_call { + if let ExprKind::MethodCall(segment, _call_sp, _args) = &e.kind { + if let (Ok(snippet), Some(tables), None) = ( + self.tcx.sess.source_map().span_to_snippet(segment.ident.span), + self.in_progress_tables, + &segment.args, + ) { + let borrow = tables.borrow(); + let sigs = borrow.node_method_sig(); + if let Some(sig) = sigs.get(e.hir_id) { + let mut params = vec![]; + for arg in sig.inputs_and_output().skip_binder().iter() { + if let ty::Param(param) = arg.kind { + if param.name != kw::SelfUpper { + let name = param.name.to_string(); + if !params.contains(&name) { + params.push(name); + } + } + } + } + if !params.is_empty() { + err.span_suggestion( + segment.ident.span, + &format!( + "consider specifying the type argument{} in the method call", + if params.len() > 1 { + "s" + } else { + "" + }, + ), + format!("{}::<{}>", snippet, params.join(", ")), + Applicability::HasPlaceholders, + ); + } else { + err.span_label(e.span, &format!( + "this method call resolves to `{:?}`", + sig.output().skip_binder(), + )); + } + } } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f7e422b0403dc..2da43bdcc1e26 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -338,6 +338,8 @@ pub struct TypeckTables<'tcx> { /// typeck::check::fn_ctxt for details. node_types: ItemLocalMap>, + node_method_sig: ItemLocalMap>, + /// Stores the type parameters which were substituted to obtain the type /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or @@ -442,6 +444,7 @@ impl<'tcx> TypeckTables<'tcx> { user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), + node_method_sig: Default::default(), node_substs: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), @@ -542,6 +545,20 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn node_method_sig(&self) -> LocalTableInContext<'_, ty::PolyFnSig<'tcx>> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.node_method_sig + } + } + + pub fn node_method_sig_mut(&mut self) -> LocalTableInContextMut<'_, ty::PolyFnSig<'tcx>> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.node_method_sig + } + } + pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> { self.node_type_opt(id).unwrap_or_else(|| bug!("node_type: no type for node `{}`", @@ -748,6 +765,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { ref user_provided_types, ref user_provided_sigs, ref node_types, + ref node_method_sig, ref node_substs, ref adjustments, ref pat_binding_modes, @@ -774,6 +792,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { user_provided_types.hash_stable(hcx, hasher); user_provided_sigs.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); + node_method_sig.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); pat_binding_modes.hash_stable(hcx, hasher); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 5bfc60c754067..5f971a1ad505b 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -871,6 +871,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) { Ok(method) => { + let sig = self.tcx.fn_sig(method.def_id); + // We could add a "consider `foo::`" suggestion here, but I wasn't able to + // trigger this codepath causing `structuraly_resolved_type` to emit an error. + + // We could do this only when type params are present in the method to reducte + // memory usage, but doing it unconditionally lets us also point at the method + // expression and state the resolved return value: + // ``` + // error[E0282]: type annotations needed + // --> $DIR/issue-65611.rs:59:20 + // | + // LL | let x = buffer.last().unwrap().0.clone(); + // | -------^^^^-- + // | | | + // | | cannot infer type for `T` + // | this method call resolves to `std::option::Option<&T>` + // | + // = note: type must be known at this point + // ``` + self.tables.borrow_mut().node_method_sig_mut().insert(expr.hir_id, sig); + self.write_method_call(expr.hir_id, method); Ok(method) } diff --git a/src/test/ui/issues/issue-65611.stderr b/src/test/ui/issues/issue-65611.stderr index 905c5ae9461d0..3be08b233e470 100644 --- a/src/test/ui/issues/issue-65611.stderr +++ b/src/test/ui/issues/issue-65611.stderr @@ -2,10 +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` - | help: consider specifying the type argument in the method call: `last::<_>` + | -------^^^^-- + | | | + | | cannot infer type for `T` + | this method call resolves to `std::option::Option<&T>` | = note: type must be known at this point diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index d32d94976451a..7911701946cd3 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -5,7 +5,7 @@ LL | l.iter().map(f).collect()? | ^^^^^^^ | | | cannot infer type - | help: consider specifying the type argument in the method call: `collect::<_>` + | help: consider specifying the type argument in the method call: `collect::` | = note: cannot resolve `<_ as std::ops::Try>::Ok == _` diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr index 1efb2720e0c55..bc1c2f6164b61 100644 --- a/src/test/ui/span/type-annotations-needed-expr.stderr +++ b/src/test/ui/span/type-annotations-needed-expr.stderr @@ -5,7 +5,7 @@ LL | let _ = (vec![1,2,3]).into_iter().sum() as f64; | ^^^ | | | cannot infer type for `S` - | help: consider specifying the type argument in the method call: `sum::<_>` + | help: consider specifying the type argument in the method call: `sum::` | = note: type must be known at this point From 6b76d82b1395e42693cf227169ef2bfd32b8418e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 10:30:08 -0800 Subject: [PATCH 05/12] Move suggestion code to its own method --- .../infer/error_reporting/need_type_info.rs | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index c5133e8843225..55a95d0569848 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -376,48 +376,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; err.span_label(pattern.span, msg); } else if let Some(e) = local_visitor.found_method_call { - if let ExprKind::MethodCall(segment, _call_sp, _args) = &e.kind { - if let (Ok(snippet), Some(tables), None) = ( - self.tcx.sess.source_map().span_to_snippet(segment.ident.span), - self.in_progress_tables, - &segment.args, - ) { - let borrow = tables.borrow(); - let sigs = borrow.node_method_sig(); - if let Some(sig) = sigs.get(e.hir_id) { - let mut params = vec![]; - for arg in sig.inputs_and_output().skip_binder().iter() { - if let ty::Param(param) = arg.kind { - if param.name != kw::SelfUpper { - let name = param.name.to_string(); - if !params.contains(&name) { - params.push(name); - } - } - } - } - if !params.is_empty() { - err.span_suggestion( - segment.ident.span, - &format!( - "consider specifying the type argument{} in the method call", - if params.len() > 1 { - "s" - } else { - "" - }, - ), - format!("{}::<{}>", snippet, params.join(", ")), - Applicability::HasPlaceholders, - ); - } else { - err.span_label(e.span, &format!( - "this method call resolves to `{:?}`", - sig.output().skip_binder(), - )); - } - } - } + if let ExprKind::MethodCall(segment, ..) = &e.kind { + // Suggest specifiying type params or point out the return type of the call. + self.annotate_method_call(segment, e, &mut err); } } // Instead of the following: @@ -447,6 +408,57 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } + /// If the `FnSig` for the method call can be found and type arguments are identified as + /// needed, suggest annotating the call, otherwise point out the resulting type of the call. + fn annotate_method_call( + &self, + segment: &hir::ptr::P, + e: &Expr, + err: &mut DiagnosticBuilder<'_>, + ) { + if let (Ok(snippet), Some(tables), None) = ( + self.tcx.sess.source_map().span_to_snippet(segment.ident.span), + self.in_progress_tables, + &segment.args, + ) { + let borrow = tables.borrow(); + let sigs = borrow.node_method_sig(); + if let Some(sig) = sigs.get(e.hir_id) { + let mut params = vec![]; + for arg in sig.inputs_and_output().skip_binder().iter() { + if let ty::Param(param) = arg.kind { + if param.name != kw::SelfUpper { + let name = param.name.to_string(); + if !params.contains(&name) { + params.push(name); + } + } + } + } + if !params.is_empty() { + err.span_suggestion( + segment.ident.span, + &format!( + "consider specifying the type argument{} in the method call", + if params.len() > 1 { + "s" + } else { + "" + }, + ), + format!("{}::<{}>", snippet, params.join(", ")), + Applicability::HasPlaceholders, + ); + } else { + err.span_label(e.span, &format!( + "this method call resolves to `{:?}`", + sig.output().skip_binder(), + )); + } + } + } + } + pub fn need_type_info_err_in_generator( &self, kind: hir::GeneratorKind, From 5d1adbb629623b10324ba32a0ff2179b9358cab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 11:05:16 -0800 Subject: [PATCH 06/12] Use `generics_of` instead of incorrectly inspecting `FnSig` arguments --- .../infer/error_reporting/need_type_info.rs | 53 +++++++++++++------ src/librustc/ty/context.rs | 16 +++--- src/librustc_typeck/check/expr.rs | 6 ++- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 55a95d0569848..487736dee30d0 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -377,7 +377,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(pattern.span, msg); } else if let Some(e) = local_visitor.found_method_call { if let ExprKind::MethodCall(segment, ..) = &e.kind { - // Suggest specifiying type params or point out the return type of the call. + // Suggest specifiying type params or point out the return type of the call: + // + // error[E0282]: type annotations needed + // --> $DIR/type-annotations-needed-expr.rs:2:39 + // | + // LL | let _ = x.into_iter().sum() as f64; + // | ^^^ + // | | + // | cannot infer type for `S` + // | help: consider specifying the type argument in + // | the method call: `sum::` + // | + // = note: type must be known at this point + // + // or + // + // error[E0282]: type annotations needed + // --> $DIR/issue-65611.rs:59:20 + // | + // LL | let x = buffer.last().unwrap().0.clone(); + // | -------^^^^-- + // | | | + // | | cannot infer type for `T` + // | this method call resolves to `std::option::Option<&T>` + // | + // = note: type must be known at this point self.annotate_method_call(segment, e, &mut err); } } @@ -422,34 +447,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &segment.args, ) { let borrow = tables.borrow(); - let sigs = borrow.node_method_sig(); - if let Some(sig) = sigs.get(e.hir_id) { - let mut params = vec![]; - for arg in sig.inputs_and_output().skip_binder().iter() { - if let ty::Param(param) = arg.kind { - if param.name != kw::SelfUpper { - let name = param.name.to_string(); - if !params.contains(&name) { - params.push(name); - } - } - } - } - if !params.is_empty() { + let method_defs = borrow.node_method_def_id(); + if let Some(did) = method_defs.get(e.hir_id) { + let generics = self.tcx.generics_of(*did); + if !generics.params.is_empty() { err.span_suggestion( segment.ident.span, &format!( "consider specifying the type argument{} in the method call", - if params.len() > 1 { + if generics.params.len() > 1 { "s" } else { "" }, ), - format!("{}::<{}>", snippet, params.join(", ")), + format!("{}::<{}>", snippet, generics.params.iter() + .map(|p| p.name.to_string()) + .collect::>() + .join(", ")), Applicability::HasPlaceholders, ); } else { + let sig = self.tcx.fn_sig(*did); err.span_label(e.span, &format!( "this method call resolves to `{:?}`", sig.output().skip_binder(), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2da43bdcc1e26..fa4ad021072de 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -338,7 +338,7 @@ pub struct TypeckTables<'tcx> { /// typeck::check::fn_ctxt for details. node_types: ItemLocalMap>, - node_method_sig: ItemLocalMap>, + node_method_def_id: ItemLocalMap, /// Stores the type parameters which were substituted to obtain the type /// of this node. This only applies to nodes that refer to entities @@ -444,7 +444,7 @@ impl<'tcx> TypeckTables<'tcx> { user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), - node_method_sig: Default::default(), + node_method_def_id: Default::default(), node_substs: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), @@ -545,17 +545,17 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn node_method_sig(&self) -> LocalTableInContext<'_, ty::PolyFnSig<'tcx>> { + pub fn node_method_def_id(&self) -> LocalTableInContext<'_, DefId> { LocalTableInContext { local_id_root: self.local_id_root, - data: &self.node_method_sig + data: &self.node_method_def_id } } - pub fn node_method_sig_mut(&mut self) -> LocalTableInContextMut<'_, ty::PolyFnSig<'tcx>> { + pub fn node_method_def_id_mut(&mut self) -> LocalTableInContextMut<'_, DefId> { LocalTableInContextMut { local_id_root: self.local_id_root, - data: &mut self.node_method_sig + data: &mut self.node_method_def_id } } @@ -765,7 +765,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { ref user_provided_types, ref user_provided_sigs, ref node_types, - ref node_method_sig, + ref node_method_def_id, ref node_substs, ref adjustments, ref pat_binding_modes, @@ -792,7 +792,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { user_provided_types.hash_stable(hcx, hasher); user_provided_sigs.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); - node_method_sig.hash_stable(hcx, hasher); + node_method_def_id.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); pat_binding_modes.hash_stable(hcx, hasher); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 5f971a1ad505b..999038e7ea790 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -871,7 +871,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) { Ok(method) => { - let sig = self.tcx.fn_sig(method.def_id); // We could add a "consider `foo::`" suggestion here, but I wasn't able to // trigger this codepath causing `structuraly_resolved_type` to emit an error. @@ -890,7 +889,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // | // = note: type must be known at this point // ``` - self.tables.borrow_mut().node_method_sig_mut().insert(expr.hir_id, sig); + self.tables.borrow_mut().node_method_def_id_mut().insert( + expr.hir_id, + method.def_id, + ); self.write_method_call(expr.hir_id, method); Ok(method) From 2924d38dd9ba0502264d5b8652ffd65f3f43f0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 11:14:49 -0800 Subject: [PATCH 07/12] Add tests --- .../type-inference/or_else-multiple-type-params.rs | 10 ++++++++++ .../or_else-multiple-type-params.stderr | 12 ++++++++++++ src/test/ui/type-inference/sort_by_key.rs | 5 +++++ src/test/ui/type-inference/sort_by_key.stderr | 11 +++++++++++ 4 files changed, 38 insertions(+) create mode 100644 src/test/ui/type-inference/or_else-multiple-type-params.rs create mode 100644 src/test/ui/type-inference/or_else-multiple-type-params.stderr create mode 100644 src/test/ui/type-inference/sort_by_key.rs create mode 100644 src/test/ui/type-inference/sort_by_key.stderr diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.rs b/src/test/ui/type-inference/or_else-multiple-type-params.rs new file mode 100644 index 0000000000000..b15de2a4559d5 --- /dev/null +++ b/src/test/ui/type-inference/or_else-multiple-type-params.rs @@ -0,0 +1,10 @@ +use std::process::{Command, Stdio}; + +fn main() { + let process = Command::new("wc") + .stdout(Stdio::piped()) + .spawn() + .or_else(|err| { //~ ERROR type annotations needed + panic!("oh no: {:?}", err); + }).unwrap(); +} diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr new file mode 100644 index 0000000000000..a15904d01f64e --- /dev/null +++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr @@ -0,0 +1,12 @@ +error[E0282]: type annotations needed + --> $DIR/or_else-multiple-type-params.rs:7:10 + | +LL | .or_else(|err| { + | ^^^^^^^ + | | + | cannot infer type for `F` + | help: consider specifying the type arguments in the method call: `or_else::` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-inference/sort_by_key.rs b/src/test/ui/type-inference/sort_by_key.rs new file mode 100644 index 0000000000000..afc4d90b8650f --- /dev/null +++ b/src/test/ui/type-inference/sort_by_key.rs @@ -0,0 +1,5 @@ +fn main() { + let mut lst: [([i32; 10], bool); 10] = [([0; 10], false); 10]; + lst.sort_by_key(|&(v, _)| v.iter().sum()); //~ ERROR type annotations needed + println!("{:?}", lst); +} diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr new file mode 100644 index 0000000000000..76b49ee1f23e4 --- /dev/null +++ b/src/test/ui/type-inference/sort_by_key.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/sort_by_key.rs:3:9 + | +LL | lst.sort_by_key(|&(v, _)| v.iter().sum()); + | ^^^^^^^^^^^ --- help: consider specifying the type argument in the method call: `sum::` + | | + | cannot infer type for `K` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From cc1ab3db8ba655508a6c8f649b2de32161a29f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 11:50:18 -0800 Subject: [PATCH 08/12] Suggest setting type param on function call --- src/librustc/traits/error_reporting.rs | 24 +++++++++++++++++++ .../ui/type/type-annotation-needed.stderr | 5 +++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 963da85880350..b8200a8e17331 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1994,6 +1994,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); err.note(&format!("cannot resolve `{}`", predicate)); + if let (Ok(ref snippet), ObligationCauseCode::BindingObligation(ref def_id, _)) = ( + self.tcx.sess.source_map().span_to_snippet(span), + &obligation.cause.code, + ) { + let generics = self.tcx.generics_of(*def_id); + if !generics.params.is_empty() { + err.span_suggestion( + span, + &format!( + "consider specifying the type argument{} in the function call", + if generics.params.len() > 1 { + "s" + } else { + "" + }, + ), + format!("{}::<{}>", snippet, generics.params.iter() + .map(|p| p.name.to_string()) + .collect::>() + .join(", ")), + Applicability::HasPlaceholders, + ); + } + } err } diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index f30bbf6b7db5b..5b7d6ba16d02d 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -5,7 +5,10 @@ LL | fn foo>(x: i32) {} | --- ------------ required by this bound in `foo` ... LL | foo(42); - | ^^^ cannot infer type for `T` + | ^^^ + | | + | cannot infer type for `T` + | help: consider specifying the type argument in the function call: `foo::` | = note: cannot resolve `_: std::convert::Into` From 860c7e425ba07a4f5f9a5d5990227a857378a8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 12:02:01 -0800 Subject: [PATCH 09/12] missing test change, bad suggestion --- src/test/ui/issues/issue-54954.stderr | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr index d99a5772e8a4c..21909baf3ba88 100644 --- a/src/test/ui/issues/issue-54954.stderr +++ b/src/test/ui/issues/issue-54954.stderr @@ -8,7 +8,10 @@ error[E0283]: type annotations needed --> $DIR/issue-54954.rs:3:24 | LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | cannot infer type + | help: consider specifying the type argument in the function call: `Tt::const_val::<[i8; 123]>::` ... LL | const fn const_val() -> usize { | --------- - required by this bound in `Tt::const_val` From 94ab9ec36bd3401b3185aff7b623ff0317b96356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Dec 2019 14:15:38 -0800 Subject: [PATCH 10/12] Avoid invalid suggestion by checking the snippet in const fn call --- src/librustc/traits/error_reporting.rs | 23 ++++++++++++++++++++++- src/test/ui/issues/issue-54954.stderr | 5 +---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b8200a8e17331..233d195766fe6 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1999,7 +1999,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &obligation.cause.code, ) { let generics = self.tcx.generics_of(*def_id); - if !generics.params.is_empty() { + if !generics.params.is_empty() && !snippet.ends_with('>'){ + // FIXME: To avoid spurious suggestions in functions where type arguments + // where already supplied, we check the snippet to make sure it doesn't + // end with a turbofish. Ideally we would have access to a `PathSegment` + // instead. Otherwise we would produce the following output: + // + // error[E0283]: type annotations needed + // --> $DIR/issue-54954.rs:3:24 + // | + // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); + // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // | | + // | cannot infer type + // | help: consider specifying the type argument + // | in the function call: + // | `Tt::const_val::<[i8; 123]>::` + // ... + // LL | const fn const_val() -> usize { + // | --------- - required by this bound in `Tt::const_val` + // | + // = note: cannot resolve `_: Tt` + err.span_suggestion( span, &format!( diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr index 21909baf3ba88..d99a5772e8a4c 100644 --- a/src/test/ui/issues/issue-54954.stderr +++ b/src/test/ui/issues/issue-54954.stderr @@ -8,10 +8,7 @@ error[E0283]: type annotations needed --> $DIR/issue-54954.rs:3:24 | LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | cannot infer type - | help: consider specifying the type argument in the function call: `Tt::const_val::<[i8; 123]>::` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type ... LL | const fn const_val() -> usize { | --------- - required by this bound in `Tt::const_val` From 45550ef2ff47020ab8af5feb08669c8c4ab879e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 11 Dec 2019 15:33:45 -0800 Subject: [PATCH 11/12] =?UTF-8?q?Reuse=20existing=20HirId=20=E2=86=92=20De?= =?UTF-8?q?fId=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infer/error_reporting/need_type_info.rs | 9 ++++----- src/librustc/ty/context.rs | 19 ------------------ src/librustc_typeck/check/expr.rs | 20 ------------------- 3 files changed, 4 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 487736dee30d0..4baab0492a5a5 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -1,4 +1,4 @@ -use crate::hir::def::Namespace; +use crate::hir::def::{DefKind, Namespace}; use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat}; use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; use crate::infer::InferCtxt; @@ -447,9 +447,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &segment.args, ) { let borrow = tables.borrow(); - let method_defs = borrow.node_method_def_id(); - if let Some(did) = method_defs.get(e.hir_id) { - let generics = self.tcx.generics_of(*did); + if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) { + let generics = self.tcx.generics_of(did); if !generics.params.is_empty() { err.span_suggestion( segment.ident.span, @@ -468,7 +467,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::HasPlaceholders, ); } else { - let sig = self.tcx.fn_sig(*did); + let sig = self.tcx.fn_sig(did); err.span_label(e.span, &format!( "this method call resolves to `{:?}`", sig.output().skip_binder(), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fa4ad021072de..f7e422b0403dc 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -338,8 +338,6 @@ pub struct TypeckTables<'tcx> { /// typeck::check::fn_ctxt for details. node_types: ItemLocalMap>, - node_method_def_id: ItemLocalMap, - /// Stores the type parameters which were substituted to obtain the type /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or @@ -444,7 +442,6 @@ impl<'tcx> TypeckTables<'tcx> { user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), - node_method_def_id: Default::default(), node_substs: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), @@ -545,20 +542,6 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn node_method_def_id(&self) -> LocalTableInContext<'_, DefId> { - LocalTableInContext { - local_id_root: self.local_id_root, - data: &self.node_method_def_id - } - } - - pub fn node_method_def_id_mut(&mut self) -> LocalTableInContextMut<'_, DefId> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.node_method_def_id - } - } - pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> { self.node_type_opt(id).unwrap_or_else(|| bug!("node_type: no type for node `{}`", @@ -765,7 +748,6 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { ref user_provided_types, ref user_provided_sigs, ref node_types, - ref node_method_def_id, ref node_substs, ref adjustments, ref pat_binding_modes, @@ -792,7 +774,6 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { user_provided_types.hash_stable(hcx, hasher); user_provided_sigs.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); - node_method_def_id.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); pat_binding_modes.hash_stable(hcx, hasher); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 999038e7ea790..fc7d19766373a 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -874,26 +874,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We could add a "consider `foo::`" suggestion here, but I wasn't able to // trigger this codepath causing `structuraly_resolved_type` to emit an error. - // We could do this only when type params are present in the method to reducte - // memory usage, but doing it unconditionally lets us also point at the method - // expression and state the resolved return value: - // ``` - // error[E0282]: type annotations needed - // --> $DIR/issue-65611.rs:59:20 - // | - // LL | let x = buffer.last().unwrap().0.clone(); - // | -------^^^^-- - // | | | - // | | cannot infer type for `T` - // | this method call resolves to `std::option::Option<&T>` - // | - // = note: type must be known at this point - // ``` - self.tables.borrow_mut().node_method_def_id_mut().insert( - expr.hir_id, - method.def_id, - ); - self.write_method_call(expr.hir_id, method); Ok(method) } From da023c0c6f3cdc72d72ef047c2dadb1a59c646df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 11 Dec 2019 17:06:24 -0800 Subject: [PATCH 12/12] Add more context for type parameters --- .../infer/error_reporting/need_type_info.rs | 42 ++++++++++++------- ...associated-types-overridden-binding.stderr | 4 +- .../ui/async-await/unresolved_type_param.rs | 2 +- .../async-await/unresolved_type_param.stderr | 2 +- .../cannot-infer-const-args.stderr | 2 +- .../fn-const-param-infer.stderr | 2 +- src/test/ui/consts/issue-64662.stderr | 4 +- src/test/ui/error-codes/E0401.stderr | 2 +- src/test/ui/issues/issue-12028.stderr | 2 +- src/test/ui/issues/issue-16966.stderr | 2 +- src/test/ui/issues/issue-17551.stderr | 2 +- src/test/ui/issues/issue-21974.stderr | 2 +- src/test/ui/issues/issue-24424.stderr | 2 +- src/test/ui/issues/issue-25368.stderr | 2 +- src/test/ui/issues/issue-29147.stderr | 2 +- src/test/ui/issues/issue-5062.stderr | 2 +- src/test/ui/issues/issue-6458-2.stderr | 2 +- src/test/ui/issues/issue-6458-3.stderr | 2 +- src/test/ui/issues/issue-6458.stderr | 2 +- src/test/ui/issues/issue-65611.stderr | 2 +- ...od-ambig-one-trait-unknown-int-type.stderr | 2 +- .../missing-type-parameter.stderr | 2 +- .../issue-42234-unknown-receiver-type.stderr | 2 +- .../span/type-annotations-needed-expr.stderr | 2 +- ...ts-multidispatch-convert-ambig-dest.stderr | 2 +- .../or_else-multiple-type-params.stderr | 2 +- src/test/ui/type-inference/sort_by_key.stderr | 2 +- .../unbounded-associated-type.rs | 16 +++++++ .../unbounded-associated-type.stderr | 15 +++++++ ...ounded-type-param-in-fn-with-assoc-type.rs | 9 ++++ ...ed-type-param-in-fn-with-assoc-type.stderr | 9 ++++ .../unbounded-type-param-in-fn.rs | 7 ++++ .../unbounded-type-param-in-fn.stderr | 9 ++++ .../ui/type/type-annotation-needed.stderr | 2 +- .../cannot_infer_local_or_vec.stderr | 2 +- ...cannot_infer_local_or_vec_in_tuples.stderr | 2 +- .../ui/type/type-check/issue-22897.stderr | 2 +- .../ui/type/type-check/issue-40294.stderr | 2 +- src/test/ui/unconstrained-none.stderr | 2 +- src/test/ui/unconstrained-ref.stderr | 2 +- src/test/ui/vector-no-ann.stderr | 2 +- 41 files changed, 128 insertions(+), 51 deletions(-) create mode 100644 src/test/ui/type-inference/unbounded-associated-type.rs create mode 100644 src/test/ui/type-inference/unbounded-associated-type.stderr create mode 100644 src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs create mode 100644 src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr create mode 100644 src/test/ui/type-inference/unbounded-type-param-in-fn.rs create mode 100644 src/test/ui/type-inference/unbounded-type-param-in-fn.stderr diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 4baab0492a5a5..8878683f3a7a4 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -9,6 +9,7 @@ use syntax::source_map::DesugaringKind; use syntax::symbol::kw; use syntax_pos::Span; use errors::{Applicability, DiagnosticBuilder}; +use std::borrow::Cow; use rustc_error_codes::*; @@ -113,6 +114,7 @@ fn closure_return_type_suggestion( err: &mut DiagnosticBuilder<'_>, output: &FunctionRetTy, body: &Body, + descr: &str, name: &str, ret: &str, ) { @@ -136,7 +138,7 @@ fn closure_return_type_suggestion( suggestion, Applicability::HasPlaceholders, ); - err.span_label(span, InferCtxt::missing_type_msg(&name)); + err.span_label(span, InferCtxt::missing_type_msg(&name, &descr)); } /// Given a closure signature, return a `String` containing a list of all its argument types. @@ -175,13 +177,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, highlight: Option, - ) -> (String, Option) { + ) -> (String, Option, Cow<'static, str>) { if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { let ty_vars = self.type_variables.borrow(); let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind { if name != kw::SelfUpper { - return (name.to_string(), Some(var_origin.span)); + return ( + name.to_string(), + Some(var_origin.span), + "type parameter".into(), + ); } } } @@ -192,7 +198,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - (s, None) + (s, None, ty.prefix_string()) } pub fn need_type_info_err( @@ -203,7 +209,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp) = self.extract_type_name(&ty, None); + let (name, name_sp, descr) = self.extract_type_name(&ty, None); let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir()); let ty_to_string = |ty: Ty<'tcx>| -> String { @@ -308,6 +314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &mut err, &decl.output, &body, + &descr, &name, &ret, ); @@ -427,7 +434,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span_label.label.is_some() && span_label.span == span }) && local_visitor.found_arg_pattern.is_none() { // Avoid multiple labels pointing at `span`. - err.span_label(span, InferCtxt::missing_type_msg(&name)); + err.span_label(span, InferCtxt::missing_type_msg(&name, &descr)); } err @@ -468,10 +475,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } else { let sig = self.tcx.fn_sig(did); - err.span_label(e.span, &format!( - "this method call resolves to `{:?}`", - sig.output().skip_binder(), - )); + let bound_output = sig.output(); + let output = bound_output.skip_binder(); + err.span_label(e.span, &format!("this method call resolves to `{:?}`", output)); + let kind = &output.kind; + if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind { + if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) { + err.span_label(span, &format!("`{:?}` defined here", output)); + } + } } } } @@ -484,19 +496,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let name = self.extract_type_name(&ty, None).0; + let (name, _, descr) = self.extract_type_name(&ty, None); let mut err = struct_span_err!( self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind, ); - err.span_label(span, InferCtxt::missing_type_msg(&name)); + err.span_label(span, InferCtxt::missing_type_msg(&name, &descr)); err } - fn missing_type_msg(type_name: &str) -> String { + fn missing_type_msg(type_name: &str, descr: &str) -> Cow<'static, str>{ if type_name == "_" { - "cannot infer type".to_owned() + "cannot infer type".into() } else { - format!("cannot infer type for `{}`", type_name) + format!("cannot infer type for {} `{}`", descr, type_name).into() } } } 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 dd6bde0c14d00..069da955b674e 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -4,7 +4,7 @@ error[E0284]: type annotations needed LL | trait Foo: Iterator {} | ------------------------------- required by `Foo` LL | trait Bar: Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self` | = note: cannot resolve `::Item == i32` @@ -14,7 +14,7 @@ error[E0284]: type annotations needed LL | trait I32Iterator = Iterator; | ----------------------------------------- required by `I32Iterator` LL | trait U32Iterator = I32Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Self` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self` | = note: cannot resolve `::Item == i32` diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs index 2876f9fea0e00..79c043b701ddb 100644 --- a/src/test/ui/async-await/unresolved_type_param.rs +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -8,7 +8,7 @@ async fn bar() -> () {} async fn foo() { bar().await; //~^ ERROR type inside `async fn` body must be known in this context - //~| NOTE cannot infer type for `T` + //~| NOTE cannot infer type for type parameter `T` //~| NOTE the type is part of the `async fn` body because of this `await` //~| NOTE in this expansion of desugaring of `await` } diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr index c7866fc774415..b9b4f5133b9a7 100644 --- a/src/test/ui/async-await/unresolved_type_param.stderr +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -2,7 +2,7 @@ error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 | LL | bar().await; - | ^^^ cannot infer type for `T` + | ^^^ cannot infer type for type parameter `T` | note: the type is part of the `async fn` body because of this `await` --> $DIR/unresolved_type_param.rs:9:5 diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr index 32adc63156a37..8379cbd4908e9 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.stderr +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -10,7 +10,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:9:5 | LL | foo(); - | ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}` + | ^^^ cannot infer type for fn item `fn() -> usize {foo::<_: usize>}` error: aborting due to previous error diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 2d9b6edb8a26a..9ccad7bcdd7e6 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -30,7 +30,7 @@ error[E0282]: type annotations needed --> $DIR/fn-const-param-infer.rs:22:23 | LL | let _ = Checked::; - | ^^^^^^^ cannot infer type for `T` + | ^^^^^^^ cannot infer type for type parameter `T` error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:25:40 diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr index b81daae330bfa..b3c673ec027ef 100644 --- a/src/test/ui/consts/issue-64662.stderr +++ b/src/test/ui/consts/issue-64662.stderr @@ -2,13 +2,13 @@ error[E0282]: type annotations needed --> $DIR/issue-64662.rs:2:9 | LL | A = foo(), - | ^^^ cannot infer type for `T` + | ^^^ cannot infer type for type parameter `T` error[E0282]: type annotations needed --> $DIR/issue-64662.rs:3:9 | LL | B = foo(), - | ^^^ cannot infer type for `T` + | ^^^ cannot infer type for type parameter `T` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 485b76a09a3c4..0adf982d71c90 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -36,7 +36,7 @@ error[E0282]: type annotations needed --> $DIR/E0401.rs:11:5 | LL | bfnr(x); - | ^^^^ cannot infer type for `U` + | ^^^^ cannot infer type for type parameter `U` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index 5f23b4f559fad..5f2dd729c739f 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -2,7 +2,7 @@ error[E0284]: type annotations needed --> $DIR/issue-12028.rs:27:14 | LL | self.input_stream(&mut stream); - | ^^^^^^^^^^^^ cannot infer type for `H` + | ^^^^^^^^^^^^ cannot infer type for type parameter `H` | = note: cannot resolve `<_ as StreamHasher>::S == ::S` diff --git a/src/test/ui/issues/issue-16966.stderr b/src/test/ui/issues/issue-16966.stderr index 13e77fe3073ca..0d565af79b5de 100644 --- a/src/test/ui/issues/issue-16966.stderr +++ b/src/test/ui/issues/issue-16966.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-16966.rs:2:5 | LL | panic!(std::default::Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `M` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr index ce16f0f58eaf0..5468268e7de94 100644 --- a/src/test/ui/issues/issue-17551.stderr +++ b/src/test/ui/issues/issue-17551.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `B` --> $DIR/issue-17551.rs:6:15 | LL | let foo = B(marker::PhantomData); - | --- ^ cannot infer type for `T` + | --- ^ cannot infer type for type parameter `T` | | | consider giving `foo` the explicit type `B`, where the type parameter `T` is specified diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr index 4002c1eac2e2a..b1536bd8ddb0a 100644 --- a/src/test/ui/issues/issue-21974.stderr +++ b/src/test/ui/issues/issue-21974.stderr @@ -11,7 +11,7 @@ LL | | { LL | | x.foo(); LL | | y.foo(); LL | | } - | |_^ cannot infer type for `&'a T` + | |_^ cannot infer type for reference `&'a T` | = note: cannot resolve `&'a T: Foo` diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr index 87214f56a1b41..8f0850328b446 100644 --- a/src/test/ui/issues/issue-24424.stderr +++ b/src/test/ui/issues/issue-24424.stderr @@ -5,7 +5,7 @@ LL | trait Trait0<'l0> {} | ----------------- required by `Trait0` LL | LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `T0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T0` | = note: cannot resolve `T0: Trait0<'l0>` diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index 0b890b573da13..de020d4b56ba1 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -5,7 +5,7 @@ LL | let (tx, rx) = channel(); | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified ... LL | tx.send(Foo{ foo: PhantomData }); - | ^^^ cannot infer type for `T` + | ^^^ cannot infer type for type parameter `T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr index 4de6a7c85146d..1efedb45cace7 100644 --- a/src/test/ui/issues/issue-29147.stderr +++ b/src/test/ui/issues/issue-29147.stderr @@ -5,7 +5,7 @@ LL | trait Foo { fn xxx(&self); } | -------------- required by `Foo::xxx` ... LL | let _ = >::xxx; - | ^^^^^^^^^^^^ cannot infer type for `S5<_>` + | ^^^^^^^^^^^^ cannot infer type for struct `S5<_>` | = note: cannot resolve `S5<_>: Foo` diff --git a/src/test/ui/issues/issue-5062.stderr b/src/test/ui/issues/issue-5062.stderr index 0f5c6d8d4bf9a..a20118d691170 100644 --- a/src/test/ui/issues/issue-5062.stderr +++ b/src/test/ui/issues/issue-5062.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-5062.rs:1:29 | LL | fn main() { format!("{:?}", None); } - | ^^^^ cannot infer type for `T` + | ^^^^ cannot infer type for type parameter `T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6458-2.stderr b/src/test/ui/issues/issue-6458-2.stderr index b5da2bf096cb3..d538a69045f32 100644 --- a/src/test/ui/issues/issue-6458-2.stderr +++ b/src/test/ui/issues/issue-6458-2.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-6458-2.rs:3:21 | LL | format!("{:?}", None); - | ^^^^ cannot infer type for `T` + | ^^^^ cannot infer type for type parameter `T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr index 784497c959d6c..6b3f469ee3789 100644 --- a/src/test/ui/issues/issue-6458-3.stderr +++ b/src/test/ui/issues/issue-6458-3.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-6458-3.rs:4:5 | LL | mem::transmute(0); - | ^^^^^^^^^^^^^^ cannot infer type for `U` + | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6458.stderr b/src/test/ui/issues/issue-6458.stderr index d59d872ba93b0..de315659b6df9 100644 --- a/src/test/ui/issues/issue-6458.stderr +++ b/src/test/ui/issues/issue-6458.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-6458.rs:9:4 | LL | foo(TypeWithState(marker::PhantomData)); - | ^^^ cannot infer type for `State` + | ^^^ cannot infer type for type parameter `State` 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 3be08b233e470..20e2ba144d926 100644 --- a/src/test/ui/issues/issue-65611.stderr +++ b/src/test/ui/issues/issue-65611.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x = buffer.last().unwrap().0.clone(); | -------^^^^-- | | | - | | cannot infer type for `T` + | | cannot infer type for type parameter `T` | this method call resolves to `std::option::Option<&T>` | = note: type must be known at this point diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index fcd976475686f..f3f3c4768095c 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `std::vec::Vec` --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17 | LL | let mut x = Vec::new(); - | ----- ^^^^^^^^ cannot infer type for `T` + | ----- ^^^^^^^^ cannot infer type for type parameter `T` | | | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified diff --git a/src/test/ui/missing/missing-items/missing-type-parameter.stderr b/src/test/ui/missing/missing-items/missing-type-parameter.stderr index dbb467d60f9ec..be97f2373c313 100644 --- a/src/test/ui/missing/missing-items/missing-type-parameter.stderr +++ b/src/test/ui/missing/missing-items/missing-type-parameter.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/missing-type-parameter.rs:4:5 | LL | foo(); - | ^^^ cannot infer type for `X` + | ^^^ cannot infer type for type parameter `X` error: aborting due to previous error 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 093a6f6f3ebac..9824d879dbdd2 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `std::option::Option<_>` LL | let x: Option<_> = None; | - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified LL | x.unwrap().method_that_could_exist_on_some_type(); - | ^^^^^^ cannot infer type for `T` + | ^^^^^^ cannot infer type for type parameter `T` | = 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 bc1c2f6164b61..8366285edcda8 100644 --- a/src/test/ui/span/type-annotations-needed-expr.stderr +++ b/src/test/ui/span/type-annotations-needed-expr.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let _ = (vec![1,2,3]).into_iter().sum() as f64; | ^^^ | | - | cannot infer type for `S` + | cannot infer type for type parameter `S` | help: consider specifying the type argument in the method call: `sum::` | = note: type must be known at this point diff --git a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr index d7d27049f431b..7bcda234c4b0d 100644 --- a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr +++ b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/traits-multidispatch-convert-ambig-dest.rs:26:5 | LL | test(22, std::default::Default::default()); - | ^^^^ cannot infer type for `U` + | ^^^^ cannot infer type for type parameter `U` error: aborting due to previous error diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr index a15904d01f64e..141cc25ffe22d 100644 --- a/src/test/ui/type-inference/or_else-multiple-type-params.stderr +++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | .or_else(|err| { | ^^^^^^^ | | - | cannot infer type for `F` + | cannot infer type for type parameter `F` | help: consider specifying the type arguments in the method call: `or_else::` error: aborting due to previous error diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr index 76b49ee1f23e4..1d386bd1f42c9 100644 --- a/src/test/ui/type-inference/sort_by_key.stderr +++ b/src/test/ui/type-inference/sort_by_key.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | lst.sort_by_key(|&(v, _)| v.iter().sum()); | ^^^^^^^^^^^ --- help: consider specifying the type argument in the method call: `sum::` | | - | cannot infer type for `K` + | cannot infer type for type parameter `K` error: aborting due to previous error diff --git a/src/test/ui/type-inference/unbounded-associated-type.rs b/src/test/ui/type-inference/unbounded-associated-type.rs new file mode 100644 index 0000000000000..0167e943612d0 --- /dev/null +++ b/src/test/ui/type-inference/unbounded-associated-type.rs @@ -0,0 +1,16 @@ +trait T { + type A; + fn foo(&self) -> Self::A { + panic!() + } +} + +struct S(std::marker::PhantomData); + +impl T for S { + type A = X; +} + +fn main() { + S(std::marker::PhantomData).foo(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/type-inference/unbounded-associated-type.stderr b/src/test/ui/type-inference/unbounded-associated-type.stderr new file mode 100644 index 0000000000000..726dd4b475817 --- /dev/null +++ b/src/test/ui/type-inference/unbounded-associated-type.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/unbounded-associated-type.rs:15:5 + | +LL | type A; + | ------- `::A` defined here +... +LL | S(std::marker::PhantomData).foo(); + | ^-------------------------------- + | | + | this method call resolves to `::A` + | cannot infer type for type parameter `X` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs new file mode 100644 index 0000000000000..81d054b3a1e07 --- /dev/null +++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs @@ -0,0 +1,9 @@ +#[allow(invalid_type_param_default)] + +fn foo() -> (T, U) { + panic!() +} + +fn main() { + foo(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr new file mode 100644 index 0000000000000..52039d0e934e6 --- /dev/null +++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5 + | +LL | foo(); + | ^^^ cannot infer type for type parameter `T` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.rs b/src/test/ui/type-inference/unbounded-type-param-in-fn.rs new file mode 100644 index 0000000000000..1f336ed59a6dd --- /dev/null +++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.rs @@ -0,0 +1,7 @@ +fn foo() -> T { + panic!() +} + +fn main() { + foo(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr new file mode 100644 index 0000000000000..8d317df6ce95a --- /dev/null +++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/unbounded-type-param-in-fn.rs:6:5 + | +LL | foo(); + | ^^^ cannot infer type for type parameter `T` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 5b7d6ba16d02d..94425440d333c 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -7,7 +7,7 @@ LL | fn foo>(x: i32) {} LL | foo(42); | ^^^ | | - | cannot infer type for `T` + | cannot infer type for type parameter `T` | help: consider specifying the type argument in the function call: `foo::` | = note: cannot resolve `_: std::convert::Into` diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr index 6524bf5dd2bc5..53cc769bae3cf 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `std::vec::Vec` --> $DIR/cannot_infer_local_or_vec.rs:2:13 | LL | let x = vec![]; - | - ^^^^^^ cannot infer type for `T` + | - ^^^^^^ cannot infer type for type parameter `T` | | | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified | diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr index 6d1ef240da60c..df7228ce9f2a8 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `(std::vec::Vec,)` --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18 | LL | let (x, ) = (vec![], ); - | ----- ^^^^^^ cannot infer type for `T` + | ----- ^^^^^^ cannot infer type for type parameter `T` | | | consider giving this pattern the explicit type `(std::vec::Vec,)`, where the type parameter `T` is specified | diff --git a/src/test/ui/type/type-check/issue-22897.stderr b/src/test/ui/type/type-check/issue-22897.stderr index 2b3f0696f3c22..fae7b79269bec 100644 --- a/src/test/ui/type/type-check/issue-22897.stderr +++ b/src/test/ui/type/type-check/issue-22897.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-22897.rs:4:5 | LL | []; - | ^^ cannot infer type for `[_; 0]` + | ^^ cannot infer type for array `[_; 0]` error: aborting due to previous error diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr index f2bfd9ba54103..4fc0285509149 100644 --- a/src/test/ui/type/type-check/issue-40294.stderr +++ b/src/test/ui/type/type-check/issue-40294.stderr @@ -11,7 +11,7 @@ LL | | { LL | | x.foo(); LL | | y.foo(); LL | | } - | |_^ cannot infer type for `&'a T` + | |_^ cannot infer type for reference `&'a T` | = note: cannot resolve `&'a T: Foo` diff --git a/src/test/ui/unconstrained-none.stderr b/src/test/ui/unconstrained-none.stderr index eb918b25d2bef..6c4fde94a6199 100644 --- a/src/test/ui/unconstrained-none.stderr +++ b/src/test/ui/unconstrained-none.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/unconstrained-none.rs:4:5 | LL | None; - | ^^^^ cannot infer type for `T` + | ^^^^ cannot infer type for type parameter `T` error: aborting due to previous error diff --git a/src/test/ui/unconstrained-ref.stderr b/src/test/ui/unconstrained-ref.stderr index d9a129a2d7b22..d6985a61daf0b 100644 --- a/src/test/ui/unconstrained-ref.stderr +++ b/src/test/ui/unconstrained-ref.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/unconstrained-ref.rs:6:5 | LL | S { o: &None }; - | ^ cannot infer type for `T` + | ^ cannot infer type for type parameter `T` error: aborting due to previous error diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr index 28100d7c89e71..62fc42fbae463 100644 --- a/src/test/ui/vector-no-ann.stderr +++ b/src/test/ui/vector-no-ann.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `std::vec::Vec` --> $DIR/vector-no-ann.rs:2:16 | LL | let _foo = Vec::new(); - | ---- ^^^^^^^^ cannot infer type for `T` + | ---- ^^^^^^^^ cannot infer type for type parameter `T` | | | consider giving `_foo` the explicit type `std::vec::Vec`, where the type parameter `T` is specified