Skip to content

Commit 3029e09

Browse files
committed
Auto merge of #31726 - jseyfried:improve_import_resolution, r=nikomatsakis
This PR improves the import resolution algorithm. First, it records that an import succeeded or failed for one namespace (by calling `decrement_outstanding_references_for` and `try_define_child` if successful) even if it is still indeterminate in the other namespace, fixing #31444. Second, it starts importing bindings from globs as soon as the glob path is determined. It maintains links from imported modules to their importers so that when a resolution becomes successful in an imported module, a corresponding binding will be added to the importer module. It also maintains links from importer modules to imported modules so that we can determine if an undefined name is indeterminate or failing by recursively checking this in the imported modules. This allows, for example: ```rust mod foo { pub mod baz {} pub use bar::baz::*; } mod bar { pub use foo::*; } ``` It also allows cycles of pub glob imports, although by to the current shadowing rules, the only way for such a cycle to compile is if each participating module defines no names. Incidentally, this PR lays the groundwork for more permissive feature-gated shadowing rules. Finally, this PR encapsulates almost all implementation details of import resolution in `resolve_imports` (some of which used to be in `lib.rs`) and refactors reexport recording, shadowed trait collecting, some duplicate checking, and the `private_in_public` lint out of the core import resolution algorithm and into a post-processing pass in `resolve_imports`. r? @nrc
2 parents 07a1803 + b3572ae commit 3029e09

File tree

3 files changed

+388
-305
lines changed

3 files changed

+388
-305
lines changed

src/librustc_resolve/build_reduced_graph.rs

+13-28
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
9898
fn try_define<T>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
9999
where T: ToNameBinding<'b>
100100
{
101-
let _ = parent.try_define_child(name, ns, self.new_name_binding(def.to_name_binding()));
101+
let _ = parent.try_define_child(name, ns, def.to_name_binding());
102102
}
103103

104104
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
105105
/// otherwise, reports an error.
106106
fn define<T: ToNameBinding<'b>>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) {
107-
let binding = self.new_name_binding(def.to_name_binding());
108-
let old_binding = match parent.try_define_child(name, ns, binding) {
107+
let binding = def.to_name_binding();
108+
let old_binding = match parent.try_define_child(name, ns, binding.clone()) {
109109
Ok(()) => return,
110110
Err(old_binding) => old_binding,
111111
};
@@ -207,7 +207,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
207207
ResolutionError::SelfImportsOnlyAllowedWithin);
208208
}
209209

210-
let subclass = SingleImport(binding, source_name);
210+
let subclass = ImportDirectiveSubclass::single(binding, source_name);
211211
self.build_import_directive(parent,
212212
module_path,
213213
subclass,
@@ -258,9 +258,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
258258
(module_path.to_vec(), name, rename)
259259
}
260260
};
261+
let subclass = ImportDirectiveSubclass::single(rename, name);
261262
self.build_import_directive(parent,
262263
module_path,
263-
SingleImport(rename, name),
264+
subclass,
264265
source_item.span,
265266
source_item.node.id(),
266267
is_public,
@@ -294,14 +295,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
294295
let module = self.new_extern_crate_module(parent_link, def, is_public, item.id);
295296
self.define(parent, name, TypeNS, (module, sp));
296297

297-
if is_public {
298-
let export = Export { name: name, def_id: def_id };
299-
if let Some(def_id) = parent.def_id() {
300-
let node_id = self.resolver.ast_map.as_local_node_id(def_id).unwrap();
301-
self.export_map.entry(node_id).or_insert(Vec::new()).push(export);
302-
}
303-
}
304-
305298
self.build_reduced_graph_for_external_crate(module);
306299
}
307300
parent
@@ -683,33 +676,25 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
683676
id: NodeId,
684677
is_public: bool,
685678
shadowable: Shadowable) {
686-
module_.unresolved_imports
687-
.borrow_mut()
688-
.push(ImportDirective::new(module_path, subclass, span, id, is_public, shadowable));
689-
self.unresolved_imports += 1;
690-
691-
if is_public {
692-
module_.inc_pub_count();
693-
}
694-
695679
// Bump the reference count on the name. Or, if this is a glob, set
696680
// the appropriate flag.
697681

698682
match subclass {
699-
SingleImport(target, _) => {
683+
SingleImport { target, .. } => {
700684
module_.increment_outstanding_references_for(target, ValueNS);
701685
module_.increment_outstanding_references_for(target, TypeNS);
702686
}
703687
GlobImport => {
704688
// Set the glob flag. This tells us that we don't know the
705689
// module's exports ahead of time.
706-
707-
module_.inc_glob_count();
708-
if is_public {
709-
module_.inc_pub_glob_count();
710-
}
690+
module_.inc_glob_count(is_public)
711691
}
712692
}
693+
694+
let directive =
695+
ImportDirective::new(module_path, subclass, span, id, is_public, shadowable);
696+
module_.add_import_directive(directive);
697+
self.unresolved_imports += 1;
713698
}
714699
}
715700

src/librustc_resolve/lib.rs

+47-94
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#![cfg_attr(not(stage0), deny(warnings))]
1919

2020
#![feature(associated_consts)]
21+
#![feature(borrow_state)]
2122
#![feature(rustc_diagnostic_macros)]
2223
#![feature(rustc_private)]
2324
#![feature(staged_api)]
@@ -812,7 +813,7 @@ pub struct ModuleS<'a> {
812813
extern_crate_id: Option<NodeId>,
813814

814815
resolutions: RefCell<HashMap<(Name, Namespace), NameResolution<'a>>>,
815-
unresolved_imports: RefCell<Vec<ImportDirective>>,
816+
unresolved_imports: RefCell<Vec<&'a ImportDirective>>,
816817

817818
// The module children of this node, including normal modules and anonymous modules.
818819
// Anonymous children are pseudo-modules that are implicitly created around items
@@ -832,26 +833,31 @@ pub struct ModuleS<'a> {
832833

833834
shadowed_traits: RefCell<Vec<&'a NameBinding<'a>>>,
834835

835-
// The number of unresolved globs that this module exports.
836-
glob_count: Cell<usize>,
836+
glob_importers: RefCell<Vec<(Module<'a>, &'a ImportDirective)>>,
837+
resolved_globs: RefCell<(Vec<Module<'a>> /* public */, Vec<Module<'a>> /* private */)>,
837838

838-
// The number of unresolved pub imports (both regular and globs) in this module
839-
pub_count: Cell<usize>,
839+
// The number of public glob imports in this module.
840+
public_glob_count: Cell<usize>,
840841

841-
// The number of unresolved pub glob imports in this module
842-
pub_glob_count: Cell<usize>,
842+
// The number of private glob imports in this module.
843+
private_glob_count: Cell<usize>,
843844

844845
// Whether this module is populated. If not populated, any attempt to
845846
// access the children must be preceded with a
846847
// `populate_module_if_necessary` call.
847848
populated: Cell<bool>,
849+
850+
arenas: &'a ResolverArenas<'a>,
848851
}
849852

850853
pub type Module<'a> = &'a ModuleS<'a>;
851854

852855
impl<'a> ModuleS<'a> {
853-
854-
fn new(parent_link: ParentLink<'a>, def: Option<Def>, external: bool, is_public: bool) -> Self {
856+
fn new(parent_link: ParentLink<'a>,
857+
def: Option<Def>,
858+
external: bool,
859+
is_public: bool,
860+
arenas: &'a ResolverArenas<'a>) -> Self {
855861
ModuleS {
856862
parent_link: parent_link,
857863
def: def,
@@ -861,53 +867,18 @@ impl<'a> ModuleS<'a> {
861867
unresolved_imports: RefCell::new(Vec::new()),
862868
module_children: RefCell::new(NodeMap()),
863869
shadowed_traits: RefCell::new(Vec::new()),
864-
glob_count: Cell::new(0),
865-
pub_count: Cell::new(0),
866-
pub_glob_count: Cell::new(0),
870+
glob_importers: RefCell::new(Vec::new()),
871+
resolved_globs: RefCell::new((Vec::new(), Vec::new())),
872+
public_glob_count: Cell::new(0),
873+
private_glob_count: Cell::new(0),
867874
populated: Cell::new(!external),
875+
arenas: arenas
868876
}
869877
}
870878

871-
fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool)
872-
-> ResolveResult<&'a NameBinding<'a>> {
873-
let glob_count =
874-
if allow_private_imports { self.glob_count.get() } else { self.pub_glob_count.get() };
875-
876-
self.resolutions.borrow().get(&(name, ns)).cloned().unwrap_or_default().result(glob_count)
877-
.and_then(|binding| {
878-
let allowed = allow_private_imports || !binding.is_import() || binding.is_public();
879-
if allowed { Success(binding) } else { Failed(None) }
880-
})
881-
}
882-
883-
// Define the name or return the existing binding if there is a collision.
884-
fn try_define_child(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>)
885-
-> Result<(), &'a NameBinding<'a>> {
886-
let mut children = self.resolutions.borrow_mut();
887-
let resolution = children.entry((name, ns)).or_insert_with(Default::default);
888-
889-
// FIXME #31379: We can use methods from imported traits shadowed by non-import items
890-
if let Some(old_binding) = resolution.binding {
891-
if !old_binding.is_import() && binding.is_import() {
892-
if let Some(Def::Trait(_)) = binding.def() {
893-
self.shadowed_traits.borrow_mut().push(binding);
894-
}
895-
}
896-
}
897-
898-
resolution.try_define(binding)
899-
}
900-
901-
fn increment_outstanding_references_for(&self, name: Name, ns: Namespace) {
902-
let mut children = self.resolutions.borrow_mut();
903-
children.entry((name, ns)).or_insert_with(Default::default).outstanding_references += 1;
904-
}
905-
906-
fn decrement_outstanding_references_for(&self, name: Name, ns: Namespace) {
907-
match self.resolutions.borrow_mut().get_mut(&(name, ns)).unwrap().outstanding_references {
908-
0 => panic!("No more outstanding references!"),
909-
ref mut outstanding_references => { *outstanding_references -= 1; }
910-
}
879+
fn add_import_directive(&self, import_directive: ImportDirective) {
880+
let import_directive = self.arenas.alloc_import_directive(import_directive);
881+
self.unresolved_imports.borrow_mut().push(import_directive);
911882
}
912883

913884
fn for_each_child<F: FnMut(Name, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
@@ -943,26 +914,9 @@ impl<'a> ModuleS<'a> {
943914
}
944915
}
945916

946-
pub fn inc_glob_count(&self) {
947-
self.glob_count.set(self.glob_count.get() + 1);
948-
}
949-
pub fn dec_glob_count(&self) {
950-
assert!(self.glob_count.get() > 0);
951-
self.glob_count.set(self.glob_count.get() - 1);
952-
}
953-
pub fn inc_pub_count(&self) {
954-
self.pub_count.set(self.pub_count.get() + 1);
955-
}
956-
pub fn dec_pub_count(&self) {
957-
assert!(self.pub_count.get() > 0);
958-
self.pub_count.set(self.pub_count.get() - 1);
959-
}
960-
pub fn inc_pub_glob_count(&self) {
961-
self.pub_glob_count.set(self.pub_glob_count.get() + 1);
962-
}
963-
pub fn dec_pub_glob_count(&self) {
964-
assert!(self.pub_glob_count.get() > 0);
965-
self.pub_glob_count.set(self.pub_glob_count.get() - 1);
917+
fn inc_glob_count(&self, is_public: bool) {
918+
let glob_count = if is_public { &self.public_glob_count } else { &self.private_glob_count };
919+
glob_count.set(glob_count.get() + 1);
966920
}
967921
}
968922

@@ -995,14 +949,14 @@ bitflags! {
995949
}
996950

997951
// Records a possibly-private value, type, or module definition.
998-
#[derive(Debug)]
952+
#[derive(Clone, Debug)]
999953
pub struct NameBinding<'a> {
1000954
modifiers: DefModifiers,
1001955
kind: NameBindingKind<'a>,
1002956
span: Option<Span>,
1003957
}
1004958

1005-
#[derive(Debug)]
959+
#[derive(Clone, Debug)]
1006960
enum NameBindingKind<'a> {
1007961
Def(Def),
1008962
Module(Module<'a>),
@@ -1167,6 +1121,19 @@ pub struct Resolver<'a, 'tcx: 'a> {
11671121
pub struct ResolverArenas<'a> {
11681122
modules: arena::TypedArena<ModuleS<'a>>,
11691123
name_bindings: arena::TypedArena<NameBinding<'a>>,
1124+
import_directives: arena::TypedArena<ImportDirective>,
1125+
}
1126+
1127+
impl<'a> ResolverArenas<'a> {
1128+
fn alloc_module(&'a self, module: ModuleS<'a>) -> Module<'a> {
1129+
self.modules.alloc(module)
1130+
}
1131+
fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> {
1132+
self.name_bindings.alloc(name_binding)
1133+
}
1134+
fn alloc_import_directive(&'a self, import_directive: ImportDirective) -> &'a ImportDirective {
1135+
self.import_directives.alloc(import_directive)
1136+
}
11701137
}
11711138

11721139
#[derive(PartialEq)]
@@ -1182,8 +1149,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
11821149
arenas: &'a ResolverArenas<'a>)
11831150
-> Resolver<'a, 'tcx> {
11841151
let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
1185-
let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, true);
1186-
let graph_root = arenas.modules.alloc(graph_root);
1152+
let graph_root =
1153+
ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, true, arenas);
1154+
let graph_root = arenas.alloc_module(graph_root);
11871155

11881156
Resolver {
11891157
session: session,
@@ -1234,6 +1202,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12341202
ResolverArenas {
12351203
modules: arena::TypedArena::new(),
12361204
name_bindings: arena::TypedArena::new(),
1205+
import_directives: arena::TypedArena::new(),
12371206
}
12381207
}
12391208

@@ -1242,11 +1211,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12421211
def: Option<Def>,
12431212
external: bool,
12441213
is_public: bool) -> Module<'a> {
1245-
self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
1246-
}
1247-
1248-
fn new_name_binding(&self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> {
1249-
self.arenas.name_bindings.alloc(name_binding)
1214+
self.arenas.alloc_module(ModuleS::new(parent_link, def, external, is_public, self.arenas))
12501215
}
12511216

12521217
fn new_extern_crate_module(&self,
@@ -1255,7 +1220,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12551220
is_public: bool,
12561221
local_node_id: NodeId)
12571222
-> Module<'a> {
1258-
let mut module = ModuleS::new(parent_link, Some(def), false, is_public);
1223+
let mut module = ModuleS::new(parent_link, Some(def), false, is_public, self.arenas);
12591224
module.extern_crate_id = Some(local_node_id);
12601225
self.arenas.modules.alloc(module)
12611226
}
@@ -1626,18 +1591,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16261591
})
16271592
}
16281593

1629-
fn report_unresolved_imports(&mut self, module_: Module<'a>) {
1630-
for import in module_.unresolved_imports.borrow().iter() {
1631-
resolve_error(self, import.span, ResolutionError::UnresolvedImport(None));
1632-
break;
1633-
}
1634-
1635-
// Descend into children and anonymous children.
1636-
for (_, module_) in module_.module_children.borrow().iter() {
1637-
self.report_unresolved_imports(module_);
1638-
}
1639-
}
1640-
16411594
// AST resolution
16421595
//
16431596
// We maintain a list of value ribs and type ribs.

0 commit comments

Comments
 (0)