Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notes to macro-not-found diagnostics to point out how things with the same name were not a match. #88232

Merged
merged 11 commits into from
Aug 23, 2021
52 changes: 52 additions & 0 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,9 +956,61 @@ impl<'a> Resolver<'a> {
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
err.span_note(ident.span, &msg);
return;
}
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
err.help("have you added the `#[macro_use]` on the module/import?");
return;
}
for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::All(ns, false),
&parent_scope,
false,
false,
ident.span,
) {
let desc = match binding.res() {
Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
"a function-like macro".to_string()
}
Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
format!("an attribute: `#[{}]`", ident)
}
Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
format!("a derive macro: `#[derive({})]`", ident)
}
Res::ToolMod => {
// Don't confuse the user with tool modules.
continue;
}
Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
"only a trait, without a derive macro".to_string()
}
res => format!(
"{} {}, not {} {}",
res.article(),
res.descr(),
macro_kind.article(),
macro_kind.descr_expected(),
),
};
if let crate::NameBindingKind::Import { import, .. } = binding.kind {
if !import.span.is_dummy() {
err.span_note(
import.span,
&format!("`{}` is imported here, but it is {}", ident, desc),
);
// Silence the 'unused import' warning we might get,
// since this diagnostic already covers that import.
self.record_use(ident, binding, false);
return;
}
}
err.note(&format!("`{}` is in scope, but it is {}", ident, desc));
return;
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/issues/issue-11692-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ error: cannot find macro `test` in this scope
|
LL | concat!(test!());
| ^^^^
|
= note: `test` is in scope, but it is an attribute: `#[test]`

error: aborting due to previous error

66 changes: 66 additions & 0 deletions src/test/ui/macros/issue-88206.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// compile-flags: -Z deduplicate-diagnostics=yes

#![warn(unused_imports)]

use std::str::*;
//~^ NOTE `from_utf8` is imported here, but it is a function
//~| NOTE `from_utf8_mut` is imported here, but it is a function
//~| NOTE `from_utf8_unchecked` is imported here, but it is a function

mod hey {
pub trait Serialize {}
pub trait Deserialize {}

pub struct X(i32);
}

use hey::{Serialize, Deserialize, X};
//~^ NOTE `Serialize` is imported here, but it is only a trait, without a derive macro
//~| NOTE `Deserialize` is imported here, but it is a trait
//~| NOTE `X` is imported here, but it is a struct

#[derive(Serialize)]
//~^ ERROR cannot find derive macro `Serialize`
struct A;

#[derive(from_utf8_mut)]
//~^ ERROR cannot find derive macro `from_utf8_mut`
struct B;

#[derive(println)]
//~^ ERROR cannot find derive macro `println`
//~| NOTE `println` is in scope, but it is a function-like macro
struct C;

#[Deserialize]
//~^ ERROR cannot find attribute `Deserialize`
struct D;

#[from_utf8_unchecked]
//~^ ERROR cannot find attribute `from_utf8_unchecked`
struct E;

#[println]
//~^ ERROR cannot find attribute `println`
//~| NOTE `println` is in scope, but it is a function-like macro
struct F;

fn main() {
from_utf8!();
//~^ ERROR cannot find macro `from_utf8`

Box!();
//~^ ERROR cannot find macro `Box`
//~| NOTE `Box` is in scope, but it is a struct

Copy!();
//~^ ERROR cannot find macro `Copy`
//~| NOTE `Copy` is in scope, but it is a derive macro

test!();
//~^ ERROR cannot find macro `test`
//~| NOTE `test` is in scope, but it is an attribute

X!();
//~^ ERROR cannot find macro `X`
}
114 changes: 114 additions & 0 deletions src/test/ui/macros/issue-88206.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
error: cannot find macro `X` in this scope
--> $DIR/issue-88206.rs:64:5
|
LL | X!();
| ^
|
note: `X` is imported here, but it is a struct, not a macro
--> $DIR/issue-88206.rs:17:35
|
LL | use hey::{Serialize, Deserialize, X};
| ^

error: cannot find macro `test` in this scope
--> $DIR/issue-88206.rs:60:5
|
LL | test!();
| ^^^^
|
= note: `test` is in scope, but it is an attribute: `#[test]`

error: cannot find macro `Copy` in this scope
--> $DIR/issue-88206.rs:56:5
|
LL | Copy!();
| ^^^^
|
= note: `Copy` is in scope, but it is a derive macro: `#[derive(Copy)]`

error: cannot find macro `Box` in this scope
--> $DIR/issue-88206.rs:52:5
|
LL | Box!();
| ^^^
|
= note: `Box` is in scope, but it is a struct, not a macro
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the cases where we don't have a span, wouldn't it make sense to turn this into the primary span? Something like:

error: cannot find macro `Copy` in this scope
  --> $DIR/issue-88206.rs:56:5
   |
LL |     Copy!();
   |     ^^^^ this is not a macro, it is a derive macro: `#[derive(Copy)]`

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid pointing the note at the identifier the user wrote, because the error already says cannot find `Thing`, and the note is about another Thing, not the Thing they wrote. (Even though they have the same name.)

So in the case we can point at an import, we do that to highlight Thing here is not found, but Thing there exists but is something else. Pointing both at the same identifier would make it less clear that we're talking about two different Things.


error: cannot find macro `from_utf8` in this scope
--> $DIR/issue-88206.rs:49:5
|
LL | from_utf8!();
| ^^^^^^^^^
|
note: `from_utf8` is imported here, but it is a function, not a macro
--> $DIR/issue-88206.rs:5:5
|
LL | use std::str::*;
| ^^^^^^^^^^^

error: cannot find attribute `println` in this scope
--> $DIR/issue-88206.rs:43:3
|
LL | #[println]
| ^^^^^^^
|
= note: `println` is in scope, but it is a function-like macro

error: cannot find attribute `from_utf8_unchecked` in this scope
--> $DIR/issue-88206.rs:39:3
|
LL | #[from_utf8_unchecked]
| ^^^^^^^^^^^^^^^^^^^
|
note: `from_utf8_unchecked` is imported here, but it is a function, not an attribute
--> $DIR/issue-88206.rs:5:5
|
LL | use std::str::*;
| ^^^^^^^^^^^

error: cannot find attribute `Deserialize` in this scope
--> $DIR/issue-88206.rs:35:3
|
LL | #[Deserialize]
| ^^^^^^^^^^^
|
note: `Deserialize` is imported here, but it is a trait, not an attribute
--> $DIR/issue-88206.rs:17:22
|
LL | use hey::{Serialize, Deserialize, X};
| ^^^^^^^^^^^

error: cannot find derive macro `println` in this scope
--> $DIR/issue-88206.rs:30:10
|
LL | #[derive(println)]
| ^^^^^^^
|
= note: `println` is in scope, but it is a function-like macro

error: cannot find derive macro `from_utf8_mut` in this scope
--> $DIR/issue-88206.rs:26:10
|
LL | #[derive(from_utf8_mut)]
| ^^^^^^^^^^^^^
|
note: `from_utf8_mut` is imported here, but it is a function, not a derive macro
--> $DIR/issue-88206.rs:5:5
|
LL | use std::str::*;
| ^^^^^^^^^^^

error: cannot find derive macro `Serialize` in this scope
--> $DIR/issue-88206.rs:22:10
|
LL | #[derive(Serialize)]
| ^^^^^^^^^
|
note: `Serialize` is imported here, but it is only a trait, without a derive macro
--> $DIR/issue-88206.rs:17:11
|
LL | use hey::{Serialize, Deserialize, X};
| ^^^^^^^^^

error: aborting due to 11 previous errors

1 change: 1 addition & 0 deletions src/test/ui/macros/issue-88228.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct A;

#[derive(println)]
//~^ ERROR cannot find derive macro `println`
//~|`println` is in scope, but it is a function-like macro
struct B;

fn main() {
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/macros/issue-88228.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: cannot find macro `bla` in this scope
--> $DIR/issue-88228.rs:19:5
--> $DIR/issue-88228.rs:20:5
|
LL | bla!();
| ^^^
Expand All @@ -12,6 +12,8 @@ error: cannot find derive macro `println` in this scope
|
LL | #[derive(println)]
| ^^^^^^^
|
= note: `println` is in scope, but it is a function-like macro

error: cannot find derive macro `Bla` in this scope
--> $DIR/issue-88228.rs:9:10
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/macros/macro-path-prelude-fail-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ LL | inline!();
|
LL | macro_rules! line {
| ----------------- similarly named macro `line` defined here
|
= note: `inline` is in scope, but it is an attribute: `#[inline]`

error: aborting due to previous error

10 changes: 10 additions & 0 deletions src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -93,30 +93,40 @@ error: cannot find macro `my_macro_attr` in this scope
|
LL | my_macro_attr!();
| ^^^^^^^^^^^^^
|
= note: `my_macro_attr` is in scope, but it is an attribute: `#[my_macro_attr]`

error: cannot find macro `MyTrait` in this scope
--> $DIR/macro-namespace-reserved-2.rs:33:5
|
LL | MyTrait!();
| ^^^^^^^
|
= note: `MyTrait` is in scope, but it is a derive macro: `#[derive(MyTrait)]`

error: cannot find attribute `my_macro` in this scope
--> $DIR/macro-namespace-reserved-2.rs:38:3
|
LL | #[my_macro]
| ^^^^^^^^
|
= note: `my_macro` is in scope, but it is a function-like macro

error: cannot find derive macro `my_macro` in this scope
--> $DIR/macro-namespace-reserved-2.rs:48:10
|
LL | #[derive(my_macro)]
| ^^^^^^^^
|
= note: `my_macro` is in scope, but it is a function-like macro

error: cannot find derive macro `my_macro` in this scope
--> $DIR/macro-namespace-reserved-2.rs:48:10
|
LL | #[derive(my_macro)]
| ^^^^^^^^
|
= note: `my_macro` is in scope, but it is a function-like macro

error: aborting due to 20 previous errors