]> git.lizzy.rs Git - rust.git/commitdiff
Emit a better diagnostic when function actually has a 'self' parameter
authorAaron Hill <aa1ronham@gmail.com>
Sun, 17 May 2020 22:28:12 +0000 (18:28 -0400)
committerAaron Hill <aa1ronham@gmail.com>
Sun, 17 May 2020 23:04:13 +0000 (19:04 -0400)
Fixes #66898

When we are unable to resolve a reference to `self`, we current assume
that the containing function doesn't have a `self` parameter, and
emit an error message accordingly.

However, if the reference to `self` was created by a macro invocation,
then resolution will correctly fail, due to hygiene. In this case, we
don't want to tell the user that the containing fuction doesn't have a
'self' paramter if it actually has one.

This PR checks for the precense of a 'self' parameter, and adjusts the
error message we emit accordingly.

TODO: The exact error message we emit could probably be improved. Should
we explicitly mention hygiene?

src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/test/ui/hygiene/missing-self-diag.rs [new file with mode: 0644]
src/test/ui/hygiene/missing-self-diag.stderr [new file with mode: 0644]

index e541920e89ed451ed96d93bdf9a07f126c6a4274..477e3be5cc2f89df6b8cc39cef04a1436da592df 100644 (file)
@@ -347,7 +347,7 @@ struct DiagnosticMetadata<'ast> {
     currently_processing_generics: bool,
 
     /// The current enclosing function (used for better errors).
-    current_function: Option<Span>,
+    current_function: Option<(FnKind<'ast>, Span)>,
 
     /// A list of labels as of yet unused. Labels will be removed from this map when
     /// they are used (in a `break` or `continue` statement)
@@ -466,7 +466,8 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
             FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind,
             FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind,
         };
-        let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
+        let previous_value =
+            replace(&mut self.diagnostic_metadata.current_function, Some((fn_kind, sp)));
         debug!("(resolving function) entering function");
         let declaration = fn_kind.decl();
 
index dc92b465c2bc1ef9469ce291151cd301906c3f3d..b1a1f8725a1801024674d10a4c247696b226a1be 100644 (file)
@@ -195,8 +195,15 @@ pub(crate) fn smart_resolve_report_errors(
                 _ => "`self` value is a keyword only available in methods with a `self` parameter"
                      .to_string(),
             });
-            if let Some(span) = &self.diagnostic_metadata.current_function {
-                err.span_label(*span, "this function doesn't have a `self` parameter");
+            if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
+                // The current function has a `self' parameter, but we were unable to resolve
+                // a reference to `self`. This can only happen if the `self` identifier we
+                // are resolving came from a different hygiene context.
+                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");
+                }
             }
             return (err, Vec::new());
         }
diff --git a/src/test/ui/hygiene/missing-self-diag.rs b/src/test/ui/hygiene/missing-self-diag.rs
new file mode 100644 (file)
index 0000000..f934f79
--- /dev/null
@@ -0,0 +1,23 @@
+// Regression test for issue #66898
+// Tests that we don't emit a nonsensical error message
+// when a macro invocation tries to access `self` from a function
+// that has a 'self' parameter
+
+pub struct Foo;
+
+macro_rules! call_bar {
+    () => {
+        self.bar(); //~ ERROR expected value
+    }
+}
+
+impl Foo {
+    pub fn foo(&self) {
+        call_bar!();
+    }
+
+    pub fn bar(&self) {
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/hygiene/missing-self-diag.stderr b/src/test/ui/hygiene/missing-self-diag.stderr
new file mode 100644 (file)
index 0000000..075d6b7
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0424]: expected value, found module `self`
+  --> $DIR/missing-self-diag.rs:10:9
+   |
+LL |           self.bar();
+   |           ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+...
+LL | /     pub fn foo(&self) {
+LL | |         call_bar!();
+   | |         ------------ in this macro invocation
+LL | |     }
+   | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0424`.