Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/nameres/path_resolution.rs')
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs141
1 files changed, 97 insertions, 44 deletions
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 25478481dd..5f6163175a 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -16,11 +16,11 @@ use hir_expand::name::Name;
use crate::{
db::DefDatabase,
item_scope::BUILTIN_SCOPE,
- nameres::{BuiltinShadowMode, DefMap},
+ nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs},
path::{ModPath, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
- AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
+ AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -58,18 +58,22 @@ impl ResolvePathResult {
}
}
-impl DefMap {
- pub(super) fn resolve_name_in_extern_prelude(
- &self,
+impl PerNs {
+ pub(super) fn filter_macro(
+ mut self,
db: &dyn DefDatabase,
- name: &Name,
- ) -> Option<ModuleId> {
- match self.block {
- Some(_) => self.crate_root(db).def_map(db).extern_prelude.get(name).copied(),
- None => self.extern_prelude.get(name).copied(),
- }
+ expected: Option<MacroSubNs>,
+ ) -> Self {
+ self.macros = self.macros.filter(|&(id, _)| {
+ let this = MacroSubNs::from_id(db, id);
+ sub_namespace_match(Some(this), expected)
+ });
+
+ self
}
+}
+impl DefMap {
pub(crate) fn resolve_visibility(
&self,
db: &dyn DefDatabase,
@@ -83,7 +87,7 @@ impl DefMap {
let mut vis = match visibility {
RawVisibility::Module(path) => {
let (result, remaining) =
- self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
+ self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
if remaining.is_some() {
return None;
}
@@ -106,7 +110,7 @@ impl DefMap {
// ...unless we're resolving visibility for an associated item in an impl.
if self.block_id() != m.block && !within_impl {
cov_mark::hit!(adjust_vis_in_block_def_map);
- vis = Visibility::Module(self.module_id(self.root()));
+ vis = Visibility::Module(self.module_id(Self::ROOT));
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
}
}
@@ -124,6 +128,9 @@ impl DefMap {
mut original_module: LocalModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
+ // Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're
+ // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths.
+ expected_macro_subns: Option<MacroSubNs>,
) -> ResolvePathResult {
let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
@@ -136,6 +143,7 @@ impl DefMap {
original_module,
path,
shadow,
+ expected_macro_subns,
);
// Merge `new` into `result`.
@@ -154,7 +162,7 @@ impl DefMap {
match &current_map.block {
Some(block) => {
original_module = block.parent.local_id;
- arc = block.parent.def_map(db);
+ arc = block.parent.def_map(db, current_map.krate);
current_map = &*arc;
}
None => return result,
@@ -169,11 +177,15 @@ impl DefMap {
original_module: LocalModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
+ expected_macro_subns: Option<MacroSubNs>,
) -> ResolvePathResult {
let graph = db.crate_graph();
let _cx = stdx::panic_context::enter(format!(
- "DefMap {:?} crate_name={:?} block={:?} path={path}",
- self.krate, graph[self.krate].display_name, self.block
+ "DefMap {:?} crate_name={:?} block={:?} path={}",
+ self.krate,
+ graph[self.krate].display_name,
+ self.block,
+ path.display(db.upcast())
));
let mut segments = path.segments().iter().enumerate();
@@ -181,21 +193,21 @@ impl DefMap {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
cov_mark::hit!(macro_dollar_crate_self);
- PerNs::types(self.crate_root(db).into(), Visibility::Public)
+ PerNs::types(self.crate_root().into(), Visibility::Public)
} else {
let def_map = db.crate_def_map(krate);
- let module = def_map.module_id(def_map.root);
+ let module = def_map.module_id(Self::ROOT);
cov_mark::hit!(macro_dollar_crate_other);
PerNs::types(module.into(), Visibility::Public)
}
}
- PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public),
+ PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public),
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
// FIXME there must be a nicer way to write this condition
PathKind::Plain | PathKind::Abs
- if self.edition == Edition::Edition2015
+ if self.data.edition == Edition::Edition2015
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
{
let (_, segment) = match segments.next() {
@@ -220,7 +232,13 @@ impl DefMap {
if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
tracing::debug!("resolving {:?} in module", segment);
- self.resolve_name_in_module(db, original_module, segment, prefer_module)
+ self.resolve_name_in_module(
+ db,
+ original_module,
+ segment,
+ prefer_module,
+ expected_macro_subns,
+ )
}
PathKind::Super(lvl) => {
let mut module = original_module;
@@ -236,16 +254,20 @@ impl DefMap {
);
tracing::debug!(
"`super` path: {} -> {} in parent map",
- path,
- new_path
- );
- return block.parent.def_map(db).resolve_path_fp_with_macro(
- db,
- mode,
- block.parent.local_id,
- &new_path,
- shadow,
+ path.display(db.upcast()),
+ new_path.display(db.upcast())
);
+ return block
+ .parent
+ .def_map(db, self.krate)
+ .resolve_path_fp_with_macro(
+ db,
+ mode,
+ block.parent.local_id,
+ &new_path,
+ shadow,
+ expected_macro_subns,
+ );
}
None => {
tracing::debug!("super path in root module");
@@ -271,7 +293,7 @@ impl DefMap {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
- if let Some(&def) = self.extern_prelude.get(segment) {
+ if let Some(&def) = self.data.extern_prelude.get(segment) {
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
PerNs::types(def.into(), Visibility::Public)
} else {
@@ -303,7 +325,12 @@ impl DefMap {
);
tracing::debug!("resolving {:?} in other crate", path);
let defp_map = module.def_map(db);
- let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
+ // Macro sub-namespaces only matter when resolving single-segment paths
+ // because `macro_use` and other preludes should be taken into account. At
+ // this point, we know we're resolving a multi-segment path so macro kind
+ // expectation is discarded.
+ let (def, s) =
+ defp_map.resolve_path(db, module.local_id, &path, shadow, None);
return ResolvePathResult::with(
def,
ReachedFixedPoint::Yes,
@@ -331,11 +358,11 @@ impl DefMap {
Some(local_id) => {
let variant = EnumVariantId { parent: e, local_id };
match &*enum_data.variants[local_id].variant_data {
- crate::adt::VariantData::Record(_) => {
+ crate::data::adt::VariantData::Record(_) => {
PerNs::types(variant.into(), Visibility::Public)
}
- crate::adt::VariantData::Tuple(_)
- | crate::adt::VariantData::Unit => {
+ crate::data::adt::VariantData::Tuple(_)
+ | crate::data::adt::VariantData::Unit => {
PerNs::both(variant.into(), variant.into(), Visibility::Public)
}
}
@@ -381,19 +408,24 @@ impl DefMap {
module: LocalModuleId,
name: &Name,
shadow: BuiltinShadowMode,
+ expected_macro_subns: Option<MacroSubNs>,
) -> PerNs {
// Resolve in:
// - legacy scope of macro
// - current module / scope
- // - extern prelude
+ // - extern prelude / macro_use prelude
// - std prelude
let from_legacy_macro = self[module]
.scope
.get_legacy_macro(name)
// FIXME: shadowing
.and_then(|it| it.last())
- .map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public));
- let from_scope = self[module].scope.get(name);
+ .copied()
+ .filter(|&id| {
+ sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns)
+ })
+ .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
+ let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns);
let from_builtin = match self.block {
Some(_) => {
// Only resolve to builtins in the root `DefMap`.
@@ -410,13 +442,27 @@ impl DefMap {
};
let extern_prelude = || {
- self.extern_prelude
+ if self.block.is_some() {
+ // Don't resolve extern prelude in block `DefMap`s.
+ return PerNs::none();
+ }
+ self.data
+ .extern_prelude
.get(name)
.map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
};
+ let macro_use_prelude = || {
+ self.macro_use_prelude
+ .get(name)
+ .map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public))
+ };
let prelude = || self.resolve_in_prelude(db, name);
- from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude)
+ from_legacy_macro
+ .or(from_scope_or_builtin)
+ .or_else(extern_prelude)
+ .or_else(macro_use_prelude)
+ .or_else(prelude)
}
fn resolve_name_in_crate_root_or_extern_prelude(
@@ -426,13 +472,20 @@ impl DefMap {
) -> PerNs {
let from_crate_root = match self.block {
Some(_) => {
- let def_map = self.crate_root(db).def_map(db);
- def_map[def_map.root].scope.get(name)
+ let def_map = self.crate_root().def_map(db);
+ def_map[Self::ROOT].scope.get(name)
}
- None => self[self.root].scope.get(name),
+ None => self[Self::ROOT].scope.get(name),
};
let from_extern_prelude = || {
- self.resolve_name_in_extern_prelude(db, name)
+ if self.block.is_some() {
+ // Don't resolve extern prelude in block `DefMap`s.
+ return PerNs::none();
+ }
+ self.data
+ .extern_prelude
+ .get(name)
+ .copied()
.map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public))
};