Skip to content

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 73 additions & 20 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib
use crate::macros::{MacroRulesScope, sub_namespace_match};
use crate::{
AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy,
Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot,
NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError,
Resolver, Scope, ScopeSet, Segment, Used, Weak, errors,
Finalize, ImportKind, LexicalScopeBinding, LookaheadItemInBlock, Module, ModuleKind,
ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res,
ResolutionError, Resolver, Scope, ScopeSet, Segment, Used, Weak, errors,
};

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -333,20 +333,73 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
*original_rib_ident_def,
ribs,
)));
} else if let RibKind::Block(Some(module)) = rib.kind
&& let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
parent_scope,
Shadowing::Unrestricted,
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
ignore_binding,
None,
)
{
// The ident resolves to an item in a block.
return Some(LexicalScopeBinding::Item(binding));
} else if let RibKind::Block { module, id: block_id } = rib.kind {
if let Some(items) = self.lookahead_items_in_block.get(&block_id) {
let mut expansion = None;
for (node_id, item) in items
.iter()
.rev()
.filter(|(_, item)| matches!(item, LookaheadItemInBlock::MacroDef { .. }))
{
let LookaheadItemInBlock::MacroDef { def_id, bindings, .. } = item else {
unreachable!();
};
if *def_id != self.macro_def(ident.span.ctxt()) {
continue;
}
expansion.get_or_insert(node_id);
ident.span.remove_mark();
if let Some((original_rib_ident_def, res)) = bindings.get_key_value(&ident)
{
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
i,
ident,
*res,
finalize.map(|finalize| finalize.path_span),
*original_rib_ident_def,
ribs,
)));
}
}
if let Some(expansion) = expansion
&& items.iter().take_while(|(item_id, _)| !expansion.eq(item_id)).any(
|(_, item)| {
if let LookaheadItemInBlock::Binding { name } = item {
name.name == ident.name
} else {
false
}
},
)
{
// return `None` for this case:
//
// ```
// let a = m!();
// let b = 1;
// macro_rules! m { () => { b } }
// use b;
// ```
return None;
}
}

if let Some(module) = module
&& let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
parent_scope,
Shadowing::Unrestricted,
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
ignore_binding,
None,
)
{
// The ident resolves to an item in a block.
return Some(LexicalScopeBinding::Item(binding));
}
} else if let RibKind::Module(module) = rib.kind {
// Encountered a module item, abandon ribs and look into that module and preludes.
return self
Expand Down Expand Up @@ -1166,7 +1219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
for rib in ribs {
match rib.kind {
RibKind::Normal
| RibKind::Block(..)
| RibKind::Block { .. }
| RibKind::FnOrCoroutine
| RibKind::Module(..)
| RibKind::MacroDefinition(..)
Expand Down Expand Up @@ -1259,7 +1312,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
for rib in ribs {
let (has_generic_params, def_kind) = match rib.kind {
RibKind::Normal
| RibKind::Block(..)
| RibKind::Block { .. }
| RibKind::FnOrCoroutine
| RibKind::Module(..)
| RibKind::MacroDefinition(..)
Expand Down Expand Up @@ -1353,7 +1406,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
for rib in ribs {
let (has_generic_params, def_kind) = match rib.kind {
RibKind::Normal
| RibKind::Block(..)
| RibKind::Block { .. }
| RibKind::FnOrCoroutine
| RibKind::Module(..)
| RibKind::MacroDefinition(..)
Expand Down
126 changes: 111 additions & 15 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(_)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Copy link
Contributor

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 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)| {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
bindings.last().unwrap().1.iter().filter_map(|(name, res)| {
bindings.last().unwrap().1.iter().copied().filter(|(name, _)| !need_removed.contains(name))

if !need_removed.contains(&name) {
Some((*name, *res))
} else {
None
}
});
macro_bindings.extend(bindings);
}
}
}
}

self.apply_pattern_bindings(bindings);
}

Expand Down Expand Up @@ -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.
Expand All @@ -4664,7 +4733,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
{
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)));
Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res)));
Copy link
Contributor

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.

}

Expand All @@ -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();
Expand Down Expand Up @@ -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<'_, '_, '_> {
Expand Down Expand Up @@ -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(..) => {}
Expand All @@ -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);
Expand Down
15 changes: 4 additions & 11 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
if path.len() == 1 {
for rib in self.ribs[ns].iter().rev() {
let item = path[0].ident;
if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind
if let RibKind::Module(module) | RibKind::Block { module: Some(module), .. } =
rib.kind
&& let Some(did) = find_doc_alias_name(self.r, module, item.name)
{
return Some((did, item));
Expand Down Expand Up @@ -2438,7 +2439,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
) -> TypoCandidate {
let mut names = Vec::new();
if let [segment] = path {
let mut ctxt = segment.ident.span.ctxt();
let ctxt = segment.ident.span.ctxt();

// Search in lexical scope.
// Walk backwards up the ribs in scope and collect candidates.
Expand All @@ -2456,7 +2457,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}
}

if let RibKind::Block(Some(module)) = rib.kind {
if let RibKind::Block { module: Some(module), .. } = rib.kind {
self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
} else if let RibKind::Module(module) = rib.kind {
// Encountered a module item, abandon ribs and look into that module and preludes.
Expand All @@ -2469,14 +2470,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
);
break;
}

if let RibKind::MacroDefinition(def) = rib.kind
&& def == self.r.macro_def(ctxt)
{
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
ctxt.remove_mark();
}
}
} else {
// Search in module.
Expand Down
Loading
Loading