Consider macro sub-namespace during name resolution
This commit is contained in:
parent
3203ea896d
commit
f2a35deb50
@ -37,7 +37,7 @@
|
|||||||
item_scope::BuiltinShadowMode,
|
item_scope::BuiltinShadowMode,
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
lower::LowerCtx,
|
lower::LowerCtx,
|
||||||
nameres::DefMap,
|
nameres::{DefMap, MacroSubNs},
|
||||||
path::{GenericArgs, Path},
|
path::{GenericArgs, Path},
|
||||||
type_ref::{Mutability, Rawness, TypeRef},
|
type_ref::{Mutability, Rawness, TypeRef},
|
||||||
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
|
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
|
||||||
@ -800,7 +800,13 @@ fn collect_macro_call<F, T, U>(
|
|||||||
let module = self.expander.module.local_id;
|
let module = self.expander.module.local_id;
|
||||||
let res = self.expander.enter_expand(self.db, mcall, |path| {
|
let res = self.expander.enter_expand(self.db, mcall, |path| {
|
||||||
self.def_map
|
self.def_map
|
||||||
.resolve_path(self.db, module, &path, crate::item_scope::BuiltinShadowMode::Other)
|
.resolve_path(
|
||||||
|
self.db,
|
||||||
|
module,
|
||||||
|
&path,
|
||||||
|
crate::item_scope::BuiltinShadowMode::Other,
|
||||||
|
Some(MacroSubNs::Bang),
|
||||||
|
)
|
||||||
.0
|
.0
|
||||||
.take_macros()
|
.take_macros()
|
||||||
});
|
});
|
||||||
@ -1056,6 +1062,7 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI
|
|||||||
self.expander.module.local_id,
|
self.expander.module.local_id,
|
||||||
&name.clone().into(),
|
&name.clone().into(),
|
||||||
BuiltinShadowMode::Other,
|
BuiltinShadowMode::Other,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
match resolved.take_values() {
|
match resolved.take_values() {
|
||||||
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
|
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
attr_resolution::ResolvedAttr,
|
attr_resolution::ResolvedAttr,
|
||||||
diagnostics::DefDiagnostic,
|
diagnostics::DefDiagnostic,
|
||||||
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
|
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
|
||||||
DefMap,
|
DefMap, MacroSubNs,
|
||||||
},
|
},
|
||||||
type_ref::{TraitRef, TypeBound, TypeRef},
|
type_ref::{TraitRef, TypeBound, TypeRef},
|
||||||
visibility::RawVisibility,
|
visibility::RawVisibility,
|
||||||
@ -673,6 +673,7 @@ fn collect_item(
|
|||||||
module,
|
module,
|
||||||
&path,
|
&path,
|
||||||
crate::item_scope::BuiltinShadowMode::Other,
|
crate::item_scope::BuiltinShadowMode::Other,
|
||||||
|
Some(MacroSubNs::Bang),
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
.take_macros()
|
.take_macros()
|
||||||
|
@ -543,6 +543,7 @@ fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKin
|
|||||||
module.local_id,
|
module.local_id,
|
||||||
&mod_path,
|
&mod_path,
|
||||||
crate::item_scope::BuiltinShadowMode::Module,
|
crate::item_scope::BuiltinShadowMode::Module,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
.take_types()
|
.take_types()
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
dyn_map::{keys, DynMap},
|
dyn_map::{keys, DynMap},
|
||||||
expander::Expander,
|
expander::Expander,
|
||||||
lower::LowerCtx,
|
lower::LowerCtx,
|
||||||
nameres::DefMap,
|
nameres::{DefMap, MacroSubNs},
|
||||||
src::{HasChildSource, HasSource},
|
src::{HasChildSource, HasSource},
|
||||||
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
||||||
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
|
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
|
||||||
@ -361,6 +361,7 @@ pub(crate) fn fill_implicit_impl_trait_args(
|
|||||||
module,
|
module,
|
||||||
&path,
|
&path,
|
||||||
crate::item_scope::BuiltinShadowMode::Other,
|
crate::item_scope::BuiltinShadowMode::Other,
|
||||||
|
Some(MacroSubNs::Bang),
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
.take_macros()
|
.take_macros()
|
||||||
|
@ -33,8 +33,13 @@
|
|||||||
use tt::token_id::{Subtree, TokenId};
|
use tt::token_id::{Subtree, TokenId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver,
|
db::DefDatabase,
|
||||||
src::HasSource, test_db::TestDB, AdtId, AsMacroCall, Lookup, ModuleDefId,
|
macro_id_to_def_id,
|
||||||
|
nameres::{MacroSubNs, ModuleSource},
|
||||||
|
resolver::HasResolver,
|
||||||
|
src::HasSource,
|
||||||
|
test_db::TestDB,
|
||||||
|
AdtId, AsMacroCall, Lookup, ModuleDefId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@ -127,7 +132,9 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
|||||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
let macro_call = InFile::new(source.file_id, ¯o_call);
|
||||||
let res = macro_call
|
let res = macro_call
|
||||||
.as_call_id_with_errors(&db, krate, |path| {
|
.as_call_id_with_errors(&db, krate, |path| {
|
||||||
resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it))
|
resolver
|
||||||
|
.resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang))
|
||||||
|
.map(|it| macro_id_to_def_id(&db, it))
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let macro_call_id = res.value.unwrap();
|
let macro_call_id = res.value.unwrap();
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
use std::{cmp::Ord, ops::Deref};
|
use std::{cmp::Ord, ops::Deref};
|
||||||
|
|
||||||
use base_db::{CrateId, Edition, FileId};
|
use base_db::{CrateId, Edition, FileId, ProcMacroKind};
|
||||||
use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
|
use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use la_arena::Arena;
|
use la_arena::Arena;
|
||||||
@ -77,7 +77,8 @@
|
|||||||
path::ModPath,
|
path::ModPath,
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
visibility::Visibility,
|
visibility::Visibility,
|
||||||
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
|
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId,
|
||||||
|
ProcMacroId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Contains the results of (early) name resolution.
|
/// Contains the results of (early) name resolution.
|
||||||
@ -380,9 +381,16 @@ pub(crate) fn resolve_path(
|
|||||||
original_module: LocalModuleId,
|
original_module: LocalModuleId,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
shadow: BuiltinShadowMode,
|
shadow: BuiltinShadowMode,
|
||||||
|
expected_macro_subns: Option<MacroSubNs>,
|
||||||
) -> (PerNs, Option<usize>) {
|
) -> (PerNs, Option<usize>) {
|
||||||
let res =
|
let res = self.resolve_path_fp_with_macro(
|
||||||
self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
|
db,
|
||||||
|
ResolveMode::Other,
|
||||||
|
original_module,
|
||||||
|
path,
|
||||||
|
shadow,
|
||||||
|
expected_macro_subns,
|
||||||
|
);
|
||||||
(res.resolved_def, res.segment_index)
|
(res.resolved_def, res.segment_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,6 +407,7 @@ pub(crate) fn resolve_path_locally(
|
|||||||
original_module,
|
original_module,
|
||||||
path,
|
path,
|
||||||
shadow,
|
shadow,
|
||||||
|
None, // Currently this function isn't used for macro resolution.
|
||||||
);
|
);
|
||||||
(res.resolved_def, res.segment_index)
|
(res.resolved_def, res.segment_index)
|
||||||
}
|
}
|
||||||
@ -568,3 +577,48 @@ pub enum ModuleSource {
|
|||||||
Module(ast::Module),
|
Module(ast::Module),
|
||||||
BlockExpr(ast::BlockExpr),
|
BlockExpr(ast::BlockExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See `sub_namespace_match()`.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum MacroSubNs {
|
||||||
|
/// Function-like macros, suffixed with `!`.
|
||||||
|
Bang,
|
||||||
|
/// Macros inside attributes, i.e. attribute macros and derive macros.
|
||||||
|
Attr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacroSubNs {
|
||||||
|
fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self {
|
||||||
|
let expander = match macro_id {
|
||||||
|
MacroId::Macro2Id(it) => it.lookup(db).expander,
|
||||||
|
MacroId::MacroRulesId(it) => it.lookup(db).expander,
|
||||||
|
MacroId::ProcMacroId(it) => {
|
||||||
|
return match it.lookup(db).kind {
|
||||||
|
ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
|
||||||
|
ProcMacroKind::FuncLike => Self::Bang,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Eager macros aren't *guaranteed* to be bang macros, but they *are* all bang macros currently.
|
||||||
|
match expander {
|
||||||
|
MacroExpander::Declarative
|
||||||
|
| MacroExpander::BuiltIn(_)
|
||||||
|
| MacroExpander::BuiltInEager(_) => Self::Bang,
|
||||||
|
MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Quoted from [rustc]:
|
||||||
|
/// Macro namespace is separated into two sub-namespaces, one for bang macros and
|
||||||
|
/// one for attribute-like macros (attributes, derives).
|
||||||
|
/// We ignore resolutions from one sub-namespace when searching names in scope for another.
|
||||||
|
///
|
||||||
|
/// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75
|
||||||
|
fn sub_namespace_match(candidate: Option<MacroSubNs>, expected: Option<MacroSubNs>) -> bool {
|
||||||
|
match (candidate, expected) {
|
||||||
|
(Some(candidate), Some(expected)) => candidate == expected,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
AstIdWithPath, LocalModuleId, UnresolvedMacro,
|
AstIdWithPath, LocalModuleId, UnresolvedMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::DefMap;
|
use super::{DefMap, MacroSubNs};
|
||||||
|
|
||||||
pub enum ResolvedAttr {
|
pub enum ResolvedAttr {
|
||||||
/// Attribute resolved to an attribute macro.
|
/// Attribute resolved to an attribute macro.
|
||||||
@ -43,9 +43,12 @@ pub(crate) fn resolve_attr_macro(
|
|||||||
original_module,
|
original_module,
|
||||||
&ast_id.path,
|
&ast_id.path,
|
||||||
BuiltinShadowMode::Module,
|
BuiltinShadowMode::Module,
|
||||||
|
Some(MacroSubNs::Attr),
|
||||||
);
|
);
|
||||||
let def = match resolved_res.resolved_def.take_macros() {
|
let def = match resolved_res.resolved_def.take_macros() {
|
||||||
Some(def) => {
|
Some(def) => {
|
||||||
|
// `MacroSubNs` is just a hint, so the path may still resolve to a custom derive
|
||||||
|
// macro, or even function-like macro when the path is qualified.
|
||||||
if def.is_attribute(db) {
|
if def.is_attribute(db) {
|
||||||
def
|
def
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
mod_resolution::ModDir,
|
mod_resolution::ModDir,
|
||||||
path_resolution::ReachedFixedPoint,
|
path_resolution::ReachedFixedPoint,
|
||||||
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
|
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
|
||||||
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
|
BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
|
||||||
},
|
},
|
||||||
path::{ImportAlias, ModPath, PathKind},
|
path::{ImportAlias, ModPath, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
@ -549,8 +549,13 @@ fn inject_prelude(&mut self, crate_attrs: &Attrs) {
|
|||||||
};
|
};
|
||||||
let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]);
|
let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]);
|
||||||
|
|
||||||
let (per_ns, _) =
|
let (per_ns, _) = self.def_map.resolve_path(
|
||||||
self.def_map.resolve_path(self.db, self.def_map.root, &path, BuiltinShadowMode::Other);
|
self.db,
|
||||||
|
self.def_map.root,
|
||||||
|
&path,
|
||||||
|
BuiltinShadowMode::Other,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
match per_ns.types {
|
match per_ns.types {
|
||||||
Some((ModuleDefId::ModuleId(m), _)) => {
|
Some((ModuleDefId::ModuleId(m), _)) => {
|
||||||
@ -796,6 +801,7 @@ fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialRe
|
|||||||
module_id,
|
module_id,
|
||||||
&import.path,
|
&import.path,
|
||||||
BuiltinShadowMode::Module,
|
BuiltinShadowMode::Module,
|
||||||
|
None, // An import may resolve to any kind of macro.
|
||||||
);
|
);
|
||||||
|
|
||||||
let def = res.resolved_def;
|
let def = res.resolved_def;
|
||||||
@ -1093,7 +1099,14 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
|
|||||||
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
|
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
|
||||||
};
|
};
|
||||||
let mut res = ReachedFixedPoint::Yes;
|
let mut res = ReachedFixedPoint::Yes;
|
||||||
|
// Retain unresolved macros after this round of resolution.
|
||||||
macros.retain(|directive| {
|
macros.retain(|directive| {
|
||||||
|
let subns = match &directive.kind {
|
||||||
|
MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
|
||||||
|
MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
|
||||||
|
MacroSubNs::Attr
|
||||||
|
}
|
||||||
|
};
|
||||||
let resolver = |path| {
|
let resolver = |path| {
|
||||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||||
self.db,
|
self.db,
|
||||||
@ -1101,6 +1114,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
|
|||||||
directive.module_id,
|
directive.module_id,
|
||||||
&path,
|
&path,
|
||||||
BuiltinShadowMode::Module,
|
BuiltinShadowMode::Module,
|
||||||
|
Some(subns),
|
||||||
);
|
);
|
||||||
resolved_res
|
resolved_res
|
||||||
.resolved_def
|
.resolved_def
|
||||||
@ -1419,6 +1433,7 @@ fn finish(mut self) -> DefMap {
|
|||||||
directive.module_id,
|
directive.module_id,
|
||||||
&path,
|
&path,
|
||||||
BuiltinShadowMode::Module,
|
BuiltinShadowMode::Module,
|
||||||
|
Some(MacroSubNs::Bang),
|
||||||
);
|
);
|
||||||
resolved_res
|
resolved_res
|
||||||
.resolved_def
|
.resolved_def
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
item_scope::BUILTIN_SCOPE,
|
item_scope::BUILTIN_SCOPE,
|
||||||
nameres::{BuiltinShadowMode, DefMap},
|
nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs},
|
||||||
path::{ModPath, PathKind},
|
path::{ModPath, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
visibility::{RawVisibility, Visibility},
|
visibility::{RawVisibility, Visibility},
|
||||||
@ -58,6 +58,17 @@ fn with(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PerNs {
|
||||||
|
fn filter_macro(mut self, db: &dyn DefDatabase, 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 {
|
impl DefMap {
|
||||||
pub(super) fn resolve_name_in_extern_prelude(
|
pub(super) fn resolve_name_in_extern_prelude(
|
||||||
&self,
|
&self,
|
||||||
@ -83,7 +94,7 @@ pub(crate) fn resolve_visibility(
|
|||||||
let mut vis = match visibility {
|
let mut vis = match visibility {
|
||||||
RawVisibility::Module(path) => {
|
RawVisibility::Module(path) => {
|
||||||
let (result, remaining) =
|
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() {
|
if remaining.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -124,6 +135,9 @@ pub(super) fn resolve_path_fp_with_macro(
|
|||||||
mut original_module: LocalModuleId,
|
mut original_module: LocalModuleId,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
shadow: BuiltinShadowMode,
|
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 {
|
) -> ResolvePathResult {
|
||||||
let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
|
let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
|
||||||
|
|
||||||
@ -136,6 +150,7 @@ pub(super) fn resolve_path_fp_with_macro(
|
|||||||
original_module,
|
original_module,
|
||||||
path,
|
path,
|
||||||
shadow,
|
shadow,
|
||||||
|
expected_macro_subns,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Merge `new` into `result`.
|
// Merge `new` into `result`.
|
||||||
@ -169,6 +184,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
|||||||
original_module: LocalModuleId,
|
original_module: LocalModuleId,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
shadow: BuiltinShadowMode,
|
shadow: BuiltinShadowMode,
|
||||||
|
expected_macro_subns: Option<MacroSubNs>,
|
||||||
) -> ResolvePathResult {
|
) -> ResolvePathResult {
|
||||||
let graph = db.crate_graph();
|
let graph = db.crate_graph();
|
||||||
let _cx = stdx::panic_context::enter(format!(
|
let _cx = stdx::panic_context::enter(format!(
|
||||||
@ -220,7 +236,13 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
|||||||
if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
|
if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
|
||||||
|
|
||||||
tracing::debug!("resolving {:?} in module", segment);
|
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) => {
|
PathKind::Super(lvl) => {
|
||||||
let mut module = original_module;
|
let mut module = original_module;
|
||||||
@ -245,6 +267,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
|||||||
block.parent.local_id,
|
block.parent.local_id,
|
||||||
&new_path,
|
&new_path,
|
||||||
shadow,
|
shadow,
|
||||||
|
expected_macro_subns,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -303,7 +326,12 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
|||||||
);
|
);
|
||||||
tracing::debug!("resolving {:?} in other crate", path);
|
tracing::debug!("resolving {:?} in other crate", path);
|
||||||
let defp_map = module.def_map(db);
|
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(
|
return ResolvePathResult::with(
|
||||||
def,
|
def,
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
@ -381,6 +409,7 @@ fn resolve_name_in_module(
|
|||||||
module: LocalModuleId,
|
module: LocalModuleId,
|
||||||
name: &Name,
|
name: &Name,
|
||||||
shadow: BuiltinShadowMode,
|
shadow: BuiltinShadowMode,
|
||||||
|
expected_macro_subns: Option<MacroSubNs>,
|
||||||
) -> PerNs {
|
) -> PerNs {
|
||||||
// Resolve in:
|
// Resolve in:
|
||||||
// - legacy scope of macro
|
// - legacy scope of macro
|
||||||
@ -392,8 +421,12 @@ fn resolve_name_in_module(
|
|||||||
.get_legacy_macro(name)
|
.get_legacy_macro(name)
|
||||||
// FIXME: shadowing
|
// FIXME: shadowing
|
||||||
.and_then(|it| it.last())
|
.and_then(|it| it.last())
|
||||||
.map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public));
|
.copied()
|
||||||
let from_scope = self[module].scope.get(name);
|
.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 {
|
let from_builtin = match self.block {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// Only resolve to builtins in the root `DefMap`.
|
// Only resolve to builtins in the root `DefMap`.
|
||||||
|
@ -1271,3 +1271,57 @@ macro_rules! bar {
|
|||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn macro_sub_namespace() {
|
||||||
|
let map = compute_crate_def_map(
|
||||||
|
r#"
|
||||||
|
//- minicore: derive, clone
|
||||||
|
macro_rules! Clone { () => {} }
|
||||||
|
macro_rules! derive { () => {} }
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct S;
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(map.modules[map.root].scope.impls().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn macro_sub_namespace2() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /main.rs edition:2021 crate:main deps:proc,core
|
||||||
|
use proc::{foo, bar};
|
||||||
|
|
||||||
|
foo!();
|
||||||
|
bar!();
|
||||||
|
|
||||||
|
//- /proc.rs crate:proc
|
||||||
|
#![crate_type="proc-macro"]
|
||||||
|
#[proc_macro_derive(foo)]
|
||||||
|
pub fn foo() {}
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn bar() {}
|
||||||
|
|
||||||
|
//- /core.rs crate:core
|
||||||
|
pub mod prelude {
|
||||||
|
pub mod rust_2021 {
|
||||||
|
pub macro foo() {
|
||||||
|
struct Ok;
|
||||||
|
}
|
||||||
|
pub macro bar() {
|
||||||
|
fn ok() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
crate
|
||||||
|
Ok: t v
|
||||||
|
bar: m
|
||||||
|
foo: m
|
||||||
|
ok: v
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
hir::{BindingId, ExprId, LabelId},
|
hir::{BindingId, ExprId, LabelId},
|
||||||
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
|
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
|
||||||
lang_item::LangItemTarget,
|
lang_item::LangItemTarget,
|
||||||
nameres::DefMap,
|
nameres::{DefMap, MacroSubNs},
|
||||||
path::{ModPath, Path, PathKind},
|
path::{ModPath, Path, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
visibility::{RawVisibility, Visibility},
|
visibility::{RawVisibility, Visibility},
|
||||||
@ -155,7 +155,8 @@ pub fn resolve_module_path_in_trait_assoc_items(
|
|||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
) -> Option<PerNs> {
|
) -> Option<PerNs> {
|
||||||
let (item_map, module) = self.item_scope();
|
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()? {
|
match module_res.take_types()? {
|
||||||
ModuleDefId::TraitId(it) => {
|
ModuleDefId::TraitId(it) => {
|
||||||
let idx = idx?;
|
let idx = idx?;
|
||||||
@ -385,9 +386,17 @@ pub fn resolve_path_in_value_ns_fully(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
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.
|
/// Returns a set of names available in the current scope.
|
||||||
@ -626,7 +635,8 @@ fn resolve_module_path(
|
|||||||
shadow: BuiltinShadowMode,
|
shadow: BuiltinShadowMode,
|
||||||
) -> PerNs {
|
) -> PerNs {
|
||||||
let (item_map, module) = self.item_scope();
|
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() {
|
if segment_index.is_some() {
|
||||||
return PerNs::none();
|
return PerNs::none();
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||||
},
|
},
|
||||||
lang_item::{lang_attr, LangItem},
|
lang_item::{lang_attr, LangItem},
|
||||||
|
nameres::MacroSubNs,
|
||||||
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
|
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
|
||||||
resolver::{HasResolver, Resolver, TypeNs},
|
resolver::{HasResolver, Resolver, TypeNs},
|
||||||
type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
|
type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
|
||||||
@ -378,9 +379,15 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
|
|||||||
};
|
};
|
||||||
let ty = {
|
let ty = {
|
||||||
let macro_call = macro_call.to_node(self.db.upcast());
|
let macro_call = macro_call.to_node(self.db.upcast());
|
||||||
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, |path| {
|
let resolver = |path| {
|
||||||
self.resolver.resolve_path_as_macro(self.db.upcast(), &path)
|
self.resolver.resolve_path_as_macro(
|
||||||
}) {
|
self.db.upcast(),
|
||||||
|
&path,
|
||||||
|
Some(MacroSubNs::Bang),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
|
||||||
|
{
|
||||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
||||||
let ctx = expander.ctx(self.db.upcast());
|
let ctx = expander.ctx(self.db.upcast());
|
||||||
// FIXME: Report syntax errors in expansion here
|
// FIXME: Report syntax errors in expansion here
|
||||||
|
@ -120,6 +120,7 @@ fn resolve_doc_path(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the item `link` points to in the scope of `def`.
|
||||||
fn resolve_doc_path(
|
fn resolve_doc_path(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
def: AttrDefId,
|
def: AttrDefId,
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
hir::Expr,
|
hir::Expr,
|
||||||
lower::LowerCtx,
|
lower::LowerCtx,
|
||||||
macro_id_to_def_id,
|
macro_id_to_def_id,
|
||||||
|
nameres::MacroSubNs,
|
||||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||||
type_ref::Mutability,
|
type_ref::Mutability,
|
||||||
AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
|
AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
|
||||||
@ -616,7 +617,7 @@ fn speculative_expand(
|
|||||||
let krate = resolver.krate();
|
let krate = resolver.krate();
|
||||||
let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
|
let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
|
||||||
resolver
|
resolver
|
||||||
.resolve_path_as_macro(self.db.upcast(), &path)
|
.resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang))
|
||||||
.map(|it| macro_id_to_def_id(self.db.upcast(), it))
|
.map(|it| macro_id_to_def_id(self.db.upcast(), it))
|
||||||
})?;
|
})?;
|
||||||
hir_expand::db::expand_speculative(
|
hir_expand::db::expand_speculative(
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
lower::LowerCtx,
|
lower::LowerCtx,
|
||||||
macro_id_to_def_id,
|
macro_id_to_def_id,
|
||||||
|
nameres::MacroSubNs,
|
||||||
path::{ModPath, Path, PathKind},
|
path::{ModPath, Path, PathKind},
|
||||||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||||
type_ref::Mutability,
|
type_ref::Mutability,
|
||||||
@ -484,7 +485,9 @@ pub(crate) fn resolve_macro_call(
|
|||||||
) -> Option<Macro> {
|
) -> Option<Macro> {
|
||||||
let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id);
|
let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id);
|
||||||
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
|
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
|
||||||
self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(|it| it.into())
|
self.resolver
|
||||||
|
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
|
||||||
|
.map(|it| it.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_bind_pat_to_const(
|
pub(crate) fn resolve_bind_pat_to_const(
|
||||||
@ -678,7 +681,7 @@ pub(crate) fn resolve_path(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
|
return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) {
|
||||||
Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
|
Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
|
||||||
// this labels any path that starts with a tool module as the tool itself, this is technically wrong
|
// this labels any path that starts with a tool module as the tool itself, this is technically wrong
|
||||||
// but there is no benefit in differentiating these two cases for the time being
|
// but there is no benefit in differentiating these two cases for the time being
|
||||||
@ -756,7 +759,7 @@ pub(crate) fn expand(
|
|||||||
let krate = self.resolver.krate();
|
let krate = self.resolver.krate();
|
||||||
let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
|
let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
|
||||||
self.resolver
|
self.resolver
|
||||||
.resolve_path_as_macro(db.upcast(), &path)
|
.resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang))
|
||||||
.map(|it| macro_id_to_def_id(db.upcast(), it))
|
.map(|it| macro_id_to_def_id(db.upcast(), it))
|
||||||
})?;
|
})?;
|
||||||
Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
|
Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
|
||||||
@ -956,12 +959,14 @@ pub(crate) fn resolve_hir_path(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn resolve_hir_path_as_macro(
|
pub(crate) fn resolve_hir_path_as_attr_macro(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
resolver: &Resolver,
|
resolver: &Resolver,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Option<Macro> {
|
) -> Option<Macro> {
|
||||||
resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(Into::into)
|
resolver
|
||||||
|
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr))
|
||||||
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_hir_path_(
|
fn resolve_hir_path_(
|
||||||
@ -1060,7 +1065,7 @@ fn resolve_hir_path_(
|
|||||||
|
|
||||||
let macros = || {
|
let macros = || {
|
||||||
resolver
|
resolver
|
||||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?)
|
.resolve_path_as_macro(db.upcast(), path.mod_path()?, None)
|
||||||
.map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
|
.map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user