Skip to content

Commit faf0852

Browse files
committed
Resolve: fix #23880, a scoping bug
This fixes a bug in which items in a block are shadowed by local variables and type parameters that are in scope. It is a [breaking-change]. For example, the following code breaks: ```rust fn foo() { let mut f = 1; { fn f() {} f += 1; // This will now resolve to the function instead of the local variable } } ``` Any breakage can be fixed by renaming the item that is no longer shadowed.
1 parent 54475e9 commit faf0852

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
}
@@ -3072,7 +3082,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
30723082
Def::Local(_, node_id) => {
30733083
for rib in ribs {
30743084
match rib.kind {
3075-
NormalRibKind => {
3085+
NormalRibKind | AnonymousModuleRibKind(..) => {
30763086
// Nothing to do. Continue.
30773087
}
30783088
ClosureRibKind(function_id) => {
@@ -3120,7 +3130,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
31203130
Def::TyParam(..) | Def::SelfTy(..) => {
31213131
for rib in ribs {
31223132
match rib.kind {
3123-
NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
3133+
NormalRibKind | MethodRibKind | ClosureRibKind(..) |
3134+
AnonymousModuleRibKind(..) => {
31243135
// Nothing to do. Continue.
31253136
}
31263137
ItemRibKind => {
@@ -3271,13 +3282,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
32713282
namespace: Namespace)
32723283
-> Option<LocalDef> {
32733284
// Check the local set of ribs.
3274-
let (name, ribs) = match namespace {
3275-
ValueNS => (ident.name, &self.value_ribs),
3276-
TypeNS => (ident.unhygienic_name, &self.type_ribs),
3277-
};
3285+
let name = match namespace { ValueNS => ident.name, TypeNS => ident.unhygienic_name };
32783286

3279-
for (i, rib) in ribs.iter().enumerate().rev() {
3280-
if let Some(def_like) = rib.bindings.get(&name).cloned() {
3287+
for i in (0 .. self.get_ribs(namespace).len()).rev() {
3288+
if let Some(def_like) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() {
32813289
match def_like {
32823290
DlDef(def) => {
32833291
debug!("(resolving path in local ribs) resolved `{}` to {:?} at {}",
@@ -3297,6 +3305,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
32973305
}
32983306
}
32993307
}
3308+
3309+
if let AnonymousModuleRibKind(module) = self.get_ribs(namespace)[i].kind {
3310+
if let Success((target, _)) = self.resolve_name_in_module(module,
3311+
ident.unhygienic_name,
3312+
namespace,
3313+
PathSearch,
3314+
true) {
3315+
if let Some(def) = target.binding.def() {
3316+
return Some(LocalDef::from_def(def));
3317+
}
3318+
}
3319+
}
33003320
}
33013321

33023322
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)