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;
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
/// 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,
}
}
(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)) =
{
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() {
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.
})
}
- /// 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,