From 643258ff6c6f545debeb2ce5b7405522843d6ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 13 Aug 2020 17:04:33 -0700 Subject: [PATCH 1/3] Tweak suggestion for `this` -> `self` --- src/librustc_resolve/late/diagnostics.rs | 30 +++++++++++++++++++--- src/test/ui/issues/issue-5099.rs | 9 ++++++- src/test/ui/issues/issue-5099.stderr | 32 +++++++++++++++++++++--- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index c57c0e5194185..ce154bb09f450 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,15 +176,38 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code); // 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()) && self.self_type_is_available(span) { 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 + { + if let Some(param) = sig.decl.inputs.get(0) { + err.span_suggestion_verbose( + param.span.shrink_to_lo(), + "you are also missing a `self` receiver argument", + "&self, ".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + self.r + .session + .source_map() + .span_through_char(*fn_span, '(') + .shrink_to_hi(), + "you are also missing a `self` receiver argument", + "&self".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } } // Emit special messages for unresolved `Self` and `self`. diff --git a/src/test/ui/issues/issue-5099.rs b/src/test/ui/issues/issue-5099.rs index d00fff3280920..ee134835c37ed 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 { + 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 cc11db9c5eca6..56b02c45a08d7 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: you are also missing a `self` receiver argument + | +LL | fn a(&self) -> A { + | ^^^^^ + +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: you are also missing a `self` receiver argument + | +LL | fn b(&self, x: i32) { + | ^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0425`. From 360388b160ca5be560fec59acb84a86e813524f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 13 Aug 2020 17:52:33 -0700 Subject: [PATCH 2/3] Suggest adding `&self` when accessing `self` in static assoc `fn` --- src/librustc_ast/visit.rs | 7 +++ src/librustc_resolve/late/diagnostics.rs | 61 ++++++++++++++++++------ src/test/ui/error-codes/E0424.rs | 4 ++ src/test/ui/error-codes/E0424.stderr | 40 +++++++++++----- src/test/ui/resolve/issue-2356.stderr | 27 +++++------ 5 files changed, 98 insertions(+), 41 deletions(-) diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs index 2c3d1e97df975..b65a88cb90e88 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 ce154bb09f450..67a9d9b4ec1b4 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -175,8 +175,9 @@ 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_type_is_available(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", @@ -187,25 +188,24 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) = &self.diagnostic_metadata.current_function { - if let Some(param) = sig.decl.inputs.get(0) { - err.span_suggestion_verbose( - param.span.shrink_to_lo(), - "you are also missing a `self` receiver argument", - "&self, ".to_string(), - Applicability::MaybeIncorrect, - ); + let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) { + (param.span.shrink_to_lo(), "&self, ") } else { - err.span_suggestion_verbose( + ( self.r .session .source_map() .span_through_char(*fn_span, '(') .shrink_to_hi(), - "you are also missing a `self` receiver argument", - "&self".to_string(), - Applicability::MaybeIncorrect, - ); - } + "&self", + ) + }; + err.span_suggestion_verbose( + span, + "you are also missing a `self` receiver argument", + sugg.to_string(), + Applicability::MaybeIncorrect, + ); } } } @@ -236,7 +236,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 3c6a1d4f88f11..fa0c86ecf4894 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 690a101496d73..9b8a29e827249 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/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index b687f0b0af0ad..0339daa0d6a18 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 From 4ecdec1fb665363ee46af24a9a6edf73a9b602ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 14 Aug 2020 10:16:34 -0700 Subject: [PATCH 3/3] review comment: suggestion message wording --- src/librustc_resolve/late/diagnostics.rs | 3 ++- src/test/ui/issues/issue-5099.stderr | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 67a9d9b4ec1b4..3df6a230b0f09 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -202,7 +202,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { }; err.span_suggestion_verbose( span, - "you are also missing a `self` receiver argument", + "if you meant to use `self`, you are also missing a `self` receiver \ + argument", sugg.to_string(), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/issues/issue-5099.stderr b/src/test/ui/issues/issue-5099.stderr index 56b02c45a08d7..b52fd28b2b575 100644 --- a/src/test/ui/issues/issue-5099.stderr +++ b/src/test/ui/issues/issue-5099.stderr @@ -8,7 +8,7 @@ help: you might have meant to use `self` here instead | LL | self.a | ^^^^ -help: you are also missing a `self` receiver argument +help: if you meant to use `self`, you are also missing a `self` receiver argument | LL | fn a(&self) -> A { | ^^^^^ @@ -23,7 +23,7 @@ help: you might have meant to use `self` here instead | LL | self.b(x); | ^^^^ -help: you are also missing a `self` receiver argument +help: if you meant to use `self`, you are also missing a `self` receiver argument | LL | fn b(&self, x: i32) { | ^^^^^^