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: https://github.com/rust-lang/rust/issues/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`.
This commit is contained in:
commit
edf0b1db0a
@ -481,7 +481,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
probe.is_ok()
|
probe.is_ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
self.note_internal_mutation_in_method(
|
self.note_internal_mutation_in_method(
|
||||||
&mut err,
|
&mut err,
|
||||||
rcvr_expr,
|
rcvr_expr,
|
||||||
@ -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);
|
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
|
||||||
return Some(err);
|
return Some(err);
|
||||||
}
|
}
|
||||||
|
31
tests/ui/structs/method-chain-expression-failure.rs
Normal file
31
tests/ui/structs/method-chain-expression-failure.rs
Normal file
@ -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
tests/ui/structs/method-chain-expression-failure.stderr
Normal file
15
tests/ui/structs/method-chain-expression-failure.stderr
Normal file
@ -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`.
|
@ -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
|
--> $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();
|
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.
|
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
|
--> $DIR/chain-method-call-mutation-in-place.rs:3:53
|
||||||
|
Loading…
x
Reference in New Issue
Block a user