-
Notifications
You must be signed in to change notification settings - Fork 13.7k
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -39,9 +39,9 @@ use thin_vec::ThinVec; | |||||
use tracing::{debug, instrument, trace}; | ||||||
|
||||||
use crate::{ | ||||||
BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, | ||||||
NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, TyCtxt, UseError, | ||||||
Used, errors, path_names_to_string, rustdoc, | ||||||
BindingError, BindingKey, Finalize, LexicalScopeBinding, LookaheadItemInBlock, Module, | ||||||
ModuleOrUniformRoot, NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, | ||||||
TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc, | ||||||
}; | ||||||
|
||||||
mod diagnostics; | ||||||
|
@@ -102,7 +102,7 @@ impl IntoDiagArg for PatternSource { | |||||
/// Denotes whether the context for the set of already bound bindings is a `Product` | ||||||
/// or `Or` context. This is used in e.g., `fresh_binding` and `resolve_pattern_inner`. | ||||||
/// See those functions for more information. | ||||||
#[derive(PartialEq)] | ||||||
#[derive(PartialEq, Debug)] | ||||||
enum PatBoundCtx { | ||||||
/// A product pattern context, e.g., `Variant(a, b)`. | ||||||
Product, | ||||||
|
@@ -197,7 +197,29 @@ pub(crate) enum RibKind<'ra> { | |||||
/// `Block(None)` must be always processed in the same way as `Block(Some(module))` | ||||||
/// with empty `module`. The module can be `None` only because creation of some definitely | ||||||
/// empty modules is skipped as an optimization. | ||||||
Block(Option<Module<'ra>>), | ||||||
Block { | ||||||
module: Option<Module<'ra>>, | ||||||
/// The node id of block kind, which stores all bindings defined in | ||||||
/// this local scope, for these features: | ||||||
/// | ||||||
/// - Forward reference detection: | ||||||
/// | ||||||
/// ```ignore (illustrative) | ||||||
/// let a = b; // displays '`b` is defined at <span>' instead of ''b' not found' | ||||||
/// let b = 42; | ||||||
/// ``` | ||||||
/// | ||||||
/// - Correctly resolves the hoisting bindings within macro expand: | ||||||
/// | ||||||
/// ```ignore (illustrative) | ||||||
/// fn f() {} | ||||||
/// let a: i16 = m!(); // throw error because it should use the local `f` rather than `fn f` | ||||||
/// let f = || -> i16 { 42 }; | ||||||
/// macro_rules! m {() => ( f() )} | ||||||
/// use m; | ||||||
/// ``` | ||||||
id: NodeId, | ||||||
}, | ||||||
|
||||||
/// We passed through an impl or trait and are now in one of its | ||||||
/// methods or associated types. Allow references to ty params that impl or trait | ||||||
|
@@ -249,7 +271,7 @@ impl RibKind<'_> { | |||||
pub(crate) fn contains_params(&self) -> bool { | ||||||
match self { | ||||||
RibKind::Normal | ||||||
| RibKind::Block(..) | ||||||
| RibKind::Block { .. } | ||||||
| RibKind::FnOrCoroutine | ||||||
| RibKind::ConstantItem(..) | ||||||
| RibKind::Module(_) | ||||||
|
@@ -2816,7 +2838,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||||
for parent_rib in self.ribs[ns].iter().rev() { | ||||||
// Break at module or block level, to account for nested items which are | ||||||
// allowed to shadow generic param names. | ||||||
if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block(..)) { | ||||||
if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block { .. }) { | ||||||
break; | ||||||
} | ||||||
|
||||||
|
@@ -3769,6 +3791,52 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||||
fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) { | ||||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; | ||||||
self.resolve_pattern(pat, pat_src, &mut bindings); | ||||||
|
||||||
let mut last_pat_id = None; | ||||||
pat.walk(&mut |pat| { | ||||||
if let PatKind::Ident(..) = pat.kind { | ||||||
last_pat_id = Some(pat.id); | ||||||
} | ||||||
true | ||||||
}); | ||||||
|
||||||
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) | ||||||
{ | ||||||
let start = items.get_index_of(&last_pat_id).unwrap_or_else(|| { | ||||||
panic!("pattern({pat:#?}) not found in lookahead items"); | ||||||
}); | ||||||
// let mut first_macro: Option<SyntaxContext> = None; | ||||||
// `need_removed` used for avoid injecting masked names into macro definition bindings: | ||||||
// | ||||||
// ``` | ||||||
// let x = 0; | ||||||
// macro_rules! m0 {() => { x; }} // Injects `let x = 0` into `m0` | ||||||
// let x = 1; | ||||||
// macro_rules! m1 {() => { x; }} // Should NOT inject `let x = 0` into `m1` | ||||||
// ``` | ||||||
let mut need_removed = FxHashSet::default(); | ||||||
for (_, item) in items.iter_mut().skip(start + 1) { | ||||||
match item { | ||||||
LookaheadItemInBlock::Binding { name } => { | ||||||
need_removed.insert(name.normalize_to_macro_rules()); | ||||||
} | ||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if !need_removed.contains(&name) { | ||||||
Some((*name, *res)) | ||||||
} else { | ||||||
None | ||||||
} | ||||||
}); | ||||||
macro_bindings.extend(bindings); | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
self.apply_pattern_bindings(bindings); | ||||||
} | ||||||
|
||||||
|
@@ -4650,11 +4718,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||||
let mut num_macro_definition_ribs = 0; | ||||||
if let Some(anonymous_module) = anonymous_module { | ||||||
debug!("(resolving block) found anonymous module, moving down"); | ||||||
self.ribs[ValueNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); | ||||||
self.ribs[TypeNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); | ||||||
let rib_kind = RibKind::Block { module: Some(anonymous_module), id: block.id }; | ||||||
self.ribs[ValueNS].push(Rib::new(rib_kind)); | ||||||
self.ribs[TypeNS].push(Rib::new(rib_kind)); | ||||||
self.parent_scope.module = anonymous_module; | ||||||
} else { | ||||||
self.ribs[ValueNS].push(Rib::new(RibKind::Block(None))); | ||||||
self.ribs[ValueNS].push(Rib::new(RibKind::Block { module: None, id: block.id })); | ||||||
} | ||||||
|
||||||
// Descend into the block. | ||||||
|
@@ -4664,7 +4733,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||||
{ | ||||||
num_macro_definition_ribs += 1; | ||||||
bvanjoi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more. I think we can remove There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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. |
||||||
self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res))); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||
} | ||||||
|
||||||
bvanjoi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
@@ -4674,7 +4742,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||||
// Move back up. | ||||||
self.parent_scope.module = orig_module; | ||||||
for _ in 0..num_macro_definition_ribs { | ||||||
self.ribs[ValueNS].pop(); | ||||||
// pop `MacroDefinition` | ||||||
self.label_ribs.pop(); | ||||||
} | ||||||
self.last_block_rib = self.ribs[ValueNS].pop(); | ||||||
|
@@ -5134,6 +5202,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||||
/// lifetime generic parameters and function parameters. | ||||||
struct ItemInfoCollector<'a, 'ra, 'tcx> { | ||||||
r: &'a mut Resolver<'ra, 'tcx>, | ||||||
current_block: Option<NodeId>, | ||||||
} | ||||||
|
||||||
impl ItemInfoCollector<'_, '_, '_> { | ||||||
|
@@ -5189,12 +5258,20 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | |||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
ItemKind::MacroDef(_, _) => { | ||||||
if let Some(block_id) = self.current_block { | ||||||
let def_id = self.r.local_def_id(item.id).to_def_id(); | ||||||
let items = self.r.lookahead_items_in_block.entry(block_id).or_default(); | ||||||
items.insert( | ||||||
item.id, | ||||||
LookaheadItemInBlock::MacroDef { bindings: Default::default(), def_id }, | ||||||
); | ||||||
} | ||||||
} | ||||||
ItemKind::Mod(..) | ||||||
| ItemKind::Static(..) | ||||||
| ItemKind::Use(..) | ||||||
| ItemKind::ExternCrate(..) | ||||||
| ItemKind::MacroDef(..) | ||||||
| ItemKind::GlobalAsm(..) | ||||||
| ItemKind::MacCall(..) | ||||||
| ItemKind::DelegationMac(..) => {} | ||||||
|
@@ -5214,11 +5291,30 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | |||||
} | ||||||
visit::walk_assoc_item(self, item, ctxt); | ||||||
} | ||||||
|
||||||
fn visit_local(&mut self, node: &'ast Local) -> Self::Result { | ||||||
// collect local bindings into block | ||||||
node.pat.walk(&mut |pat| { | ||||||
if let PatKind::Ident(_, name, _) = &pat.kind { | ||||||
let block_id = self.current_block.unwrap(); | ||||||
let items = self.r.lookahead_items_in_block.entry(block_id).or_default(); | ||||||
items.insert(pat.id, LookaheadItemInBlock::Binding { name: *name }); | ||||||
} | ||||||
true | ||||||
}); | ||||||
visit::walk_local(self, node) | ||||||
} | ||||||
|
||||||
fn visit_block(&mut self, node: &'ast Block) -> Self::Result { | ||||||
let saved_block_id = self.current_block.replace(node.id); | ||||||
visit::walk_block(self, node); | ||||||
self.current_block = saved_block_id; | ||||||
} | ||||||
} | ||||||
|
||||||
impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | ||||||
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { | ||||||
visit::walk_crate(&mut ItemInfoCollector { r: self }, krate); | ||||||
visit::walk_crate(&mut ItemInfoCollector { r: self, current_block: None }, krate); | ||||||
let mut late_resolution_visitor = LateResolutionVisitor::new(self); | ||||||
late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); | ||||||
visit::walk_crate(&mut late_resolution_visitor, krate); | ||||||
|
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
only
b
will be added toLookaheadItemInBlock::MacroDef
bindings form
, but nota
.Is this ok?
If yes, why is this ok?