Recurse over the method chain and maintain a stack to peek at previou… · rust-lang/rust@56a109d
@@ -481,7 +481,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
481481);
482482 probe.is_ok()
483483});
484-485484self.note_internal_mutation_in_method(
486485&mut err,
487486 rcvr_expr,
@@ -1240,7 +1239,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12401239}
12411240}
12421241}
1243-1242+// If an appropriate error source is not found, check method chain for possible candiates
1243+if unsatisfied_predicates.is_empty() && let Mode::MethodCall = mode && let SelfSource::MethodCall(mut source_expr) = source {
1244+let mut stack_methods = vec![];
1245+while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, method_span) =
1246+ source_expr.kind
1247+{
1248+// Pop the matching receiver, to align on it's notional span
1249+if let Some(prev_match) = stack_methods.pop() {
1250+ err.span_label(method_span, format!("{item_kind} `{item_name}` is available on `{prev_match}`"));
1251+}
1252+let rcvr_ty = self.resolve_vars_if_possible(
1253+self.typeck_results
1254+.borrow()
1255+.expr_ty_adjusted_opt(rcvr_expr)
1256+.unwrap_or(Ty::new_misc_error(self.tcx)),);
1257+1258+for _matched_method in self.probe_for_name_many(
1259+Mode::MethodCall,
1260+ item_name,
1261+None,
1262+IsSuggestion(true),
1263+ rcvr_ty,
1264+ source_expr.hir_id,
1265+ProbeScope::TraitsInScope,) {
1266+// found a match, push to stack
1267+ stack_methods.push(rcvr_ty);
1268+}
1269+ source_expr = rcvr_expr;
1270+}
1271+// If there is a match at the start of the chain, add a label for it too!
1272+if let Some(prev_match) = stack_methods.pop() {
1273+ err.span_label(source_expr.span, format!("{item_kind} `{item_name}` is available on `{prev_match}`"));
1274+}
1275+}
12441276self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
12451277return Some(err);
12461278}