Skip to content

Commit

Permalink
Auto merge of #115229 - iSwapna:issue-115222-fix, r=estebank
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
bors committed Nov 10, 2023
2 parents d4c86cf + 56a109d commit edf0b1d
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
36 changes: 34 additions & 2 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
probe.is_ok()
});

self.note_internal_mutation_in_method(
&mut err,
rcvr_expr,
Expand Down Expand Up @@ -1240,7 +1239,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}

// If an appropriate error source is not found, check method chain for possible candiates
if unsatisfied_predicates.is_empty() && let Mode::MethodCall = mode && let SelfSource::MethodCall(mut source_expr) = source {
let mut stack_methods = vec![];
while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, method_span) =
source_expr.kind
{
// Pop the matching receiver, to align on it's notional span
if let Some(prev_match) = stack_methods.pop() {
err.span_label(method_span, format!("{item_kind} `{item_name}` is available on `{prev_match}`"));
}
let rcvr_ty = self.resolve_vars_if_possible(
self.typeck_results
.borrow()
.expr_ty_adjusted_opt(rcvr_expr)
.unwrap_or(Ty::new_misc_error(self.tcx)),);

for _matched_method in self.probe_for_name_many(
Mode::MethodCall,
item_name,
None,
IsSuggestion(true),
rcvr_ty,
source_expr.hir_id,
ProbeScope::TraitsInScope,) {
// found a match, push to stack
stack_methods.push(rcvr_ty);
}
source_expr = rcvr_expr;
}
// If there is a match at the start of the chain, add a label for it too!
if let Some(prev_match) = stack_methods.pop() {
err.span_label(source_expr.span, format!("{item_kind} `{item_name}` is available on `{prev_match}`"));
}
}
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
return Some(err);
}
Expand Down
31 changes: 31 additions & 0 deletions tests/ui/structs/method-chain-expression-failure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
struct A;
struct B;
struct C;
struct D;
struct E;

impl A {
fn b(&self) -> B { B }
fn foo(&self) {}
}

impl B {
fn c(&self) -> C { C }
}

impl C {
fn d(&self) -> D { D }
fn foo(&self) {}
}

impl D {
fn e(&self) -> E { E }
}

impl E {
fn f(&self) {}
}
fn main() {
A.b().c().d().e().foo();
//~^ ERROR no method named `foo` found for struct `E` in the current scope
}
15 changes: 15 additions & 0 deletions tests/ui/structs/method-chain-expression-failure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0599]: no method named `foo` found for struct `E` in the current scope
--> $DIR/method-chain-expression-failure.rs:29:23
|
LL | struct E;
| -------- method `foo` not found for this struct
...
LL | A.b().c().d().e().foo();
| - --- ^^^ method not found in `E`
| | |
| | method `foo` is available on `&C`
| method `foo` is available on `&A`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ error[E0599]: no method named `sort` found for unit type `()` in the current sco
--> $DIR/chain-method-call-mutation-in-place.rs:3:72
|
LL | vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
| ^^^^ method not found in `()`
| ------------- --------------------- ^^^^ method not found in `()`
| | |
| | method `sort` is available on `&mut [i32]`
| method `sort` is available on `Vec<i32>`
|
note: method `sort_by_key` modifies its receiver in-place, it is not meant to be used in method chains.
--> $DIR/chain-method-call-mutation-in-place.rs:3:53
Expand Down

0 comments on commit edf0b1d

Please sign in to comment.