Correctly resolve variables and labels from before macro definition in macro expansion

E.g.:
```rust
let v;
macro_rules! m { () => { v }; }
```

This was an existing bug, but it was less severe because unless the variable was shadowed it would be correctly resolved. With hygiene however, without this fix the variable is never resolved.
This commit is contained in:
Chayim Refael Friedman 2024-10-22 20:58:25 +03:00
parent 8adcbdcc49
commit 4ac3dc1a2f
12 changed files with 287 additions and 50 deletions

View file

@ -747,7 +747,7 @@ impl InferenceContext<'_> {
Statement::Expr { expr, has_semi: _ } => {
self.consume_expr(*expr);
}
Statement::Item => (),
Statement::Item(_) => (),
}
}
if let Some(tail) = tail {

View file

@ -1656,7 +1656,7 @@ impl InferenceContext<'_> {
);
}
}
Statement::Item => (),
Statement::Item(_) => (),
}
}

View file

@ -89,7 +89,7 @@ impl InferenceContext<'_> {
Statement::Expr { expr, has_semi: _ } => {
self.infer_mut_expr(*expr, Mutability::Not);
}
Statement::Item => (),
Statement::Item(_) => (),
}
}
if let Some(tail) = tail {

View file

@ -1783,7 +1783,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.push_fake_read(c, p, expr.into());
current = scope2.pop_and_drop(self, c, expr.into());
}
hir_def::hir::Statement::Item => (),
hir_def::hir::Statement::Item(_) => (),
}
}
if let Some(tail) = tail {

View file

@ -3737,3 +3737,68 @@ fn foo() {
"#,
);
}
#[test]
fn macro_expansion_can_refer_variables_defined_before_macro_definition() {
check_types(
r#"
fn foo() {
let v: i32 = 0;
macro_rules! m {
() => { v };
}
let v: bool = true;
m!();
// ^^^^ i32
}
"#,
);
}
#[test]
fn macro_rules_shadowing_works_with_hygiene() {
check_types(
r#"
fn foo() {
let v: bool;
macro_rules! m { () => { v } }
m!();
// ^^^^ bool
let v: char;
macro_rules! m { () => { v } }
m!();
// ^^^^ char
{
let v: u8;
macro_rules! m { () => { v } }
m!();
// ^^^^ u8
let v: i8;
macro_rules! m { () => { v } }
m!();
// ^^^^ i8
let v: i16;
macro_rules! m { () => { v } }
m!();
// ^^^^ i16
{
let v: u32;
macro_rules! m { () => { v } }
m!();
// ^^^^ u32
let v: u64;
macro_rules! m { () => { v } }
m!();
// ^^^^ u64
}
}
}
"#,
);
}