Skip to content

Commit 0ef7c28

Browse files
committed
resolve: Populate external modules in more automatic and lazy way
The modules are now populated implicitly on the first access
1 parent 534b423 commit 0ef7c28

File tree

4 files changed

+67
-71
lines changed

4 files changed

+67
-71
lines changed

src/librustc_resolve/build_reduced_graph.rs

+5-18
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,6 @@ impl<'a> Resolver<'a> {
365365
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
366366
};
367367

368-
self.populate_module_if_necessary(module);
369368
if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() {
370369
if name.as_str() == ident.name.as_str() {
371370
self.injected_crate = Some(module);
@@ -632,7 +631,7 @@ impl<'a> Resolver<'a> {
632631
}
633632

634633
/// Builds the reduced graph for a single item in an external crate.
635-
fn build_reduced_graph_for_external_crate_res(
634+
crate fn build_reduced_graph_for_external_crate_res(
636635
&mut self,
637636
parent: Module<'a>,
638637
child: Export<ast::NodeId>,
@@ -686,6 +685,7 @@ impl<'a> Resolver<'a> {
686685
span);
687686
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
688687

688+
module.populate_on_access.set(false);
689689
for child in self.cstore.item_children_untracked(def_id, self.session) {
690690
let res = child.res.map_id(|_| panic!("unexpected id"));
691691
let ns = if let Res::Def(DefKind::AssocTy, _) = res {
@@ -699,7 +699,6 @@ impl<'a> Resolver<'a> {
699699
self.has_self.insert(res.def_id());
700700
}
701701
}
702-
module.populated.set(true);
703702
}
704703
Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => {
705704
self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
@@ -780,18 +779,6 @@ impl<'a> Resolver<'a> {
780779
Some(ext)
781780
}
782781

783-
/// Ensures that the reduced graph rooted at the given external module
784-
/// is built, building it if it is not.
785-
pub fn populate_module_if_necessary(&mut self, module: Module<'a>) {
786-
if module.populated.get() { return }
787-
let def_id = module.def_id().unwrap();
788-
for child in self.cstore.item_children_untracked(def_id, self.session) {
789-
let child = child.map_id(|_| panic!("unexpected id"));
790-
self.build_reduced_graph_for_external_crate_res(module, child);
791-
}
792-
module.populated.set(true)
793-
}
794-
795782
fn legacy_import_macro(&mut self,
796783
name: Name,
797784
binding: &'a NameBinding<'a>,
@@ -863,9 +850,9 @@ impl<'a> Resolver<'a> {
863850
if let Some(span) = import_all {
864851
let directive = macro_use_directive(span);
865852
self.potentially_unused_imports.push(directive);
866-
module.for_each_child(|ident, ns, binding| if ns == MacroNS {
867-
let imported_binding = self.import(binding, directive);
868-
self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
853+
module.for_each_child(self, |this, ident, ns, binding| if ns == MacroNS {
854+
let imported_binding = this.import(binding, directive);
855+
this.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
869856
});
870857
} else {
871858
for ident in single_imports.iter().cloned() {

src/librustc_resolve/diagnostics.rs

+21-24
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,13 @@ fn add_typo_suggestion(
6565
false
6666
}
6767

68-
fn add_module_candidates(
69-
module: Module<'_>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool
68+
fn add_module_candidates<'a>(
69+
resolver: &mut Resolver<'a>,
70+
module: Module<'a>,
71+
names: &mut Vec<TypoSuggestion>,
72+
filter_fn: &impl Fn(Res) -> bool,
7073
) {
71-
for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
74+
for (&(ident, _), resolution) in resolver.resolutions(module).borrow().iter() {
7275
if let Some(binding) = resolution.borrow().binding {
7376
let res = binding.res();
7477
if filter_fn(res) {
@@ -593,10 +596,10 @@ impl<'a> Resolver<'a> {
593596
Scope::CrateRoot => {
594597
let root_ident = Ident::new(kw::PathRoot, ident.span);
595598
let root_module = this.resolve_crate_root(root_ident);
596-
add_module_candidates(root_module, &mut suggestions, filter_fn);
599+
add_module_candidates(this, root_module, &mut suggestions, filter_fn);
597600
}
598601
Scope::Module(module) => {
599-
add_module_candidates(module, &mut suggestions, filter_fn);
602+
add_module_candidates(this, module, &mut suggestions, filter_fn);
600603
}
601604
Scope::MacroUsePrelude => {
602605
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
@@ -644,7 +647,7 @@ impl<'a> Resolver<'a> {
644647
Scope::StdLibPrelude => {
645648
if let Some(prelude) = this.prelude {
646649
let mut tmp_suggestions = Vec::new();
647-
add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
650+
add_module_candidates(this, prelude, &mut tmp_suggestions, filter_fn);
648651
suggestions.extend(tmp_suggestions.into_iter().filter(|s| {
649652
use_prelude || this.is_builtin_macro(s.res.opt_def_id())
650653
}));
@@ -694,7 +697,9 @@ impl<'a> Resolver<'a> {
694697
if path.len() == 1 {
695698
// Search in lexical scope.
696699
// Walk backwards up the ribs in scope and collect candidates.
697-
for rib in self.ribs[ns].iter().rev() {
700+
// Ribs have to be cloned to avoid borrowing the resolver.
701+
let ribs = self.ribs[ns].clone();
702+
for rib in ribs.iter().rev() {
698703
// Locals and type parameters
699704
for (ident, &res) in &rib.bindings {
700705
if filter_fn(res) {
@@ -704,7 +709,7 @@ impl<'a> Resolver<'a> {
704709
// Items in scope
705710
if let RibKind::ModuleRibKind(module) = rib.kind {
706711
// Items from this module
707-
add_module_candidates(module, &mut names, &filter_fn);
712+
add_module_candidates(self, module, &mut names, &filter_fn);
708713

709714
if let ModuleKind::Block(..) = module.kind {
710715
// We can see through blocks
@@ -732,7 +737,7 @@ impl<'a> Resolver<'a> {
732737
}));
733738

734739
if let Some(prelude) = self.prelude {
735-
add_module_candidates(prelude, &mut names, &filter_fn);
740+
add_module_candidates(self, prelude, &mut names, &filter_fn);
736741
}
737742
}
738743
break;
@@ -754,7 +759,7 @@ impl<'a> Resolver<'a> {
754759
mod_path, Some(TypeNS), false, span, CrateLint::No
755760
) {
756761
if let ModuleOrUniformRoot::Module(module) = module {
757-
add_module_candidates(module, &mut names, &filter_fn);
762+
add_module_candidates(self, module, &mut names, &filter_fn);
758763
}
759764
}
760765
}
@@ -792,11 +797,9 @@ impl<'a> Resolver<'a> {
792797
while let Some((in_module,
793798
path_segments,
794799
in_module_is_extern)) = worklist.pop() {
795-
self.populate_module_if_necessary(in_module);
796-
797800
// We have to visit module children in deterministic order to avoid
798801
// instabilities in reported imports (#43552).
799-
in_module.for_each_child_stable(|ident, ns, name_binding| {
802+
in_module.for_each_child_stable(self, |this, ident, ns, name_binding| {
800803
// avoid imports entirely
801804
if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
802805
// avoid non-importable candidates as well
@@ -830,7 +833,7 @@ impl<'a> Resolver<'a> {
830833
// outside crate private modules => no need to check this)
831834
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
832835
let did = match res {
833-
Res::Def(DefKind::Ctor(..), did) => self.parent(did),
836+
Res::Def(DefKind::Ctor(..), did) => this.parent(did),
834837
_ => res.opt_def_id(),
835838
};
836839
candidates.push(ImportSuggestion { did, path });
@@ -890,8 +893,6 @@ impl<'a> Resolver<'a> {
890893
krate: crate_id,
891894
index: CRATE_DEF_INDEX,
892895
});
893-
self.populate_module_if_necessary(&crate_root);
894-
895896
suggestions.extend(self.lookup_import_candidates_from_module(
896897
lookup_ident, namespace, crate_root, ident, &filter_fn));
897898
}
@@ -910,9 +911,7 @@ impl<'a> Resolver<'a> {
910911
// abort if the module is already found
911912
if result.is_some() { break; }
912913

913-
self.populate_module_if_necessary(in_module);
914-
915-
in_module.for_each_child_stable(|ident, _, name_binding| {
914+
in_module.for_each_child_stable(self, |_, ident, _, name_binding| {
916915
// abort if the module is already found or if name_binding is private external
917916
if result.is_some() || !name_binding.vis.is_visible_locally() {
918917
return
@@ -943,10 +942,8 @@ impl<'a> Resolver<'a> {
943942

944943
fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
945944
self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
946-
self.populate_module_if_necessary(enum_module);
947-
948945
let mut variants = Vec::new();
949-
enum_module.for_each_child_stable(|ident, _, name_binding| {
946+
enum_module.for_each_child_stable(self, |_, ident, _, name_binding| {
950947
if let Res::Def(DefKind::Variant, _) = name_binding.res() {
951948
let mut segms = enum_import_suggestion.path.segments.clone();
952949
segms.push(ast::PathSegment::from_ident(ident));
@@ -1147,7 +1144,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
11471144
/// at the root of the crate instead of the module where it is defined
11481145
/// ```
11491146
pub(crate) fn check_for_module_export_macro(
1150-
&self,
1147+
&mut self,
11511148
directive: &'b ImportDirective<'b>,
11521149
module: ModuleOrUniformRoot<'b>,
11531150
ident: Ident,
@@ -1168,7 +1165,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
11681165
return None;
11691166
}
11701167

1171-
let resolutions = crate_module.resolutions.borrow();
1168+
let resolutions = self.resolutions(crate_module).borrow();
11721169
let resolution = resolutions.get(&(ident, MacroNS))?;
11731170
let binding = resolution.borrow().binding()?;
11741171
if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {

src/librustc_resolve/lib.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,7 @@ enum RibKind<'a> {
10351035
///
10361036
/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
10371037
/// resolving, the name is looked up from inside out.
1038-
#[derive(Debug)]
1038+
#[derive(Clone, Debug)]
10391039
struct Rib<'a, R = Res> {
10401040
bindings: FxHashMap<Ident, R>,
10411041
kind: RibKind<'a>,
@@ -1156,6 +1156,8 @@ impl ModuleKind {
11561156
}
11571157
}
11581158

1159+
type Resolutions<'a> = RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
1160+
11591161
/// One node in the tree of modules.
11601162
pub struct ModuleData<'a> {
11611163
parent: Option<Module<'a>>,
@@ -1164,7 +1166,11 @@ pub struct ModuleData<'a> {
11641166
// The def id of the closest normal module (`mod`) ancestor (including this module).
11651167
normal_ancestor_id: DefId,
11661168

1167-
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
1169+
// Mapping between names and their (possibly in-progress) resolutions in this module.
1170+
// Resolutions in modules from other crates are not populated until accessed.
1171+
lazy_resolutions: Resolutions<'a>,
1172+
// True if this is a module from other crate that needs to be populated on access.
1173+
populate_on_access: Cell<bool>,
11681174
single_segment_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
11691175
Option<&'a NameBinding<'a>>)>>,
11701176
multi_segment_macro_resolutions: RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>,
@@ -1182,11 +1188,6 @@ pub struct ModuleData<'a> {
11821188
// Used to memoize the traits in this module for faster searches through all traits in scope.
11831189
traits: RefCell<Option<Box<[(Ident, &'a NameBinding<'a>)]>>>,
11841190

1185-
// Whether this module is populated. If not populated, any attempt to
1186-
// access the children must be preceded with a
1187-
// `populate_module_if_necessary` call.
1188-
populated: Cell<bool>,
1189-
11901191
/// Span of the module itself. Used for error reporting.
11911192
span: Span,
11921193

@@ -1205,7 +1206,8 @@ impl<'a> ModuleData<'a> {
12051206
parent,
12061207
kind,
12071208
normal_ancestor_id,
1208-
resolutions: Default::default(),
1209+
lazy_resolutions: Default::default(),
1210+
populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
12091211
single_segment_macro_resolutions: RefCell::new(Vec::new()),
12101212
multi_segment_macro_resolutions: RefCell::new(Vec::new()),
12111213
builtin_attrs: RefCell::new(Vec::new()),
@@ -1214,24 +1216,27 @@ impl<'a> ModuleData<'a> {
12141216
glob_importers: RefCell::new(Vec::new()),
12151217
globs: RefCell::new(Vec::new()),
12161218
traits: RefCell::new(None),
1217-
populated: Cell::new(normal_ancestor_id.is_local()),
12181219
span,
12191220
expansion,
12201221
}
12211222
}
12221223

1223-
fn for_each_child<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
1224-
for (&(ident, ns), name_resolution) in self.resolutions.borrow().iter() {
1225-
name_resolution.borrow().binding.map(|binding| f(ident, ns, binding));
1224+
fn for_each_child<F>(&'a self, resolver: &mut Resolver<'a>, mut f: F)
1225+
where F: FnMut(&mut Resolver<'a>, Ident, Namespace, &'a NameBinding<'a>)
1226+
{
1227+
for (&(ident, ns), name_resolution) in resolver.resolutions(self).borrow().iter() {
1228+
name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
12261229
}
12271230
}
12281231

1229-
fn for_each_child_stable<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
1230-
let resolutions = self.resolutions.borrow();
1232+
fn for_each_child_stable<F>(&'a self, resolver: &mut Resolver<'a>, mut f: F)
1233+
where F: FnMut(&mut Resolver<'a>, Ident, Namespace, &'a NameBinding<'a>)
1234+
{
1235+
let resolutions = resolver.resolutions(self).borrow();
12311236
let mut resolutions = resolutions.iter().collect::<Vec<_>>();
12321237
resolutions.sort_by_cached_key(|&(&(ident, ns), _)| (ident.as_str(), ns));
12331238
for &(&(ident, ns), &resolution) in resolutions.iter() {
1234-
resolution.borrow().binding.map(|binding| f(ident, ns, binding));
1239+
resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
12351240
}
12361241
}
12371242

@@ -4526,7 +4531,7 @@ impl<'a> Resolver<'a> {
45264531
let mut traits = module.traits.borrow_mut();
45274532
if traits.is_none() {
45284533
let mut collected_traits = Vec::new();
4529-
module.for_each_child(|name, ns, binding| {
4534+
module.for_each_child(self, |_, name, ns, binding| {
45304535
if ns != TypeNS { return }
45314536
match binding.res() {
45324537
Res::Def(DefKind::Trait, _) |
@@ -5080,7 +5085,6 @@ impl<'a> Resolver<'a> {
50805085
return None;
50815086
};
50825087
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
5083-
self.populate_module_if_necessary(&crate_root);
50845088
Some((crate_root, ty::Visibility::Public, DUMMY_SP, ExpnId::root())
50855089
.to_name_binding(self.arenas))
50865090
}

0 commit comments

Comments
 (0)