mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Resolve textual scoped macros inside item
This commit is contained in:
parent
e0f305a6bf
commit
26b092bd3b
@ -489,16 +489,21 @@ impl CrateDefMap {
|
|||||||
name: &Name,
|
name: &Name,
|
||||||
) -> ItemOrMacro {
|
) -> ItemOrMacro {
|
||||||
// Resolve in:
|
// Resolve in:
|
||||||
|
// - textual scoped macros
|
||||||
// - current module / scope
|
// - current module / scope
|
||||||
// - extern prelude
|
// - extern prelude
|
||||||
// - std 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 =
|
let from_scope =
|
||||||
self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
|
self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
|
||||||
let from_extern_prelude =
|
let from_extern_prelude =
|
||||||
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
|
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
|
||||||
let from_prelude = self.resolve_in_prelude(db, name);
|
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> {
|
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
|
||||||
|
@ -14,8 +14,8 @@ use crate::{
|
|||||||
raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs,
|
raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs,
|
||||||
ReachedFixedPoint, Resolution, ResolveMode,
|
ReachedFixedPoint, Resolution, ResolveMode,
|
||||||
},
|
},
|
||||||
AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, Struct, Trait,
|
AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
|
||||||
TypeAlias, Union,
|
Struct, Trait, TypeAlias, Union,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
|
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
|
||||||
@ -156,9 +156,6 @@ where
|
|||||||
/// the definition of current module.
|
/// the definition of current module.
|
||||||
/// And also, `macro_use` on a module will import all textual macros visable inside to
|
/// And also, `macro_use` on a module will import all textual macros visable inside to
|
||||||
/// current textual scope, with possible shadowing.
|
/// 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) {
|
fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) {
|
||||||
// Always shadowing
|
// Always shadowing
|
||||||
self.def_map.modules[module_id]
|
self.def_map.modules[module_id]
|
||||||
@ -700,8 +697,13 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 3: path to a macro from another crate, expand during name resolution
|
// Case 3: resolve in module scope, expand during name resolution.
|
||||||
self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone()))
|
// 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) {
|
fn import_all_textual_macros(&mut self, module_id: CrateModuleId) {
|
||||||
|
@ -279,7 +279,7 @@ fn prelude_cycle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn plain_macros_are_textual_scoped_between_modules() {
|
fn plain_macros_are_textual_scoped() {
|
||||||
let map = def_map(
|
let map = def_map(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
//- /main.rs
|
||||||
@ -310,6 +310,15 @@ fn plain_macros_are_textual_scoped_between_modules() {
|
|||||||
}
|
}
|
||||||
foo!(ok_double_macro_use_shadow);
|
foo!(ok_double_macro_use_shadow);
|
||||||
|
|
||||||
|
baz!(NotFoundBefore);
|
||||||
|
#[macro_use]
|
||||||
|
mod m7 {
|
||||||
|
macro_rules! baz {
|
||||||
|
($x:ident) => { struct $x; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baz!(OkAfter);
|
||||||
|
|
||||||
//- /m1.rs
|
//- /m1.rs
|
||||||
foo!(NotFoundBeforeInside1);
|
foo!(NotFoundBeforeInside1);
|
||||||
macro_rules! bar {
|
macro_rules! bar {
|
||||||
@ -337,14 +346,19 @@ fn plain_macros_are_textual_scoped_between_modules() {
|
|||||||
assert_snapshot!(map, @r###"
|
assert_snapshot!(map, @r###"
|
||||||
⋮crate
|
⋮crate
|
||||||
⋮Ok: t v
|
⋮Ok: t v
|
||||||
|
⋮OkAfter: t v
|
||||||
⋮OkShadowStop: t v
|
⋮OkShadowStop: t v
|
||||||
⋮foo: m
|
⋮foo: m
|
||||||
⋮m1: t
|
⋮m1: t
|
||||||
⋮m2: t
|
⋮m2: t
|
||||||
⋮m3: t
|
⋮m3: t
|
||||||
⋮m5: t
|
⋮m5: t
|
||||||
|
⋮m7: t
|
||||||
⋮ok_double_macro_use_shadow: v
|
⋮ok_double_macro_use_shadow: v
|
||||||
⋮
|
⋮
|
||||||
|
⋮crate::m7
|
||||||
|
⋮baz: m
|
||||||
|
⋮
|
||||||
⋮crate::m1
|
⋮crate::m1
|
||||||
⋮bar: m
|
⋮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]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn method_resolution_trait_before_autoref() {
|
fn method_resolution_trait_before_autoref() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user