Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/resolver.rs')
| -rw-r--r-- | crates/hir-def/src/resolver.rs | 258 |
1 files changed, 196 insertions, 62 deletions
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 86958e3dae..61e64fc103 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -1,5 +1,5 @@ //! Name resolution façade. -use std::{hash::BuildHasherDefault, sync::Arc}; +use std::{fmt, hash::BuildHasherDefault, sync::Arc}; use base_db::CrateId; use hir_expand::name::{name, Name}; @@ -12,7 +12,7 @@ use crate::{ body::scope::{ExprScopes, ScopeId}, builtin_type::BuiltinType, db::DefDatabase, - expr::{ExprId, LabelId, PatId}, + expr::{BindingId, ExprId, LabelId}, generics::{GenericParams, TypeOrConstParamData}, item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, nameres::DefMap, @@ -22,7 +22,8 @@ use crate::{ AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + VariantId, }; #[derive(Debug, Clone)] @@ -35,19 +36,34 @@ pub struct Resolver { module_scope: ModuleItemMap, } -#[derive(Debug, Clone)] +#[derive(Clone)] struct ModuleItemMap { def_map: Arc<DefMap>, module_id: LocalModuleId, } -#[derive(Debug, Clone)] +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<ExprScopes>, 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 { /// All the items and imported names of a module @@ -74,6 +90,7 @@ pub enum TypeNs { TypeAliasId(TypeAliasId), BuiltinType(BuiltinType), TraitId(TraitId), + TraitAliasId(TraitAliasId), // Module belong to type ns, but the resolver is used when all module paths // are fully resolved. // ModuleId(ModuleId) @@ -85,10 +102,10 @@ pub enum ResolveValueResult { Partial(TypeNs, usize), } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ValueNs { ImplSelf(ImplId), - LocalBinding(PatId), + LocalBinding(BindingId), FunctionId(FunctionId), ConstId(ConstId), StaticId(StaticId), @@ -214,10 +231,12 @@ impl Resolver { db: &dyn DefDatabase, visibility: &RawVisibility, ) -> Option<Visibility> { + let within_impl = + self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some(); match visibility { RawVisibility::Module(_) => { let (item_map, module) = self.item_scope(); - item_map.resolve_visibility(db, module, visibility) + item_map.resolve_visibility(db, module, visibility, within_impl) } RawVisibility::Public => Some(Visibility::Public), } @@ -236,69 +255,81 @@ impl Resolver { return self.module_scope.resolve_path_in_value_ns(db, path); } - for scope in self.scopes() { - match scope { - Scope::ExprScope(_) if n_segments > 1 => continue, - Scope::ExprScope(scope) => { - let entry = scope - .expr_scopes - .entries(scope.scope_id) - .iter() - .find(|entry| entry.name() == first_name); - - if let Some(e) = entry { - return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); + if n_segments <= 1 { + 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); + + if let Some(e) = entry { + return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding( + e.binding(), + ))); + } } - } - Scope::GenericParams { params, def } if n_segments > 1 => { - if let Some(id) = params.find_type_by_name(first_name, *def) { - let ty = TypeNs::GenericParam(id); - return Some(ResolveValueResult::Partial(ty, 1)); + Scope::GenericParams { params, def } => { + if let Some(id) = params.find_const_by_name(first_name, *def) { + let val = ValueNs::GenericParam(id); + return Some(ResolveValueResult::ValueNs(val)); + } } - } - Scope::GenericParams { .. } if n_segments != 1 => continue, - Scope::GenericParams { params, def } => { - if let Some(id) = params.find_const_by_name(first_name, *def) { - let val = ValueNs::GenericParam(id); - return Some(ResolveValueResult::ValueNs(val)); + &Scope::ImplDefScope(impl_) => { + if first_name == &name![Self] { + return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))); + } } - } - - &Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { - return Some(if n_segments > 1 { - ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1) - } else { - ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)) - }); + // bare `Self` doesn't work in the value namespace in a struct/enum definition + Scope::AdtScope(_) => continue, + Scope::BlockScope(m) => { + if let Some(def) = m.resolve_path_in_value_ns(db, path) { + return Some(def); + } } } - // bare `Self` doesn't work in the value namespace in a struct/enum definition - Scope::AdtScope(_) if n_segments == 1 => continue, - Scope::AdtScope(adt) => { - if first_name == &name![Self] { - let ty = TypeNs::AdtSelfType(*adt); - return Some(ResolveValueResult::Partial(ty, 1)); + } + } else { + for scope in self.scopes() { + match scope { + Scope::ExprScope(_) => continue, + Scope::GenericParams { params, def } => { + if let Some(id) = params.find_type_by_name(first_name, *def) { + let ty = TypeNs::GenericParam(id); + return Some(ResolveValueResult::Partial(ty, 1)); + } } - } - - Scope::BlockScope(m) => { - if let Some(def) = m.resolve_path_in_value_ns(db, path) { - return Some(def); + &Scope::ImplDefScope(impl_) => { + if first_name == &name![Self] { + return Some(ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)); + } + } + Scope::AdtScope(adt) => { + if first_name == &name![Self] { + let ty = TypeNs::AdtSelfType(*adt); + return Some(ResolveValueResult::Partial(ty, 1)); + } + } + Scope::BlockScope(m) => { + if let Some(def) = m.resolve_path_in_value_ns(db, path) { + return Some(def); + } } } } } - if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) { - return res; + 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 && path.segments().len() > 1 { - if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) { + 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)); } } @@ -400,6 +431,8 @@ impl Resolver { } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> { + // 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() { @@ -428,6 +461,15 @@ impl Resolver { traits } + pub fn traits_in_scope_from_block_scopes(&self) -> impl Iterator<Item = TraitId> + '_ { + 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) @@ -459,14 +501,85 @@ impl Resolver { }) } + pub fn generic_params(&self) -> Option<&Interned<GenericParams>> { + self.scopes().find_map(|scope| match scope { + Scope::GenericParams { params, .. } => Some(params), + _ => None, + }) + } + pub fn body_owner(&self) -> Option<DefWithBodyId> { self.scopes().find_map(|scope| match scope { Scope::ExprScope(it) => Some(it.owner), _ => 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: &dyn DefDatabase, + owner: DefWithBodyId, + expr_id: ExprId, + ) -> UpdateGuard { + #[inline(always)] + fn append_expr_scope( + db: &dyn DefDatabase, + resolver: &mut Resolver, + owner: DefWithBodyId, + expr_scopes: &Arc<ExprScopes>, + scope_id: ScopeId, + ) { + resolver.scopes.push(Scope::ExprScope(ExprScope { + owner, + expr_scopes: expr_scopes.clone(), + scope_id, + })); + if let Some(block) = expr_scopes.block(scope_id) { + if let Some(def_map) = db.block_def_map(block) { + let root = def_map.root(); + resolver + .scopes + .push(Scope::BlockScope(ModuleItemMap { def_map, module_id: 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().next(); + 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); + } } +pub struct UpdateGuard(usize); + impl Resolver { fn scopes(&self) -> impl Iterator<Item = &Scope> { self.scopes.iter().rev() @@ -504,7 +617,7 @@ pub enum ScopeDef { ImplSelfType(ImplId), AdtSelfType(AdtId), GenericParam(GenericParamId), - Local(PatId), + Local(BindingId), Label(LabelId), } @@ -556,17 +669,18 @@ impl Scope { acc.add(&name, ScopeDef::Label(label)) } scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { - acc.add_local(e.name(), e.pat()); + acc.add_local(e.name(), e.binding()); }); } } } } -// needs arbitrary_self_types to be a method... or maybe move to the def? 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); - resolver_for_scope(db, owner, scopes.scope_for(expr_id)) + let scope_id = scopes.scope_for(expr_id); + resolver_for_scope_(db, scopes, scope_id, r, owner) } pub fn resolver_for_scope( @@ -574,8 +688,18 @@ pub fn resolver_for_scope( owner: DefWithBodyId, scope_id: Option<ScopeId>, ) -> Resolver { - let mut r = owner.resolver(db); + 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: &dyn DefDatabase, + scopes: Arc<ExprScopes>, + scope_id: Option<ScopeId>, + mut r: Resolver, + owner: DefWithBodyId, +) -> Resolver { let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); r.scopes.reserve(scope_chain.len()); @@ -641,6 +765,7 @@ impl ModuleItemMap { let ty = match module_def.take_types()? { 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), @@ -678,6 +803,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> { ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_)) | ModuleDefId::TraitId(_) + | ModuleDefId::TraitAliasId(_) | ModuleDefId::TypeAliasId(_) | ModuleDefId::BuiltinType(_) | ModuleDefId::MacroId(_) @@ -695,6 +821,7 @@ fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> { ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), + ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::FunctionId(_) | ModuleDefId::ConstId(_) @@ -732,7 +859,7 @@ impl ScopeNames { self.add(name, ScopeDef::Unknown) } } - fn add_local(&mut self, name: &Name, pat: PatId) { + 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. // @@ -743,7 +870,7 @@ impl ScopeNames { cov_mark::hit!(shadowing_shows_single_completion); return; } - set.push(ScopeDef::Local(pat)) + set.push(ScopeDef::Local(binding)) } } @@ -779,6 +906,12 @@ impl HasResolver for TraitId { } } +impl HasResolver for TraitAliasId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + } +} + impl<T: Into<AdtId> + Copy> HasResolver for T { fn resolver(self, db: &dyn DefDatabase) -> Resolver { let def = self.into(); @@ -858,6 +991,7 @@ impl HasResolver for GenericDefId { 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::EnumVariantId(inner) => inner.parent.resolver(db), |