]> git.lizzy.rs Git - rust.git/commitdiff
resolve: Populate external modules in more automatic and lazy way
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Mon, 29 Jul 2019 18:19:50 +0000 (21:19 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Fri, 16 Aug 2019 18:10:12 +0000 (21:10 +0300)
The modules are now populated implicitly on the first access

src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs

index 539e4a301e01238ca8225c06e84d858907d9c69d..852353b7c1f01e4381da65e2f94b07967064e086 100644 (file)
@@ -159,19 +159,6 @@ fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option<Lrc<SyntaxExtension>>
         Some(ext)
     }
 
-    /// Ensures that the reduced graph rooted at the given external module
-    /// is built, building it if it is not.
-    crate fn populate_module_if_necessary(&mut self, module: Module<'a>) {
-        if module.populated.get() { return }
-        let def_id = module.def_id().unwrap();
-        for child in self.cstore.item_children_untracked(def_id, self.session) {
-            let child = child.map_id(|_| panic!("unexpected id"));
-            BuildReducedGraphVisitor { parent_scope: ParentScope::module(module), r: self }
-                .build_reduced_graph_for_external_crate_res(child);
-        }
-        module.populated.set(true)
-    }
-
     crate fn build_reduced_graph(
         &mut self, fragment: &AstFragment, parent_scope: ParentScope<'a>
     ) -> LegacyScope<'a> {
@@ -186,6 +173,10 @@ struct BuildReducedGraphVisitor<'a, 'b> {
     parent_scope: ParentScope<'a>,
 }
 
+impl<'a> AsMut<Resolver<'a>> for BuildReducedGraphVisitor<'a, '_> {
+    fn as_mut(&mut self) -> &mut Resolver<'a> { self.r }
+}
+
 impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
     fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
         let parent_scope = &self.parent_scope;
@@ -603,8 +594,6 @@ fn build_reduced_graph_for_item(&mut self, item: &Item) {
                     self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
                 };
 
-                self.r.populate_module_if_necessary(module);
-
                 let used = self.process_legacy_macro_imports(item, module);
                 let binding =
                     (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
@@ -922,6 +911,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<ast::Node
                                              span);
                 self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
 
+                module.populate_on_access.set(false);
                 for child in self.r.cstore.item_children_untracked(def_id, self.r.session) {
                     let res = child.res.map_id(|_| panic!("unexpected id"));
                     let ns = if let Res::Def(DefKind::AssocTy, _) = res {
@@ -935,7 +925,6 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<ast::Node
                         self.r.has_self.insert(res.def_id());
                     }
                 }
-                module.populated.set(true);
             }
             Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => {
                 self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
@@ -952,7 +941,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<ast::Node
     }
 
     fn legacy_import_macro(&mut self,
-                           name: Name,
+                           name: ast::Name,
                            binding: &'a NameBinding<'a>,
                            span: Span,
                            allow_shadowing: bool) {
@@ -1021,9 +1010,9 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> b
         if let Some(span) = import_all {
             let directive = macro_use_directive(self, span);
             self.r.potentially_unused_imports.push(directive);
-            module.for_each_child(|ident, ns, binding| if ns == MacroNS {
-                let imported_binding = self.r.import(binding, directive);
-                self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
+            module.for_each_child(self, |this, ident, ns, binding| if ns == MacroNS {
+                let imported_binding = this.r.import(binding, directive);
+                this.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
             });
         } else {
             for ident in single_imports.iter().cloned() {
index 861b0fd44ac41f1ae53981b523260227405aa562..80d1322ff31763a368ac0ff9448ba56a2b4199e8 100644 (file)
@@ -73,10 +73,13 @@ fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
     false
 }
 
-crate fn add_module_candidates(
-    module: Module<'_>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool
+crate fn add_module_candidates<'a>(
+    resolver: &mut Resolver<'a>,
+    module: Module<'a>,
+    names: &mut Vec<TypoSuggestion>,
+    filter_fn: &impl Fn(Res) -> bool,
 ) {
-    for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
+    for (&(ident, _), resolution) in resolver.resolutions(module).borrow().iter() {
         if let Some(binding) = resolution.borrow().binding {
             let res = binding.res();
             if filter_fn(res) {
@@ -402,10 +405,10 @@ fn early_lookup_typo_candidate(
                 Scope::CrateRoot => {
                     let root_ident = Ident::new(kw::PathRoot, ident.span);
                     let root_module = this.resolve_crate_root(root_ident);
-                    add_module_candidates(root_module, &mut suggestions, filter_fn);
+                    add_module_candidates(this, root_module, &mut suggestions, filter_fn);
                 }
                 Scope::Module(module) => {
-                    add_module_candidates(module, &mut suggestions, filter_fn);
+                    add_module_candidates(this, module, &mut suggestions, filter_fn);
                 }
                 Scope::MacroUsePrelude => {
                     suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
@@ -453,7 +456,7 @@ fn early_lookup_typo_candidate(
                 Scope::StdLibPrelude => {
                     if let Some(prelude) = this.prelude {
                         let mut tmp_suggestions = Vec::new();
-                        add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
+                        add_module_candidates(this, prelude, &mut tmp_suggestions, filter_fn);
                         suggestions.extend(tmp_suggestions.into_iter().filter(|s| {
                             use_prelude || this.is_builtin_macro(s.res)
                         }));
@@ -509,11 +512,9 @@ fn lookup_import_candidates_from_module<FilterFn>(&mut self,
         while let Some((in_module,
                         path_segments,
                         in_module_is_extern)) = worklist.pop() {
-            self.populate_module_if_necessary(in_module);
-
             // We have to visit module children in deterministic order to avoid
             // instabilities in reported imports (#43552).
-            in_module.for_each_child_stable(|ident, ns, name_binding| {
+            in_module.for_each_child_stable(self, |this, ident, ns, name_binding| {
                 // avoid imports entirely
                 if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
                 // avoid non-importable candidates as well
@@ -547,7 +548,7 @@ fn lookup_import_candidates_from_module<FilterFn>(&mut self,
                         // outside crate private modules => no need to check this)
                         if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
                             let did = match res {
-                                Res::Def(DefKind::Ctor(..), did) => self.parent(did),
+                                Res::Def(DefKind::Ctor(..), did) => this.parent(did),
                                 _ => res.opt_def_id(),
                             };
                             candidates.push(ImportSuggestion { did, path });
@@ -607,8 +608,6 @@ fn lookup_import_candidates_from_module<FilterFn>(&mut self,
                         krate: crate_id,
                         index: CRATE_DEF_INDEX,
                     });
-                    self.populate_module_if_necessary(&crate_root);
-
                     suggestions.extend(self.lookup_import_candidates_from_module(
                         lookup_ident, namespace, crate_root, ident, &filter_fn));
                 }
@@ -805,7 +804,7 @@ fn make_external_crate_suggestion(
     ///            at the root of the crate instead of the module where it is defined
     /// ```
     pub(crate) fn check_for_module_export_macro(
-        &self,
+        &mut self,
         directive: &'b ImportDirective<'b>,
         module: ModuleOrUniformRoot<'b>,
         ident: Ident,
@@ -826,7 +825,7 @@ pub(crate) fn check_for_module_export_macro(
             return None;
         }
 
-        let resolutions = crate_module.resolutions.borrow();
+        let resolutions = self.r.resolutions(crate_module).borrow();
         let resolution = resolutions.get(&(ident, MacroNS))?;
         let binding = resolution.borrow().binding()?;
         if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
index ffdfd85002bca66794f0557c3013b0810a26c74c..d8bd86699b7af966982543c6143c77599f8d110d 100644 (file)
@@ -1929,7 +1929,7 @@ fn get_traits_in_module_containing_item(&mut self,
         let mut traits = module.traits.borrow_mut();
         if traits.is_none() {
             let mut collected_traits = Vec::new();
-            module.for_each_child(|name, ns, binding| {
+            module.for_each_child(self.r, |_, name, ns, binding| {
                 if ns != TypeNS { return }
                 match binding.res() {
                     Res::Def(DefKind::Trait, _) |
index 68f9c1684d6fbc2d78015c6879b1de6424c182d6..960bde3180915b0c86029305e9b3154831c95671 100644 (file)
@@ -548,7 +548,7 @@ fn lookup_typo_candidate(
                 // Items in scope
                 if let RibKind::ModuleRibKind(module) = rib.kind {
                     // Items from this module
-                    add_module_candidates(module, &mut names, &filter_fn);
+                    add_module_candidates(self.r, module, &mut names, &filter_fn);
 
                     if let ModuleKind::Block(..) = module.kind {
                         // We can see through blocks
@@ -577,7 +577,7 @@ fn lookup_typo_candidate(
                             }));
 
                             if let Some(prelude) = self.r.prelude {
-                                add_module_candidates(prelude, &mut names, &filter_fn);
+                                add_module_candidates(self.r, prelude, &mut names, &filter_fn);
                             }
                         }
                         break;
@@ -599,7 +599,7 @@ fn lookup_typo_candidate(
                 mod_path, Some(TypeNS), false, span, CrateLint::No
             ) {
                 if let ModuleOrUniformRoot::Module(module) = module {
-                    add_module_candidates(module, &mut names, &filter_fn);
+                    add_module_candidates(self.r, module, &mut names, &filter_fn);
                 }
             }
         }
@@ -717,9 +717,7 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion
             // abort if the module is already found
             if result.is_some() { break; }
 
-            self.r.populate_module_if_necessary(in_module);
-
-            in_module.for_each_child_stable(|ident, _, name_binding| {
+            in_module.for_each_child_stable(self.r, |_, ident, _, name_binding| {
                 // abort if the module is already found or if name_binding is private external
                 if result.is_some() || !name_binding.vis.is_visible_locally() {
                     return
@@ -750,10 +748,8 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion
 
     fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
-            self.r.populate_module_if_necessary(enum_module);
-
             let mut variants = Vec::new();
-            enum_module.for_each_child_stable(|ident, _, name_binding| {
+            enum_module.for_each_child_stable(self.r, |_, ident, _, name_binding| {
                 if let Res::Def(DefKind::Variant, _) = name_binding.res() {
                     let mut segms = enum_import_suggestion.path.segments.clone();
                     segms.push(ast::PathSegment::from_ident(ident));
index 9b5eb51eb582dfb6b3df8adf3f2d00931420a159..bf51ba212ff07b147bb7096886fff5141e9061b5 100644 (file)
@@ -431,6 +431,8 @@ pub fn name(&self) -> Option<Name> {
     }
 }
 
+type Resolutions<'a> = RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
+
 /// One node in the tree of modules.
 pub struct ModuleData<'a> {
     parent: Option<Module<'a>>,
@@ -439,7 +441,11 @@ pub struct ModuleData<'a> {
     // The def id of the closest normal module (`mod`) ancestor (including this module).
     normal_ancestor_id: DefId,
 
-    resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
+    // Mapping between names and their (possibly in-progress) resolutions in this module.
+    // Resolutions in modules from other crates are not populated until accessed.
+    lazy_resolutions: Resolutions<'a>,
+    // True if this is a module from other crate that needs to be populated on access.
+    populate_on_access: Cell<bool>,
 
     // Macro invocations that can expand into items in this module.
     unresolved_invocations: RefCell<FxHashSet<ExpnId>>,
@@ -452,11 +458,6 @@ pub struct ModuleData<'a> {
     // Used to memoize the traits in this module for faster searches through all traits in scope.
     traits: RefCell<Option<Box<[(Ident, &'a NameBinding<'a>)]>>>,
 
-    // Whether this module is populated. If not populated, any attempt to
-    // access the children must be preceded with a
-    // `populate_module_if_necessary` call.
-    populated: Cell<bool>,
-
     /// Span of the module itself. Used for error reporting.
     span: Span,
 
@@ -475,30 +476,34 @@ fn new(parent: Option<Module<'a>>,
             parent,
             kind,
             normal_ancestor_id,
-            resolutions: Default::default(),
+            lazy_resolutions: Default::default(),
+            populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
             unresolved_invocations: Default::default(),
             no_implicit_prelude: false,
             glob_importers: RefCell::new(Vec::new()),
             globs: RefCell::new(Vec::new()),
             traits: RefCell::new(None),
-            populated: Cell::new(normal_ancestor_id.is_local()),
             span,
             expansion,
         }
     }
 
-    fn for_each_child<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
-        for (&(ident, ns), name_resolution) in self.resolutions.borrow().iter() {
-            name_resolution.borrow().binding.map(|binding| f(ident, ns, binding));
+    fn for_each_child<R, F>(&'a self, resolver: &mut R, mut f: F)
+        where R: AsMut<Resolver<'a>>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>)
+    {
+        for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
+            name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
         }
     }
 
-    fn for_each_child_stable<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
-        let resolutions = self.resolutions.borrow();
+    fn for_each_child_stable<R, F>(&'a self, resolver: &mut R, mut f: F)
+        where R: AsMut<Resolver<'a>>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>)
+    {
+        let resolutions = resolver.as_mut().resolutions(self).borrow();
         let mut resolutions = resolutions.iter().collect::<Vec<_>>();
         resolutions.sort_by_cached_key(|&(&(ident, ns), _)| (ident.as_str(), ns));
         for &(&(ident, ns), &resolution) in resolutions.iter() {
-            resolution.borrow().binding.map(|binding| f(ident, ns, binding));
+            resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
         }
     }
 
@@ -983,6 +988,10 @@ fn alloc_ast_paths(&'a self, paths: &[ast::Path]) -> &'a [ast::Path] {
     }
 }
 
+impl<'a> AsMut<Resolver<'a>> for Resolver<'a> {
+    fn as_mut(&mut self) -> &mut Resolver<'a> { self }
+}
+
 impl<'a, 'b> ty::DefIdTree for &'a Resolver<'b> {
     fn parent(self, id: DefId) -> Option<DefId> {
         match id.krate {
@@ -2634,7 +2643,6 @@ fn extern_prelude_get(&mut self, ident: Ident, speculative: bool)
                     return None;
                 };
                 let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
-                self.populate_module_if_necessary(&crate_root);
                 Some((crate_root, ty::Visibility::Public, DUMMY_SP, ExpnId::root())
                     .to_name_binding(self.arenas))
             }
index 693893e9ef13b00c1d3cbbea42a5a46bb1958a59..d68dbb78e9d000c965c657fb1228e7283c4c608a 100644 (file)
@@ -7,9 +7,10 @@
 use crate::Determinacy::{self, *};
 use crate::Namespace::{self, TypeNS, MacroNS};
 use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use crate::{Resolver, ResolutionError, Segment};
+use crate::{Resolutions, Resolver, ResolutionError, Segment};
 use crate::{names_to_string, module_to_string};
 use crate::ModuleKind;
+use crate::build_reduced_graph::BuildReducedGraphVisitor;
 use crate::diagnostics::Suggestion;
 
 use errors::Applicability;
@@ -161,9 +162,22 @@ pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> {
 }
 
 impl<'a> Resolver<'a> {
-    crate fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
+    crate fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> {
+        if module.populate_on_access.get() {
+            module.populate_on_access.set(false);
+            let def_id = module.def_id().expect("unpopulated module without a def-id");
+            for child in self.cstore.item_children_untracked(def_id, self.session) {
+                let child = child.map_id(|_| panic!("unexpected id"));
+                BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self }
+                    .build_reduced_graph_for_external_crate_res(module, child);
+            }
+        }
+        &module.lazy_resolutions
+    }
+
+    crate fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace)
                   -> &'a RefCell<NameResolution<'a>> {
-        *module.resolutions.borrow_mut().entry((ident.modern(), ns))
+        *self.resolutions(module).borrow_mut().entry((ident.modern(), ns))
                .or_insert_with(|| self.arenas.alloc_name_resolution())
     }
 
@@ -242,8 +256,6 @@ impl<'a> Resolver<'a> {
             }
         };
 
-        self.populate_module_if_necessary(module);
-
         let resolution = self.resolution(module, ident, ns)
             .try_borrow_mut()
             .map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
@@ -1027,7 +1039,7 @@ fn finalize_import(
 
             return if all_ns_failed {
                 let resolutions = match module {
-                    ModuleOrUniformRoot::Module(module) => Some(module.resolutions.borrow()),
+                    ModuleOrUniformRoot::Module(module) => Some(self.r.resolutions(module).borrow()),
                     _ => None,
                 };
                 let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
@@ -1265,8 +1277,6 @@ fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
             }
         };
 
-        self.r.populate_module_if_necessary(module);
-
         if module.is_trait() {
             self.r.session.span_err(directive.span, "items in traits are not importable.");
             return;
@@ -1282,7 +1292,7 @@ fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
 
         // Ensure that `resolutions` isn't borrowed during `try_define`,
         // since it might get updated via a glob cycle.
-        let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
+        let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(&ident, resolution)| {
             resolution.borrow().binding().map(|binding| (ident, binding))
         }).collect::<Vec<_>>();
         for ((mut ident, ns), binding) in bindings {
@@ -1310,7 +1320,7 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
 
         let mut reexports = Vec::new();
 
-        for (&(ident, ns), resolution) in module.resolutions.borrow().iter() {
+        for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() {
             let resolution = &mut *resolution.borrow_mut();
             let binding = match resolution.binding {
                 Some(binding) => binding,
@@ -1369,8 +1379,8 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
                             Some(ModuleOrUniformRoot::Module(module)) => module,
                             _ => bug!("module should exist"),
                         };
-                        let resolutions = imported_module.parent.expect("parent should exist")
-                            .resolutions.borrow();
+                        let parent_module = imported_module.parent.expect("parent should exist");
+                        let resolutions = self.r.resolutions(parent_module).borrow();
                         let enum_path_segment_index = directive.module_path.len() - 1;
                         let enum_ident = directive.module_path[enum_path_segment_index].ident;