Resolve textual scoped macros inside item
This commit is contained in:
parent
e0f305a6bf
commit
26b092bd3b
4 changed files with 65 additions and 9 deletions
|
@ -489,16 +489,21 @@ impl CrateDefMap {
|
|||
name: &Name,
|
||||
) -> ItemOrMacro {
|
||||
// Resolve in:
|
||||
// - textual scoped macros
|
||||
// - current module / scope
|
||||
// - extern prelude
|
||||
// - std prelude
|
||||
let from_textual_mcro = self[module]
|
||||
.scope
|
||||
.get_textual_macro(name)
|
||||
.map_or_else(|| Either::A(PerNs::none()), Either::B);
|
||||
let from_scope =
|
||||
self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
|
||||
let from_extern_prelude =
|
||||
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
|
||||
let from_prelude = self.resolve_in_prelude(db, name);
|
||||
|
||||
or(from_scope, or(Either::A(from_extern_prelude), from_prelude))
|
||||
or(from_textual_mcro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude)))
|
||||
}
|
||||
|
||||
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
|
||||
|
|
|
@ -14,8 +14,8 @@ use crate::{
|
|||
raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs,
|
||||
ReachedFixedPoint, Resolution, ResolveMode,
|
||||
},
|
||||
AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, Struct, Trait,
|
||||
TypeAlias, Union,
|
||||
AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
|
||||
Struct, Trait, TypeAlias, Union,
|
||||
};
|
||||
|
||||
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
|
||||
|
@ -156,9 +156,6 @@ where
|
|||
/// the definition of current module.
|
||||
/// And also, `macro_use` on a module will import all textual macros visable inside to
|
||||
/// current textual scope, with possible shadowing.
|
||||
///
|
||||
/// In a single module, the order of definition/usage of textual scoped macros matters.
|
||||
/// But we ignore it here to make it easy to implement.
|
||||
fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) {
|
||||
// Always shadowing
|
||||
self.def_map.modules[module_id]
|
||||
|
@ -700,8 +697,13 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
// Case 3: path to a macro from another crate, expand during name resolution
|
||||
self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone()))
|
||||
// Case 3: resolve in module scope, expand during name resolution.
|
||||
// We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
|
||||
let mut path = mac.path.clone();
|
||||
if path.is_ident() {
|
||||
path.kind = PathKind::Self_;
|
||||
}
|
||||
self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path));
|
||||
}
|
||||
|
||||
fn import_all_textual_macros(&mut self, module_id: CrateModuleId) {
|
||||
|
|
|
@ -279,7 +279,7 @@ fn prelude_cycle() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn plain_macros_are_textual_scoped_between_modules() {
|
||||
fn plain_macros_are_textual_scoped() {
|
||||
let map = def_map(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
@ -310,6 +310,15 @@ fn plain_macros_are_textual_scoped_between_modules() {
|
|||
}
|
||||
foo!(ok_double_macro_use_shadow);
|
||||
|
||||
baz!(NotFoundBefore);
|
||||
#[macro_use]
|
||||
mod m7 {
|
||||
macro_rules! baz {
|
||||
($x:ident) => { struct $x; }
|
||||
}
|
||||
}
|
||||
baz!(OkAfter);
|
||||
|
||||
//- /m1.rs
|
||||
foo!(NotFoundBeforeInside1);
|
||||
macro_rules! bar {
|
||||
|
@ -337,14 +346,19 @@ fn plain_macros_are_textual_scoped_between_modules() {
|
|||
assert_snapshot!(map, @r###"
|
||||
⋮crate
|
||||
⋮Ok: t v
|
||||
⋮OkAfter: t v
|
||||
⋮OkShadowStop: t v
|
||||
⋮foo: m
|
||||
⋮m1: t
|
||||
⋮m2: t
|
||||
⋮m3: t
|
||||
⋮m5: t
|
||||
⋮m7: t
|
||||
⋮ok_double_macro_use_shadow: v
|
||||
⋮
|
||||
⋮crate::m7
|
||||
⋮baz: m
|
||||
⋮
|
||||
⋮crate::m1
|
||||
⋮bar: m
|
||||
⋮
|
||||
|
|
|
@ -2803,6 +2803,41 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_textual_scoped_macros_expanded() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
struct Foo(Vec<i32>);
|
||||
|
||||
#[macro_use]
|
||||
mod m {
|
||||
macro_rules! foo {
|
||||
($($item:expr),*) => {
|
||||
{
|
||||
Foo(vec![$($item,)*])
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = foo!(1,2);
|
||||
let y = crate::foo!(1,2);
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
![0; 17) '{Foo(v...,2,])}': Foo
|
||||
![1; 4) 'Foo': Foo({unknown}) -> Foo
|
||||
![1; 16) 'Foo(vec![1,2,])': Foo
|
||||
![5; 15) 'vec![1,2,]': {unknown}
|
||||
[195; 251) '{ ...,2); }': ()
|
||||
[205; 206) 'x': Foo
|
||||
[228; 229) 'y': {unknown}
|
||||
[232; 248) 'crate:...!(1,2)': {unknown}
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn method_resolution_trait_before_autoref() {
|
||||
|
|
Loading…
Add table
Reference in a new issue