Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On method chain expression failure, look for missing method in earlier segments of the chain #115229

Merged
merged 1 commit into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,) {
iSwapna marked this conversation as resolved.
Show resolved Hide resolved
// 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