diff options
| author | bors <bors@rust-lang.org> | 2023-05-13 18:47:42 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-05-13 18:47:42 +0000 |
| commit | daa03b0b0be6bd51dd43f4556dd4e27649bc6f57 (patch) | |
| tree | 8e273656d17347bcc25e38f674dc3ea246bfca0c | |
| parent | f38264fa567144adba2d846347d66e00b9d08f35 (diff) | |
| parent | e9ddb62c658b35e3026c470217f38a465f2a3dc7 (diff) | |
| download | rust-daa03b0b0be6bd51dd43f4556dd4e27649bc6f57.tar.gz rust-daa03b0b0be6bd51dd43f4556dd4e27649bc6f57.zip | |
Auto merge of #14800 - lowr:patch/macro-subns-and-prelude, r=Veykril
Expand more single ident macro calls upon item collection
Addresses https://github.com/rust-lang/rust-analyzer/pull/14781#issuecomment-1546201022
I believe this (almost) brings the number of unresolved names back to pre-#14781:
|r-a version|`analysis-stats compiler/rustc` (rust-lang/rust@69fef92ab2f287f072b66fb7b4f62c8bb4acba43) |
|---|---|
|pre-#14781 (b069eb720bec6ce40ab224f57d271687b19b5a07) | exprs: 2747778, ??ty: 122236 (4%), ?ty: 107826 (3%), !ty: 728 |
| #14781 (a7944a93a1520b96f079bbbcd841d6aec9e4ba5d) | exprs: 2713080, ??ty: 139651 (5%), ?ty: 114444 (4%), !ty: 730 |
| with this fix | exprs: 2747871, ??ty: 122237 (4%), ?ty: 108171 (3%), !ty: 676 |
(I haven't investigated on the increase in some numbers but hopefully not too much of a problem)
This is only a temporary solution. The core problem is that we haven't fully implemented the textual scope of legacy macros. For example, we *have been* failing to resolve `foo` in the following snippet, even before #14781 or after this patch. As noted in a FIXME, we need a way to resolve names in textual scope without eager expansion during item collection.
```rust
//- /main.rs crate:main deps:lib
lib::mk_foo!();
const A: i32 = foo!();
//^^^^^^ unresolved-macro-call
//- /lib.rs crate:lib
#[macro_export]
macro_rules! mk_foo {
() => {
macro_rules! foo { () => { 42 } }
}
}
```
| -rw-r--r-- | crates/hir-def/src/nameres/collector.rs | 37 | ||||
| -rw-r--r-- | crates/hir-def/src/nameres/path_resolution.rs | 6 | ||||
| -rw-r--r-- | crates/hir-def/src/nameres/tests/macros.rs | 33 |
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 177edcbb7f2..d1288b7b59b 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 4740fd7f449..981171013a1 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 e795b7b9b7e..7eb64beb1d7 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#" |
