diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index dc01c94af5729..c1b3aff4e69f6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -318,7 +318,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let normalized_ident = Ident { span: normalized_span, ..ident }; // Walk backwards up the ribs in scope. - let mut module = self.graph_root; for (i, rib) in ribs.iter().enumerate().rev() { debug!("walk rib\n{:?}", rib.bindings); // Use the rib kind to determine whether we are resolving parameters @@ -334,51 +333,47 @@ 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::Module(module) = rib.kind { + // Encountered a module item, abandon ribs and look into that module and preludes. + return self + .cm() + .early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + None, + ) + .ok() + .map(LexicalScopeBinding::Item); } - module = match rib.kind { - RibKind::Module(module) => module, - RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { - // If an invocation of this macro created `ident`, give up on `ident` - // and switch to `ident`'s source from the macro definition. - ident.span.remove_mark(); - continue; - } - _ => continue, - }; - - match module.kind { - ModuleKind::Block => {} // We can see through blocks - _ => break, - } - - let item = 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, - ); - if let Ok(binding) = item { - // The ident resolves to an item. - return Some(LexicalScopeBinding::Item(binding)); + if let RibKind::MacroDefinition(def) = rib.kind + && def == self.macro_def(ident.span.ctxt()) + { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ident.span.remove_mark(); } } - self.cm() - .early_resolve_ident_in_lexical_scope( - orig_ident, - ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), - parent_scope, - finalize, - finalize.is_some(), - ignore_binding, - None, - ) - .ok() - .map(LexicalScopeBinding::Item) + + unreachable!() } /// Resolve an identifier in lexical scope. @@ -1171,6 +1166,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1263,6 +1259,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::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1356,6 +1353,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::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1e4ab57a3160a..5200f9340e115 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -192,6 +192,13 @@ pub(crate) enum RibKind<'ra> { /// No restriction needs to be applied. Normal, + /// We passed through an `ast::Block`. + /// Behaves like `Normal`, but also partially like `Module` if the block contains items. + /// `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>), + /// 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 /// binds. Disallow any other upvars (including other ty params that are @@ -210,7 +217,7 @@ pub(crate) enum RibKind<'ra> { /// All other constants aren't allowed to use generic params at all. ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), - /// We passed through a module. + /// We passed through a module item. Module(Module<'ra>), /// We passed through a `macro_rules!` statement @@ -242,6 +249,7 @@ impl RibKind<'_> { pub(crate) fn contains_params(&self) -> bool { match self { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::ConstantItem(..) | RibKind::Module(_) @@ -258,15 +266,8 @@ impl RibKind<'_> { fn is_label_barrier(self) -> bool { match self { RibKind::Normal | RibKind::MacroDefinition(..) => false, - - RibKind::AssocItem - | RibKind::FnOrCoroutine - | RibKind::Item(..) - | RibKind::ConstantItem(..) - | RibKind::Module(..) - | RibKind::ForwardGenericParamBan(_) - | RibKind::ConstParamTy - | RibKind::InlineAsmSym => true, + RibKind::FnOrCoroutine | RibKind::ConstantItem(..) => true, + kind => bug!("unexpected rib kind: {kind:?}"), } } } @@ -1527,19 +1528,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ret } - fn with_mod_rib(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let module = self.r.expect_module(self.r.local_def_id(id).to_def_id()); - // Move down in the graph. - let orig_module = replace(&mut self.parent_scope.module, module); - self.with_rib(ValueNS, RibKind::Module(module), |this| { - this.with_rib(TypeNS, RibKind::Module(module), |this| { - let ret = f(this); - this.parent_scope.module = orig_module; - ret - }) - }) - } - fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) { // For type parameter defaults, we have to ban access // to following type parameters, as the GenericArgs can only @@ -2677,20 +2665,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Mod(..) => { - self.with_mod_rib(item.id, |this| { - if mod_inner_docs { - this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); - } - let old_macro_rules = this.parent_scope.macro_rules; - visit::walk_item(this, item); - // Maintain macro_rules scopes in the same way as during early resolution - // for diagnostics and doc links. - if item.attrs.iter().all(|attr| { - !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape) - }) { - this.parent_scope.macro_rules = old_macro_rules; - } + let module = self.r.expect_module(self.r.local_def_id(item.id).to_def_id()); + let orig_module = replace(&mut self.parent_scope.module, module); + self.with_rib(ValueNS, RibKind::Module(module), |this| { + this.with_rib(TypeNS, RibKind::Module(module), |this| { + if mod_inner_docs { + this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); + } + let old_macro_rules = this.parent_scope.macro_rules; + visit::walk_item(this, item); + // Maintain macro_rules scopes in the same way as during early resolution + // for diagnostics and doc links. + if item.attrs.iter().all(|attr| { + !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape) + }) { + this.parent_scope.macro_rules = old_macro_rules; + } + }) }); + self.parent_scope.module = orig_module; } ItemKind::Static(box ast::StaticItem { @@ -2821,9 +2814,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // We also can't shadow bindings from associated parent items. for ns in [ValueNS, TypeNS] { for parent_rib in self.ribs[ns].iter().rev() { - // Break at mod level, to account for nested items which are + // 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(..)) { + if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block(..)) { break; } @@ -4652,16 +4645,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("(resolving block) entering block"); // 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 anonymous_module = self.r.block_map.get(&block.id).copied(); 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::Module(anonymous_module))); - self.ribs[TypeNS].push(Rib::new(RibKind::Module(anonymous_module))); + self.ribs[ValueNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); + self.ribs[TypeNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); self.parent_scope.module = anonymous_module; } else { - self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); + self.ribs[ValueNS].push(Rib::new(RibKind::Block(None))); } // Descend into the block. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6a753b380359f..9b201e40d1393 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -849,9 +849,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } // Try to find in last block rib - if let Some(rib) = &self.last_block_rib - && let RibKind::Normal = rib.kind - { + if let Some(rib) = &self.last_block_rib { for (ident, &res) in &rib.bindings { if let Res::Local(_) = res && path.len() == 1 @@ -900,7 +898,7 @@ 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) = rib.kind + if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind && let Some(did) = find_doc_alias_name(self.r, module, item.name) { return Some((did, item)); @@ -2458,9 +2456,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - if let RibKind::Module(module) = rib.kind - && let ModuleKind::Block = module.kind - { + if let RibKind::Block(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. diff --git a/tests/ui/resolve/issue-104700-inner_scope.rs b/tests/ui/resolve/issue-104700-inner_scope.rs index e8f28c113e3ad..fb77ab2626b5f 100644 --- a/tests/ui/resolve/issue-104700-inner_scope.rs +++ b/tests/ui/resolve/issue-104700-inner_scope.rs @@ -7,5 +7,12 @@ fn main() { if bar == 2 { //~ ERROR cannot find value println!("yes"); } + { + let baz = 3; + struct S; + } + if baz == 3 { //~ ERROR cannot find value + println!("yes"); + } test_func(1); //~ ERROR cannot find function } diff --git a/tests/ui/resolve/issue-104700-inner_scope.stderr b/tests/ui/resolve/issue-104700-inner_scope.stderr index 051b234fc72d8..b579f8e76d951 100644 --- a/tests/ui/resolve/issue-104700-inner_scope.stderr +++ b/tests/ui/resolve/issue-104700-inner_scope.stderr @@ -10,12 +10,24 @@ help: the binding `bar` is available in a different scope in the same function LL | let bar = 2; | ^^^ +error[E0425]: cannot find value `baz` in this scope + --> $DIR/issue-104700-inner_scope.rs:14:8 + | +LL | if baz == 3 { + | ^^^ + | +help: the binding `baz` is available in a different scope in the same function + --> $DIR/issue-104700-inner_scope.rs:11:13 + | +LL | let baz = 3; + | ^^^ + error[E0425]: cannot find function `test_func` in this scope - --> $DIR/issue-104700-inner_scope.rs:10:5 + --> $DIR/issue-104700-inner_scope.rs:17:5 | LL | test_func(1); | ^^^^^^^^^ not found in this scope -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`.