Skip to content

Commit 28bed3f

Browse files
committed
Auto merge of #31317 - jseyfried:remove_external_module_children, r=nrc
This PR refactors away `Module`'s `external_module_children` and instead puts `extern crate` declarations in `children` like other items, simplifying duplicate checking and name resolution. This PR also allows values to share a name with extern crates, which are only defined in the type namespace. Other than that, it is a pure refactoring. r? @nrc
2 parents 91e8044 + e768fa7 commit 28bed3f

File tree

4 files changed

+76
-115
lines changed

4 files changed

+76
-115
lines changed

src/librustc_resolve/build_reduced_graph.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -107,20 +107,37 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
107107
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
108108
/// otherwise, reports an error.
109109
fn define<T: ToNameBinding<'b>>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) {
110-
let name_binding = def.to_name_binding();
111-
let span = name_binding.span.unwrap_or(DUMMY_SP);
112-
self.check_for_conflicts_between_external_crates_and_items(&parent, name, span);
113-
if !parent.try_define_child(name, ns, name_binding) {
110+
let binding = def.to_name_binding();
111+
let old_binding = match parent.try_define_child(name, ns, binding.clone()) {
112+
Some(old_binding) => old_binding,
113+
None => return,
114+
};
115+
116+
let span = binding.span.unwrap_or(DUMMY_SP);
117+
if !old_binding.is_extern_crate() && !binding.is_extern_crate() {
114118
// Record an error here by looking up the namespace that had the duplicate
115119
let ns_str = match ns { TypeNS => "type or module", ValueNS => "value" };
116120
let resolution_error = ResolutionError::DuplicateDefinition(ns_str, name);
117121
let mut err = resolve_struct_error(self, span, resolution_error);
118122

119-
if let Some(sp) = parent.children.borrow().get(&(name, ns)).unwrap().span {
123+
if let Some(sp) = old_binding.span {
120124
let note = format!("first definition of {} `{}` here", ns_str, name);
121125
err.span_note(sp, &note);
122126
}
123127
err.emit();
128+
} else if old_binding.is_extern_crate() && binding.is_extern_crate() {
129+
span_err!(self.session,
130+
span,
131+
E0259,
132+
"an external crate named `{}` has already been imported into this module",
133+
name);
134+
} else {
135+
span_err!(self.session,
136+
span,
137+
E0260,
138+
"the name `{}` conflicts with an external crate \
139+
that has been imported into this module",
140+
name);
124141
}
125142
}
126143

@@ -289,14 +306,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
289306
self.external_exports.insert(def_id);
290307
let parent_link = ModuleParentLink(parent, name);
291308
let def = Def::Mod(def_id);
292-
let external_module = self.new_module(parent_link, Some(def), false, true);
293-
294-
debug!("(build reduced graph for item) found extern `{}`",
295-
module_to_string(&*external_module));
296-
self.check_for_conflicts_for_external_crate(parent, name, sp);
297-
parent.external_module_children
298-
.borrow_mut()
299-
.insert(name, external_module);
309+
let external_module = self.new_extern_crate_module(parent_link, def);
310+
self.define(parent, name, TypeNS, (external_module, sp));
311+
300312
self.build_reduced_graph_for_external_crate(&external_module);
301313
}
302314
parent

src/librustc_resolve/lib.rs

+32-72
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,6 @@ enum SuggestionType {
120120
}
121121

122122
pub enum ResolutionError<'a> {
123-
/// error E0260: name conflicts with an extern crate
124-
NameConflictsWithExternCrate(Name),
125123
/// error E0401: can't use type parameters from outer function
126124
TypeParametersFromOuterFunction,
127125
/// error E0402: cannot use an outer type parameter in this context
@@ -228,14 +226,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
228226
}
229227

230228
match resolution_error {
231-
ResolutionError::NameConflictsWithExternCrate(name) => {
232-
struct_span_err!(resolver.session,
233-
span,
234-
E0260,
235-
"the name `{}` conflicts with an external crate \
236-
that has been imported into this module",
237-
name)
238-
}
239229
ResolutionError::TypeParametersFromOuterFunction => {
240230
struct_span_err!(resolver.session,
241231
span,
@@ -801,14 +791,11 @@ pub struct ModuleS<'a> {
801791
parent_link: ParentLink<'a>,
802792
def: Cell<Option<Def>>,
803793
is_public: bool,
794+
is_extern_crate: bool,
804795

805796
children: RefCell<HashMap<(Name, Namespace), NameBinding<'a>>>,
806797
imports: RefCell<Vec<ImportDirective>>,
807798

808-
// The external module children of this node that were declared with
809-
// `extern crate`.
810-
external_module_children: RefCell<HashMap<Name, Module<'a>>>,
811-
812799
// The anonymous children of this node. Anonymous children are pseudo-
813800
// modules that are implicitly created around items contained within
814801
// blocks.
@@ -854,9 +841,9 @@ impl<'a> ModuleS<'a> {
854841
parent_link: parent_link,
855842
def: Cell::new(def),
856843
is_public: is_public,
844+
is_extern_crate: false,
857845
children: RefCell::new(HashMap::new()),
858846
imports: RefCell::new(Vec::new()),
859-
external_module_children: RefCell::new(HashMap::new()),
860847
anonymous_children: RefCell::new(NodeMap()),
861848
import_resolutions: RefCell::new(HashMap::new()),
862849
glob_count: Cell::new(0),
@@ -871,10 +858,21 @@ impl<'a> ModuleS<'a> {
871858
self.children.borrow().get(&(name, ns)).cloned()
872859
}
873860

874-
fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>) -> bool {
861+
// If the name is not yet defined, define the name and return None.
862+
// Otherwise, return the existing definition.
863+
fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>)
864+
-> Option<NameBinding<'a>> {
875865
match self.children.borrow_mut().entry((name, ns)) {
876-
hash_map::Entry::Vacant(entry) => { entry.insert(binding); true }
877-
hash_map::Entry::Occupied(_) => false,
866+
hash_map::Entry::Vacant(entry) => { entry.insert(binding); None }
867+
hash_map::Entry::Occupied(entry) => { Some(entry.get().clone()) },
868+
}
869+
}
870+
871+
fn for_each_local_child<F: FnMut(Name, Namespace, &NameBinding<'a>)>(&self, mut f: F) {
872+
for (&(name, ns), name_binding) in self.children.borrow().iter() {
873+
if !name_binding.is_extern_crate() {
874+
f(name, ns, name_binding)
875+
}
878876
}
879877
}
880878

@@ -1005,6 +1003,10 @@ impl<'a> NameBinding<'a> {
10051003
let def = self.def().unwrap();
10061004
(def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) }))
10071005
}
1006+
1007+
fn is_extern_crate(&self) -> bool {
1008+
self.module().map(|module| module.is_extern_crate).unwrap_or(false)
1009+
}
10081010
}
10091011

10101012
/// Interns the names of the primitive types.
@@ -1184,6 +1186,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
11841186
self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
11851187
}
11861188

1189+
fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def) -> Module<'a> {
1190+
let mut module = ModuleS::new(parent_link, Some(def), false, true);
1191+
module.is_extern_crate = true;
1192+
self.arenas.modules.alloc(module)
1193+
}
1194+
11871195
fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
11881196
match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
11891197
}
@@ -1211,32 +1219,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12111219
}
12121220
}
12131221

1214-
/// Check that an external crate doesn't collide with items or other external crates.
1215-
fn check_for_conflicts_for_external_crate(&self, module: Module<'a>, name: Name, span: Span) {
1216-
if module.external_module_children.borrow().contains_key(&name) {
1217-
span_err!(self.session,
1218-
span,
1219-
E0259,
1220-
"an external crate named `{}` has already been imported into this module",
1221-
name);
1222-
}
1223-
if let Some(name_binding) = module.get_child(name, TypeNS) {
1224-
resolve_error(self,
1225-
name_binding.span.unwrap_or(codemap::DUMMY_SP),
1226-
ResolutionError::NameConflictsWithExternCrate(name));
1227-
}
1228-
}
1229-
1230-
/// Checks that the names of items don't collide with external crates.
1231-
fn check_for_conflicts_between_external_crates_and_items(&self,
1232-
module: Module<'a>,
1233-
name: Name,
1234-
span: Span) {
1235-
if module.external_module_children.borrow().contains_key(&name) {
1236-
resolve_error(self, span, ResolutionError::NameConflictsWithExternCrate(name));
1237-
}
1238-
}
1239-
12401222
/// Resolves the given module path from the given root `module_`.
12411223
fn resolve_module_path_from_root(&mut self,
12421224
module_: Module<'a>,
@@ -1245,11 +1227,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12451227
span: Span,
12461228
lp: LastPrivate)
12471229
-> ResolveResult<(Module<'a>, LastPrivate)> {
1248-
fn search_parent_externals<'a>(needle: Name, module: Module<'a>)
1249-
-> Option<Module<'a>> {
1250-
match module.external_module_children.borrow().get(&needle) {
1251-
Some(_) => Some(module),
1252-
None => match module.parent_link {
1230+
fn search_parent_externals<'a>(needle: Name, module: Module<'a>) -> Option<Module<'a>> {
1231+
match module.get_child(needle, TypeNS) {
1232+
Some(ref binding) if binding.is_extern_crate() => Some(module),
1233+
_ => match module.parent_link {
12531234
ModuleParentLink(ref parent, _) => {
12541235
search_parent_externals(needle, parent)
12551236
}
@@ -1480,17 +1461,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14801461
}
14811462
}
14821463

1483-
// Search for external modules.
1484-
if namespace == TypeNS {
1485-
let children = module_.external_module_children.borrow();
1486-
if let Some(module) = children.get(&name) {
1487-
let name_binding = NameBinding::create_from_module(module, None);
1488-
debug!("lower name bindings succeeded");
1489-
return Success((Target::new(module_, name_binding, Shadowable::Never),
1490-
false));
1491-
}
1492-
}
1493-
14941464
// Finally, proceed up the scope chain looking for parent modules.
14951465
let mut search_module = module_;
14961466
loop {
@@ -1684,16 +1654,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16841654
Some(..) | None => {} // Continue.
16851655
}
16861656

1687-
// Finally, search through external children.
1688-
if namespace == TypeNS {
1689-
let children = module_.external_module_children.borrow();
1690-
if let Some(module) = children.get(&name) {
1691-
let name_binding = NameBinding::create_from_module(module, None);
1692-
return Success((Target::new(module_, name_binding, Shadowable::Never),
1693-
false));
1694-
}
1695-
}
1696-
16971657
// We're out of luck.
16981658
debug!("(resolving name in module) failed to resolve `{}`", name);
16991659
return Failed(None);
@@ -1712,7 +1672,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
17121672
// Descend into children and anonymous children.
17131673
build_reduced_graph::populate_module_if_necessary(self, &module_);
17141674

1715-
for (_, child_node) in module_.children.borrow().iter() {
1675+
module_.for_each_local_child(|_, _, child_node| {
17161676
match child_node.module() {
17171677
None => {
17181678
// Continue.
@@ -1721,7 +1681,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
17211681
self.report_unresolved_imports(child_module);
17221682
}
17231683
}
1724-
}
1684+
});
17251685

17261686
for (_, module_) in module_.anonymous_children.borrow().iter() {
17271687
self.report_unresolved_imports(module_);

src/librustc_resolve/resolve_imports.rs

+17-29
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
213213
self.resolver.current_module = orig_module;
214214

215215
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
216-
for (_, child_node) in module_.children.borrow().iter() {
216+
module_.for_each_local_child(|_, _, child_node| {
217217
match child_node.module() {
218218
None => {
219219
// Nothing to do.
@@ -222,7 +222,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
222222
errors.extend(self.resolve_imports_for_module_subtree(child_module));
223223
}
224224
}
225-
}
225+
});
226226

227227
for (_, child_module) in module_.anonymous_children.borrow().iter() {
228228
errors.extend(self.resolve_imports_for_module_subtree(child_module));
@@ -386,18 +386,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
386386
-> (ResolveResult<(Module<'b>, NameBinding<'b>)>, bool) {
387387
build_reduced_graph::populate_module_if_necessary(self.resolver, module);
388388
if let Some(name_binding) = module.get_child(name, ns) {
389-
return (Success((module, name_binding)), false);
390-
}
391-
392-
if ns == TypeNS {
393-
if let Some(extern_crate) = module.external_module_children.borrow().get(&name) {
389+
if name_binding.is_extern_crate() {
394390
// track the extern crate as used.
395-
if let Some(DefId{ krate: kid, .. }) = extern_crate.def_id() {
396-
self.resolver.used_crates.insert(kid);
391+
if let Some(DefId { krate, .. }) = name_binding.module().unwrap().def_id() {
392+
self.resolver.used_crates.insert(krate);
397393
}
398-
let name_binding = NameBinding::create_from_module(extern_crate, None);
399-
return (Success((module, name_binding)), false);
400394
}
395+
return (Success((module, name_binding)), false)
401396
}
402397

403398
// If there is an unresolved glob at this point in the containing module, bail out.
@@ -725,13 +720,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
725720
// Add all children from the containing module.
726721
build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
727722

728-
for (&name, name_binding) in target_module.children.borrow().iter() {
723+
target_module.for_each_local_child(|name, ns, name_binding| {
729724
self.merge_import_resolution(module_,
730725
target_module,
731726
import_directive,
732-
name,
727+
(name, ns),
733728
name_binding.clone());
734-
}
729+
});
735730

736731
// Record the destination of this import
737732
if let Some(did) = target_module.def_id() {
@@ -878,21 +873,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
878873
import: &ImportResolution<'b>,
879874
import_span: Span,
880875
(name, ns): (Name, Namespace)) {
881-
// First, check for conflicts between imports and `extern crate`s.
882-
if ns == TypeNS {
883-
if module.external_module_children.borrow().contains_key(&name) {
884-
match import.target {
885-
Some(ref target) if target.shadowable != Shadowable::Always => {
886-
let msg = format!("import `{0}` conflicts with imported crate \
887-
in this module (maybe you meant `use {0}::*`?)",
888-
name);
889-
span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
890-
}
891-
Some(_) | None => {}
892-
}
893-
}
894-
}
895-
896876
// Check for item conflicts.
897877
let name_binding = match module.get_child(name, ns) {
898878
None => {
@@ -921,6 +901,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
921901
} else {
922902
match import.target {
923903
Some(ref target) if target.shadowable != Shadowable::Always => {
904+
if name_binding.is_extern_crate() {
905+
let msg = format!("import `{0}` conflicts with imported crate \
906+
in this module (maybe you meant `use {0}::*`?)",
907+
name);
908+
span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
909+
return;
910+
}
911+
924912
let (what, note) = match name_binding.module() {
925913
Some(ref module) if module.is_normal() =>
926914
("existing submodule", "note conflicting module here"),

src/test/compile-fail/resolve-conflict-item-vs-extern-crate.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
fn std() {} //~ ERROR the name `std` conflicts with an external crate
11+
fn std() {}
12+
mod std {} //~ ERROR the name `std` conflicts with an external crate
1213

1314
fn main() {
1415
}

0 commit comments

Comments
 (0)