Skip to content

Commit edf0b1d

Browse files
committed
Auto merge of #115229 - iSwapna:issue-115222-fix, r=estebank
On method chain expression failure, look for missing method in earlier segments of the chain This PR tries to fix the issue: #115222 As suggested by `@estebank` , I did the following: 1. Add new test `tests/ui/structs/method-chain-expression-failure.rs` 2. In `compiler/rusct_hir_tycheck/src/method/suggest.rs` walking up the method chain and calling `probe_for_name` with the method name. But the call fails to return `Ok`.
2 parents d4c86cf + 56a109d commit edf0b1d

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -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
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
struct A;
2+
struct B;
3+
struct C;
4+
struct D;
5+
struct E;
6+
7+
impl A {
8+
fn b(&self) -> B { B }
9+
fn foo(&self) {}
10+
}
11+
12+
impl B {
13+
fn c(&self) -> C { C }
14+
}
15+
16+
impl C {
17+
fn d(&self) -> D { D }
18+
fn foo(&self) {}
19+
}
20+
21+
impl D {
22+
fn e(&self) -> E { E }
23+
}
24+
25+
impl E {
26+
fn f(&self) {}
27+
}
28+
fn main() {
29+
A.b().c().d().e().foo();
30+
//~^ ERROR no method named `foo` found for struct `E` in the current scope
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0599]: no method named `foo` found for struct `E` in the current scope
2+
--> $DIR/method-chain-expression-failure.rs:29:23
3+
|
4+
LL | struct E;
5+
| -------- method `foo` not found for this struct
6+
...
7+
LL | A.b().c().d().e().foo();
8+
| - --- ^^^ method not found in `E`
9+
| | |
10+
| | method `foo` is available on `&C`
11+
| method `foo` is available on `&A`
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0599`.

tests/ui/suggestions/chain-method-call-mutation-in-place.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ error[E0599]: no method named `sort` found for unit type `()` in the current sco
1818
--> $DIR/chain-method-call-mutation-in-place.rs:3:72
1919
|
2020
LL | vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
21-
| ^^^^ method not found in `()`
21+
| ------------- --------------------- ^^^^ method not found in `()`
22+
| | |
23+
| | method `sort` is available on `&mut [i32]`
24+
| method `sort` is available on `Vec<i32>`
2225
|
2326
note: method `sort_by_key` modifies its receiver in-place, it is not meant to be used in method chains.
2427
--> $DIR/chain-method-call-mutation-in-place.rs:3:53

0 commit comments

Comments
 (0)