diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 55a95d056984..487736dee30d 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 2da43bdcc1e2..fa4ad021072d 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 5f971a1ad505..999038e7ea79 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)