Skip to content

Commit f69c11b

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 f690098 commit f69c11b

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
@@ -1036,7 +1036,7 @@ enum RibKind<'a> {
10361036
///
10371037
/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
10381038
/// resolving, the name is looked up from inside out.
1039-
#[derive(Debug)]
1039+
#[derive(Clone, Debug)]
10401040
struct Rib<'a, R = Res> {
10411041
bindings: FxHashMap<Ident, R>,
10421042
kind: RibKind<'a>,
@@ -1157,6 +1157,8 @@ impl ModuleKind {
11571157
}
11581158
}
11591159

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

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

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

@@ -1206,7 +1207,8 @@ impl<'a> ModuleData<'a> {
12061207
parent,
12071208
kind,
12081209
normal_ancestor_id,
1209-
resolutions: Default::default(),
1210+
lazy_resolutions: Default::default(),
1211+
populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
12101212
single_segment_macro_resolutions: RefCell::new(Vec::new()),
12111213
multi_segment_macro_resolutions: RefCell::new(Vec::new()),
12121214
builtin_attrs: RefCell::new(Vec::new()),
@@ -1215,24 +1217,27 @@ impl<'a> ModuleData<'a> {
12151217
glob_importers: RefCell::new(Vec::new()),
12161218
globs: RefCell::new(Vec::new()),
12171219
traits: RefCell::new(None),
1218-
populated: Cell::new(normal_ancestor_id.is_local()),
12191220
span,
12201221
expansion,
12211222
}
12221223
}
12231224

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

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

@@ -4517,7 +4522,7 @@ impl<'a> Resolver<'a> {
45174522
let mut traits = module.traits.borrow_mut();
45184523
if traits.is_none() {
45194524
let mut collected_traits = Vec::new();
4520-
module.for_each_child(|name, ns, binding| {
4525+
module.for_each_child(self, |_, name, ns, binding| {
45214526
if ns != TypeNS { return }
45224527
match binding.res() {
45234528
Res::Def(DefKind::Trait, _) |
@@ -5071,7 +5076,6 @@ impl<'a> Resolver<'a> {
50715076
return None;
50725077
};
50735078
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
5074-
self.populate_module_if_necessary(&crate_root);
50755079
Some((crate_root, ty::Visibility::Public, DUMMY_SP, ExpnId::root())
50765080
.to_name_binding(self.arenas))
50775081
}

0 commit comments

Comments
 (0)