Unnamed repository; edit this file 'description' to name the repository.
Expand more single ident macro calls upon their collection
Ryo Yoshida 2023-05-14
parent f2a35de · commit e9ddb62
-rw-r--r--crates/hir-def/src/nameres/collector.rs37
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs6
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs33
3 files changed, 61 insertions, 15 deletions
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 177edcbb7f..d1288b7b59 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -44,7 +44,8 @@ use crate::{
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,26 +2142,34 @@ impl ModCollector<'_, '_> {
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))
})
},
) {
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 4740fd7f44..981171013a 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -59,7 +59,11 @@ impl ResolvePathResult {
}
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)
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index e795b7b9b7..7eb64beb1d 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -1273,6 +1273,39 @@ pub mod prelude {
}
#[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(
r#"