about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-09-24 01:14:06 +0200
committerGitHub <noreply@github.com>2023-09-24 01:14:06 +0200
commit61b38b216a683af2f5df42c036c52c5bee34ef1c (patch)
tree25a00d437d27a7a6302b4aeaa3e6f5a15b90378d
parent8c9e516e6e97bd8a03f6d171ee3f678e43ee7858 (diff)
parent7d8559ac9077e35a687d5b16f17f2f493421f3ab (diff)
downloadrust-61b38b216a683af2f5df42c036c52c5bee34ef1c.tar.gz
rust-61b38b216a683af2f5df42c036c52c5bee34ef1c.zip
Rollup merge of #116086 - estebank:issue-115992, r=compiler-errors
More accurate suggestion for `self.` and `Self::`

Detect that we can't suggest `self.` in an associated function without `&self` receiver.

Partially address #115992.

r? ``@compiler-errors``
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs58
-rw-r--r--tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.rs15
-rw-r--r--tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr21
-rw-r--r--tests/ui/resolve/issue-103474.stderr2
-rw-r--r--tests/ui/resolve/issue-2356.stderr4
-rw-r--r--tests/ui/self/class-missing-self.stderr2
-rw-r--r--tests/ui/suggestions/assoc-const-without-self.stderr2
-rw-r--r--tests/ui/suggestions/assoc_fn_without_self.rs8
-rw-r--r--tests/ui/suggestions/assoc_fn_without_self.stderr49
9 files changed, 126 insertions, 35 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c34b7df9b46..06a08f29a1e 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,32 +225,41 @@ 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
+                        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
-                        }
-                        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_) if fn_.sig.decl.has_self() => Some((
+                            sp,
+                            "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 on `Self`",
+                            "Self::".to_string(),
+                        )),
+                        _ => None
+                    }
                 } else {
                     None
                 };
@@ -314,7 +324,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/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 00000000000..9e72c36151e
--- /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 00000000000..2eb3861e5f1
--- /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`.
diff --git a/tests/ui/resolve/issue-103474.stderr b/tests/ui/resolve/issue-103474.stderr
index 415d231552a..e48fb31eccc 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 30f5f059526..273e8b2a661 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 3c37d819743..08493b4f9a2 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 88d72da70cb..05528d277be 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.rs b/tests/ui/suggestions/assoc_fn_without_self.rs
index 778d9847773..35c16ef3e9f 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 febdd67338c..9cee7c7ee5e 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();
    |         ++++++
@@ -12,31 +12,68 @@ 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
+
+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 on `Self`
+   |
+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 on `Self`
+   |
+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
    |
-help: consider using the associated function
+help: consider using the method on `Self`
    |
 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
    |
-help: consider using the associated function
+help: consider using the associated function on `Self`
    |
 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`.