Skip to content

Commit 1dbca66

Browse files
committed
Use a stack to store rvcr_type and match up with span
1 parent b060c18 commit 1dbca66

File tree

4 files changed

+39
-24
lines changed

4 files changed

+39
-24
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -1239,12 +1239,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12391239
}
12401240
}
12411241
}
1242-
// Only if an appropriate error source is not found, check method chain for possible candiates
1243-
let error_source_not_found = unsatisfied_predicates.is_empty();
1244-
if error_source_not_found && let Mode::MethodCall = mode && let SelfSource::MethodCall(mut source_expr) = source {
1245-
while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, _span) =
1246-
source_expr.kind
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
12471247
{
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+
}
12481252
let rcvr_ty = self.resolve_vars_if_possible(
12491253
self.typeck_results
12501254
.borrow()
@@ -1259,10 +1263,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12591263
rcvr_ty,
12601264
source_expr.hir_id,
12611265
ProbeScope::TraitsInScope,) {
1262-
err.span_label(rcvr_expr.span, format!("{item_kind} `{item_name}` is available on `{rcvr_ty}`"));
1263-
}
1264-
source_expr = rcvr_expr;
1265-
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}`"));
12661274
}
12671275
}
12681276
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);

tests/ui/structs/method-chain-expression-failure.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,31 @@ struct A;
22
struct B;
33
struct C;
44
struct D;
5+
struct E;
56

67
impl A {
78
fn b(&self) -> B { B }
9+
fn foo(&self) {}
810
}
911

1012
impl B {
1113
fn c(&self) -> C { C }
12-
fn foo(&self) {}
1314
}
1415

1516
impl C {
1617
fn d(&self) -> D { D }
18+
fn foo(&self) {}
1719
}
1820

1921
impl D {
20-
fn e(&self) {}
22+
fn e(&self) -> E { E }
2123
}
2224

25+
impl E {
26+
fn f(&self) {}
27+
}
2328
fn main() {
24-
A.b().c().d().foo();
25-
//~^ ERROR no method named `foo` found for struct `D` in the current scope
29+
A.b().c().d().e().foo();
30+
//~^ ERROR no method named `foo` found for struct `E` in the current scope
2631
}
32+

tests/ui/structs/method-chain-expression-failure.stderr

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
error[E0599]: no method named `foo` found for struct `D` in the current scope
2-
--> $DIR/method-chain-expression-failure.rs:24:19
1+
error[E0599]: no method named `foo` found for struct `E` in the current scope
2+
--> $DIR/method-chain-expression-failure.rs:29:23
33
|
4-
LL | struct D;
4+
LL | struct E;
55
| -------- method `foo` not found for this struct
66
...
7-
LL | A.b().c().d().foo();
8-
| ----- ^^^ method not found in `D`
9-
| |
10-
| method `foo` is available on `&B`
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`
1112

1213
error: aborting due to previous error
1314

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,10 +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 `()`
22-
| | |
23-
| | method `sort` is available on `&mut [i32]`
24-
| method `sort` is available on `Vec<i32>`
21+
| ------------- --------------------- ^^^^ method not found in `()`
22+
| | |
23+
| | method `sort` is available on `&mut [i32]`
24+
| method `sort` is available on `Vec<i32>`
2525
|
2626
note: method `sort_by_key` modifies its receiver in-place, it is not meant to be used in method chains.
2727
--> $DIR/chain-method-call-mutation-in-place.rs:3:53

0 commit comments

Comments
 (0)