Skip to content

Commit 3849ccd

Browse files
authored
Rollup merge of rust-lang#66913 - VirrageS:help-self, r=varkor
Suggest calling method when first argument is `self` Closes: rust-lang#66782 I've explored different approaches for this MR but I think the most straightforward is the best one. I've tried to find out if the methods for given type exist (to maybe have a better suggestion), but we don't collect them anywhere and collecting them is quite problematic. Moreover, collecting all the methods would require rewriting big part of the code and also could potentially include performance degradation, which I don't think is necessary for this simple case.
2 parents 699a2c7 + 9273f59 commit 3849ccd

File tree

4 files changed

+123
-8
lines changed

4 files changed

+123
-8
lines changed

src/librustc_resolve/late.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ struct DiagnosticMetadata {
345345
/// The current self item if inside an ADT (used for better errors).
346346
current_self_item: Option<NodeId>,
347347

348-
/// The current enclosing funciton (used for better errors).
348+
/// The current enclosing function (used for better errors).
349349
current_function: Option<Span>,
350350

351351
/// A list of labels as of yet unused. Labels will be removed from this map when

src/librustc_resolve/late/diagnostics.rs

+57-7
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,56 @@ impl<'a> LateResolutionVisitor<'a, '_> {
253253
}
254254
return (err, candidates);
255255
}
256+
257+
// Check if the first argument is `self` and suggest calling a method.
258+
let mut has_self_arg = None;
259+
if let PathSource::Expr(parent) = source {
260+
match &parent.map(|p| &p.kind) {
261+
Some(ExprKind::Call(_, args)) if args.len() > 0 => {
262+
let mut expr_kind = &args[0].kind;
263+
loop {
264+
match expr_kind {
265+
ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
266+
if arg_name.segments[0].ident.name == kw::SelfLower {
267+
let call_span = parent.unwrap().span;
268+
let args_span = if args.len() > 1 {
269+
Some(Span::new(
270+
args[1].span.lo(),
271+
args.last().unwrap().span.hi(),
272+
call_span.ctxt(),
273+
))
274+
} else {
275+
None
276+
};
277+
has_self_arg = Some((call_span, args_span));
278+
}
279+
break;
280+
},
281+
ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
282+
_ => break,
283+
}
284+
}
285+
}
286+
_ => (),
287+
}
288+
};
289+
290+
if let Some((call_span, args_span)) = has_self_arg {
291+
let mut args_snippet: String = String::from("");
292+
if let Some(args_span) = args_span {
293+
if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) {
294+
args_snippet = snippet;
295+
}
296+
}
297+
298+
err.span_suggestion(
299+
call_span,
300+
&format!("try calling `{}` as a method", ident),
301+
format!("self.{}({})", path_str, args_snippet),
302+
Applicability::MachineApplicable,
303+
);
304+
return (err, candidates);
305+
}
256306
}
257307

258308
// Try Levenshtein algorithm.
@@ -553,13 +603,13 @@ impl<'a> LateResolutionVisitor<'a, '_> {
553603
// Look for associated items in the current trait.
554604
if let Some((module, _)) = self.current_trait_ref {
555605
if let Ok(binding) = self.r.resolve_ident_in_module(
556-
ModuleOrUniformRoot::Module(module),
557-
ident,
558-
ns,
559-
&self.parent_scope,
560-
false,
561-
module.span,
562-
) {
606+
ModuleOrUniformRoot::Module(module),
607+
ident,
608+
ns,
609+
&self.parent_scope,
610+
false,
611+
module.span,
612+
) {
563613
let res = binding.res();
564614
if filter_fn(res) {
565615
return Some(if self.r.has_self.contains(&res.def_id()) {

src/test/ui/self/suggest-self-2.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
struct Foo {}
2+
3+
impl Foo {
4+
fn foo(&self) {
5+
bar(self);
6+
//~^ ERROR cannot find function `bar` in this scope
7+
//~| HELP try calling `bar` as a method
8+
9+
bar(&&self, 102);
10+
//~^ ERROR cannot find function `bar` in this scope
11+
//~| HELP try calling `bar` as a method
12+
13+
bar(&mut self, 102, &"str");
14+
//~^ ERROR cannot find function `bar` in this scope
15+
//~| HELP try calling `bar` as a method
16+
17+
bar();
18+
//~^ ERROR cannot find function `bar` in this scope
19+
20+
self.bar();
21+
//~^ ERROR no method named `bar` found for type
22+
}
23+
}
24+
25+
fn main() {}
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error[E0425]: cannot find function `bar` in this scope
2+
--> $DIR/suggest-self-2.rs:5:9
3+
|
4+
LL | bar(self);
5+
| ^^^------
6+
| |
7+
| help: try calling `bar` as a method: `self.bar()`
8+
9+
error[E0425]: cannot find function `bar` in this scope
10+
--> $DIR/suggest-self-2.rs:9:9
11+
|
12+
LL | bar(&&self, 102);
13+
| ^^^-------------
14+
| |
15+
| help: try calling `bar` as a method: `self.bar(102)`
16+
17+
error[E0425]: cannot find function `bar` in this scope
18+
--> $DIR/suggest-self-2.rs:13:9
19+
|
20+
LL | bar(&mut self, 102, &"str");
21+
| ^^^------------------------
22+
| |
23+
| help: try calling `bar` as a method: `self.bar(102, &"str")`
24+
25+
error[E0425]: cannot find function `bar` in this scope
26+
--> $DIR/suggest-self-2.rs:17:9
27+
|
28+
LL | bar();
29+
| ^^^ not found in this scope
30+
31+
error[E0599]: no method named `bar` found for type `&Foo` in the current scope
32+
--> $DIR/suggest-self-2.rs:20:14
33+
|
34+
LL | self.bar();
35+
| ^^^ method not found in `&Foo`
36+
37+
error: aborting due to 5 previous errors
38+
39+
Some errors have detailed explanations: E0425, E0599.
40+
For more information about an error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)