Skip to content

Commit 0c8d5ca

Browse files
committed
Consider methods from traits when suggesting typos
Do not provide a structured suggestion when the arguments don't match. ``` error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | LL | a.test_mut(); | ^^^^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test_mut`, perhaps you need to implement it --> $DIR/auto-ref-slice-plus-ref.rs:14:1 | LL | trait MyIter { | ^^^^^^^^^^^^ help: there is a method `get_mut` with a similar name, but with different arguments --> $SRC_DIR/core/src/slice/mod.rs:LL:COL ``` Consider methods beyond inherent ones when suggesting typos. ``` error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:11:7 | LL | fn owned(self: Box<Self>); | --------- the method might not be found because of this arbitrary self type ... LL | x.owned(); | ^^^^^ help: there is a method with a similar name: `to_owned` ``` Fix rust-lang#101013.
1 parent 0624790 commit 0c8d5ca

23 files changed

+223
-68
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -553,14 +553,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
553553
&& let ty::AssocKind::Fn = assoc.kind
554554
&& assoc.fn_has_self_parameter
555555
{
556-
let fn_sig =
557-
if let ty::Adt(_, args) = callee_ty.peel_refs().kind() {
558-
let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id)
559-
.rebase_onto(tcx, assoc.container_id(tcx), args);
560-
tcx.fn_sig(assoc.def_id).instantiate(tcx, args)
561-
} else {
562-
tcx.fn_sig(assoc.def_id).instantiate_identity()
563-
};
556+
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
557+
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
564558
let fn_sig =
565559
self.instantiate_binder_with_fresh_vars(call_name.span, FnCall, fn_sig);
566560
Some((assoc, fn_sig));

compiler/rustc_hir_typeck/src/method/probe.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17691769
);
17701770
pcx.allow_similar_names = true;
17711771
pcx.assemble_inherent_candidates();
1772+
pcx.assemble_extension_candidates_for_all_traits();
17721773

17731774
let method_names = pcx.candidate_method_names(|_| true);
17741775
pcx.allow_similar_names = false;
@@ -1778,6 +1779,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17781779
pcx.reset();
17791780
pcx.method_name = Some(method_name);
17801781
pcx.assemble_inherent_candidates();
1782+
pcx.assemble_extension_candidates_for_all_traits();
17811783
pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
17821784
})
17831785
.collect();

compiler/rustc_hir_typeck/src/method/suggest.rs

+75-13
Original file line numberDiff line numberDiff line change
@@ -1263,27 +1263,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12631263
&& Some(similar_candidate.name) != confusable_suggested
12641264
{
12651265
let def_kind = similar_candidate.kind.as_def_kind();
1266-
// Methods are defined within the context of a struct and their first parameter is always self,
1267-
// which represents the instance of the struct the method is being called on
1268-
// Associated functions don’t take self as a parameter and
1269-
// they are not methods because they don’t have an instance of the struct to work with.
1270-
if def_kind == DefKind::AssocFn && similar_candidate.fn_has_self_parameter {
1266+
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
1267+
// Methods are defined within the context of a struct and their first parameter
1268+
// is always `self`, which represents the instance of the struct the method is
1269+
// being called on Associated functions don’t take self as a parameter and they are
1270+
// not methods because they don’t have an instance of the struct to work with.
1271+
if def_kind == DefKind::AssocFn {
1272+
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
1273+
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
1274+
let fn_sig =
1275+
self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
1276+
if similar_candidate.fn_has_self_parameter {
1277+
if let Some(args) = args
1278+
&& fn_sig.inputs()[1..].len() == args.len()
1279+
{
1280+
// We found a method with the same number of arguments as the method
1281+
// call expression the user wrote.
1282+
err.span_suggestion(
1283+
span,
1284+
format!("there is {an} method with a similar name"),
1285+
similar_candidate.name,
1286+
Applicability::MaybeIncorrect,
1287+
);
1288+
} else {
1289+
// We found a method but either the expression is not a method call or
1290+
// the argument count didn't match.
1291+
err.span_help(
1292+
tcx.def_span(similar_candidate.def_id),
1293+
format!(
1294+
"there is {an} method `{}` with a similar name{}",
1295+
similar_candidate.name,
1296+
if let None = args {
1297+
""
1298+
} else {
1299+
", but with different arguments"
1300+
},
1301+
),
1302+
);
1303+
}
1304+
} else if let Some(args) = args
1305+
&& fn_sig.inputs().len() == args.len()
1306+
{
1307+
// We have fn call expression and the argument count match the associated
1308+
// function we found.
1309+
err.span_suggestion(
1310+
span,
1311+
format!(
1312+
"there is {an} {} with a similar name",
1313+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1314+
),
1315+
similar_candidate.name,
1316+
Applicability::MaybeIncorrect,
1317+
);
1318+
} else {
1319+
err.span_help(
1320+
tcx.def_span(similar_candidate.def_id),
1321+
format!(
1322+
"there is {an} {} `{}` with a similar name",
1323+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1324+
similar_candidate.name,
1325+
),
1326+
);
1327+
}
1328+
} else if let Mode::Path = mode {
1329+
// We have an associated item syntax and we found something that isn't an fn.
12711330
err.span_suggestion(
12721331
span,
1273-
"there is a method with a similar name",
1332+
format!(
1333+
"there is {an} {} with a similar name",
1334+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1335+
),
12741336
similar_candidate.name,
12751337
Applicability::MaybeIncorrect,
12761338
);
12771339
} else {
1278-
err.span_suggestion(
1279-
span,
1340+
// The expression is a function or method call, but the item we found is an
1341+
// associated const or type.
1342+
err.span_help(
1343+
tcx.def_span(similar_candidate.def_id),
12801344
format!(
1281-
"there is {} {} with a similar name",
1282-
self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id),
1283-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1345+
"there is {an} {} `{}` with a similar name",
1346+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1347+
similar_candidate.name,
12841348
),
1285-
similar_candidate.name,
1286-
Applicability::MaybeIncorrect,
12871349
);
12881350
}
12891351
}

tests/ui/associated-item/associated-item-enum.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | Enum::mispellable_trait();
2020
| ^^^^^^^^^^^^^^^^^
2121
| |
2222
| variant or associated item not found in `Enum`
23-
| help: there is an associated function with a similar name: `misspellable`
23+
| help: there is an associated function with a similar name: `misspellable_trait`
2424

2525
error[E0599]: no variant or associated item named `MISPELLABLE` found for enum `Enum` in the current scope
2626
--> $DIR/associated-item-enum.rs:19:11

tests/ui/attributes/rustc_confusables_std_cases.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fn main() {
1616
//~^ HELP you might have meant to use `len`
1717
x.size(); //~ ERROR E0599
1818
//~^ HELP you might have meant to use `len`
19-
//~| HELP there is a method with a similar name
19+
//~| HELP there is a method `resize` with a similar name
2020
x.append(42); //~ ERROR E0308
2121
//~^ HELP you might have meant to use `push`
2222
String::new().push(""); //~ ERROR E0308

tests/ui/attributes/rustc_confusables_std_cases.stderr

+2-4
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,12 @@ error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the cu
4848
LL | x.size();
4949
| ^^^^
5050
|
51+
help: there is a method `resize` with a similar name, but with different arguments
52+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
5153
help: you might have meant to use `len`
5254
|
5355
LL | x.len();
5456
| ~~~
55-
help: there is a method with a similar name
56-
|
57-
LL | x.resize();
58-
| ~~~~~~
5957

6058
error[E0308]: mismatched types
6159
--> $DIR/rustc_confusables_std_cases.rs:20:14

tests/ui/auto-ref-slice-plus-ref.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in th
22
--> $DIR/auto-ref-slice-plus-ref.rs:7:7
33
|
44
LL | a.test_mut();
5-
| ^^^^^^^^ help: there is a method with a similar name: `get_mut`
5+
| ^^^^^^^^
66
|
77
= help: items from traits can only be used if the trait is implemented and in scope
88
note: `MyIter` defines an item `test_mut`, perhaps you need to implement it
99
--> $DIR/auto-ref-slice-plus-ref.rs:14:1
1010
|
1111
LL | trait MyIter {
1212
| ^^^^^^^^^^^^
13+
help: there is a method `get_mut` with a similar name, but with different arguments
14+
--> $SRC_DIR/core/src/slice/mod.rs:LL:COL
1315

1416
error[E0599]: no method named `test` found for struct `Vec<{integer}>` in the current scope
1517
--> $DIR/auto-ref-slice-plus-ref.rs:8:7

tests/ui/confuse-field-and-method/issue-33784.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ help: to call the function stored in `closure`, surround the field access with p
88
|
99
LL | (p.closure)();
1010
| + +
11+
help: there is a method with a similar name
12+
|
13+
LL | p.clone();
14+
| ~~~~~
1115

1216
error[E0599]: no method named `fn_ptr` found for reference `&&Obj<{closure@$DIR/issue-33784.rs:25:43: 25:45}>` in the current scope
1317
--> $DIR/issue-33784.rs:29:7

tests/ui/hygiene/no_implicit_prelude.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ LL | fn f() { ::bar::m!(); }
2020
| ----------- in this macro invocation
2121
...
2222
LL | ().clone()
23-
| ^^^^^ method not found in `()`
23+
| ^^^^^
2424
|
2525
= help: items from traits can only be used if the trait is in scope
26+
help: there is a method `clone_from` with a similar name, but with different arguments
27+
--> $SRC_DIR/core/src/clone.rs:LL:COL
2628
= note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info)
2729
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
2830
|

tests/ui/impl-trait/no-method-suggested-traits.stderr

+30-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0599]: no method named `method` found for type `u32` in the current scope
22
--> $DIR/no-method-suggested-traits.rs:23:10
33
|
44
LL | 1u32.method();
5-
| ^^^^^^ method not found in `u32`
5+
| ^^^^^^
66
|
77
= help: items from traits can only be used if the trait is in scope
88
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
@@ -15,12 +15,16 @@ LL + use no_method_suggested_traits::foo::PubPub;
1515
|
1616
LL + use no_method_suggested_traits::qux::PrivPub;
1717
|
18+
help: there is a method with a similar name
19+
|
20+
LL | 1u32.method2();
21+
| ~~~~~~~
1822

1923
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope
2024
--> $DIR/no-method-suggested-traits.rs:26:44
2125
|
2226
LL | std::rc::Rc::new(&mut Box::new(&1u32)).method();
23-
| ^^^^^^ method not found in `Rc<&mut Box<&u32>>`
27+
| ^^^^^^
2428
|
2529
= help: items from traits can only be used if the trait is in scope
2630
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
@@ -33,6 +37,10 @@ LL + use no_method_suggested_traits::foo::PubPub;
3337
|
3438
LL + use no_method_suggested_traits::qux::PrivPub;
3539
|
40+
help: there is a method with a similar name
41+
|
42+
LL | std::rc::Rc::new(&mut Box::new(&1u32)).method2();
43+
| ~~~~~~~
3644

3745
error[E0599]: no method named `method` found for type `char` in the current scope
3846
--> $DIR/no-method-suggested-traits.rs:30:9
@@ -41,31 +49,39 @@ LL | fn method(&self) {}
4149
| ------ the method is available for `char` here
4250
...
4351
LL | 'a'.method();
44-
| ^^^^^^ method not found in `char`
52+
| ^^^^^^
4553
|
4654
= help: items from traits can only be used if the trait is in scope
4755
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
4856
|
4957
LL + use foo::Bar;
5058
|
59+
help: there is a method with a similar name
60+
|
61+
LL | 'a'.method2();
62+
| ~~~~~~~
5163

5264
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope
5365
--> $DIR/no-method-suggested-traits.rs:32:43
5466
|
5567
LL | std::rc::Rc::new(&mut Box::new(&'a')).method();
56-
| ^^^^^^ method not found in `Rc<&mut Box<&char>>`
68+
| ^^^^^^
5769
|
5870
= help: items from traits can only be used if the trait is in scope
5971
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
6072
|
6173
LL + use foo::Bar;
6274
|
75+
help: there is a method with a similar name
76+
|
77+
LL | std::rc::Rc::new(&mut Box::new(&'a')).method2();
78+
| ~~~~~~~
6379

6480
error[E0599]: no method named `method` found for type `i32` in the current scope
6581
--> $DIR/no-method-suggested-traits.rs:35:10
6682
|
6783
LL | 1i32.method();
68-
| ^^^^^^ method not found in `i32`
84+
| ^^^^^^
6985
|
7086
::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12
7187
|
@@ -77,18 +93,26 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
7793
|
7894
LL + use no_method_suggested_traits::foo::PubPub;
7995
|
96+
help: there is a method with a similar name
97+
|
98+
LL | 1i32.method3();
99+
| ~~~~~~~
80100

81101
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope
82102
--> $DIR/no-method-suggested-traits.rs:37:44
83103
|
84104
LL | std::rc::Rc::new(&mut Box::new(&1i32)).method();
85-
| ^^^^^^ method not found in `Rc<&mut Box<&i32>>`
105+
| ^^^^^^
86106
|
87107
= help: items from traits can only be used if the trait is in scope
88108
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
89109
|
90110
LL + use no_method_suggested_traits::foo::PubPub;
91111
|
112+
help: there is a method with a similar name
113+
|
114+
LL | std::rc::Rc::new(&mut Box::new(&1i32)).method3();
115+
| ~~~~~~~
92116

93117
error[E0599]: no method named `method` found for struct `Foo` in the current scope
94118
--> $DIR/no-method-suggested-traits.rs:40:9

tests/ui/issues/issue-28344.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ error[E0599]: no function or associated item named `bitor` found for trait objec
2222
--> $DIR/issue-28344.rs:4:25
2323
|
2424
LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
25-
| ^^^^^
26-
| |
27-
| function or associated item not found in `dyn BitXor<_>`
28-
| help: there is a method with a similar name: `bitxor`
25+
| ^^^^^ function or associated item not found in `dyn BitXor<_>`
26+
|
27+
help: there is a method `bitxor` with a similar name, but with different arguments
28+
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
2929

3030
warning: trait objects without an explicit `dyn` are deprecated
3131
--> $DIR/issue-28344.rs:10:13
@@ -50,10 +50,10 @@ error[E0599]: no function or associated item named `bitor` found for trait objec
5050
--> $DIR/issue-28344.rs:10:21
5151
|
5252
LL | let g = BitXor::bitor;
53-
| ^^^^^
54-
| |
55-
| function or associated item not found in `dyn BitXor<_>`
56-
| help: there is a method with a similar name: `bitxor`
53+
| ^^^^^ function or associated item not found in `dyn BitXor<_>`
54+
|
55+
help: there is a method `bitxor` with a similar name, but with different arguments
56+
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
5757

5858
error: aborting due to 4 previous errors; 2 warnings emitted
5959

tests/ui/issues/issue-39175.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ error[E0599]: no method named `exec` found for mutable reference `&mut Command`
22
--> $DIR/issue-39175.rs:14:39
33
|
44
LL | Command::new("echo").arg("hello").exec();
5-
| ^^^^ method not found in `&mut Command`
5+
| ^^^^
66
|
77
= help: items from traits can only be used if the trait is in scope
8+
help: there is a method `pre_exec` with a similar name, but with different arguments
9+
--> $SRC_DIR/std/src/os/unix/process.rs:LL:COL
810
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
911
|
1012
LL + use std::os::unix::process::CommandExt;

0 commit comments

Comments
 (0)