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-485484

self.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+

}

12441276

self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);

12451277

return Some(err);

12461278

}