Skip to content

Commit

Permalink
Only point at the two macro invocations that diverged
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Oct 10, 2023
1 parent 9b76e07 commit 51f3d24
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 40 deletions.
46 changes: 29 additions & 17 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2168,39 +2168,51 @@ impl<'a> Parser<'a> {
// Walk the chain of macro expansions for the current token to point at how the original
// code was interpreted. This helps the user realize when a macro argument of one type is
// later reinterpreted as a different type, like `$x:expr` being reinterpreted as `$x:pat`
// in a subsequent macro invokation (#71039).
// in a subsequent macro invocation (#71039).
let mut tok = self.token.clone();
let mut labels = vec![];
let mut pos = 0;
while let TokenKind::Interpolated(node) = &tok.kind {
// FIXME: figure out how to point at `$x:pat` when `tok`
// is a `NtPat` corresponding to `$x`.
let tokens = node.tokens();
labels.push((
pos,
node.span(),
format!("this is interpreted as {} {}", node.descr(), super::token_descr(&tok)),
));
labels.push((node.span(), node.descr()));
if let Some(tokens) = tokens
&& let tokens = tokens.to_attr_token_stream()
&& let tokens = tokens.0.deref()
&& let [AttrTokenTree::Token(token, _)] = &tokens[..]
{
info!(?token);
tok = token.clone();
pos += 1;
} else {
break;
}
}
for (i, span, label) in labels {
let post = if pos > 0 {
// When there are more than one macro expansions at play, clarify the order.
format!(" (in expansion #{})", pos + 1 - i)
} else {
String::new()
};
err.span_label(span, format!("{label}{post}"));
let mut iter = labels.into_iter().peekable();
let mut show_link = false;
while let Some((span, descr)) = iter.next() {
if let Some((next_span, next_descr)) = iter.peek()
&& next_descr != &descr
{
err.span_label(
*next_span,
format!("this is interpreted as {next_descr}"),
);
err.span_label(
span,
format!(
"this is interpreted as {}, but it was previously interpreted as {}",
descr,
next_descr,
),
);
show_link = true;
}
}
if show_link {
err.note(
"when forwarding a matched fragment to another macro-by-example, matchers in the \
second macro will see an opaque AST of the fragment type, not the underlying \
tokens",
);
}
err
}
Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,14 @@ impl TokenDescription {
pub(super) fn token_descr(token: &Token) -> String {
let name = pprust::token_to_string(token).to_string();

let kind = TokenDescription::from_token(token).map(|kind| match kind {
TokenDescription::ReservedIdentifier => "reserved identifier",
TokenDescription::Keyword => "keyword",
TokenDescription::ReservedKeyword => "reserved keyword",
TokenDescription::DocComment => "doc comment",
});
let kind = match (TokenDescription::from_token(token), &token.kind) {
(Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"),
(Some(TokenDescription::Keyword), _) => Some("keyword"),
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
(None, TokenKind::Interpolated(node)) => Some(node.descr()),
(None, _) => None,
};

if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-39848.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
macro_rules! get_opt {
($tgt:expr, $field:ident) => {
if $tgt.has_$field() {} //~ ERROR expected `{`, found `foo`
if $tgt.has_$field() {} //~ ERROR expected `{`, found identifier `foo`
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-39848.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: expected `{`, found `foo`
error: expected `{`, found identifier `foo`
--> $DIR/issue-39848.rs:3:21
|
LL | if $tgt.has_$field() {}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/macros/syntax-error-recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ macro_rules! values {
}
};
}
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)`
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
//~| ERROR macro expansion ignores token `(String)` and any following

values!(STRING(1) as (String) => cfg(test),);
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/macros/syntax-error-recovery.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)`
error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
--> $DIR/syntax-error-recovery.rs:7:26
|
LL | $token $($inner)? = $value,
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/macros/trace_faulty_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ macro_rules! test {
(let $p:pat = $e:expr) => {test!(($p,$e))};
// this should be expr
// vvv
(($p:pat, $e:pat)) => {let $p = $e;}; //~ ERROR expected expression, found `1 + 1`
(($p:pat, $e:pat)) => {let $p = $e;}; //~ ERROR expected expression, found pattern `1 + 1`
}

fn foo() {
test!(let x = 1+1);
}
}
12 changes: 5 additions & 7 deletions tests/ui/macros/trace_faulty_macros.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,9 @@ LL | my_recursive_macro!();
= note: expanding `my_recursive_macro! { }`
= note: to `my_recursive_macro! () ;`

error: expected expression, found `A { a: a, b: 0, c: _, .. }`
error: expected expression, found pattern `A { a: a, b: 0, c: _, .. }`
--> $DIR/trace_faulty_macros.rs:16:9
|
LL | pat_macro!(A{a:a, b:0, c:_, ..});
| -------------------- this is interpreted as pattern `A { a: a, b: 0, c: _, .. }`
...
LL | $a
| ^^ expected expression
...
Expand All @@ -72,21 +69,22 @@ LL | #[derive(Debug)]
LL | fn use_derive_macro_as_attr() {}
| -------------------------------- not a `struct`, `enum` or `union`

error: expected expression, found `1 + 1`
error: expected expression, found pattern `1 + 1`
--> $DIR/trace_faulty_macros.rs:49:37
|
LL | (let $p:pat = $e:expr) => {test!(($p,$e))};
| -- this is interpreted as pattern `1 + 1` (in expansion #2)
| -- this is interpreted as pattern, but it was previously interpreted as expression
...
LL | (($p:pat, $e:pat)) => {let $p = $e;};
| ^^ expected expression
...
LL | test!(let x = 1+1);
| ------------------
| | |
| | this is interpreted as expression `1 + 1` (in expansion #1)
| | this is interpreted as expression
| in this macro invocation
|
= note: when forwarding a matched fragment to another macro-by-example, matchers in the second macro will see an opaque AST of the fragment type, not the underlying tokens
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

note: trace_macro
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/parser/float-field-interpolated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ macro_rules! generate_field_accesses {

s.$a; // OK
{ s.$b; } //~ ERROR unexpected token: `1.1`
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1`
{ s.$c; } //~ ERROR unexpected token: `1.1`
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1`
};
}

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/parser/float-field-interpolated.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1);
|
= note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
error: expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1`
--> $DIR/float-field-interpolated.rs:8:13
|
LL | { s.$b; }
Expand All @@ -31,7 +31,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1);
|
= note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
error: expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1`
--> $DIR/float-field-interpolated.rs:10:13
|
LL | { s.$c; }
Expand Down

0 comments on commit 51f3d24

Please sign in to comment.