Skip to content

Commit 681a14f

Browse files
committed
item_like_imports: Allow unused ambiguous glob imports.
1 parent f582fa3 commit 681a14f

File tree

4 files changed

+79
-10
lines changed

4 files changed

+79
-10
lines changed

src/librustc_resolve/lib.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,10 @@ enum NameBindingKind<'a> {
874874
binding: &'a NameBinding<'a>,
875875
directive: &'a ImportDirective<'a>,
876876
},
877+
Ambiguity {
878+
b1: &'a NameBinding<'a>,
879+
b2: &'a NameBinding<'a>,
880+
}
877881
}
878882

879883
#[derive(Clone, Debug)]
@@ -885,6 +889,7 @@ impl<'a> NameBinding<'a> {
885889
NameBindingKind::Module(module) => Some(module),
886890
NameBindingKind::Def(_) => None,
887891
NameBindingKind::Import { binding, .. } => binding.module(),
892+
NameBindingKind::Ambiguity { .. } => None,
888893
}
889894
}
890895

@@ -893,6 +898,7 @@ impl<'a> NameBinding<'a> {
893898
NameBindingKind::Def(def) => def,
894899
NameBindingKind::Module(module) => module.def.unwrap(),
895900
NameBindingKind::Import { binding, .. } => binding.def(),
901+
NameBindingKind::Ambiguity { .. } => Def::Err,
896902
}
897903
}
898904

@@ -922,6 +928,7 @@ impl<'a> NameBinding<'a> {
922928
fn is_glob_import(&self) -> bool {
923929
match self.kind {
924930
NameBindingKind::Import { directive, .. } => directive.is_glob(),
931+
NameBindingKind::Ambiguity { .. } => true,
925932
_ => false,
926933
}
927934
}
@@ -932,6 +939,14 @@ impl<'a> NameBinding<'a> {
932939
_ => true,
933940
}
934941
}
942+
943+
fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> {
944+
match self.kind {
945+
NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)),
946+
NameBindingKind::Import { binding, .. } => binding.ambiguity(),
947+
_ => None,
948+
}
949+
}
935950
}
936951

937952
/// Interns the names of the primitive types.
@@ -1249,7 +1264,8 @@ impl<'a> Resolver<'a> {
12491264
match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
12501265
}
12511266

1252-
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
1267+
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
1268+
-> bool /* true if an error was reported */ {
12531269
// track extern crates for unused_extern_crate lint
12541270
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
12551271
self.used_crates.insert(krate);
@@ -1259,6 +1275,19 @@ impl<'a> Resolver<'a> {
12591275
self.used_imports.insert((directive.id, ns));
12601276
self.add_to_glob_map(directive.id, name);
12611277
}
1278+
1279+
if let Some((b1, b2)) = binding.ambiguity() {
1280+
let msg1 = format!("`{}` could resolve to the name imported here", name);
1281+
let msg2 = format!("`{}` could also resolve to the name imported here", name);
1282+
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
1283+
.span_note(b1.span, &msg1)
1284+
.span_note(b2.span, &msg2)
1285+
.note(&format!("Consider adding an explicit import of `{}` to disambiguate", name))
1286+
.emit();
1287+
return true;
1288+
}
1289+
1290+
false
12621291
}
12631292

12641293
fn add_to_glob_map(&mut self, id: NodeId, name: Name) {
@@ -2294,7 +2323,8 @@ impl<'a> Resolver<'a> {
22942323
Def::Struct(..) | Def::Variant(..) |
22952324
Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
22962325
// A constant, unit variant, etc pattern.
2297-
self.record_use(ident.node.name, ValueNS, binding.unwrap());
2326+
let name = ident.node.name;
2327+
self.record_use(name, ValueNS, binding.unwrap(), ident.span);
22982328
Some(PathResolution::new(def))
22992329
}
23002330
Def::Struct(..) | Def::Variant(..) |

src/librustc_resolve/resolve_imports.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ impl<'a> Resolver<'a> {
181181
if is_disallowed_private_import(binding) {
182182
return Failed(None);
183183
}
184-
self.record_use(name, ns, binding);
184+
if self.record_use(name, ns, binding, span) {
185+
return Success(self.dummy_binding);
186+
}
185187
if !self.is_accessible(binding.vis) {
186188
self.privacy_errors.push(PrivacyError(span, name, binding));
187189
}
@@ -323,7 +325,18 @@ impl<'a> Resolver<'a> {
323325
if !this.new_import_semantics || !old_binding.is_glob_import() {
324326
resolution.duplicate_globs.push(binding);
325327
} else if binding.def() != old_binding.def() {
326-
resolution.duplicate_globs.push(binding);
328+
resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding {
329+
kind: NameBindingKind::Ambiguity {
330+
b1: old_binding,
331+
b2: binding,
332+
},
333+
vis: if old_binding.vis.is_at_least(binding.vis, this) {
334+
old_binding.vis
335+
} else {
336+
binding.vis
337+
},
338+
span: old_binding.span,
339+
}));
327340
} else if !old_binding.vis.is_at_least(binding.vis, this) {
328341
// We are glob-importing the same item but with greater visibility.
329342
resolution.binding = Some(binding);
@@ -597,7 +610,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
597610

598611
for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
599612
if let Ok(binding) = result {
600-
self.record_use(name, ns, binding);
613+
if self.record_use(name, ns, binding, directive.span) {
614+
self.resolution(module, name, ns).borrow_mut().binding =
615+
Some(self.dummy_binding);
616+
}
601617
}
602618
}
603619

@@ -759,17 +775,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
759775
}
760776
}
761777

762-
self.report_conflict(module, name, ns, duplicate_glob, binding);
763-
}
764-
} else if binding.is_glob_import() {
765-
for duplicate_glob in resolution.duplicate_globs.iter() {
766778
self.report_conflict(module, name, ns, duplicate_glob, binding);
767779
}
768780
}
769781

770782
if binding.vis == ty::Visibility::Public &&
771783
(binding.is_import() || binding.is_extern_crate()) {
772-
reexports.push(Export { name: name, def_id: binding.def().def_id() });
784+
let def = binding.def();
785+
if def != Def::Err {
786+
reexports.push(Export { name: name, def_id: def.def_id() });
787+
}
773788
}
774789

775790
if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {

src/test/compile-fail/imports/duplicate.rs

+14
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ mod e {
3333
pub use c::*; // ok
3434
}
3535

36+
mod f {
37+
pub use a::*; //~ NOTE `foo` could resolve to the name imported here
38+
pub use b::*; //~ NOTE `foo` could also resolve to the name imported here
39+
}
40+
41+
mod g {
42+
pub use a::*; //~ NOTE `foo` could resolve to the name imported here
43+
pub use f::*; //~ NOTE `foo` could also resolve to the name imported here
44+
}
45+
3646
fn main() {
3747
e::foo();
48+
f::foo(); //~ ERROR `foo` is ambiguous
49+
//~| NOTE Consider adding an explicit import of `foo` to disambiguate
50+
g::foo(); //~ ERROR `foo` is ambiguous
51+
//~| NOTE Consider adding an explicit import of `foo` to disambiguate
3852
}

src/test/run-pass/imports.rs

+10
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,14 @@ mod c {
6363
}
6464
}
6565

66+
// Unused names can be ambiguous.
67+
mod d {
68+
pub use foo::*; // This imports `f` in the value namespace.
69+
pub use bar::*; // This also imports `f` in the value namespace.
70+
}
71+
72+
mod e {
73+
pub use d::*; // n.b. Since `e::f` is not used, this is not considered to be a use of `d::f`.
74+
}
75+
6676
fn main() {}

0 commit comments

Comments
 (0)