//! Name resolution façade. use std::{fmt, mem}; use base_db::Crate; use hir_expand::{ MacroDefId, mod_path::{ModPath, PathKind}, name::Name, }; use intern::{Symbol, sym}; use itertools::Itertools as _; use rustc_hash::FxHashSet; use smallvec::{SmallVec, smallvec}; use span::SyntaxContext; use triomphe::Arc; use crate::{ AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ HygieneId, path::Path, scope::{ExprScopes, ScopeId}, }, hir::{ BindingId, ExprId, LabelId, generics::{GenericParams, TypeOrConstParamData}, }, item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope}, item_tree::ImportAlias, lang_item::LangItemTarget, nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, per_ns::PerNs, type_ref::LifetimeRef, visibility::{RawVisibility, Visibility}, }; #[derive(Debug, Clone)] pub struct Resolver<'db> { /// The stack of scopes, where the inner-most scope is the last item. /// /// When using, you generally want to process the scopes in reverse order, /// there's `scopes` *method* for that. scopes: Vec>, module_scope: ModuleItemMap<'db>, } #[derive(Clone)] struct ModuleItemMap<'db> { def_map: &'db DefMap, local_def_map: &'db LocalDefMap, module_id: LocalModuleId, } impl fmt::Debug for ModuleItemMap<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish() } } #[derive(Clone)] struct ExprScope { owner: DefWithBodyId, expr_scopes: Arc, scope_id: ScopeId, } impl fmt::Debug for ExprScope { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExprScope") .field("owner", &self.owner) .field("scope_id", &self.scope_id) .finish() } } #[derive(Debug, Clone)] enum Scope<'db> { /// All the items and imported names of a module BlockScope(ModuleItemMap<'db>), /// Brings the generic parameters of an item into scope as well as the `Self` type alias / /// generic for ADTs and impls. GenericParams { def: GenericDefId, params: Arc }, /// Local bindings ExprScope(ExprScope), /// Macro definition inside bodies that affects all paths after it in the same block. MacroDefScope(MacroDefId), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum TypeNs { SelfType(ImplId), GenericParam(TypeParamId), AdtId(AdtId), AdtSelfType(AdtId), // Yup, enum variants are added to the types ns, but any usage of variant as // type is an error. EnumVariantId(EnumVariantId), TypeAliasId(TypeAliasId), BuiltinType(BuiltinType), TraitId(TraitId), TraitAliasId(TraitAliasId), ModuleId(ModuleId), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ResolveValueResult { ValueNs(ValueNs, Option), Partial(TypeNs, usize, Option), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ValueNs { ImplSelf(ImplId), LocalBinding(BindingId), FunctionId(FunctionId), ConstId(ConstId), StaticId(StaticId), StructId(StructId), EnumVariantId(EnumVariantId), GenericParam(ConstParamId), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum LifetimeNs { Static, LifetimeParam(LifetimeParamId), } impl<'db> Resolver<'db> { /// Resolve known trait from std, like `std::futures::Future` pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; match res { ModuleDefId::TraitId(it) => Some(it), _ => None, } } /// Resolve known struct from std, like `std::boxed::Box` pub fn resolve_known_struct(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; match res { ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), _ => None, } } /// Resolve known enum from std, like `std::result::Result` pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; match res { ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), _ => None, } } pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs { self.resolve_module_path(db, path, BuiltinShadowMode::Module) } pub fn resolve_path_in_type_ns( &self, db: &dyn DefDatabase, path: &Path, ) -> Option<(TypeNs, Option, Option)> { self.resolve_path_in_type_ns_with_prefix_info(db, path).map( |(resolution, remaining_segments, import, _)| (resolution, remaining_segments, import), ) } pub fn resolve_path_in_type_ns_with_prefix_info( &self, db: &dyn DefDatabase, path: &Path, ) -> Option<(TypeNs, Option, Option, ResolvePathResultPrefixInfo)> { let path = match path { Path::BarePath(mod_path) => mod_path, Path::Normal(it) => &it.mod_path, Path::LangItem(l, seg) => { let type_ns = match *l { LangItemTarget::Union(it) => TypeNs::AdtId(it.into()), LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it), LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()), LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it), LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()), LangItemTarget::Trait(it) => TypeNs::TraitId(it), LangItemTarget::Function(_) | LangItemTarget::ImplDef(_) | LangItemTarget::Static(_) => return None, }; return Some(( type_ns, seg.as_ref().map(|_| 1), None, ResolvePathResultPrefixInfo::default(), )); } }; let first_name = path.segments().first()?; let skip_to_mod = path.kind != PathKind::Plain; if skip_to_mod { return self.module_scope.resolve_path_in_type_ns(db, path); } let remaining_idx = || { if path.segments().len() == 1 { None } else { Some(1) } }; for scope in self.scopes() { match scope { Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let &GenericDefId::ImplId(impl_) = def { if *first_name == sym::Self_ { return Some(( TypeNs::SelfType(impl_), remaining_idx(), None, ResolvePathResultPrefixInfo::default(), )); } } else if let &GenericDefId::AdtId(adt) = def { if *first_name == sym::Self_ { return Some(( TypeNs::AdtSelfType(adt), remaining_idx(), None, ResolvePathResultPrefixInfo::default(), )); } } if let Some(id) = params.find_type_by_name(first_name, *def) { return Some(( TypeNs::GenericParam(id), remaining_idx(), None, ResolvePathResultPrefixInfo::default(), )); } } Scope::BlockScope(m) => { if let Some(res) = m.resolve_path_in_type_ns(db, path) { let res = match res.0 { TypeNs::ModuleId(_) if res.1.is_none() => { if let Some(ModuleDefId::BuiltinType(builtin)) = BUILTIN_SCOPE .get(first_name) .and_then(|builtin| builtin.take_types()) { ( TypeNs::BuiltinType(builtin), remaining_idx(), None, ResolvePathResultPrefixInfo::default(), ) } else { res } } _ => res, }; return Some(res); } } } } self.module_scope.resolve_path_in_type_ns(db, path) } pub fn resolve_path_in_type_ns_fully( &self, db: &dyn DefDatabase, path: &Path, ) -> Option { let (res, unresolved, _) = self.resolve_path_in_type_ns(db, path)?; if unresolved.is_some() { return None; } Some(res) } pub fn resolve_visibility( &self, db: &dyn DefDatabase, visibility: &RawVisibility, ) -> Option { match visibility { RawVisibility::Module(_, _) => { let (item_map, item_local_map, module) = self.item_scope_(); item_map.resolve_visibility( item_local_map, db, module, visibility, self.scopes().any(|scope| { matches!(scope, Scope::GenericParams { def: GenericDefId::ImplId(_), .. }) }), ) } RawVisibility::Public => Some(Visibility::Public), } } pub fn resolve_path_in_value_ns( &self, db: &dyn DefDatabase, path: &Path, hygiene_id: HygieneId, ) -> Option { self.resolve_path_in_value_ns_with_prefix_info(db, path, hygiene_id).map(|(it, _)| it) } pub fn resolve_path_in_value_ns_with_prefix_info( &self, db: &dyn DefDatabase, path: &Path, mut hygiene_id: HygieneId, ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> { let path = match path { Path::BarePath(mod_path) => mod_path, Path::Normal(it) => &it.mod_path, Path::LangItem(l, None) => { return Some(( ResolveValueResult::ValueNs( match *l { LangItemTarget::Function(it) => ValueNs::FunctionId(it), LangItemTarget::Static(it) => ValueNs::StaticId(it), LangItemTarget::Struct(it) => ValueNs::StructId(it), LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it), LangItemTarget::Union(_) | LangItemTarget::ImplDef(_) | LangItemTarget::TypeAlias(_) | LangItemTarget::Trait(_) | LangItemTarget::EnumId(_) => return None, }, None, ), ResolvePathResultPrefixInfo::default(), )); } Path::LangItem(l, Some(_)) => { let type_ns = match *l { LangItemTarget::Union(it) => TypeNs::AdtId(it.into()), LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it), LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()), LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it), LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()), LangItemTarget::Trait(it) => TypeNs::TraitId(it), LangItemTarget::Function(_) | LangItemTarget::ImplDef(_) | LangItemTarget::Static(_) => return None, }; // Remaining segments start from 0 because lang paths have no segments other than the remaining. return Some(( ResolveValueResult::Partial(type_ns, 0, None), ResolvePathResultPrefixInfo::default(), )); } }; let n_segments = path.segments().len(); let tmp = Name::new_symbol_root(sym::self_); let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); if skip_to_mod { return self.module_scope.resolve_path_in_value_ns(db, path); } if n_segments <= 1 { let mut hygiene_info = hygiene_info(db, hygiene_id); for scope in self.scopes() { match scope { Scope::ExprScope(scope) => { let entry = scope.expr_scopes.entries(scope.scope_id).iter().find(|entry| { entry.name() == first_name && entry.hygiene() == hygiene_id }); if let Some(e) = entry { return Some(( ResolveValueResult::ValueNs( ValueNs::LocalBinding(e.binding()), None, ), ResolvePathResultPrefixInfo::default(), )); } } Scope::MacroDefScope(macro_id) => { handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id) } Scope::GenericParams { params, def } => { if let &GenericDefId::ImplId(impl_) = def { if *first_name == sym::Self_ { return Some(( ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None), ResolvePathResultPrefixInfo::default(), )); } } if let Some(id) = params.find_const_by_name(first_name, *def) { let val = ValueNs::GenericParam(id); return Some(( ResolveValueResult::ValueNs(val, None), ResolvePathResultPrefixInfo::default(), )); } } Scope::BlockScope(m) => { if let Some(def) = m.resolve_path_in_value_ns(db, path) { return Some(def); } } } } } else { for scope in self.scopes() { match scope { Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let &GenericDefId::ImplId(impl_) = def { if *first_name == sym::Self_ { return Some(( ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1, None), ResolvePathResultPrefixInfo::default(), )); } } else if let &GenericDefId::AdtId(adt) = def { if *first_name == sym::Self_ { let ty = TypeNs::AdtSelfType(adt); return Some(( ResolveValueResult::Partial(ty, 1, None), ResolvePathResultPrefixInfo::default(), )); } } if let Some(id) = params.find_type_by_name(first_name, *def) { let ty = TypeNs::GenericParam(id); return Some(( ResolveValueResult::Partial(ty, 1, None), ResolvePathResultPrefixInfo::default(), )); } } Scope::BlockScope(m) => { if let Some(def) = m.resolve_path_in_value_ns(db, path) { return Some(def); } } } } } if let Some(res) = self.module_scope.resolve_path_in_value_ns(db, path) { return Some(res); } // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back // to resolving to the primitive type, to allow this to still work in the presence of // `use core::u16;`. if path.kind == PathKind::Plain && n_segments > 1 { if let Some(builtin) = BuiltinType::by_name(first_name) { return Some(( ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None), ResolvePathResultPrefixInfo::default(), )); } } None } pub fn resolve_path_in_value_ns_fully( &self, db: &dyn DefDatabase, path: &Path, hygiene: HygieneId, ) -> Option { match self.resolve_path_in_value_ns(db, path, hygiene)? { ResolveValueResult::ValueNs(it, _) => Some(it), ResolveValueResult::Partial(..) => None, } } pub fn resolve_path_as_macro( &self, db: &dyn DefDatabase, path: &ModPath, expected_macro_kind: Option, ) -> Option<(MacroId, Option)> { let (item_map, item_local_map, module) = self.item_scope_(); item_map .resolve_path( item_local_map, db, module, path, BuiltinShadowMode::Other, expected_macro_kind, ) .0 .take_macros_import() } pub fn resolve_path_as_macro_def( &self, db: &dyn DefDatabase, path: &ModPath, expected_macro_kind: Option, ) -> Option { self.resolve_path_as_macro(db, path, expected_macro_kind).map(|(it, _)| db.macro_def(it)) } pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option { match lifetime { LifetimeRef::Static => Some(LifetimeNs::Static), LifetimeRef::Named(name) => self.scopes().find_map(|scope| match scope { Scope::GenericParams { def, params } => { params.find_lifetime_by_name(name, *def).map(LifetimeNs::LifetimeParam) } _ => None, }), LifetimeRef::Placeholder | LifetimeRef::Error => None, LifetimeRef::Param(lifetime_param_id) => { Some(LifetimeNs::LifetimeParam(*lifetime_param_id)) } } } /// Returns a set of names available in the current scope. /// /// Note that this is a somewhat fuzzy concept -- internally, the compiler /// doesn't necessary follow a strict scoping discipline. Rather, it just /// tells for each ident what it resolves to. /// /// A good example is something like `str::from_utf8`. From scopes point of /// view, this code is erroneous -- both `str` module and `str` type occupy /// the same type namespace. /// /// We don't try to model that super-correctly -- this functionality is /// primarily exposed for completions. /// /// Note that in Rust one name can be bound to several items: /// /// ``` /// # #![allow(non_camel_case_types)] /// macro_rules! t { () => (()) } /// type t = t!(); /// const t: t = t!(); /// ``` /// /// That's why we return a multimap. /// /// The shadowing is accounted for: in /// /// ```ignore /// let it = 92; /// { /// let it = 92; /// $0 /// } /// ``` /// /// there will be only one entry for `it` in the result. /// /// The result is ordered *roughly* from the innermost scope to the /// outermost: when the name is introduced in two namespaces in two scopes, /// we use the position of the first scope. pub fn names_in_scope( &self, db: &dyn DefDatabase, ) -> FxIndexMap> { let mut res = ScopeNames::default(); for scope in self.scopes() { scope.process_names(&mut res, db); } let ModuleItemMap { def_map, module_id, local_def_map } = self.module_scope; // FIXME: should we provide `self` here? // f( // Name::self_param(), // PerNs::types(Resolution::Def { // def: m.module.into(), // }), // ); def_map[module_id].scope.entries().for_each(|(name, def)| { res.add_per_ns(name, def); }); def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| { macs.iter().for_each(|&mac| { res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))); }) }); def_map.macro_use_prelude().iter().sorted_by_key(|&(k, _)| k.clone()).for_each( |(name, &(def, _extern_crate))| { res.add(name, ScopeDef::ModuleDef(def.into())); }, ); local_def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| { res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into()))); }); BUILTIN_SCOPE.iter().for_each(|(name, &def)| { res.add_per_ns(name, def); }); if let Some((prelude, _use)) = def_map.prelude() { let prelude_def_map = prelude.def_map(db); for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { res.add_per_ns(name, def) } } res.map } /// Note: Not to be used directly within hir-def/hir-ty pub fn extern_crate_decls_in_scope<'a>( &'a self, db: &'a dyn DefDatabase, ) -> impl Iterator + 'a { self.module_scope.def_map[self.module_scope.module_id] .scope .extern_crate_decls() .filter_map(|id| { let loc = id.lookup(db); let tree = loc.item_tree_id().item_tree(db); match &tree[loc.id.value].alias { Some(alias) => match alias { ImportAlias::Underscore => None, ImportAlias::Alias(name) => Some(name.clone()), }, None => Some(tree[loc.id.value].name.clone()), } }) } pub fn extern_crates_in_scope(&self) -> impl Iterator + '_ { self.module_scope .local_def_map .extern_prelude() .map(|(name, module_id)| (name.clone(), module_id.0.into())) } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { // FIXME(trait_alias): Trait alias brings aliased traits in scope! Note that supertraits of // aliased traits are NOT brought in scope (unless also aliased). let mut traits = FxHashSet::default(); for scope in self.scopes() { match scope { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::GenericParams { def: GenericDefId::ImplId(impl_), .. } => { let impl_data = db.impl_signature(impl_); if let Some(target_trait) = impl_data.target_trait { if let Some(TypeNs::TraitId(trait_)) = self .resolve_path_in_type_ns_fully(db, &impl_data.store[target_trait.path]) { traits.insert(trait_); } } } _ => (), } } // Fill in the prelude traits if let Some((prelude, _use)) = self.module_scope.def_map.prelude() { let prelude_def_map = prelude.def_map(db); traits.extend(prelude_def_map[prelude.local_id].scope.traits()); } // Fill in module visible traits traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits()); traits } pub fn traits_in_scope_from_block_scopes(&self) -> impl Iterator + '_ { self.scopes() .filter_map(|scope| match scope { Scope::BlockScope(m) => Some(m.def_map[m.module_id].scope.traits()), _ => None, }) .flatten() } pub fn module(&self) -> ModuleId { let (def_map, _, local_id) = self.item_scope_(); def_map.module_id(local_id) } pub fn item_scope(&self) -> &ItemScope { let (def_map, _, local_id) = self.item_scope_(); &def_map[local_id].scope } pub fn krate(&self) -> Crate { self.module_scope.def_map.krate() } pub fn def_map(&self) -> &DefMap { self.item_scope_().0 } pub fn generic_def(&self) -> Option { self.scopes().find_map(|scope| match scope { Scope::GenericParams { def, .. } => Some(*def), _ => None, }) } pub fn generic_params(&self) -> Option<&GenericParams> { self.scopes().find_map(|scope| match scope { Scope::GenericParams { params, .. } => Some(&**params), _ => None, }) } pub fn all_generic_params(&self) -> impl Iterator { self.scopes().filter_map(|scope| match scope { Scope::GenericParams { params, def } => Some((&**params, def)), _ => None, }) } pub fn body_owner(&self) -> Option { self.scopes().find_map(|scope| match scope { Scope::ExprScope(it) => Some(it.owner), _ => None, }) } pub fn impl_def(&self) -> Option { self.scopes().find_map(|scope| match scope { &Scope::GenericParams { def: GenericDefId::ImplId(def), .. } => Some(def), _ => None, }) } /// Checks if we rename `renamed` (currently named `current_name`) to `new_name`, will the meaning of this reference /// (that contains `current_name` path) change from `renamed` to some another variable (returned as `Some`). pub fn rename_will_conflict_with_another_variable( &self, db: &dyn DefDatabase, current_name: &Name, current_name_as_path: &ModPath, mut hygiene_id: HygieneId, new_name: &Symbol, to_be_renamed: BindingId, ) -> Option { let mut hygiene_info = hygiene_info(db, hygiene_id); let mut will_be_resolved_to = None; for scope in self.scopes() { match scope { Scope::ExprScope(scope) => { for entry in scope.expr_scopes.entries(scope.scope_id) { if entry.hygiene() == hygiene_id { if entry.binding() == to_be_renamed { // This currently resolves to our renamed variable, now `will_be_resolved_to` // contains `Some` if the meaning will change or `None` if not. return will_be_resolved_to; } else if entry.name().symbol() == new_name { will_be_resolved_to = Some(entry.binding()); } } } } Scope::MacroDefScope(macro_id) => { handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id) } Scope::GenericParams { params, def } => { if params.find_const_by_name(current_name, *def).is_some() { // It does not resolve to our renamed variable. return None; } } Scope::BlockScope(m) => { if m.resolve_path_in_value_ns(db, current_name_as_path).is_some() { // It does not resolve to our renamed variable. return None; } } } } // It does not resolve to our renamed variable. None } /// Checks if we rename `renamed` to `name`, will the meaning of this reference (that contains `name` path) change /// from some other variable (returned as `Some`) to `renamed`. pub fn rename_will_conflict_with_renamed( &self, db: &dyn DefDatabase, name: &Name, name_as_path: &ModPath, mut hygiene_id: HygieneId, to_be_renamed: BindingId, ) -> Option { let mut hygiene_info = hygiene_info(db, hygiene_id); let mut will_resolve_to_renamed = false; for scope in self.scopes() { match scope { Scope::ExprScope(scope) => { for entry in scope.expr_scopes.entries(scope.scope_id) { if entry.binding() == to_be_renamed { will_resolve_to_renamed = true; } else if entry.hygiene() == hygiene_id && entry.name() == name { if will_resolve_to_renamed { // This will resolve to the renamed variable before it resolves to the original variable. return Some(entry.binding()); } else { // This will resolve to the original variable. return None; } } } } Scope::MacroDefScope(macro_id) => { handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id) } Scope::GenericParams { params, def } => { if params.find_const_by_name(name, *def).is_some() { // Here and below, it might actually resolve to our renamed variable - in which case it'll // hide the generic parameter or some other thing (not a variable). We don't check for that // because due to naming conventions, it is rare that variable will shadow a non-variable. return None; } } Scope::BlockScope(m) => { if m.resolve_path_in_value_ns(db, name_as_path).is_some() { return None; } } } } None } /// `expr_id` is required to be an expression id that comes after the top level expression scope in the given resolver #[must_use] pub fn update_to_inner_scope( &mut self, db: &'db dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId, ) -> UpdateGuard { #[inline(always)] fn append_expr_scope<'db>( db: &'db dyn DefDatabase, resolver: &mut Resolver<'db>, owner: DefWithBodyId, expr_scopes: &Arc, scope_id: ScopeId, ) { if let Some(macro_id) = expr_scopes.macro_def(scope_id) { resolver.scopes.push(Scope::MacroDefScope(**macro_id)); } resolver.scopes.push(Scope::ExprScope(ExprScope { owner, expr_scopes: expr_scopes.clone(), scope_id, })); if let Some(block) = expr_scopes.block(scope_id) { let def_map = block_def_map(db, block); let local_def_map = block.lookup(db).module.only_local_def_map(db); resolver.scopes.push(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, module_id: DefMap::ROOT, })); // FIXME: This adds as many module scopes as there are blocks, but resolving in each // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? } } let start = self.scopes.len(); let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_))); match innermost_scope { Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => { let expr_scopes = expr_scopes.clone(); let scope_chain = expr_scopes .scope_chain(expr_scopes.scope_for(expr_id)) .take_while(|&it| it != scope_id); for scope_id in scope_chain { append_expr_scope(db, self, owner, &expr_scopes, scope_id); } } _ => { let expr_scopes = db.expr_scopes(owner); let scope_chain = expr_scopes.scope_chain(expr_scopes.scope_for(expr_id)); for scope_id in scope_chain { append_expr_scope(db, self, owner, &expr_scopes, scope_id); } } } self.scopes[start..].reverse(); UpdateGuard(start) } pub fn reset_to_guard(&mut self, UpdateGuard(start): UpdateGuard) { self.scopes.truncate(start); } } #[inline] fn handle_macro_def_scope( db: &dyn DefDatabase, hygiene_id: &mut HygieneId, hygiene_info: &mut Option<(SyntaxContext, MacroDefId)>, macro_id: &MacroDefId, ) { if let Some((parent_ctx, label_macro_id)) = hygiene_info { if label_macro_id == macro_id { // A macro is allowed to refer to variables from before its declaration. // Therefore, if we got to the rib of its declaration, give up its hygiene // and use its parent expansion. *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db)); *hygiene_info = parent_ctx.outer_expn(db).map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion.into()); (parent_ctx.parent(db), expansion.def) }); } } } #[inline] fn hygiene_info( db: &dyn DefDatabase, hygiene_id: HygieneId, ) -> Option<(SyntaxContext, MacroDefId)> { if !hygiene_id.is_root() { let ctx = hygiene_id.lookup(); ctx.outer_expn(db).map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion.into()); (ctx.parent(db), expansion.def) }) } else { None } } pub struct UpdateGuard(usize); impl<'db> Resolver<'db> { fn scopes(&self) -> impl Iterator> { self.scopes.iter().rev() } fn resolve_module_path( &self, db: &dyn DefDatabase, path: &ModPath, shadow: BuiltinShadowMode, ) -> PerNs { let (item_map, item_local_map, module) = self.item_scope_(); // This method resolves `path` just like import paths, so no expected macro subns is given. let (module_res, segment_index) = item_map.resolve_path(item_local_map, db, module, path, shadow, None); if segment_index.is_some() { return PerNs::none(); } module_res } /// The innermost block scope that contains items or the module scope that contains this resolver. fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) { self.scopes() .find_map(|scope| match scope { Scope::BlockScope(m) => Some((m.def_map, m.local_def_map, m.module_id)), _ => None, }) .unwrap_or(( self.module_scope.def_map, self.module_scope.local_def_map, self.module_scope.module_id, )) } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ScopeDef { ModuleDef(ModuleDefId), Unknown, ImplSelfType(ImplId), AdtSelfType(AdtId), GenericParam(GenericParamId), Local(BindingId), Label(LabelId), } impl<'db> Scope<'db> { fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { match self { Scope::BlockScope(m) => { m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { acc.add_per_ns(name, def); }); m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| { macs.iter().for_each(|&mac| { acc.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))); }) }); } &Scope::GenericParams { ref params, def: parent } => { if let GenericDefId::ImplId(impl_) = parent { acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::ImplSelfType(impl_)); } else if let GenericDefId::AdtId(adt) = parent { acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::AdtSelfType(adt)); } for (local_id, param) in params.iter_type_or_consts() { if let Some(name) = ¶m.name() { let id = TypeOrConstParamId { parent, local_id }; let data = &db.generic_params(parent)[local_id]; acc.add( name, ScopeDef::GenericParam(match data { TypeOrConstParamData::TypeParamData(_) => { GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)) } TypeOrConstParamData::ConstParamData(_) => { GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)) } }), ); } } for (local_id, param) in params.iter_lt() { let id = LifetimeParamId { parent, local_id }; acc.add(¶m.name, ScopeDef::GenericParam(id.into())) } } Scope::ExprScope(scope) => { if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { acc.add(&name, ScopeDef::Label(label)) } scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { acc.add_local(e.name(), e.binding()); }); } Scope::MacroDefScope(_) => {} } } } pub fn resolver_for_expr( db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId, ) -> Resolver<'_> { let r = owner.resolver(db); let scopes = db.expr_scopes(owner); let scope_id = scopes.scope_for(expr_id); resolver_for_scope_(db, scopes, scope_id, r, owner) } pub fn resolver_for_scope( db: &dyn DefDatabase, owner: DefWithBodyId, scope_id: Option, ) -> Resolver<'_> { let r = owner.resolver(db); let scopes = db.expr_scopes(owner); resolver_for_scope_(db, scopes, scope_id, r, owner) } fn resolver_for_scope_<'db>( db: &'db dyn DefDatabase, scopes: Arc, scope_id: Option, mut r: Resolver<'db>, owner: DefWithBodyId, ) -> Resolver<'db> { let scope_chain = scopes.scope_chain(scope_id).collect::>(); r.scopes.reserve(scope_chain.len()); for scope in scope_chain.into_iter().rev() { if let Some(block) = scopes.block(scope) { let def_map = block_def_map(db, block); let local_def_map = block.lookup(db).module.only_local_def_map(db); r = r.push_block_scope(def_map, local_def_map); // FIXME: This adds as many module scopes as there are blocks, but resolving in each // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? } if let Some(macro_id) = scopes.macro_def(scope) { r = r.push_scope(Scope::MacroDefScope(**macro_id)); } r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); } r } impl<'db> Resolver<'db> { fn push_scope(mut self, scope: Scope<'db>) -> Resolver<'db> { self.scopes.push(scope); self } fn push_generic_params_scope( self, db: &'db dyn DefDatabase, def: GenericDefId, ) -> Resolver<'db> { let params = db.generic_params(def); self.push_scope(Scope::GenericParams { def, params }) } fn push_block_scope( self, def_map: &'db DefMap, local_def_map: &'db LocalDefMap, ) -> Resolver<'db> { self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, module_id: DefMap::ROOT, })) } fn push_expr_scope( self, owner: DefWithBodyId, expr_scopes: Arc, scope_id: ScopeId, ) -> Resolver<'db> { self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) } } impl<'db> ModuleItemMap<'db> { fn resolve_path_in_value_ns( &self, db: &'db dyn DefDatabase, path: &ModPath, ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> { let (module_def, unresolved_idx, prefix_info) = self.def_map.resolve_path_locally( self.local_def_map, db, self.module_id, path, BuiltinShadowMode::Other, ); match unresolved_idx { None => { let (value, import) = to_value_ns(module_def)?; Some((ResolveValueResult::ValueNs(value, import), prefix_info)) } Some(unresolved_idx) => { let def = module_def.take_types_full()?; let ty = match def.def { ModuleDefId::AdtId(it) => TypeNs::AdtId(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), ModuleDefId::ModuleId(_) | ModuleDefId::FunctionId(_) | ModuleDefId::EnumVariantId(_) | ModuleDefId::ConstId(_) | ModuleDefId::MacroId(_) | ModuleDefId::StaticId(_) => return None, }; Some((ResolveValueResult::Partial(ty, unresolved_idx, def.import), prefix_info)) } } } fn resolve_path_in_type_ns( &self, db: &dyn DefDatabase, path: &ModPath, ) -> Option<(TypeNs, Option, Option, ResolvePathResultPrefixInfo)> { let (module_def, idx, prefix_info) = self.def_map.resolve_path_locally( self.local_def_map, db, self.module_id, path, BuiltinShadowMode::Other, ); let (res, import) = to_type_ns(module_def)?; Some((res, idx, import, prefix_info)) } } fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option)> { let (def, import) = per_ns.take_values_import()?; let res = match def { ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), ModuleDefId::ConstId(it) => ValueNs::ConstId(it), ModuleDefId::StaticId(it) => ValueNs::StaticId(it), ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_)) | ModuleDefId::TraitId(_) | ModuleDefId::TraitAliasId(_) | ModuleDefId::TypeAliasId(_) | ModuleDefId::BuiltinType(_) | ModuleDefId::MacroId(_) | ModuleDefId::ModuleId(_) => return None, }; Some((res, import)) } fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option)> { let def = per_ns.take_types_full()?; let res = match def.def { ModuleDefId::AdtId(it) => TypeNs::AdtId(it), ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::ModuleId(it) => TypeNs::ModuleId(it), ModuleDefId::FunctionId(_) | ModuleDefId::ConstId(_) | ModuleDefId::MacroId(_) | ModuleDefId::StaticId(_) => return None, }; Some((res, def.import)) } #[derive(Default)] struct ScopeNames { map: FxIndexMap>, } impl ScopeNames { fn add(&mut self, name: &Name, def: ScopeDef) { let set = self.map.entry(name.clone()).or_default(); if !set.contains(&def) { set.push(def) } } fn add_per_ns(&mut self, name: &Name, def: PerNs) { if let Some(ty) = &def.types { self.add(name, ScopeDef::ModuleDef(ty.def)) } if let Some(def) = &def.values { self.add(name, ScopeDef::ModuleDef(def.def)) } if let Some(mac) = &def.macros { self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac.def))) } if def.is_none() { self.add(name, ScopeDef::Unknown) } } fn add_local(&mut self, name: &Name, binding: BindingId) { let set = self.map.entry(name.clone()).or_default(); // XXX: hack, account for local (and only local) shadowing. // // This should be somewhat more principled and take namespaces into // accounts, but, alas, scoping rules are a hoax. `str` type and `str` // module can be both available in the same scope. if set.iter().any(|it| matches!(it, &ScopeDef::Local(_))) { cov_mark::hit!(shadowing_shows_single_completion); return; } set.push(ScopeDef::Local(binding)) } } pub trait HasResolver: Copy { /// Builds a resolver for type references inside this def. fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_>; } impl HasResolver for ModuleId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { let (mut def_map, local_def_map) = self.local_def_map(db); let mut module_id = self.local_id; if !self.is_block_module() { return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, local_def_map, module_id }, }; } let mut modules: SmallVec<[_; 1]> = smallvec![]; while let Some(parent) = def_map.parent() { let block_def_map = mem::replace(&mut def_map, parent.def_map(db)); modules.push(block_def_map); if !parent.is_block_module() { module_id = parent.local_id; break; } } let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()), module_scope: ModuleItemMap { def_map, local_def_map, module_id }, }; for def_map in modules.into_iter().rev() { resolver = resolver.push_block_scope(def_map, local_def_map); } resolver } } impl HasResolver for CrateRootModuleId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { let (def_map, local_def_map) = self.local_def_map(db); Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, local_def_map, module_id: DefMap::ROOT }, } } } impl HasResolver for TraitId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for TraitAliasId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl + Copy> HasResolver for T { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { let def = self.into(); def.module(db).resolver(db).push_generic_params_scope(db, def.into()) } } impl HasResolver for FunctionId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for ConstId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for StaticId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for TypeAliasId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for ImplId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) } } impl HasResolver for ExternBlockId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { // Same as parent's lookup_resolver(db, self) } } impl HasResolver for ExternCrateId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for UseId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for DefWithBodyId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { DefWithBodyId::ConstId(c) => c.resolver(db), DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), DefWithBodyId::VariantId(v) => v.resolver(db), } } } impl HasResolver for ItemContainerId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { ItemContainerId::ModuleId(it) => it.resolver(db), ItemContainerId::TraitId(it) => it.resolver(db), ItemContainerId::ImplId(it) => it.resolver(db), ItemContainerId::ExternBlockId(it) => it.resolver(db), } } } impl HasResolver for GenericDefId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { GenericDefId::FunctionId(inner) => inner.resolver(db), GenericDefId::AdtId(adt) => adt.resolver(db), GenericDefId::TraitId(inner) => inner.resolver(db), GenericDefId::TraitAliasId(inner) => inner.resolver(db), GenericDefId::TypeAliasId(inner) => inner.resolver(db), GenericDefId::ImplId(inner) => inner.resolver(db), GenericDefId::ConstId(inner) => inner.resolver(db), GenericDefId::StaticId(inner) => inner.resolver(db), } } } impl HasResolver for EnumVariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { self.lookup(db).parent.resolver(db) } } impl HasResolver for VariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { VariantId::EnumVariantId(it) => it.resolver(db), VariantId::StructId(it) => it.resolver(db), VariantId::UnionId(it) => it.resolver(db), } } } impl HasResolver for MacroId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { MacroId::Macro2Id(it) => it.resolver(db), MacroId::MacroRulesId(it) => it.resolver(db), MacroId::ProcMacroId(it) => it.resolver(db), } } } impl HasResolver for Macro2Id { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for ProcMacroId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } impl HasResolver for MacroRulesId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { lookup_resolver(db, self) } } fn lookup_resolver( db: &dyn DefDatabase, lookup: impl Lookup< Database = dyn DefDatabase, Data = impl ItemTreeLoc, >, ) -> Resolver<'_> { lookup.lookup(db).container().resolver(db) }