Skip to content

Commit d5e3115

Browse files
committed
Better support for import resolution in 3 namespaces
1 parent 428ef19 commit d5e3115

File tree

2 files changed

+107
-22
lines changed

2 files changed

+107
-22
lines changed

src/librustc_resolve/resolve_imports.rs

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
3333
use syntax_pos::Span;
3434

3535
use std::cell::{Cell, RefCell};
36-
use std::mem;
36+
use std::{mem, ptr};
3737

3838
/// Contains data for specific types of import directives.
3939
#[derive(Clone, Debug)]
@@ -89,6 +89,8 @@ enum SingleImports<'a> {
8989
None,
9090
/// Only the given single import can define the name in the namespace.
9191
MaybeOne(&'a ImportDirective<'a>),
92+
/// Only one of these two single imports can define the name in the namespace.
93+
MaybeTwo(&'a ImportDirective<'a>, &'a ImportDirective<'a>),
9294
/// At least one single import will define the name in the namespace.
9395
AtLeastOne,
9496
}
@@ -101,21 +103,28 @@ impl<'a> Default for SingleImports<'a> {
101103
}
102104

103105
impl<'a> SingleImports<'a> {
104-
fn add_directive(&mut self, directive: &'a ImportDirective<'a>) {
106+
fn add_directive(&mut self, directive: &'a ImportDirective<'a>, use_extern_macros: bool) {
105107
match *self {
106108
SingleImports::None => *self = SingleImports::MaybeOne(directive),
107-
// If two single imports can define the name in the namespace, we can assume that at
108-
// least one of them will define it since otherwise both would have to define only one
109-
// namespace, leading to a duplicate error.
110-
SingleImports::MaybeOne(_) => *self = SingleImports::AtLeastOne,
109+
SingleImports::MaybeOne(directive_one) => *self = if use_extern_macros {
110+
SingleImports::MaybeTwo(directive_one, directive)
111+
} else {
112+
SingleImports::AtLeastOne
113+
},
114+
// If three single imports can define the name in the namespace, we can assume that at
115+
// least one of them will define it since otherwise we'd get duplicate errors in one of
116+
// other namespaces.
117+
SingleImports::MaybeTwo(..) => *self = SingleImports::AtLeastOne,
111118
SingleImports::AtLeastOne => {}
112119
};
113120
}
114121

115-
fn directive_failed(&mut self) {
122+
fn directive_failed(&mut self, dir: &'a ImportDirective<'a>) {
116123
match *self {
117124
SingleImports::None => unreachable!(),
118125
SingleImports::MaybeOne(_) => *self = SingleImports::None,
126+
SingleImports::MaybeTwo(dir1, dir2) =>
127+
*self = SingleImports::MaybeOne(if ptr::eq(dir1, dir) { dir1 } else { dir2 }),
119128
SingleImports::AtLeastOne => {}
120129
}
121130
}
@@ -199,23 +208,50 @@ impl<'a> Resolver<'a> {
199208
}
200209

201210
// Check if a single import can still define the name.
211+
let resolve_single_import = |this: &mut Self, directive: &'a ImportDirective<'a>| {
212+
let module = match directive.imported_module.get() {
213+
Some(module) => module,
214+
None => return false,
215+
};
216+
let ident = match directive.subclass {
217+
SingleImport { source, .. } => source,
218+
_ => unreachable!(),
219+
};
220+
match this.resolve_ident_in_module(module, ident, ns, false, false, path_span) {
221+
Err(Determined) => {}
222+
_ => return false,
223+
}
224+
true
225+
};
202226
match resolution.single_imports {
203227
SingleImports::AtLeastOne => return Err(Undetermined),
204-
SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
205-
let module = match directive.imported_module.get() {
206-
Some(module) => module,
207-
None => return Err(Undetermined),
208-
};
209-
let ident = match directive.subclass {
210-
SingleImport { source, .. } => source,
211-
_ => unreachable!(),
212-
};
213-
match self.resolve_ident_in_module(module, ident, ns, false, false, path_span) {
214-
Err(Determined) => {}
215-
_ => return Err(Undetermined),
228+
SingleImports::MaybeOne(directive) => {
229+
let accessible = self.is_accessible(directive.vis.get());
230+
if accessible {
231+
if !resolve_single_import(self, directive) {
232+
return Err(Undetermined)
233+
}
234+
}
235+
}
236+
SingleImports::MaybeTwo(directive1, directive2) => {
237+
let accessible1 = self.is_accessible(directive1.vis.get());
238+
let accessible2 = self.is_accessible(directive2.vis.get());
239+
if accessible1 && accessible2 {
240+
if !resolve_single_import(self, directive1) &&
241+
!resolve_single_import(self, directive2) {
242+
return Err(Undetermined)
243+
}
244+
} else if accessible1 {
245+
if !resolve_single_import(self, directive1) {
246+
return Err(Undetermined)
247+
}
248+
} else {
249+
if !resolve_single_import(self, directive2) {
250+
return Err(Undetermined)
251+
}
216252
}
217253
}
218-
SingleImports::MaybeOne(_) | SingleImports::None => {},
254+
SingleImports::None => {},
219255
}
220256

221257
let no_unresolved_invocations =
@@ -281,7 +317,7 @@ impl<'a> Resolver<'a> {
281317
SingleImport { target, .. } => {
282318
self.per_ns(|this, ns| {
283319
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
284-
resolution.single_imports.add_directive(directive);
320+
resolution.single_imports.add_directive(directive, this.use_extern_macros);
285321
});
286322
}
287323
// We don't add prelude imports to the globs since they only affect lexical scopes,
@@ -575,7 +611,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
575611
Err(Undetermined) => indeterminate = true,
576612
Err(Determined) => {
577613
this.update_resolution(parent, target, ns, |_, resolution| {
578-
resolution.single_imports.directive_failed()
614+
resolution.single_imports.directive_failed(directive)
579615
});
580616
}
581617
Ok(binding) if !binding.is_importable() => {

src/test/ui/issue-50187.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2018 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+
// compile-pass
12+
13+
#![feature(use_extern_macros, decl_macro)]
14+
15+
mod type_ns {
16+
pub type A = u8;
17+
}
18+
mod value_ns {
19+
pub const A: u8 = 0;
20+
}
21+
mod macro_ns {
22+
pub macro A() {}
23+
}
24+
25+
mod merge2 {
26+
pub use type_ns::A;
27+
pub use value_ns::A;
28+
}
29+
mod merge3 {
30+
pub use type_ns::A;
31+
pub use value_ns::A;
32+
pub use macro_ns::A;
33+
}
34+
35+
mod use2 {
36+
pub use merge2::A;
37+
}
38+
mod use3 {
39+
pub use merge3::A;
40+
}
41+
42+
fn main() {
43+
type B2 = use2::A;
44+
let a2 = use2::A;
45+
46+
type B3 = use3::A;
47+
let a3 = use3::A;
48+
use3::A!();
49+
}

0 commit comments

Comments
 (0)