Skip to content

Commit 2fb2af4

Browse files
authored
Rollup merge of #75509 - estebank:coming-merrily-from-java-land, r=lcnr
Tweak suggestion for `this` -> `self` * When referring to `this` in associated `fn`s always suggest `self`. * Point at ident for `fn` lacking `self` * Suggest adding `self` to assoc `fn`s when appropriate _Improvements based on the narrative in https://fasterthanli.me/articles/i-am-a-java-csharp-c-or-cplusplus-dev-time-to-do-some-rust_
2 parents ad1bfd2 + 4ecdec1 commit 2fb2af4

File tree

7 files changed

+148
-35
lines changed

7 files changed

+148
-35
lines changed

src/librustc_ast/visit.rs

+7
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ impl<'a> FnKind<'a> {
5050
}
5151
}
5252

53+
pub fn ident(&self) -> Option<&Ident> {
54+
match self {
55+
FnKind::Fn(_, ident, ..) => Some(ident),
56+
_ => None,
57+
}
58+
}
59+
5360
pub fn decl(&self) -> &'a FnDecl {
5461
match self {
5562
FnKind::Fn(_, _, sig, _, _) => &sig.decl,

src/librustc_resolve/late/diagnostics.rs

+60-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{PathResult, PathSource, Segment};
77

88
use rustc_ast::ast::{self, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
99
use rustc_ast::util::lev_distance::find_best_match_for_name;
10+
use rustc_ast::visit::FnKind;
1011
use rustc_data_structures::fx::FxHashSet;
1112
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
1213
use rustc_hir as hir;
@@ -175,16 +176,40 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
175176
let code = source.error_code(res.is_some());
176177
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
177178

179+
let is_assoc_fn = self.self_type_is_available(span);
178180
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
179-
if ["this", "my"].contains(&&*item_str.as_str())
180-
&& self.self_value_is_available(path[0].ident.span, span)
181-
{
181+
if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn {
182182
err.span_suggestion_short(
183183
span,
184184
"you might have meant to use `self` here instead",
185185
"self".to_string(),
186186
Applicability::MaybeIncorrect,
187187
);
188+
if !self.self_value_is_available(path[0].ident.span, span) {
189+
if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
190+
&self.diagnostic_metadata.current_function
191+
{
192+
let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
193+
(param.span.shrink_to_lo(), "&self, ")
194+
} else {
195+
(
196+
self.r
197+
.session
198+
.source_map()
199+
.span_through_char(*fn_span, '(')
200+
.shrink_to_hi(),
201+
"&self",
202+
)
203+
};
204+
err.span_suggestion_verbose(
205+
span,
206+
"if you meant to use `self`, you are also missing a `self` receiver \
207+
argument",
208+
sugg.to_string(),
209+
Applicability::MaybeIncorrect,
210+
);
211+
}
212+
}
188213
}
189214

190215
// Emit special messages for unresolved `Self` and `self`.
@@ -213,7 +238,38 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
213238
if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
214239
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
215240
} else {
216-
err.span_label(*span, "this function doesn't have a `self` parameter");
241+
let doesnt = if is_assoc_fn {
242+
let (span, sugg) = fn_kind
243+
.decl()
244+
.inputs
245+
.get(0)
246+
.map(|p| (p.span.shrink_to_lo(), "&self, "))
247+
.unwrap_or_else(|| {
248+
(
249+
self.r
250+
.session
251+
.source_map()
252+
.span_through_char(*span, '(')
253+
.shrink_to_hi(),
254+
"&self",
255+
)
256+
});
257+
err.span_suggestion_verbose(
258+
span,
259+
"add a `self` receiver parameter to make the associated `fn` a method",
260+
sugg.to_string(),
261+
Applicability::MaybeIncorrect,
262+
);
263+
"doesn't"
264+
} else {
265+
"can't"
266+
};
267+
if let Some(ident) = fn_kind.ident() {
268+
err.span_label(
269+
ident.span,
270+
&format!("this function {} have a `self` parameter", doesnt),
271+
);
272+
}
217273
}
218274
}
219275
return (err, Vec::new());

src/test/ui/error-codes/E0424.rs

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ impl Foo {
66
fn foo() {
77
self.bar(); //~ ERROR E0424
88
}
9+
10+
fn baz(_: i32) {
11+
self.bar(); //~ ERROR E0424
12+
}
913
}
1014

1115
fn main () {

src/test/ui/error-codes/E0424.stderr

+28-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
11
error[E0424]: expected value, found module `self`
22
--> $DIR/E0424.rs:7:9
33
|
4-
LL | / fn foo() {
5-
LL | | self.bar();
6-
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
7-
LL | | }
8-
| |_____- this function doesn't have a `self` parameter
4+
LL | fn foo() {
5+
| --- this function doesn't have a `self` parameter
6+
LL | self.bar();
7+
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
8+
|
9+
help: add a `self` receiver parameter to make the associated `fn` a method
10+
|
11+
LL | fn foo(&self) {
12+
| ^^^^^
13+
14+
error[E0424]: expected value, found module `self`
15+
--> $DIR/E0424.rs:11:9
16+
|
17+
LL | fn baz(_: i32) {
18+
| --- this function doesn't have a `self` parameter
19+
LL | self.bar();
20+
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
21+
|
22+
help: add a `self` receiver parameter to make the associated `fn` a method
23+
|
24+
LL | fn baz(&self, _: i32) {
25+
| ^^^^^^
926

1027
error[E0424]: expected unit struct, unit variant or constant, found module `self`
11-
--> $DIR/E0424.rs:12:9
28+
--> $DIR/E0424.rs:16:9
1229
|
13-
LL | / fn main () {
14-
LL | | let self = "self";
15-
| | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
16-
LL | | }
17-
| |_- this function doesn't have a `self` parameter
30+
LL | fn main () {
31+
| ---- this function can't have a `self` parameter
32+
LL | let self = "self";
33+
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
1834

19-
error: aborting due to 2 previous errors
35+
error: aborting due to 3 previous errors
2036

2137
For more information about this error, try `rustc --explain E0424`.

src/test/ui/issues/issue-5099.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1-
trait B < A > { fn a() -> A { this.a } } //~ ERROR cannot find value `this` in this scope
1+
trait B <A> {
2+
fn a() -> A {
3+
this.a //~ ERROR cannot find value `this` in this scope
4+
}
5+
fn b(x: i32) {
6+
this.b(x); //~ ERROR cannot find value `this` in this scope
7+
}
8+
}
29

310
fn main() {}

src/test/ui/issues/issue-5099.stderr

+28-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,33 @@
11
error[E0425]: cannot find value `this` in this scope
2-
--> $DIR/issue-5099.rs:1:31
2+
--> $DIR/issue-5099.rs:3:9
33
|
4-
LL | trait B < A > { fn a() -> A { this.a } }
5-
| ^^^^ not found in this scope
4+
LL | this.a
5+
| ^^^^ not found in this scope
6+
|
7+
help: you might have meant to use `self` here instead
8+
|
9+
LL | self.a
10+
| ^^^^
11+
help: if you meant to use `self`, you are also missing a `self` receiver argument
12+
|
13+
LL | fn a(&self) -> A {
14+
| ^^^^^
15+
16+
error[E0425]: cannot find value `this` in this scope
17+
--> $DIR/issue-5099.rs:6:9
18+
|
19+
LL | this.b(x);
20+
| ^^^^ not found in this scope
21+
|
22+
help: you might have meant to use `self` here instead
23+
|
24+
LL | self.b(x);
25+
| ^^^^
26+
help: if you meant to use `self`, you are also missing a `self` receiver argument
27+
|
28+
LL | fn b(&self, x: i32) {
29+
| ^^^^^^
630

7-
error: aborting due to previous error
31+
error: aborting due to 2 previous errors
832

933
For more information about this error, try `rustc --explain E0425`.

src/test/ui/resolve/issue-2356.stderr

+13-14
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,15 @@ LL | purr();
7070
error[E0424]: expected value, found module `self`
7171
--> $DIR/issue-2356.rs:65:8
7272
|
73-
LL | / fn meow() {
74-
LL | | if self.whiskers > 3 {
75-
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
76-
LL | |
77-
LL | | println!("MEOW");
78-
LL | | }
79-
LL | | }
80-
| |___- this function doesn't have a `self` parameter
73+
LL | fn meow() {
74+
| ---- this function doesn't have a `self` parameter
75+
LL | if self.whiskers > 3 {
76+
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
77+
|
78+
help: add a `self` receiver parameter to make the associated `fn` a method
79+
|
80+
LL | fn meow(&self) {
81+
| ^^^^^
8182

8283
error[E0425]: cannot find function `grow_older` in this scope
8384
--> $DIR/issue-2356.rs:72:5
@@ -112,12 +113,10 @@ LL | purr_louder();
112113
error[E0424]: expected value, found module `self`
113114
--> $DIR/issue-2356.rs:92:5
114115
|
115-
LL | / fn main() {
116-
LL | | self += 1;
117-
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
118-
LL | |
119-
LL | | }
120-
| |_- this function doesn't have a `self` parameter
116+
LL | fn main() {
117+
| ---- this function can't have a `self` parameter
118+
LL | self += 1;
119+
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
121120

122121
error: aborting due to 17 previous errors
123122

0 commit comments

Comments
 (0)