-
Notifications
You must be signed in to change notification settings - Fork 13.6k
fresh binding should shadow the def in expand #143141
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
base: master
Are you sure you want to change the base?
Conversation
tests/ui/resolve/fresh-should-shallow-definitation-after-macro-expand.rs
Outdated
Show resolved
Hide resolved
tests/ui/resolve/fresh-should-shallow-definitation-after-macro-expand.rs
Outdated
Show resolved
Hide resolved
tests/ui/resolve/fresh-should-shallow-definitation-after-macro-expand.rs
Outdated
Show resolved
Hide resolved
I don't understand why this works and how it fixes the issue. |
Also "shallow" -> "shadow" in the PR/commit messages and file names. |
There may be a bug if
rust/compiler/rustc_resolve/src/ident.rs Lines 320 to 328 in 86e05cd
|
@rustbot ready |
@bvanjoi |
Are you sure this cannot successfully resolve some names that should not be resolved? I need to test this with additional cases across different rib contexts. @rustbot author |
Reminder, once the PR becomes ready for a review, use |
tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.rs
Outdated
Show resolved
Hide resolved
tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.rs
Outdated
Show resolved
Hide resolved
tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.rs
Outdated
Show resolved
Hide resolved
tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.rs
Outdated
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Update: The key change in this patch introduces @rustbot ready |
// Descend into the block. | ||
for stmt in &block.stmts { | ||
if let StmtKind::Item(ref item) = stmt.kind | ||
&& let ItemKind::MacroDef(..) = item.kind | ||
{ | ||
num_macro_definition_ribs += 1; | ||
let res = self.r.local_def_id(item.id).to_def_id(); | ||
self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove RibKind::MacroDefinition
in the future since all macro bindings can be accessed through RibKind::Block
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the new scheme is already implemented, then it's better to remove it now to make sure everything is migrated correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, it's still there due to labels, but labels are supposed to be resolved just like local variables, so they can migrate to the new scheme too.
@@ -4658,6 +4729,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||
// Move down in the graph, if there's an anonymous module rooted here. | |||
let orig_module = self.parent_scope.module; | |||
let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference | |||
let is_module_block = anonymous_module.is_some(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove RibKind::Module
in the future and use something like RibKind::Block { id: NodeId, module: Option<Module> }
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do this, and only add Block
ribs for blocks, not Module
ribs or Normal
ribs.
I'd rather do it before making changes from this PR.
); | ||
} | ||
|
||
fn collect_fresh_binding_in_pat(&mut self, pat: &ast::Pat) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you inline these 3 methods?
They are all small and are called only once.
@@ -4669,14 +4741,15 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||
self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); | |||
} | |||
|
|||
self.ribs[ValueNS] | |||
.push(Rib::new(RibKind::Block { id: block.id, is_module: is_module_block })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.push(Rib::new(RibKind::Block { id: block.id, is_module: is_module_block })); | |
.push(Rib::new(RibKind::Block { id: block.id, is_module })); |
Nit: rename for brevity.
// Descend into the block. | ||
for stmt in &block.stmts { | ||
if let StmtKind::Item(ref item) = stmt.kind | ||
&& let ItemKind::MacroDef(..) = item.kind | ||
{ | ||
num_macro_definition_ribs += 1; | ||
let res = self.r.local_def_id(item.id).to_def_id(); | ||
self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res))); | ||
self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Labels have the same hygiene as local variables and are also resolved at macro definition site.
self.label_ribs.pop(); | ||
} | ||
self.last_block_rib = self.ribs[ValueNS].pop(); | ||
let block_rib = self.ribs[ValueNS].pop(); // pop `RibKind::Block` | ||
if !is_module_block { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Module
s are indeed not created for some blocks, but that's only a performance optimization.
There should be zero semantic difference between module blocks and non-module blocks, but this PR seems to add some.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I remove the optimization and run ui tests some diagnostics change.
That's not very good, it means there are some pre-existing issues with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but this PR seems to add some
They're only to generate last_block_rib
which is only used for diagnostics, specifically to display information about non-module blocks:
rust/compiler/rustc_resolve/src/late/diagnostics.rs
Lines 853 to 870 in 6bcdcc7
// Try to find in last block rib | |
if let Some(rib) = &self.last_block_rib | |
&& let RibKind::Normal = rib.kind | |
{ | |
for (ident, &res) in &rib.bindings { | |
if let Res::Local(_) = res | |
&& path.len() == 1 | |
&& ident.span.eq_ctxt(path[0].ident.span) | |
&& ident.name == path[0].ident.name | |
{ | |
err.span_help( | |
ident.span, | |
format!("the binding `{path_str}` is available in a different scope in the same function"), | |
); | |
return (true, suggested_candidates, candidates); | |
} | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specifically to display information about non-module blocks
That's exactly what I'm talking about - a pre-existing bug.
This code should work for all blocks, regardless of whether those blocks potentially have items in them or not.
(I didn't review everything yet, will continue later this week.) |
} | ||
LookaheadItemInBlock::MacroDef { bindings: macro_bindings, .. } => { | ||
let bindings = | ||
bindings.last().unwrap().1.iter().filter_map(|(name, res)| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bindings.last().unwrap().1.iter().filter_map(|(name, res)| { | |
bindings.last().unwrap().1.iter().copied().filter(|(name, _)| !need_removed.contains(name)) |
|
||
if let Some(last_pat_id) = last_pat_id | ||
&& let RibKind::Block { id: block, .. } = self.ribs[ValueNS].last_mut().unwrap().kind | ||
&& let Some(items) = self.r.lookahead_items_in_block.get_mut(&block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, in
let a = 0;
{
let b = 1;
macro_rules! m { ... }
}
only b
will be added to LookaheadItemInBlock::MacroDef
bindings for m
, but not a
.
Is this ok?
If yes, why is this ok?
let a0: BindingF = m!(); //~ NOTE in this expansion of m! | ||
let f = || -> BindingF { 42 }; | ||
let a1: BindingF = m!(); | ||
macro m() { f() } //~ ERROR cannot find function `f` in this scope |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f
can be found at m
's definition site, we should report a different error in this case, like "f
is not yet alive at point of use" or something.
Could you also add a test case demonstrating what happens with this example? fn f() {
let a = 10;
#[macro_export]
macro_rules! m { () => { a } }
}
fn main() {
fn a() {}
crate::m!();
} |
☔ The latest upstream changes (presumably #145077) made this pull request unmergeable. Please resolve the merge conflicts. |
Fixes #95237
r? @petrochenkov or @cjgillot