]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_resolve/src/lib.rs
Add more self-profile info to rustc_resolve
[rust.git] / compiler / rustc_resolve / src / lib.rs
index 2c68e0418589b6839dbbe513f83bd9f81a3018c9..2b4a1d9e3fa0a45a0ed676d9892a38e794bbcd9d 100644 (file)
@@ -33,7 +33,7 @@
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_expand::base::SyntaxExtension;
+use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::hir::exports::ExportMap;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
+use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, ResolverOutputs};
-use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
+use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -763,10 +764,13 @@ fn pseudo_vis(&self) -> ty::Visibility {
     }
 
     fn is_variant(&self) -> bool {
-        matches!(self.kind, NameBindingKind::Res(
+        matches!(
+            self.kind,
+            NameBindingKind::Res(
                 Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _),
                 _,
-            ))
+            )
+        )
     }
 
     fn is_extern_crate(&self) -> bool {
@@ -870,7 +874,7 @@ pub struct ExternPreludeEntry<'a> {
 
 /// Used for better errors for E0773
 enum BuiltinMacroState {
-    NotYetSeen(SyntaxExtension),
+    NotYetSeen(SyntaxExtensionKind),
     AlreadySeen(Span),
 }
 
@@ -1048,7 +1052,7 @@ pub struct ResolverArenas<'a> {
 impl<'a> ResolverArenas<'a> {
     fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> {
         let module = self.modules.alloc(module);
-        if module.def_id().map(|def_id| def_id.is_local()).unwrap_or(true) {
+        if module.def_id().map_or(true, |def_id| def_id.is_local()) {
             self.local_modules.borrow_mut().push(module);
         }
         module
@@ -1447,7 +1451,7 @@ fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
     }
 
     fn is_builtin_macro(&mut self, res: Res) -> bool {
-        self.get_macro(res).map_or(false, |ext| ext.is_builtin)
+        self.get_macro(res).map_or(false, |ext| ext.builtin_name.is_some())
     }
 
     fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
@@ -1461,61 +1465,86 @@ fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
-        let _prof_timer = self.session.prof.generic_activity("resolve_crate");
+        self.session.time("resolve_crate", || {
+            self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
+            self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
+            self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
+            self.session.time("resolve_check_unused", || self.check_unused(krate));
+            self.session.time("resolve_report_errors", || self.report_errors(krate));
+            self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
+        });
+    }
 
-        ImportResolver { r: self }.finalize_imports();
-        self.finalize_macro_resolutions();
+    pub fn traits_in_scope(
+        &mut self,
+        current_trait: Option<Module<'a>>,
+        parent_scope: &ParentScope<'a>,
+        ctxt: SyntaxContext,
+        assoc_item: Option<(Symbol, Namespace)>,
+    ) -> Vec<TraitCandidate> {
+        let mut found_traits = Vec::new();
+
+        if let Some(module) = current_trait {
+            if self.trait_may_have_item(Some(module), assoc_item) {
+                let def_id = module.def_id().unwrap();
+                found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
+            }
+        }
 
-        self.late_resolve_crate(krate);
+        self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
+            match scope {
+                Scope::Module(module) => {
+                    this.traits_in_module(module, assoc_item, &mut found_traits);
+                }
+                Scope::StdLibPrelude => {
+                    if let Some(module) = this.prelude {
+                        this.traits_in_module(module, assoc_item, &mut found_traits);
+                    }
+                }
+                Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {}
+                _ => unreachable!(),
+            }
+            None::<()>
+        });
 
-        self.check_unused(krate);
-        self.report_errors(krate);
-        self.crate_loader.postprocess(krate);
+        found_traits
     }
 
-    fn get_traits_in_module_containing_item(
+    fn traits_in_module(
         &mut self,
-        ident: Ident,
-        ns: Namespace,
         module: Module<'a>,
+        assoc_item: Option<(Symbol, Namespace)>,
         found_traits: &mut Vec<TraitCandidate>,
-        parent_scope: &ParentScope<'a>,
     ) {
-        assert!(ns == TypeNS || ns == ValueNS);
         module.ensure_traits(self);
         let traits = module.traits.borrow();
+        for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() {
+            if self.trait_may_have_item(trait_binding.module(), assoc_item) {
+                let def_id = trait_binding.res().def_id();
+                let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name);
+                found_traits.push(TraitCandidate { def_id, import_ids });
+            }
+        }
+    }
 
-        for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
-            // Traits have pseudo-modules that can be used to search for the given ident.
-            if let Some(module) = binding.module() {
-                let mut ident = ident;
-                if ident.span.glob_adjust(module.expansion, binding.span).is_none() {
-                    continue;
-                }
-                if self
-                    .resolve_ident_in_module_unadjusted(
-                        ModuleOrUniformRoot::Module(module),
-                        ident,
-                        ns,
-                        parent_scope,
-                        false,
-                        module.span,
-                    )
-                    .is_ok()
-                {
-                    let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
-                    let trait_def_id = module.def_id().unwrap();
-                    found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
-                }
-            } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
-                // For now, just treat all trait aliases as possible candidates, since we don't
-                // know if the ident is somewhere in the transitive bounds.
-                let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
-                let trait_def_id = binding.res().def_id();
-                found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
-            } else {
-                bug!("candidate is not trait or trait alias?")
+    // List of traits in scope is pruned on best effort basis. We reject traits not having an
+    // associated item with the given name and namespace (if specified). This is a conservative
+    // optimization, proper hygienic type-based resolution of associated items is done in typeck.
+    // We don't reject trait aliases (`trait_module == None`) because we don't have access to their
+    // associated items.
+    fn trait_may_have_item(
+        &mut self,
+        trait_module: Option<Module<'a>>,
+        assoc_item: Option<(Symbol, Namespace)>,
+    ) -> bool {
+        match (trait_module, assoc_item) {
+            (Some(trait_module), Some((name, ns))) => {
+                self.resolutions(trait_module).borrow().iter().any(|resolution| {
+                    let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution;
+                    assoc_ns == ns && assoc_ident.name == name
+                })
             }
+            _ => true,
         }
     }
 
@@ -1630,8 +1659,13 @@ fn visit_scopes<T>(
         &mut self,
         scope_set: ScopeSet,
         parent_scope: &ParentScope<'a>,
-        ident: Ident,
-        mut visitor: impl FnMut(&mut Self, Scope<'a>, /*use_prelude*/ bool, Ident) -> Option<T>,
+        ctxt: SyntaxContext,
+        mut visitor: impl FnMut(
+            &mut Self,
+            Scope<'a>,
+            /*use_prelude*/ bool,
+            SyntaxContext,
+        ) -> Option<T>,
     ) -> Option<T> {
         // General principles:
         // 1. Not controlled (user-defined) names should have higher priority than controlled names
@@ -1674,7 +1708,7 @@ fn visit_scopes<T>(
         // 4c. Standard library prelude (de-facto closed, controlled).
         // 6. Language prelude: builtin attributes (closed, controlled).
 
-        let rust_2015 = ident.span.rust_2015();
+        let rust_2015 = ctxt.edition() == Edition::Edition2015;
         let (ns, macro_kind, is_absolute_path) = match scope_set {
             ScopeSet::All(ns, _) => (ns, None, false),
             ScopeSet::AbsolutePath(ns) => (ns, None, true),
@@ -1687,7 +1721,7 @@ fn visit_scopes<T>(
             TypeNS | ValueNS => Scope::Module(module),
             MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
         };
-        let mut ident = ident.normalize_to_macros_2_0();
+        let mut ctxt = ctxt.normalize_to_macros_2_0();
         let mut use_prelude = !module.no_implicit_prelude;
 
         loop {
@@ -1723,7 +1757,7 @@ fn visit_scopes<T>(
             };
 
             if visit {
-                if let break_result @ Some(..) = visitor(self, scope, use_prelude, ident) {
+                if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) {
                     return break_result;
                 }
             }
@@ -1753,17 +1787,17 @@ fn visit_scopes<T>(
                 },
                 Scope::CrateRoot => match ns {
                     TypeNS => {
-                        ident.span.adjust(ExpnId::root());
+                        ctxt.adjust(ExpnId::root());
                         Scope::ExternPrelude
                     }
                     ValueNS | MacroNS => break,
                 },
                 Scope::Module(module) => {
                     use_prelude = !module.no_implicit_prelude;
-                    match self.hygienic_lexical_parent(module, &mut ident.span) {
+                    match self.hygienic_lexical_parent(module, &mut ctxt) {
                         Some(parent_module) => Scope::Module(parent_module),
                         None => {
-                            ident.span.adjust(ExpnId::root());
+                            ctxt.adjust(ExpnId::root());
                             match ns {
                                 TypeNS => Scope::ExternPrelude,
                                 ValueNS => Scope::StdLibPrelude,
@@ -1888,16 +1922,18 @@ fn resolve_ident_in_lexical_scope(
         ident = normalized_ident;
         let mut poisoned = None;
         loop {
+            let mut span_data = ident.span.data();
             let opt_module = if let Some(node_id) = record_used_id {
                 self.hygienic_lexical_parent_with_compatibility_fallback(
                     module,
-                    &mut ident.span,
+                    &mut span_data.ctxt,
                     node_id,
                     &mut poisoned,
                 )
             } else {
-                self.hygienic_lexical_parent(module, &mut ident.span)
+                self.hygienic_lexical_parent(module, &mut span_data.ctxt)
             };
+            ident.span = span_data.span();
             module = unwrap_or!(opt_module, break);
             let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
             let result = self.resolve_ident_in_module_unadjusted(
@@ -1971,10 +2007,10 @@ fn resolve_ident_in_lexical_scope(
     fn hygienic_lexical_parent(
         &mut self,
         module: Module<'a>,
-        span: &mut Span,
+        ctxt: &mut SyntaxContext,
     ) -> Option<Module<'a>> {
-        if !module.expansion.outer_expn_is_descendant_of(span.ctxt()) {
-            return Some(self.macro_def_scope(span.remove_mark()));
+        if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
+            return Some(self.macro_def_scope(ctxt.remove_mark()));
         }
 
         if let ModuleKind::Block(..) = module.kind {
@@ -1987,11 +2023,11 @@ fn hygienic_lexical_parent(
     fn hygienic_lexical_parent_with_compatibility_fallback(
         &mut self,
         module: Module<'a>,
-        span: &mut Span,
+        ctxt: &mut SyntaxContext,
         node_id: NodeId,
         poisoned: &mut Option<NodeId>,
     ) -> Option<Module<'a>> {
-        if let module @ Some(..) = self.hygienic_lexical_parent(module, span) {
+        if let module @ Some(..) = self.hygienic_lexical_parent(module, ctxt) {
             return module;
         }
 
@@ -2014,9 +2050,9 @@ fn hygienic_lexical_parent_with_compatibility_fallback(
                 // The macro is a proc macro derive
                 if let Some(def_id) = module.expansion.expn_data().macro_def_id {
                     let ext = self.get_macro_by_def_id(def_id);
-                    if !ext.is_builtin
+                    if ext.builtin_name.is_none()
                         && ext.macro_kind() == MacroKind::Derive
-                        && parent.expansion.outer_expn_is_descendant_of(span.ctxt())
+                        && parent.expansion.outer_expn_is_descendant_of(*ctxt)
                     {
                         *poisoned = Some(node_id);
                         return module.parent;
@@ -2447,8 +2483,14 @@ enum FindBindingResult<'a> {
                             (format!("use of undeclared crate or module `{}`", ident), None)
                         }
                     } else {
-                        let mut msg =
-                            format!("could not find `{}` in `{}`", ident, path[i - 1].ident);
+                        let parent = path[i - 1].ident.name;
+                        let parent = if parent == kw::PathRoot {
+                            "crate root".to_owned()
+                        } else {
+                            format!("`{}`", parent)
+                        };
+
+                        let mut msg = format!("could not find `{}` in {}", ident, parent);
                         if ns == TypeNS || ns == ValueNS {
                             let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
                             if let FindBindingResult::Binding(Ok(binding)) =
@@ -2456,11 +2498,11 @@ enum FindBindingResult<'a> {
                             {
                                 let mut found = |what| {
                                     msg = format!(
-                                        "expected {}, found {} `{}` in `{}`",
+                                        "expected {}, found {} `{}` in {}",
                                         ns.descr(),
                                         what,
                                         ident,
-                                        path[i - 1].ident
+                                        parent
                                     )
                                 };
                                 if binding.module().is_some() {
@@ -3020,7 +3062,7 @@ fn report_conflict<'b>(
         let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
         let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
         let from_item =
-            self.extern_prelude.get(&ident).map(|entry| entry.introduced_by_item).unwrap_or(true);
+            self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
         // Only suggest removing an import if both bindings are to the same def, if both spans
         // aren't dummy spans. Further, if both bindings are imports, then the ident must have
         // been introduced by a item.
@@ -3216,34 +3258,6 @@ fn extern_prelude_get(
         })
     }
 
-    /// This is equivalent to `get_traits_in_module_containing_item`, but without filtering by the associated item.
-    ///
-    /// This is used by rustdoc for intra-doc links.
-    pub fn traits_in_scope(&mut self, module_id: DefId) -> Vec<TraitCandidate> {
-        let module = self.get_module(module_id);
-        module.ensure_traits(self);
-        let traits = module.traits.borrow();
-        let to_candidate =
-            |this: &mut Self, &(trait_name, binding): &(Ident, &NameBinding<'_>)| TraitCandidate {
-                def_id: binding.res().def_id(),
-                import_ids: this.find_transitive_imports(&binding.kind, trait_name),
-            };
-
-        let mut candidates: Vec<_> =
-            traits.as_ref().unwrap().iter().map(|x| to_candidate(self, x)).collect();
-
-        if let Some(prelude) = self.prelude {
-            if !module.no_implicit_prelude {
-                prelude.ensure_traits(self);
-                candidates.extend(
-                    prelude.traits.borrow().as_ref().unwrap().iter().map(|x| to_candidate(self, x)),
-                );
-            }
-        }
-
-        candidates
-    }
-
     /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
     /// isn't something that can be returned because it can't be made to live that long,
     /// and also it's a private type. Fortunately rustdoc doesn't need to know the error,