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.rs114
1 files changed, 83 insertions, 31 deletions
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 61e64fc103..06f5b2526a 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::{fmt, hash::BuildHasherDefault, sync::Arc};
+use std::{fmt, hash::BuildHasherDefault};
use base_db::CrateId;
use hir_expand::name::{name, Name};
@@ -7,16 +7,18 @@ use indexmap::IndexMap;
use intern::Interned;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
+use triomphe::Arc;
use crate::{
body::scope::{ExprScopes, ScopeId},
builtin_type::BuiltinType,
db::DefDatabase,
- expr::{BindingId, ExprId, LabelId},
generics::{GenericParams, TypeOrConstParamData},
+ hir::{BindingId, ExprId, LabelId},
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
- nameres::DefMap,
- path::{ModPath, PathKind},
+ lang_item::LangItemTarget,
+ nameres::{DefMap, MacroSubNs},
+ path::{ModPath, Path, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
@@ -78,7 +80,7 @@ enum Scope {
ExprScope(ExprScope),
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TypeNs {
SelfType(ImplId),
GenericParam(TypeParamId),
@@ -153,7 +155,8 @@ impl Resolver {
path: &ModPath,
) -> Option<PerNs> {
let (item_map, module) = self.item_scope();
- let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
+ let (module_res, idx) =
+ item_map.resolve_path(db, module, path, BuiltinShadowMode::Module, None);
match module_res.take_types()? {
ModuleDefId::TraitId(it) => {
let idx = idx?;
@@ -176,8 +179,27 @@ impl Resolver {
pub fn resolve_path_in_type_ns(
&self,
db: &dyn DefDatabase,
- path: &ModPath,
+ path: &Path,
) -> Option<(TypeNs, Option<usize>)> {
+ let path = match path {
+ Path::Normal { mod_path, .. } => mod_path,
+ Path::LangItem(l) => {
+ return Some((
+ match *l {
+ LangItemTarget::Union(x) => TypeNs::AdtId(x.into()),
+ LangItemTarget::TypeAlias(x) => TypeNs::TypeAliasId(x),
+ LangItemTarget::Struct(x) => TypeNs::AdtId(x.into()),
+ LangItemTarget::EnumVariant(x) => TypeNs::EnumVariantId(x),
+ LangItemTarget::EnumId(x) => TypeNs::AdtId(x.into()),
+ LangItemTarget::Trait(x) => TypeNs::TraitId(x),
+ LangItemTarget::Function(_)
+ | LangItemTarget::ImplDef(_)
+ | LangItemTarget::Static(_) => return None,
+ },
+ None,
+ ))
+ }
+ };
let first_name = path.segments().first()?;
let skip_to_mod = path.kind != PathKind::Plain;
if skip_to_mod {
@@ -217,7 +239,7 @@ impl Resolver {
pub fn resolve_path_in_type_ns_fully(
&self,
db: &dyn DefDatabase,
- path: &ModPath,
+ path: &Path,
) -> Option<TypeNs> {
let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
if unresolved.is_some() {
@@ -245,8 +267,24 @@ impl Resolver {
pub fn resolve_path_in_value_ns(
&self,
db: &dyn DefDatabase,
- path: &ModPath,
+ path: &Path,
) -> Option<ResolveValueResult> {
+ let path = match path {
+ Path::Normal { mod_path, .. } => mod_path,
+ Path::LangItem(l) => {
+ return Some(ResolveValueResult::ValueNs(match *l {
+ LangItemTarget::Function(x) => ValueNs::FunctionId(x),
+ LangItemTarget::Static(x) => ValueNs::StaticId(x),
+ LangItemTarget::Struct(x) => ValueNs::StructId(x),
+ LangItemTarget::EnumVariant(x) => ValueNs::EnumVariantId(x),
+ LangItemTarget::Union(_)
+ | LangItemTarget::ImplDef(_)
+ | LangItemTarget::TypeAlias(_)
+ | LangItemTarget::Trait(_)
+ | LangItemTarget::EnumId(_) => return None,
+ }))
+ }
+ };
let n_segments = path.segments().len();
let tmp = name![self];
let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
@@ -340,7 +378,7 @@ impl Resolver {
pub fn resolve_path_in_value_ns_fully(
&self,
db: &dyn DefDatabase,
- path: &ModPath,
+ path: &Path,
) -> Option<ValueNs> {
match self.resolve_path_in_value_ns(db, path)? {
ResolveValueResult::ValueNs(it) => Some(it),
@@ -348,9 +386,17 @@ impl Resolver {
}
}
- pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
+ pub fn resolve_path_as_macro(
+ &self,
+ db: &dyn DefDatabase,
+ path: &ModPath,
+ expected_macro_kind: Option<MacroSubNs>,
+ ) -> Option<MacroId> {
let (item_map, module) = self.item_scope();
- item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
+ item_map
+ .resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
+ .0
+ .take_macros()
}
/// Returns a set of names available in the current scope.
@@ -415,7 +461,10 @@ impl Resolver {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
})
});
- def_map.extern_prelude().for_each(|(name, &def)| {
+ def_map.macro_use_prelude().for_each(|(name, def)| {
+ res.add(name, ScopeDef::ModuleDef(def.into()));
+ });
+ def_map.extern_prelude().for_each(|(name, def)| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
});
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
@@ -441,7 +490,7 @@ impl Resolver {
&Scope::ImplDefScope(impl_) => {
if let Some(target_trait) = &db.impl_data(impl_).target_trait {
if let Some(TypeNs::TraitId(trait_)) =
- self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path())
+ self.resolve_path_in_type_ns_fully(db, &target_trait.path)
{
traits.insert(trait_);
}
@@ -536,15 +585,13 @@ impl Resolver {
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 def_map = db.block_def_map(block);
+ resolver
+ .scopes
+ .push(Scope::BlockScope(ModuleItemMap { 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?
}
}
@@ -592,7 +639,8 @@ impl Resolver {
shadow: BuiltinShadowMode,
) -> PerNs {
let (item_map, module) = self.item_scope();
- let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
+ // This method resolves `path` just like import paths, so no expected macro subns is given.
+ let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None);
if segment_index.is_some() {
return PerNs::none();
}
@@ -705,13 +753,11 @@ fn resolver_for_scope_(
for scope in scope_chain.into_iter().rev() {
if let Some(block) = scopes.block(scope) {
- if let Some(def_map) = db.block_def_map(block) {
- let root = def_map.root();
- r = r.push_block_scope(def_map, 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 def_map = db.block_def_map(block);
+ r = r.push_block_scope(def_map, 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?
}
r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
@@ -1000,6 +1046,12 @@ impl HasResolver for GenericDefId {
}
}
+impl HasResolver for EnumVariantId {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ self.parent.resolver(db)
+ }
+}
+
impl HasResolver for VariantId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
match self {