Expand more single ident macro calls upon their collection

This commit is contained in:
Ryo Yoshida 2023-05-14 00:50:51 +09:00
parent f2a35deb50
commit e9ddb62c65
No known key found for this signature in database
GPG Key ID: E25698A930586171
3 changed files with 61 additions and 15 deletions

View File

@ -44,7 +44,8 @@
mod_resolution::ModDir,
path_resolution::ReachedFixedPoint,
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin,
ResolveMode,
},
path::{ImportAlias, ModPath, PathKind},
per_ns::PerNs,
@ -2141,27 +2142,35 @@ fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>, module: ModuleId)
fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
let db = self.def_collector.db;
// Case 1: try to resolve in legacy scope and expand macro_rules
// FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define
// new legacy macros that create textual scopes. We need a way to resolve names in textual
// scopes without eager expansion.
// Case 1: try to resolve macro calls with single-segment name and expand macro_rules
if let Ok(res) = macro_call_as_call_id(
self.def_collector.db.upcast(),
db.upcast(),
&ast_id,
mac.expand_to,
self.def_collector.def_map.krate,
|path| {
path.as_ident().and_then(|name| {
self.def_collector.def_map.with_ancestor_maps(
self.def_collector.db,
self.module_id,
&mut |map, module| {
map[module]
.scope
.get_legacy_macro(name)
.and_then(|it| it.last())
.map(|&it| macro_id_to_def_id(self.def_collector.db, it))
},
let def_map = &self.def_collector.def_map;
def_map
.with_ancestor_maps(db, self.module_id, &mut |map, module| {
map[module].scope.get_legacy_macro(name)?.last().copied()
})
.or_else(|| def_map[self.module_id].scope.get(name).take_macros())
.or_else(|| def_map.macro_use_prelude.get(name).copied())
.filter(|&id| {
sub_namespace_match(
Some(MacroSubNs::from_id(db, id)),
Some(MacroSubNs::Bang),
)
})
.map(|it| macro_id_to_def_id(self.def_collector.db, it))
})
},
) {
// Legacy macros need to be expanded immediately, so that any macros they produce

View File

@ -59,7 +59,11 @@ fn with(
}
impl PerNs {
fn filter_macro(mut self, db: &dyn DefDatabase, expected: Option<MacroSubNs>) -> Self {
pub(super) 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)

View File

@ -1272,6 +1272,39 @@ macro_rules! bar {
);
}
#[test]
fn macro_use_prelude_is_eagerly_expanded() {
// See FIXME in `ModCollector::collect_macro_call()`.
check(
r#"
//- /main.rs crate:main deps:lib
#[macro_use]
extern crate lib;
mk_foo!();
mod a {
foo!();
}
//- /lib.rs crate:lib
#[macro_export]
macro_rules! mk_foo {
() => {
macro_rules! foo {
() => { struct Ok; }
}
}
}
"#,
expect![[r#"
crate
a: t
lib: t
crate::a
Ok: t v
"#]],
);
}
#[test]
fn macro_sub_namespace() {
let map = compute_crate_def_map(