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_
This commit is contained in:
commit
2fb2af4f1d
7 changed files with 148 additions and 35 deletions
|
@ -50,6 +50,13 @@ impl<'a> FnKind<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ident(&self) -> Option<&Ident> {
|
||||||
|
match self {
|
||||||
|
FnKind::Fn(_, ident, ..) => Some(ident),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decl(&self) -> &'a FnDecl {
|
pub fn decl(&self) -> &'a FnDecl {
|
||||||
match self {
|
match self {
|
||||||
FnKind::Fn(_, _, sig, _, _) => &sig.decl,
|
FnKind::Fn(_, _, sig, _, _) => &sig.decl,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::{PathResult, PathSource, Segment};
|
||||||
|
|
||||||
use rustc_ast::ast::{self, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
|
use rustc_ast::ast::{self, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
|
||||||
use rustc_ast::util::lev_distance::find_best_match_for_name;
|
use rustc_ast::util::lev_distance::find_best_match_for_name;
|
||||||
|
use rustc_ast::visit::FnKind;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -175,16 +176,40 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
|
||||||
let code = source.error_code(res.is_some());
|
let code = source.error_code(res.is_some());
|
||||||
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
|
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
|
||||||
|
|
||||||
|
let is_assoc_fn = self.self_type_is_available(span);
|
||||||
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
|
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
|
||||||
if ["this", "my"].contains(&&*item_str.as_str())
|
if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn {
|
||||||
&& self.self_value_is_available(path[0].ident.span, span)
|
|
||||||
{
|
|
||||||
err.span_suggestion_short(
|
err.span_suggestion_short(
|
||||||
span,
|
span,
|
||||||
"you might have meant to use `self` here instead",
|
"you might have meant to use `self` here instead",
|
||||||
"self".to_string(),
|
"self".to_string(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
if !self.self_value_is_available(path[0].ident.span, span) {
|
||||||
|
if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
|
||||||
|
&self.diagnostic_metadata.current_function
|
||||||
|
{
|
||||||
|
let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
|
||||||
|
(param.span.shrink_to_lo(), "&self, ")
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
self.r
|
||||||
|
.session
|
||||||
|
.source_map()
|
||||||
|
.span_through_char(*fn_span, '(')
|
||||||
|
.shrink_to_hi(),
|
||||||
|
"&self",
|
||||||
|
)
|
||||||
|
};
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"if you meant to use `self`, you are also missing a `self` receiver \
|
||||||
|
argument",
|
||||||
|
sugg.to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit special messages for unresolved `Self` and `self`.
|
// Emit special messages for unresolved `Self` and `self`.
|
||||||
|
@ -213,7 +238,38 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
|
||||||
if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
|
if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
|
||||||
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
|
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
|
||||||
} else {
|
} else {
|
||||||
err.span_label(*span, "this function doesn't have a `self` parameter");
|
let doesnt = if is_assoc_fn {
|
||||||
|
let (span, sugg) = fn_kind
|
||||||
|
.decl()
|
||||||
|
.inputs
|
||||||
|
.get(0)
|
||||||
|
.map(|p| (p.span.shrink_to_lo(), "&self, "))
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
(
|
||||||
|
self.r
|
||||||
|
.session
|
||||||
|
.source_map()
|
||||||
|
.span_through_char(*span, '(')
|
||||||
|
.shrink_to_hi(),
|
||||||
|
"&self",
|
||||||
|
)
|
||||||
|
});
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"add a `self` receiver parameter to make the associated `fn` a method",
|
||||||
|
sugg.to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
"doesn't"
|
||||||
|
} else {
|
||||||
|
"can't"
|
||||||
|
};
|
||||||
|
if let Some(ident) = fn_kind.ident() {
|
||||||
|
err.span_label(
|
||||||
|
ident.span,
|
||||||
|
&format!("this function {} have a `self` parameter", doesnt),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (err, Vec::new());
|
return (err, Vec::new());
|
||||||
|
|
|
@ -6,6 +6,10 @@ impl Foo {
|
||||||
fn foo() {
|
fn foo() {
|
||||||
self.bar(); //~ ERROR E0424
|
self.bar(); //~ ERROR E0424
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn baz(_: i32) {
|
||||||
|
self.bar(); //~ ERROR E0424
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main () {
|
fn main () {
|
||||||
|
|
|
@ -1,21 +1,37 @@
|
||||||
error[E0424]: expected value, found module `self`
|
error[E0424]: expected value, found module `self`
|
||||||
--> $DIR/E0424.rs:7:9
|
--> $DIR/E0424.rs:7:9
|
||||||
|
|
|
|
||||||
LL | / fn foo() {
|
LL | fn foo() {
|
||||||
LL | | self.bar();
|
| --- this function doesn't have a `self` parameter
|
||||||
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
LL | self.bar();
|
||||||
LL | | }
|
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||||
| |_____- this function doesn't have a `self` parameter
|
|
|
||||||
|
help: add a `self` receiver parameter to make the associated `fn` a method
|
||||||
|
|
|
||||||
|
LL | fn foo(&self) {
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error[E0424]: expected value, found module `self`
|
||||||
|
--> $DIR/E0424.rs:11:9
|
||||||
|
|
|
||||||
|
LL | fn baz(_: i32) {
|
||||||
|
| --- this function doesn't have a `self` parameter
|
||||||
|
LL | self.bar();
|
||||||
|
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||||
|
|
|
||||||
|
help: add a `self` receiver parameter to make the associated `fn` a method
|
||||||
|
|
|
||||||
|
LL | fn baz(&self, _: i32) {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error[E0424]: expected unit struct, unit variant or constant, found module `self`
|
error[E0424]: expected unit struct, unit variant or constant, found module `self`
|
||||||
--> $DIR/E0424.rs:12:9
|
--> $DIR/E0424.rs:16:9
|
||||||
|
|
|
|
||||||
LL | / fn main () {
|
LL | fn main () {
|
||||||
LL | | let self = "self";
|
| ---- this function can't have a `self` parameter
|
||||||
| | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
LL | let self = "self";
|
||||||
LL | | }
|
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
||||||
| |_- this function doesn't have a `self` parameter
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0424`.
|
For more information about this error, try `rustc --explain E0424`.
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
trait B < A > { fn a() -> A { this.a } } //~ ERROR cannot find value `this` in this scope
|
trait B <A> {
|
||||||
|
fn a() -> A {
|
||||||
|
this.a //~ ERROR cannot find value `this` in this scope
|
||||||
|
}
|
||||||
|
fn b(x: i32) {
|
||||||
|
this.b(x); //~ ERROR cannot find value `this` in this scope
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,9 +1,33 @@
|
||||||
error[E0425]: cannot find value `this` in this scope
|
error[E0425]: cannot find value `this` in this scope
|
||||||
--> $DIR/issue-5099.rs:1:31
|
--> $DIR/issue-5099.rs:3:9
|
||||||
|
|
|
|
||||||
LL | trait B < A > { fn a() -> A { this.a } }
|
LL | this.a
|
||||||
| ^^^^ not found in this scope
|
| ^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: you might have meant to use `self` here instead
|
||||||
|
|
|
||||||
|
LL | self.a
|
||||||
|
| ^^^^
|
||||||
|
help: if you meant to use `self`, you are also missing a `self` receiver argument
|
||||||
|
|
|
||||||
|
LL | fn a(&self) -> A {
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0425]: cannot find value `this` in this scope
|
||||||
|
--> $DIR/issue-5099.rs:6:9
|
||||||
|
|
|
||||||
|
LL | this.b(x);
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: you might have meant to use `self` here instead
|
||||||
|
|
|
||||||
|
LL | self.b(x);
|
||||||
|
| ^^^^
|
||||||
|
help: if you meant to use `self`, you are also missing a `self` receiver argument
|
||||||
|
|
|
||||||
|
LL | fn b(&self, x: i32) {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0425`.
|
For more information about this error, try `rustc --explain E0425`.
|
||||||
|
|
|
@ -70,14 +70,15 @@ LL | purr();
|
||||||
error[E0424]: expected value, found module `self`
|
error[E0424]: expected value, found module `self`
|
||||||
--> $DIR/issue-2356.rs:65:8
|
--> $DIR/issue-2356.rs:65:8
|
||||||
|
|
|
|
||||||
LL | / fn meow() {
|
LL | fn meow() {
|
||||||
LL | | if self.whiskers > 3 {
|
| ---- this function doesn't have a `self` parameter
|
||||||
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
LL | if self.whiskers > 3 {
|
||||||
LL | |
|
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||||
LL | | println!("MEOW");
|
|
|
||||||
LL | | }
|
help: add a `self` receiver parameter to make the associated `fn` a method
|
||||||
LL | | }
|
|
|
||||||
| |___- this function doesn't have a `self` parameter
|
LL | fn meow(&self) {
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
error[E0425]: cannot find function `grow_older` in this scope
|
error[E0425]: cannot find function `grow_older` in this scope
|
||||||
--> $DIR/issue-2356.rs:72:5
|
--> $DIR/issue-2356.rs:72:5
|
||||||
|
@ -112,12 +113,10 @@ LL | purr_louder();
|
||||||
error[E0424]: expected value, found module `self`
|
error[E0424]: expected value, found module `self`
|
||||||
--> $DIR/issue-2356.rs:92:5
|
--> $DIR/issue-2356.rs:92:5
|
||||||
|
|
|
|
||||||
LL | / fn main() {
|
LL | fn main() {
|
||||||
LL | | self += 1;
|
| ---- this function can't have a `self` parameter
|
||||||
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
LL | self += 1;
|
||||||
LL | |
|
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||||
LL | | }
|
|
||||||
| |_- this function doesn't have a `self` parameter
|
|
||||||
|
|
||||||
error: aborting due to 17 previous errors
|
error: aborting due to 17 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue