Skip to content

Commit 43c1a17

Browse files
committed
Auto merge of #31105 - jseyfried:fix_lexical_scoping, r=nrc
This fixes #23880, a scoping bug in which items in a block are shadowed by local variables and type parameters that are in scope. After this PR, an item in a block will shadow any local variables or type parameters above the item in the scope hierarchy. Items in a block will continue to be shadowed by local variables in the same block (even if the item is defined after the local variable). This is a [breaking-change]. For example, the following code breaks: ```rust fn foo() { let mut f = 1; { fn f() {} f += 1; // This will resolve to the function instead of the local variable } }
2 parents 1972c50 + faf0852 commit 43c1a17

File tree

2 files changed

+78
-30
lines changed

2 files changed

+78
-30
lines changed

src/librustc_resolve/lib.rs

+50-30
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ enum FallbackSuggestion {
723723
}
724724

725725
#[derive(Copy, Clone)]
726-
enum TypeParameters<'a> {
726+
enum TypeParameters<'tcx, 'a> {
727727
NoTypeParameters,
728728
HasTypeParameters(// Type parameters.
729729
&'a Generics,
@@ -733,13 +733,13 @@ enum TypeParameters<'a> {
733733
ParamSpace,
734734

735735
// The kind of the rib used for type parameters.
736-
RibKind),
736+
RibKind<'tcx>),
737737
}
738738

739739
// The rib kind controls the translation of local
740740
// definitions (`Def::Local`) to upvars (`Def::Upvar`).
741741
#[derive(Copy, Clone, Debug)]
742-
enum RibKind {
742+
enum RibKind<'a> {
743743
// No translation needs to be applied.
744744
NormalRibKind,
745745

@@ -758,6 +758,9 @@ enum RibKind {
758758

759759
// We're in a constant item. Can't refer to dynamic stuff.
760760
ConstantItemRibKind,
761+
762+
// We passed through an anonymous module.
763+
AnonymousModuleRibKind(Module<'a>),
761764
}
762765

763766
#[derive(Copy, Clone)]
@@ -799,13 +802,13 @@ enum BareIdentifierPatternResolution {
799802

800803
/// One local scope.
801804
#[derive(Debug)]
802-
struct Rib {
805+
struct Rib<'a> {
803806
bindings: HashMap<Name, DefLike>,
804-
kind: RibKind,
807+
kind: RibKind<'a>,
805808
}
806809

807-
impl Rib {
808-
fn new(kind: RibKind) -> Rib {
810+
impl<'a> Rib<'a> {
811+
fn new(kind: RibKind<'a>) -> Rib<'a> {
809812
Rib {
810813
bindings: HashMap::new(),
811814
kind: kind,
@@ -1180,13 +1183,13 @@ pub struct Resolver<'a, 'tcx: 'a> {
11801183

11811184
// The current set of local scopes, for values.
11821185
// FIXME #4948: Reuse ribs to avoid allocation.
1183-
value_ribs: Vec<Rib>,
1186+
value_ribs: Vec<Rib<'a>>,
11841187

11851188
// The current set of local scopes, for types.
1186-
type_ribs: Vec<Rib>,
1189+
type_ribs: Vec<Rib<'a>>,
11871190

11881191
// The current set of local scopes, for labels.
1189-
label_ribs: Vec<Rib>,
1192+
label_ribs: Vec<Rib<'a>>,
11901193

11911194
// The trait that the current context can refer to.
11921195
current_trait_ref: Option<(DefId, TraitRef)>,
@@ -1304,6 +1307,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13041307
self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
13051308
}
13061309

1310+
fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
1311+
match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
1312+
}
1313+
13071314
#[inline]
13081315
fn record_import_use(&mut self, import_id: NodeId, name: Name) {
13091316
if !self.make_glob_map {
@@ -2122,7 +2129,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
21222129
}
21232130
}
21242131

2125-
fn with_type_parameter_rib<F>(&mut self, type_parameters: TypeParameters, f: F)
2132+
fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F)
21262133
where F: FnOnce(&mut Resolver)
21272134
{
21282135
match type_parameters {
@@ -2191,7 +2198,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
21912198
}
21922199
}
21932200

2194-
fn resolve_function(&mut self, rib_kind: RibKind, declaration: &FnDecl, block: &Block) {
2201+
fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) {
21952202
// Create a value rib for the function.
21962203
self.value_ribs.push(Rib::new(rib_kind));
21972204

@@ -2494,18 +2501,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
24942501

24952502
fn resolve_block(&mut self, block: &Block) {
24962503
debug!("(resolving block) entering block");
2497-
self.value_ribs.push(Rib::new(NormalRibKind));
2498-
24992504
// Move down in the graph, if there's an anonymous module rooted here.
25002505
let orig_module = self.current_module;
2501-
match orig_module.anonymous_children.borrow().get(&block.id) {
2502-
None => {
2503-
// Nothing to do.
2504-
}
2505-
Some(anonymous_module) => {
2506-
debug!("(resolving block) found anonymous module, moving down");
2507-
self.current_module = anonymous_module;
2508-
}
2506+
let anonymous_module =
2507+
orig_module.anonymous_children.borrow().get(&block.id).map(|module| *module);
2508+
2509+
if let Some(anonymous_module) = anonymous_module {
2510+
debug!("(resolving block) found anonymous module, moving down");
2511+
self.value_ribs.push(Rib::new(AnonymousModuleRibKind(anonymous_module)));
2512+
self.type_ribs.push(Rib::new(AnonymousModuleRibKind(anonymous_module)));
2513+
self.current_module = anonymous_module;
2514+
} else {
2515+
self.value_ribs.push(Rib::new(NormalRibKind));
25092516
}
25102517

25112518
// Check for imports appearing after non-item statements.
@@ -2538,6 +2545,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
25382545
if !self.resolved {
25392546
self.current_module = orig_module;
25402547
self.value_ribs.pop();
2548+
if let Some(_) = anonymous_module {
2549+
self.type_ribs.pop();
2550+
}
25412551
}
25422552
debug!("(resolving block) leaving block");
25432553
}
@@ -3076,7 +3086,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
30763086
Def::Local(_, node_id) => {
30773087
for rib in ribs {
30783088
match rib.kind {
3079-
NormalRibKind => {
3089+
NormalRibKind | AnonymousModuleRibKind(..) => {
30803090
// Nothing to do. Continue.
30813091
}
30823092
ClosureRibKind(function_id) => {
@@ -3124,7 +3134,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
31243134
Def::TyParam(..) | Def::SelfTy(..) => {
31253135
for rib in ribs {
31263136
match rib.kind {
3127-
NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
3137+
NormalRibKind | MethodRibKind | ClosureRibKind(..) |
3138+
AnonymousModuleRibKind(..) => {
31283139
// Nothing to do. Continue.
31293140
}
31303141
ItemRibKind => {
@@ -3275,13 +3286,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
32753286
namespace: Namespace)
32763287
-> Option<LocalDef> {
32773288
// Check the local set of ribs.
3278-
let (name, ribs) = match namespace {
3279-
ValueNS => (ident.name, &self.value_ribs),
3280-
TypeNS => (ident.unhygienic_name, &self.type_ribs),
3281-
};
3289+
let name = match namespace { ValueNS => ident.name, TypeNS => ident.unhygienic_name };
32823290

3283-
for (i, rib) in ribs.iter().enumerate().rev() {
3284-
if let Some(def_like) = rib.bindings.get(&name).cloned() {
3291+
for i in (0 .. self.get_ribs(namespace).len()).rev() {
3292+
if let Some(def_like) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() {
32853293
match def_like {
32863294
DlDef(def) => {
32873295
debug!("(resolving path in local ribs) resolved `{}` to {:?} at {}",
@@ -3301,6 +3309,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
33013309
}
33023310
}
33033311
}
3312+
3313+
if let AnonymousModuleRibKind(module) = self.get_ribs(namespace)[i].kind {
3314+
if let Success((target, _)) = self.resolve_name_in_module(module,
3315+
ident.unhygienic_name,
3316+
namespace,
3317+
PathSearch,
3318+
true) {
3319+
if let Some(def) = target.binding.def() {
3320+
return Some(LocalDef::from_def(def));
3321+
}
3322+
}
3323+
}
33043324
}
33053325

33063326
None

src/test/run-pass/lexical-scoping.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Tests that items in subscopes can shadow type parameters and local variables (see issue #23880).
12+
13+
#![allow(unused)]
14+
struct Foo<X> { x: Box<X> }
15+
impl<Bar> Foo<Bar> {
16+
fn foo(&self) {
17+
type Bar = i32;
18+
let _: Bar = 42;
19+
}
20+
}
21+
22+
fn main() {
23+
let f = 1;
24+
{
25+
fn f() {}
26+
f();
27+
}
28+
}

0 commit comments

Comments
 (0)