diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs index 2c3d1e97df9..b65a88cb90e 100644 --- a/src/librustc_ast/visit.rs +++ b/src/librustc_ast/visit.rs @@ -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 { match self { FnKind::Fn(_, _, sig, _, _) => &sig.decl, diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index a7d36974057..b3746ac2db2 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -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::util::lev_distance::find_best_match_for_name; +use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -175,16 +176,40 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { 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 is_assoc_fn = self.self_type_is_available(span); // Emit help message for fake-self from other languages (e.g., `this` in Javascript). - if ["this", "my"].contains(&&*item_str.as_str()) - && self.self_value_is_available(path[0].ident.span, span) - { + if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn { err.span_suggestion_short( span, "you might have meant to use `self` here instead", "self".to_string(), 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`. @@ -213,7 +238,38 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { 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"); } 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()); diff --git a/src/test/ui/error-codes/E0424.rs b/src/test/ui/error-codes/E0424.rs index 3c6a1d4f88f..fa0c86ecf48 100644 --- a/src/test/ui/error-codes/E0424.rs +++ b/src/test/ui/error-codes/E0424.rs @@ -6,6 +6,10 @@ impl Foo { fn foo() { self.bar(); //~ ERROR E0424 } + + fn baz(_: i32) { + self.bar(); //~ ERROR E0424 + } } fn main () { diff --git a/src/test/ui/error-codes/E0424.stderr b/src/test/ui/error-codes/E0424.stderr index 690a101496d..9b8a29e8272 100644 --- a/src/test/ui/error-codes/E0424.stderr +++ b/src/test/ui/error-codes/E0424.stderr @@ -1,21 +1,37 @@ error[E0424]: expected value, found module `self` --> $DIR/E0424.rs:7:9 | -LL | / fn foo() { -LL | | self.bar(); - | | ^^^^ `self` value is a keyword only available in methods with a `self` parameter -LL | | } - | |_____- this function doesn't have a `self` parameter +LL | fn foo() { + | --- 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 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` - --> $DIR/E0424.rs:12:9 + --> $DIR/E0424.rs:16:9 | -LL | / fn main () { -LL | | let self = "self"; - | | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed -LL | | } - | |_- this function doesn't have a `self` parameter +LL | fn main () { + | ---- this function can't have a `self` parameter +LL | let self = "self"; + | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0424`. diff --git a/src/test/ui/issues/issue-5099.rs b/src/test/ui/issues/issue-5099.rs index d00fff32809..ee134835c37 100644 --- a/src/test/ui/issues/issue-5099.rs +++ b/src/test/ui/issues/issue-5099.rs @@ -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() {} diff --git a/src/test/ui/issues/issue-5099.stderr b/src/test/ui/issues/issue-5099.stderr index cc11db9c5ec..b52fd28b2b5 100644 --- a/src/test/ui/issues/issue-5099.stderr +++ b/src/test/ui/issues/issue-5099.stderr @@ -1,9 +1,33 @@ 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 } } - | ^^^^ not found in this scope +LL | this.a + | ^^^^ 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`. diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index b687f0b0af0..0339daa0d6a 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -70,14 +70,15 @@ LL | purr(); error[E0424]: expected value, found module `self` --> $DIR/issue-2356.rs:65:8 | -LL | / fn meow() { -LL | | if self.whiskers > 3 { - | | ^^^^ `self` value is a keyword only available in methods with a `self` parameter -LL | | -LL | | println!("MEOW"); -LL | | } -LL | | } - | |___- this function doesn't have a `self` parameter +LL | fn meow() { + | ---- this function doesn't have a `self` parameter +LL | if self.whiskers > 3 { + | ^^^^ `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 meow(&self) { + | ^^^^^ error[E0425]: cannot find function `grow_older` in this scope --> $DIR/issue-2356.rs:72:5 @@ -112,12 +113,10 @@ LL | purr_louder(); error[E0424]: expected value, found module `self` --> $DIR/issue-2356.rs:92:5 | -LL | / fn main() { -LL | | self += 1; - | | ^^^^ `self` value is a keyword only available in methods with a `self` parameter -LL | | -LL | | } - | |_- this function doesn't have a `self` parameter +LL | fn main() { + | ---- this function can't have a `self` parameter +LL | self += 1; + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter error: aborting due to 17 previous errors