diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index bb6e5700cca..53f52038ed0 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -17,23 +17,27 @@ struct FindHirNodeVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, + target_span: Span, found_node_ty: Option>, found_local_pattern: Option<&'tcx Pat<'tcx>>, found_arg_pattern: Option<&'tcx Pat<'tcx>>, found_closure: Option<&'tcx Expr<'tcx>>, found_method_call: Option<&'tcx Expr<'tcx>>, + found_exact_method_call: Option<&'tcx Expr<'tcx>>, } impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self { + fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self { Self { infcx, target, + target_span, found_node_ty: None, found_local_pattern: None, found_arg_pattern: None, found_closure: None, found_method_call: None, + found_exact_method_call: None, } } @@ -103,6 +107,17 @@ fn visit_body(&mut self, body: &'tcx Body<'tcx>) { } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind { + if call_span == self.target_span + && Some(self.target) + == self.infcx.in_progress_tables.and_then(|tables| { + tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into) + }) + { + self.found_exact_method_call = Some(&expr); + return; + } + } if self.node_ty_contains_target(expr.hir_id).is_some() { match expr.kind { ExprKind::Closure(..) => self.found_closure = Some(&expr), @@ -234,7 +249,7 @@ pub fn need_type_info_err( let ty = self.resolve_vars_if_possible(&ty); let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into()); + let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -287,14 +302,15 @@ pub fn need_type_info_err( (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) }; - let ty_msg = match local_visitor.found_node_ty { - Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { + let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) { + (_, Some(_)) => String::new(), + (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => { let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); let ret = fn_sig.output().skip_binder().to_string(); format!(" for the closure `fn({}) -> {}`", args, ret) } - Some(ty) if is_named_and_not_impl_trait(ty) => { + (Some(ty), _) if is_named_and_not_impl_trait(ty) => { let ty = ty_to_string(ty); format!(" for `{}`", ty) } @@ -370,7 +386,37 @@ pub fn need_type_info_err( _ => "a type".to_string(), }; - if let Some(pattern) = local_visitor.found_arg_pattern { + if let Some(e) = local_visitor.found_exact_method_call { + if let ExprKind::MethodCall(segment, ..) = &e.kind { + // Suggest specifying 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); + } + } else if let Some(pattern) = local_visitor.found_arg_pattern { // We don't want to show the default label for closures. // // So, before clearing, the output would look something like this: diff --git a/src/test/ui/issues/issue-69455.rs b/src/test/ui/issues/issue-69455.rs new file mode 100644 index 00000000000..017654554be --- /dev/null +++ b/src/test/ui/issues/issue-69455.rs @@ -0,0 +1,30 @@ +// Regression test for #69455: projection predicate was not satisfied. +// Compiler should indicate the correct location of the +// unsatisfied projection predicate + +pub trait Test { + type Output; + + fn test(self, rhs: Rhs) -> Self::Output; +} + +impl Test for u64 { + type Output = u64; + + fn test(self, other: u32) -> u64 { + self + (other as u64) + } +} + +impl Test for u64 { + type Output = u64; + + fn test(self, other: u64) -> u64 { + (self + other) as u64 + } +} + +fn main() { + let xs: Vec = vec![1, 2, 3]; + println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284] +} diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr new file mode 100644 index 00000000000..4caa1aca9fd --- /dev/null +++ b/src/test/ui/issues/issue-69455.stderr @@ -0,0 +1,17 @@ +error[E0284]: type annotations needed + --> $DIR/issue-69455.rs:29:26 + | +LL | type Output; + | ------------ `>::Output` defined here +... +LL | println!("{}", 23u64.test(xs.iter().sum())); + | ------^^^^----------------- + | | | + | | cannot infer type for type `u64` + | this method call resolves to `>::Output` + | + = note: cannot satisfy `>::Output == _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`.