From c4a4926083e9f0b9aeef549f93cb66cd9d4076d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 23 Sep 2023 01:34:50 +0000 Subject: [PATCH 1/4] More accurate suggestion for `self.` and `Self::` Fix #115992. --- .../rustc_resolve/src/late/diagnostics.rs | 17 +++++--- tests/ui/suggestions/assoc_fn_without_self.rs | 8 ++++ .../suggestions/assoc_fn_without_self.stderr | 40 +++++++++++++++++-- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c34b7df9b4603..44dba9b7be776 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -224,14 +224,21 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { && let FnKind::Fn(_, _, sig, ..) = fn_kind && let Some(items) = self.diagnostic_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { - if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind - && i.ident.name == item_str.name - // don't suggest if the item is in Fn signature arguments - // issue #112590 + if i.ident.name == item_str.name + // Don't suggest if the item is in Fn signature arguments (#112590). && !sig.span.contains(item_span) { debug!(?item_str.name); - return true + return match &i.kind { + AssocItemKind::Fn(fn_) + if !sig.decl.has_self() && fn_.sig.decl.has_self() => { + // Ensure that we only suggest `self.` if `self` is available, + // you can't call `fn foo(&self)` from `fn bar()` (#115992). + false + } + AssocItemKind::Fn(_) | AssocItemKind::Const(..) => true, + _ => false + } } false }) diff --git a/tests/ui/suggestions/assoc_fn_without_self.rs b/tests/ui/suggestions/assoc_fn_without_self.rs index 778d9847773f3..35c16ef3e9f7c 100644 --- a/tests/ui/suggestions/assoc_fn_without_self.rs +++ b/tests/ui/suggestions/assoc_fn_without_self.rs @@ -17,4 +17,12 @@ impl S { bar(); //~ ERROR cannot find function `bar` in this scope baz(2, 3); //~ ERROR cannot find function `baz` in this scope } + fn d(&self) { + fn c() { + foo(); //~ ERROR cannot find function `foo` in this scope + } + foo(); //~ ERROR cannot find function `foo` in this scope + bar(); //~ ERROR cannot find function `bar` in this scope + baz(2, 3); //~ ERROR cannot find function `baz` in this scope + } } diff --git a/tests/ui/suggestions/assoc_fn_without_self.stderr b/tests/ui/suggestions/assoc_fn_without_self.stderr index febdd67338c99..a7fab36bf8d84 100644 --- a/tests/ui/suggestions/assoc_fn_without_self.stderr +++ b/tests/ui/suggestions/assoc_fn_without_self.stderr @@ -12,6 +12,40 @@ LL | Self::foo(); error[E0425]: cannot find function `bar` in this scope --> $DIR/assoc_fn_without_self.rs:17:9 | +LL | bar(); + | ^^^ not found in this scope + +error[E0425]: cannot find function `baz` in this scope + --> $DIR/assoc_fn_without_self.rs:18:9 + | +LL | baz(2, 3); + | ^^^ not found in this scope + | +help: consider using the associated function + | +LL | Self::baz(2, 3); + | ++++++ + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/assoc_fn_without_self.rs:14:13 + | +LL | foo(); + | ^^^ not found in this scope + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/assoc_fn_without_self.rs:24:9 + | +LL | foo(); + | ^^^ not found in this scope + | +help: consider using the associated function + | +LL | Self::foo(); + | ++++++ + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/assoc_fn_without_self.rs:25:9 + | LL | bar(); | ^^^ not found in this scope | @@ -21,7 +55,7 @@ LL | self.bar(); | +++++ error[E0425]: cannot find function `baz` in this scope - --> $DIR/assoc_fn_without_self.rs:18:9 + --> $DIR/assoc_fn_without_self.rs:26:9 | LL | baz(2, 3); | ^^^ not found in this scope @@ -32,11 +66,11 @@ LL | Self::baz(2, 3); | ++++++ error[E0425]: cannot find function `foo` in this scope - --> $DIR/assoc_fn_without_self.rs:14:13 + --> $DIR/assoc_fn_without_self.rs:22:13 | LL | foo(); | ^^^ not found in this scope -error: aborting due to 4 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0425`. From 0e986825762edd031bc6bf4a78d9162ac2ed6268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 23 Sep 2023 01:47:06 +0000 Subject: [PATCH 2/4] When encountering method on `Self` that we can't suggest, mention it --- .../rustc_resolve/src/late/diagnostics.rs | 58 +++++++++---------- .../suggestions/assoc_fn_without_self.stderr | 3 + 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 44dba9b7be776..c690ac6c043f9 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -214,6 +214,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { module: None, } } else { + let mut span_label = None; let item_span = path.last().unwrap().ident.span; let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 { debug!(?self.diagnostic_metadata.current_impl_items); @@ -224,39 +225,36 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { && let FnKind::Fn(_, _, sig, ..) = fn_kind && let Some(items) = self.diagnostic_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { - if i.ident.name == item_str.name + i.ident.name == item_str.name // Don't suggest if the item is in Fn signature arguments (#112590). && !sig.span.contains(item_span) - { - debug!(?item_str.name); - return match &i.kind { - AssocItemKind::Fn(fn_) - if !sig.decl.has_self() && fn_.sig.decl.has_self() => { - // Ensure that we only suggest `self.` if `self` is available, - // you can't call `fn foo(&self)` from `fn bar()` (#115992). - false - } - AssocItemKind::Fn(_) | AssocItemKind::Const(..) => true, - _ => false - } - } - false }) { - let self_sugg = match &item.kind { - AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.", - _ => "Self::", - }; - - Some(( - item_span.shrink_to_lo(), - match &item.kind { - AssocItemKind::Fn(..) => "consider using the associated function", - AssocItemKind::Const(..) => "consider using the associated constant", - _ => unreachable!("item kind was filtered above"), - }, - self_sugg.to_string() - )) + let sp = item_span.shrink_to_lo(); + match &item.kind { + AssocItemKind::Fn(fn_) + if !sig.decl.has_self() && fn_.sig.decl.has_self() => { + // Ensure that we only suggest `self.` if `self` is available, + // you can't call `fn foo(&self)` from `fn bar()` (#115992). + // We also want to mention that the method exists. + span_label = Some(( + item.ident.span, + "a method by that name is available on `Self` here", + )); + None + } + AssocItemKind::Fn(fn_) => Some(( + sp, + "consider using the associated function", + if fn_.sig.decl.has_self() { "self." } else { "Self::" }, + )), + AssocItemKind::Const(..) => Some(( + sp, + "consider using the associated constant", + "Self::", + )), + _ => None + } } else { None }; @@ -321,7 +319,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"), fallback_label, span: item_span, - span_label: None, + span_label, could_be_expr: false, suggestion, module, diff --git a/tests/ui/suggestions/assoc_fn_without_self.stderr b/tests/ui/suggestions/assoc_fn_without_self.stderr index a7fab36bf8d84..26fcc2a018100 100644 --- a/tests/ui/suggestions/assoc_fn_without_self.stderr +++ b/tests/ui/suggestions/assoc_fn_without_self.stderr @@ -12,6 +12,9 @@ LL | Self::foo(); error[E0425]: cannot find function `bar` in this scope --> $DIR/assoc_fn_without_self.rs:17:9 | +LL | fn bar(&self) {} + | --- a method by that name is available on `Self` here +... LL | bar(); | ^^^ not found in this scope From ac5e18756a4f0987c5861e45b82ac6f410fd4734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 23 Sep 2023 01:54:05 +0000 Subject: [PATCH 3/4] Tweak wording and logic --- compiler/rustc_resolve/src/late/diagnostics.rs | 15 ++++++++++----- tests/ui/resolve/issue-103474.stderr | 2 +- tests/ui/resolve/issue-2356.stderr | 4 ++-- tests/ui/self/class-missing-self.stderr | 2 +- .../suggestions/assoc-const-without-self.stderr | 2 +- tests/ui/suggestions/assoc_fn_without_self.stderr | 10 +++++----- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c690ac6c043f9..06a08f29a1ee8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -243,15 +243,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { )); None } - AssocItemKind::Fn(fn_) => Some(( + AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => Some(( sp, - "consider using the associated function", - if fn_.sig.decl.has_self() { "self." } else { "Self::" }, + "consider using the method on `Self`", + "self.".to_string(), + )), + AssocItemKind::Fn(_) => Some(( + sp, + "consider using the associated function on `Self`", + "Self::".to_string(), )), AssocItemKind::Const(..) => Some(( sp, - "consider using the associated constant", - "Self::", + "consider using the associated constant on `Self`", + "Self::".to_string(), )), _ => None } diff --git a/tests/ui/resolve/issue-103474.stderr b/tests/ui/resolve/issue-103474.stderr index 415d231552a03..e48fb31eccc9a 100644 --- a/tests/ui/resolve/issue-103474.stderr +++ b/tests/ui/resolve/issue-103474.stderr @@ -19,7 +19,7 @@ error[E0425]: cannot find function `first` in this scope LL | first() | ^^^^^ not found in this scope | -help: consider using the associated function +help: consider using the method on `Self` | LL | self.first() | +++++ diff --git a/tests/ui/resolve/issue-2356.stderr b/tests/ui/resolve/issue-2356.stderr index 30f5f05952664..273e8b2a661fb 100644 --- a/tests/ui/resolve/issue-2356.stderr +++ b/tests/ui/resolve/issue-2356.stderr @@ -73,7 +73,7 @@ error[E0425]: cannot find function `static_method` in this scope LL | static_method(); | ^^^^^^^^^^^^^ not found in this scope | -help: consider using the associated function +help: consider using the associated function on `Self` | LL | Self::static_method(); | ++++++ @@ -102,7 +102,7 @@ error[E0425]: cannot find function `grow_older` in this scope LL | grow_older(); | ^^^^^^^^^^ not found in this scope | -help: consider using the associated function +help: consider using the associated function on `Self` | LL | Self::grow_older(); | ++++++ diff --git a/tests/ui/self/class-missing-self.stderr b/tests/ui/self/class-missing-self.stderr index 3c37d8197432c..08493b4f9a2da 100644 --- a/tests/ui/self/class-missing-self.stderr +++ b/tests/ui/self/class-missing-self.stderr @@ -10,7 +10,7 @@ error[E0425]: cannot find function `sleep` in this scope LL | sleep(); | ^^^^^ not found in this scope | -help: consider using the associated function +help: consider using the method on `Self` | LL | self.sleep(); | +++++ diff --git a/tests/ui/suggestions/assoc-const-without-self.stderr b/tests/ui/suggestions/assoc-const-without-self.stderr index 88d72da70cb9b..05528d277be5b 100644 --- a/tests/ui/suggestions/assoc-const-without-self.stderr +++ b/tests/ui/suggestions/assoc-const-without-self.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `A_CONST` in this scope LL | A_CONST | ^^^^^^^ not found in this scope | -help: consider using the associated constant +help: consider using the associated constant on `Self` | LL | Self::A_CONST | ++++++ diff --git a/tests/ui/suggestions/assoc_fn_without_self.stderr b/tests/ui/suggestions/assoc_fn_without_self.stderr index 26fcc2a018100..9cee7c7ee5ee8 100644 --- a/tests/ui/suggestions/assoc_fn_without_self.stderr +++ b/tests/ui/suggestions/assoc_fn_without_self.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `foo` in this scope LL | foo(); | ^^^ not found in this scope | -help: consider using the associated function +help: consider using the associated function on `Self` | LL | Self::foo(); | ++++++ @@ -24,7 +24,7 @@ error[E0425]: cannot find function `baz` in this scope LL | baz(2, 3); | ^^^ not found in this scope | -help: consider using the associated function +help: consider using the associated function on `Self` | LL | Self::baz(2, 3); | ++++++ @@ -41,7 +41,7 @@ error[E0425]: cannot find function `foo` in this scope LL | foo(); | ^^^ not found in this scope | -help: consider using the associated function +help: consider using the associated function on `Self` | LL | Self::foo(); | ++++++ @@ -52,7 +52,7 @@ error[E0425]: cannot find function `bar` in this scope LL | bar(); | ^^^ not found in this scope | -help: consider using the associated function +help: consider using the method on `Self` | LL | self.bar(); | +++++ @@ -63,7 +63,7 @@ error[E0425]: cannot find function `baz` in this scope LL | baz(2, 3); | ^^^ not found in this scope | -help: consider using the associated function +help: consider using the associated function on `Self` | LL | Self::baz(2, 3); | ++++++ From 7d8559ac9077e35a687d5b16f17f2f493421f3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 23 Sep 2023 01:59:22 +0000 Subject: [PATCH 4/4] Add test --- ...ethod-in-self-not-available-in-assoc-fn.rs | 15 +++++++++++++ ...d-in-self-not-available-in-assoc-fn.stderr | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs create mode 100644 tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr diff --git a/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs new file mode 100644 index 0000000000000..9e72c36151e5d --- /dev/null +++ b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs @@ -0,0 +1,15 @@ +struct Foo { + field: u32, +} + +impl Foo { + fn field(&self) -> u32 { + self.field + } + + fn new() -> Foo { + field; //~ ERROR cannot find value `field` in this scope + Foo { field } //~ ERROR cannot find value `field` in this scope + } +} +fn main() {} diff --git a/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr new file mode 100644 index 0000000000000..2eb3861e5f11b --- /dev/null +++ b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find value `field` in this scope + --> $DIR/field-and-method-in-self-not-available-in-assoc-fn.rs:11:9 + | +LL | fn field(&self) -> u32 { + | ----- a method by that name is available on `Self` here +... +LL | field; + | ^^^^^ a field by this name exists in `Self` + +error[E0425]: cannot find value `field` in this scope + --> $DIR/field-and-method-in-self-not-available-in-assoc-fn.rs:12:15 + | +LL | fn field(&self) -> u32 { + | ----- a method by that name is available on `Self` here +... +LL | Foo { field } + | ^^^^^ a field by this name exists in `Self` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`.