From a0a78601413f27d93f91044eff4979a1d76a13c5 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 11 May 2023 15:55:41 +0900 Subject: [PATCH 1/5] Refactor --- crates/hir-def/src/nameres/collector.rs | 126 ++++++++++++------------ crates/hir/src/attrs.rs | 5 +- 2 files changed, 67 insertions(+), 64 deletions(-) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 3ec33f663a3d..2c8205d14b02 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -289,80 +289,84 @@ impl DefCollector<'_> { let module_id = self.def_map.root; let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); - if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { - self.inject_prelude(&attrs); - - // Process other crate-level attributes. - for attr in &*attrs { - let attr_name = match attr.path.as_ident() { - Some(name) => name, - None => continue, - }; + if let Some(cfg) = attrs.cfg() { + if self.cfg_options.check(&cfg) == Some(false) { + return; + } + } - if *attr_name == hir_expand::name![recursion_limit] { - if let Some(limit) = attr.string_value() { - if let Ok(limit) = limit.parse() { - self.def_map.recursion_limit = Some(limit); - } - } - continue; - } + self.inject_prelude(&attrs); - if *attr_name == hir_expand::name![crate_type] { - if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { - self.is_proc_macro = true; - } - continue; - } + // Process other crate-level attributes. + for attr in &*attrs { + let attr_name = match attr.path.as_ident() { + Some(name) => name, + None => continue, + }; - if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { - self.def_map.rustc_coherence_is_core = true; - continue; + if *attr_name == hir_expand::name![recursion_limit] { + if let Some(limit) = attr.string_value() { + if let Ok(limit) = limit.parse() { + self.def_map.recursion_limit = Some(limit); + } } + continue; + } - if *attr_name == hir_expand::name![feature] { - let hygiene = &Hygiene::new_unhygienic(); - let features = attr - .parse_path_comma_token_tree(self.db.upcast(), hygiene) - .into_iter() - .flatten() - .filter_map(|feat| match feat.segments() { - [name] => Some(name.to_smol_str()), - _ => None, - }); - self.def_map.unstable_features.extend(features); + if *attr_name == hir_expand::name![crate_type] { + if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { + self.is_proc_macro = true; } + continue; + } - let attr_is_register_like = *attr_name == hir_expand::name![register_attr] - || *attr_name == hir_expand::name![register_tool]; - if !attr_is_register_like { - continue; - } + if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { + self.def_map.rustc_coherence_is_core = true; + continue; + } - let registered_name = match attr.single_ident_value() { - Some(ident) => ident.as_name(), - _ => continue, - }; + if *attr_name == hir_expand::name![feature] { + let hygiene = &Hygiene::new_unhygienic(); + let features = attr + .parse_path_comma_token_tree(self.db.upcast(), hygiene) + .into_iter() + .flatten() + .filter_map(|feat| match feat.segments() { + [name] => Some(name.to_smol_str()), + _ => None, + }); + self.def_map.unstable_features.extend(features); + } - if *attr_name == hir_expand::name![register_attr] { - self.def_map.registered_attrs.push(registered_name.to_smol_str()); - cov_mark::hit!(register_attr); - } else { - self.def_map.registered_tools.push(registered_name.to_smol_str()); - cov_mark::hit!(register_tool); - } + let attr_is_register_like = *attr_name == hir_expand::name![register_attr] + || *attr_name == hir_expand::name![register_tool]; + if !attr_is_register_like { + continue; } - ModCollector { - def_collector: self, - macro_depth: 0, - module_id, - tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, - mod_dir: ModDir::root(), + let registered_name = match attr.single_ident_value() { + Some(ident) => ident.as_name(), + _ => continue, + }; + + if *attr_name == hir_expand::name![register_attr] { + self.def_map.registered_attrs.push(registered_name.to_smol_str()); + cov_mark::hit!(register_attr); + } else { + self.def_map.registered_tools.push(registered_name.to_smol_str()); + cov_mark::hit!(register_tool); } - .collect_in_top_module(item_tree.top_level_items()); } + + ModCollector { + def_collector: self, + macro_depth: 0, + module_id, + tree_id: TreeId::new(file_id.into(), None), + item_tree: &item_tree, + mod_dir: ModDir::root(), + } + .collect_in_top_module(item_tree.top_level_items()); } fn seed_with_inner(&mut self, tree_id: TreeId) { diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index d025aa8f5a49..f747b63d75c2 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -4,7 +4,6 @@ use hir_def::{ attr::{AttrsWithOwner, Documentation}, item_scope::ItemInNs, path::ModPath, - per_ns::PerNs, resolver::HasResolver, AttrDefId, GenericParamId, ModuleDefId, }; @@ -155,14 +154,14 @@ fn resolve_doc_path( .syntax_node() .descendants() .find_map(ast::Path::cast)?; - if ast_path.to_string() != link { + if ast_path.syntax().text() != link { return None; } ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())? }; let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); - let resolved = if resolved == PerNs::none() { + let resolved = if resolved.is_none() { resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)? } else { resolved From 34a912933323aa343ffa016b19c6e73155a26431 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 11 May 2023 18:15:28 +0900 Subject: [PATCH 2/5] fix: `column!()` and `line!()` built-in macros return u32 --- .../macro_expansion_tests/builtin_fn_macro.rs | 12 +++++------ .../hir-def/src/macro_expansion_tests/mbe.rs | 4 ++-- .../src/macro_expansion_tests/mbe/matching.rs | 2 +- .../macro_expansion_tests/mbe/regression.rs | 20 +++++++++---------- .../hir-def/src/macro_expansion_tests/mod.rs | 1 + crates/hir-expand/src/builtin_fn_macro.rs | 6 ++---- crates/hir-ty/src/tests/macros.rs | 6 ++++-- 7 files changed, 26 insertions(+), 25 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 0b72ca1eec18..6cb741dac719 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -13,12 +13,12 @@ macro_rules! column {() => {}} fn main() { column!(); } "#, - expect![[r##" + expect![[r#" #[rustc_builtin_macro] macro_rules! column {() => {}} -fn main() { 0; } -"##]], +fn main() { 0 as u32; } +"#]], ); } @@ -31,12 +31,12 @@ macro_rules! line {() => {}} fn main() { line!() } "#, - expect![[r##" + expect![[r#" #[rustc_builtin_macro] macro_rules! line {() => {}} -fn main() { 0 } -"##]], +fn main() { 0 as u32 } +"#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index 99c405fb9171..c056c077a568 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -922,7 +922,7 @@ macro_rules! m { fn bar() -> &'a Baz {} -fn bar() -> extern "Rust"fn() -> Ret {} +fn bar() -> extern "Rust" fn() -> Ret {} "#]], ); } @@ -1333,7 +1333,7 @@ macro_rules! matches { } fn main() { match 0 { - 0|1if true =>true , _=>false + 0|1 if true =>true , _=>false }; } "#]], diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs index e5fb15b6be4a..0909d8c83544 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs @@ -73,7 +73,7 @@ fn main() { macro_rules! asi { ($($stmt:stmt)*) => ($($stmt)*); } fn main() { - let a = 2let b = 5drop(b-a)println!("{}", a+b) + let a = 2 let b = 5 drop(b-a)println!("{}", a+b) } "#]], ) diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index b663a2917897..d8e4a4dcc7c2 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -297,55 +297,55 @@ macro_rules! impl_fn_for_zst { #[derive(Clone)] struct CharEscapeDebugContinue; impl Fn<(char, )> for CharEscapeDebugContinue { - #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDebug { { + #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDebug { { c.escape_debug_ext(false ) } } } impl FnMut<(char, )> for CharEscapeDebugContinue { - #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug { + #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug { Fn::call(&*self , (c, )) } } impl FnOnce<(char, )> for CharEscapeDebugContinue { type Output = char::EscapeDebug; - #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDebug { + #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDebug { Fn::call(&self , (c, )) } } #[derive(Clone)] struct CharEscapeUnicode; impl Fn<(char, )> for CharEscapeUnicode { - #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { { + #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { { c.escape_unicode() } } } impl FnMut<(char, )> for CharEscapeUnicode { - #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode { + #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode { Fn::call(&*self , (c, )) } } impl FnOnce<(char, )> for CharEscapeUnicode { type Output = char::EscapeUnicode; - #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode { + #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode { Fn::call(&self , (c, )) } } #[derive(Clone)] struct CharEscapeDefault; impl Fn<(char, )> for CharEscapeDefault { - #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDefault { { + #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDefault { { c.escape_default() } } } impl FnMut<(char, )> for CharEscapeDefault { - #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault { + #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault { Fn::call(&*self , (c, )) } } impl FnOnce<(char, )> for CharEscapeDefault { type Output = char::EscapeDefault; - #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDefault { + #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDefault { Fn::call(&self , (c, )) } } @@ -833,7 +833,7 @@ macro_rules! rgb_color { /* parse error: expected SEMICOLON */ /* parse error: expected expression, item or let statement */ pub fn new() { - let _ = 0as u32<<(8+8); + let _ = 0 as u32<<(8+8); } // MACRO_ITEMS@0..31 // FN@0..31 diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index c48c0c1aee59..a59a3dc81ef0 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -280,6 +280,7 @@ fn pretty_print_macro_expansion(expn: SyntaxNode, map: Option<&TokenMap>) -> Str let curr_kind = token.kind(); let space = match (prev_kind, curr_kind) { _ if prev_kind.is_trivia() || curr_kind.is_trivia() => "", + _ if prev_kind.is_literal() && !curr_kind.is_punct() => " ", (T!['{'], T!['}']) => "", (T![=], _) | (_, T![=]) => " ", (_, T!['{']) => " ", diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 9a25141d8f19..9c8dc4ed1fca 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -135,9 +135,8 @@ fn line_expand( _tt: &tt::Subtree, ) -> ExpandResult { // dummy implementation for type-checking purposes - let line_num = 0; let expanded = quote! { - #line_num + 0 as u32 }; ExpandResult::ok(expanded) @@ -179,9 +178,8 @@ fn column_expand( _tt: &tt::Subtree, ) -> ExpandResult { // dummy implementation for type-checking purposes - let col_num = 0; let expanded = quote! { - #col_num + 0 as u32 }; ExpandResult::ok(expanded) diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index d45edf730ad5..9377a3a5f26a 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -661,8 +661,9 @@ fn infer_builtin_macros_line() { "#, expect![[r#" !0..1 '0': i32 + !0..6 '0asu32': u32 63..87 '{ ...!(); }': () - 73..74 'x': i32 + 73..74 'x': u32 "#]], ); } @@ -699,8 +700,9 @@ fn infer_builtin_macros_column() { "#, expect![[r#" !0..1 '0': i32 + !0..6 '0asu32': u32 65..91 '{ ...!(); }': () - 75..76 'x': i32 + 75..76 'x': u32 "#]], ); } From 96113b7b8e3239b14768f009728f1dc094a4612f Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 10 May 2023 18:27:28 +0900 Subject: [PATCH 3/5] Remove prelude fallback path for Rust <1.52.0 We've already removed non-sysroot proc macro server, which effectively removed support for Rust <1.64.0, so this removal of fallback path shouldn't be problem at this point. --- crates/hir-def/src/nameres/collector.rs | 40 +++++++++---------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 2c8205d14b02..2d8870af9fbf 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -547,33 +547,21 @@ impl DefCollector<'_> { Edition::Edition2015 => PathKind::Plain, _ => PathKind::Abs, }; - let path = - ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter()); - // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0 - // FIXME remove this fallback - let fallback_path = - ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter()); - - for path in &[path, fallback_path] { - let (per_ns, _) = self.def_map.resolve_path( - self.db, - self.def_map.root, - path, - BuiltinShadowMode::Other, - ); + let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]); - match per_ns.types { - Some((ModuleDefId::ModuleId(m), _)) => { - self.def_map.prelude = Some(m); - break; - } - types => { - tracing::debug!( - "could not resolve prelude path `{}` to module (resolved to {:?})", - path, - types - ); - } + let (per_ns, _) = + self.def_map.resolve_path(self.db, self.def_map.root, &path, BuiltinShadowMode::Other); + + match per_ns.types { + Some((ModuleDefId::ModuleId(m), _)) => { + self.def_map.prelude = Some(m); + } + types => { + tracing::debug!( + "could not resolve prelude path `{}` to module (resolved to {:?})", + path, + types + ); } } } From 3203ea896d1ed9f6b8a8af25a8028df51a6bd5b3 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 11 May 2023 15:41:24 +0900 Subject: [PATCH 4/5] Add `macro_use` prelude to `DefMap` --- crates/hir-def/src/nameres.rs | 6 ++ crates/hir-def/src/nameres/collector.rs | 28 +++++---- crates/hir-def/src/nameres/path_resolution.rs | 13 ++++- crates/hir-def/src/nameres/tests/macros.rs | 57 ++++++++++++++++--- 4 files changed, 84 insertions(+), 20 deletions(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 803342fdab50..2e5f090ce76d 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -105,6 +105,9 @@ pub struct DefMap { prelude: Option, /// The extern prelude is only populated for non-block DefMaps extern_prelude: FxHashMap, + /// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that + /// this contains all kinds of macro, not just `macro_rules!` macro. + macro_use_prelude: FxHashMap, /// Side table for resolving derive helpers. exported_derives: FxHashMap>, @@ -277,6 +280,7 @@ impl DefMap { edition, recursion_limit: None, extern_prelude: FxHashMap::default(), + macro_use_prelude: FxHashMap::default(), exported_derives: FxHashMap::default(), fn_proc_macro_mapping: FxHashMap::default(), proc_macro_loading_error: None, @@ -489,6 +493,7 @@ impl DefMap { _c: _, exported_derives, extern_prelude, + macro_use_prelude, diagnostics, modules, registered_attrs, @@ -507,6 +512,7 @@ impl DefMap { } = self; extern_prelude.shrink_to_fit(); + macro_use_prelude.shrink_to_fit(); exported_derives.shrink_to_fit(); diagnostics.shrink_to_fit(); modules.shrink_to_fit(); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 2d8870af9fbf..84e9b9f57190 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -707,6 +707,7 @@ impl DefCollector<'_> { } /// Import macros from `#[macro_use] extern crate`. + // FIXME: Support `#[macro_rules(macro_name, ...)]`. fn import_macros_from_extern_crate( &mut self, current_module_id: LocalModuleId, @@ -725,7 +726,7 @@ impl DefCollector<'_> { } cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); - self.import_all_macros_exported(current_module_id, m.krate); + self.import_all_macros_exported(m.krate); } } @@ -734,11 +735,12 @@ impl DefCollector<'_> { /// Exported macros are just all macros in the root module scope. /// Note that it contains not only all `#[macro_export]` macros, but also all aliases /// created by `use` in the root module, ignoring the visibility of `use`. - fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) { + fn import_all_macros_exported(&mut self, krate: CrateId) { let def_map = self.db.crate_def_map(krate); for (name, def) in def_map[def_map.root].scope.macros() { - // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros. - self.define_legacy_macro(current_module_id, name.clone(), def); + // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!` + // macros. + self.def_map.macro_use_prelude.insert(name.clone(), def); } } @@ -1509,6 +1511,7 @@ impl ModCollector<'_, '_> { fn collect(&mut self, items: &[ModItem], container: ItemContainerId) { let krate = self.def_collector.def_map.krate; + let is_crate_root = self.module_id == self.def_collector.def_map.root; // Note: don't assert that inserted value is fresh: it's simply not true // for macros. @@ -1516,19 +1519,24 @@ impl ModCollector<'_, '_> { // Prelude module is always considered to be `#[macro_use]`. if let Some(prelude_module) = self.def_collector.def_map.prelude { - if prelude_module.krate != krate { + if prelude_module.krate != krate && is_crate_root { cov_mark::hit!(prelude_is_macro_use); - self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); + self.def_collector.import_all_macros_exported(prelude_module.krate); } } // This should be processed eagerly instead of deferred to resolving. // `#[macro_use] extern crate` is hoisted to imports macros before collecting // any other items. - for &item in items { - let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into()); - if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { - if let ModItem::ExternCrate(id) = item { + // + // If we're not at the crate root, `macro_use`d extern crates are an error so let's just + // ignore them. + // FIXME: Support `#[macro_rules(macro_name, ...)]`. + if is_crate_root { + for &item in items { + let ModItem::ExternCrate(id) = item else { continue; }; + let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into()); + if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { let import = &self.item_tree[id]; let attrs = self.item_tree.attrs( self.def_collector.db, diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 8299d9684bbb..5b454620e7bb 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -385,7 +385,7 @@ impl DefMap { // Resolve in: // - legacy scope of macro // - current module / scope - // - extern prelude + // - extern prelude / macro_use prelude // - std prelude let from_legacy_macro = self[module] .scope @@ -414,9 +414,18 @@ impl DefMap { .get(name) .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)) }; + let macro_use_prelude = || { + self.macro_use_prelude + .get(name) + .map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public)) + }; let prelude = || self.resolve_in_prelude(db, name); - from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude) + from_legacy_macro + .or(from_scope_or_builtin) + .or_else(extern_prelude) + .or_else(macro_use_prelude) + .or_else(prelude) } fn resolve_name_in_crate_root_or_extern_prelude( diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index 6ee56c9368e4..ea3209b9c20a 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -1216,17 +1216,58 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } "#, ); - let root = &def_map[def_map.root()].scope; - let actual = root - .legacy_macros() - .sorted_by(|a, b| std::cmp::Ord::cmp(&a.0, &b.0)) - .map(|(name, _)| format!("{name}\n")) - .collect::(); + let root_module = &def_map[def_map.root()].scope; + assert!( + root_module.legacy_macros().count() == 0, + "`#[macro_use]` shouldn't bring macros into textual macro scope", + ); + + let actual = def_map.macro_use_prelude.iter().map(|(name, _)| name).sorted().join("\n"); expect![[r#" legacy macro20 - proc_attr - "#]] + proc_attr"#]] .assert_eq(&actual); } + +#[test] +fn non_prelude_macros_take_precedence_over_macro_use_prelude() { + check( + r#" +//- /lib.rs edition:2021 crate:lib deps:dep,core +#[macro_use] +extern crate dep; + +macro foo() { struct Ok; } +macro bar() { fn ok() {} } + +foo!(); +bar!(); + +//- /dep.rs crate:dep +#[macro_export] +macro_rules! foo { + () => { struct NotOk; } +} + +//- /core.rs crate:core +pub mod prelude { + pub mod rust_2021 { + #[macro_export] + macro_rules! bar { + () => { fn not_ok() {} } + } + } +} + "#, + expect![[r#" + crate + Ok: t v + bar: m + dep: t + foo: m + ok: v + "#]], + ); +} From f2a35deb50fb5c6e28c5eddbd6a4cffd47ddb444 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 11 May 2023 15:52:13 +0900 Subject: [PATCH 5/5] Consider macro sub-namespace during name resolution --- crates/hir-def/src/body/lower.rs | 11 +++- crates/hir-def/src/data.rs | 3 +- crates/hir-def/src/find_path.rs | 1 + crates/hir-def/src/generics.rs | 3 +- .../hir-def/src/macro_expansion_tests/mod.rs | 13 +++- crates/hir-def/src/nameres.rs | 62 +++++++++++++++++-- crates/hir-def/src/nameres/attr_resolution.rs | 5 +- crates/hir-def/src/nameres/collector.rs | 21 ++++++- crates/hir-def/src/nameres/path_resolution.rs | 45 ++++++++++++-- crates/hir-def/src/nameres/tests/macros.rs | 54 ++++++++++++++++ crates/hir-def/src/resolver.rs | 20 ++++-- crates/hir-ty/src/lower.rs | 13 +++- crates/hir/src/attrs.rs | 1 + crates/hir/src/semantics.rs | 3 +- crates/hir/src/source_analyzer.rs | 17 +++-- 15 files changed, 236 insertions(+), 36 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 80aa1af057c7..d92698a938a7 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -37,7 +37,7 @@ use crate::{ item_scope::BuiltinShadowMode, lang_item::LangItem, lower::LowerCtx, - nameres::DefMap, + nameres::{DefMap, MacroSubNs}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro, @@ -800,7 +800,13 @@ impl ExprCollector<'_> { let module = self.expander.module.local_id; let res = self.expander.enter_expand(self.db, mcall, |path| { self.def_map - .resolve_path(self.db, module, &path, crate::item_scope::BuiltinShadowMode::Other) + .resolve_path( + self.db, + module, + &path, + crate::item_scope::BuiltinShadowMode::Other, + Some(MacroSubNs::Bang), + ) .0 .take_macros() }); @@ -1056,6 +1062,7 @@ impl ExprCollector<'_> { self.expander.module.local_id, &name.clone().into(), BuiltinShadowMode::Other, + None, ); match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index de67f0b23cfc..40e6a4308784 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -22,7 +22,7 @@ use crate::{ attr_resolution::ResolvedAttr, diagnostics::DefDiagnostic, proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind}, - DefMap, + DefMap, MacroSubNs, }, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, @@ -673,6 +673,7 @@ impl<'a> AssocItemCollector<'a> { module, &path, crate::item_scope::BuiltinShadowMode::Other, + Some(MacroSubNs::Bang), ) .0 .take_macros() diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 30d6d0193090..b401762255ef 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -543,6 +543,7 @@ mod tests { module.local_id, &mod_path, crate::item_scope::BuiltinShadowMode::Module, + None, ) .0 .take_types() diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index c79c17096305..f19c3f028f42 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -22,7 +22,7 @@ use crate::{ dyn_map::{keys, DynMap}, expander::Expander, lower::LowerCtx, - nameres::DefMap, + nameres::{DefMap, MacroSubNs}, src::{HasChildSource, HasSource}, type_ref::{LifetimeRef, TypeBound, TypeRef}, AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, @@ -361,6 +361,7 @@ impl GenericParams { module, &path, crate::item_scope::BuiltinShadowMode::Other, + Some(MacroSubNs::Bang), ) .0 .take_macros() diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index a59a3dc81ef0..40849d4a66d8 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -33,8 +33,13 @@ use syntax::{ use tt::token_id::{Subtree, TokenId}; use crate::{ - db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver, - src::HasSource, test_db::TestDB, AdtId, AsMacroCall, Lookup, ModuleDefId, + db::DefDatabase, + macro_id_to_def_id, + nameres::{MacroSubNs, ModuleSource}, + resolver::HasResolver, + src::HasSource, + test_db::TestDB, + AdtId, AsMacroCall, Lookup, ModuleDefId, }; #[track_caller] @@ -127,7 +132,9 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let macro_call = InFile::new(source.file_id, ¯o_call); let res = macro_call .as_call_id_with_errors(&db, krate, |path| { - resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it)) + resolver + .resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang)) + .map(|it| macro_id_to_def_id(&db, it)) }) .unwrap(); let macro_call_id = res.value.unwrap(); diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 2e5f090ce76d..39a56814ed88 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -59,7 +59,7 @@ mod tests; use std::{cmp::Ord, ops::Deref}; -use base_db::{CrateId, Edition, FileId}; +use base_db::{CrateId, Edition, FileId, ProcMacroKind}; use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; use itertools::Itertools; use la_arena::Arena; @@ -77,7 +77,8 @@ use crate::{ path::ModPath, per_ns::PerNs, visibility::Visibility, - AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId, + AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, + ProcMacroId, }; /// Contains the results of (early) name resolution. @@ -380,9 +381,16 @@ impl DefMap { original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + expected_macro_subns: Option, ) -> (PerNs, Option) { - let res = - self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); + let res = self.resolve_path_fp_with_macro( + db, + ResolveMode::Other, + original_module, + path, + shadow, + expected_macro_subns, + ); (res.resolved_def, res.segment_index) } @@ -399,6 +407,7 @@ impl DefMap { original_module, path, shadow, + None, // Currently this function isn't used for macro resolution. ); (res.resolved_def, res.segment_index) } @@ -568,3 +577,48 @@ pub enum ModuleSource { Module(ast::Module), BlockExpr(ast::BlockExpr), } + +/// See `sub_namespace_match()`. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum MacroSubNs { + /// Function-like macros, suffixed with `!`. + Bang, + /// Macros inside attributes, i.e. attribute macros and derive macros. + Attr, +} + +impl MacroSubNs { + fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self { + let expander = match macro_id { + MacroId::Macro2Id(it) => it.lookup(db).expander, + MacroId::MacroRulesId(it) => it.lookup(db).expander, + MacroId::ProcMacroId(it) => { + return match it.lookup(db).kind { + ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr, + ProcMacroKind::FuncLike => Self::Bang, + }; + } + }; + + // Eager macros aren't *guaranteed* to be bang macros, but they *are* all bang macros currently. + match expander { + MacroExpander::Declarative + | MacroExpander::BuiltIn(_) + | MacroExpander::BuiltInEager(_) => Self::Bang, + MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr, + } + } +} + +/// Quoted from [rustc]: +/// Macro namespace is separated into two sub-namespaces, one for bang macros and +/// one for attribute-like macros (attributes, derives). +/// We ignore resolutions from one sub-namespace when searching names in scope for another. +/// +/// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75 +fn sub_namespace_match(candidate: Option, expected: Option) -> bool { + match (candidate, expected) { + (Some(candidate), Some(expected)) => candidate == expected, + _ => true, + } +} diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs index 84271ef51d8e..6567bda709d6 100644 --- a/crates/hir-def/src/nameres/attr_resolution.rs +++ b/crates/hir-def/src/nameres/attr_resolution.rs @@ -14,7 +14,7 @@ use crate::{ AstIdWithPath, LocalModuleId, UnresolvedMacro, }; -use super::DefMap; +use super::{DefMap, MacroSubNs}; pub enum ResolvedAttr { /// Attribute resolved to an attribute macro. @@ -43,9 +43,12 @@ impl DefMap { original_module, &ast_id.path, BuiltinShadowMode::Module, + Some(MacroSubNs::Attr), ); let def = match resolved_res.resolved_def.take_macros() { Some(def) => { + // `MacroSubNs` is just a hint, so the path may still resolve to a custom derive + // macro, or even function-like macro when the path is qualified. if def.is_attribute(db) { def } else { diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 84e9b9f57190..177edcbb7f24 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -44,7 +44,7 @@ use crate::{ mod_resolution::ModDir, path_resolution::ReachedFixedPoint, proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind}, - BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, + BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode, }, path::{ImportAlias, ModPath, PathKind}, per_ns::PerNs, @@ -549,8 +549,13 @@ impl DefCollector<'_> { }; let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]); - let (per_ns, _) = - self.def_map.resolve_path(self.db, self.def_map.root, &path, BuiltinShadowMode::Other); + let (per_ns, _) = self.def_map.resolve_path( + self.db, + self.def_map.root, + &path, + BuiltinShadowMode::Other, + None, + ); match per_ns.types { Some((ModuleDefId::ModuleId(m), _)) => { @@ -796,6 +801,7 @@ impl DefCollector<'_> { module_id, &import.path, BuiltinShadowMode::Module, + None, // An import may resolve to any kind of macro. ); let def = res.resolved_def; @@ -1093,7 +1099,14 @@ impl DefCollector<'_> { resolved.push((directive.module_id, directive.depth, directive.container, call_id)); }; let mut res = ReachedFixedPoint::Yes; + // Retain unresolved macros after this round of resolution. macros.retain(|directive| { + let subns = match &directive.kind { + MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang, + MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => { + MacroSubNs::Attr + } + }; let resolver = |path| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, @@ -1101,6 +1114,7 @@ impl DefCollector<'_> { directive.module_id, &path, BuiltinShadowMode::Module, + Some(subns), ); resolved_res .resolved_def @@ -1419,6 +1433,7 @@ impl DefCollector<'_> { directive.module_id, &path, BuiltinShadowMode::Module, + Some(MacroSubNs::Bang), ); resolved_res .resolved_def diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 5b454620e7bb..4740fd7f4499 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -16,7 +16,7 @@ use hir_expand::name::Name; use crate::{ db::DefDatabase, item_scope::BUILTIN_SCOPE, - nameres::{BuiltinShadowMode, DefMap}, + nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs}, path::{ModPath, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, @@ -58,6 +58,17 @@ impl ResolvePathResult { } } +impl PerNs { + fn filter_macro(mut self, db: &dyn DefDatabase, expected: Option) -> Self { + self.macros = self.macros.filter(|&(id, _)| { + let this = MacroSubNs::from_id(db, id); + sub_namespace_match(Some(this), expected) + }); + + self + } +} + impl DefMap { pub(super) fn resolve_name_in_extern_prelude( &self, @@ -83,7 +94,7 @@ impl DefMap { let mut vis = match visibility { RawVisibility::Module(path) => { let (result, remaining) = - self.resolve_path(db, original_module, path, BuiltinShadowMode::Module); + self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None); if remaining.is_some() { return None; } @@ -124,6 +135,9 @@ impl DefMap { mut original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + // Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're + // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths. + expected_macro_subns: Option, ) -> ResolvePathResult { let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); @@ -136,6 +150,7 @@ impl DefMap { original_module, path, shadow, + expected_macro_subns, ); // Merge `new` into `result`. @@ -169,6 +184,7 @@ impl DefMap { original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + expected_macro_subns: Option, ) -> ResolvePathResult { let graph = db.crate_graph(); let _cx = stdx::panic_context::enter(format!( @@ -220,7 +236,13 @@ impl DefMap { if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module }; tracing::debug!("resolving {:?} in module", segment); - self.resolve_name_in_module(db, original_module, segment, prefer_module) + self.resolve_name_in_module( + db, + original_module, + segment, + prefer_module, + expected_macro_subns, + ) } PathKind::Super(lvl) => { let mut module = original_module; @@ -245,6 +267,7 @@ impl DefMap { block.parent.local_id, &new_path, shadow, + expected_macro_subns, ); } None => { @@ -303,7 +326,12 @@ impl DefMap { ); tracing::debug!("resolving {:?} in other crate", path); let defp_map = module.def_map(db); - let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); + // Macro sub-namespaces only matter when resolving single-segment paths + // because `macro_use` and other preludes should be taken into account. At + // this point, we know we're resolving a multi-segment path so macro kind + // expectation is discarded. + let (def, s) = + defp_map.resolve_path(db, module.local_id, &path, shadow, None); return ResolvePathResult::with( def, ReachedFixedPoint::Yes, @@ -381,6 +409,7 @@ impl DefMap { module: LocalModuleId, name: &Name, shadow: BuiltinShadowMode, + expected_macro_subns: Option, ) -> PerNs { // Resolve in: // - legacy scope of macro @@ -392,8 +421,12 @@ impl DefMap { .get_legacy_macro(name) // FIXME: shadowing .and_then(|it| it.last()) - .map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public)); - let from_scope = self[module].scope.get(name); + .copied() + .filter(|&id| { + sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns) + }) + .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); + let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns); let from_builtin = match self.block { Some(_) => { // Only resolve to builtins in the root `DefMap`. diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index ea3209b9c20a..e795b7b9b7e6 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -1271,3 +1271,57 @@ pub mod prelude { "#]], ); } + +#[test] +fn macro_sub_namespace() { + let map = compute_crate_def_map( + r#" +//- minicore: derive, clone +macro_rules! Clone { () => {} } +macro_rules! derive { () => {} } + +#[derive(Clone)] +struct S; + "#, + ); + assert_eq!(map.modules[map.root].scope.impls().len(), 1); +} + +#[test] +fn macro_sub_namespace2() { + check( + r#" +//- /main.rs edition:2021 crate:main deps:proc,core +use proc::{foo, bar}; + +foo!(); +bar!(); + +//- /proc.rs crate:proc +#![crate_type="proc-macro"] +#[proc_macro_derive(foo)] +pub fn foo() {} +#[proc_macro_attribute] +pub fn bar() {} + +//- /core.rs crate:core +pub mod prelude { + pub mod rust_2021 { + pub macro foo() { + struct Ok; + } + pub macro bar() { + fn ok() {} + } + } +} + "#, + expect![[r#" + crate + Ok: t v + bar: m + foo: m + ok: v + "#]], + ); +} diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 45ec454b9ebc..4bec2b4dea42 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -17,7 +17,7 @@ use crate::{ hir::{BindingId, ExprId, LabelId}, item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, lang_item::LangItemTarget, - nameres::DefMap, + nameres::{DefMap, MacroSubNs}, path::{ModPath, Path, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, @@ -155,7 +155,8 @@ impl Resolver { path: &ModPath, ) -> Option { let (item_map, module) = self.item_scope(); - let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module); + let (module_res, idx) = + item_map.resolve_path(db, module, path, BuiltinShadowMode::Module, None); match module_res.take_types()? { ModuleDefId::TraitId(it) => { let idx = idx?; @@ -385,9 +386,17 @@ impl Resolver { } } - pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { + pub fn resolve_path_as_macro( + &self, + db: &dyn DefDatabase, + path: &ModPath, + expected_macro_kind: Option, + ) -> Option { let (item_map, module) = self.item_scope(); - item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros() + item_map + .resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind) + .0 + .take_macros() } /// Returns a set of names available in the current scope. @@ -626,7 +635,8 @@ impl Resolver { shadow: BuiltinShadowMode, ) -> PerNs { let (item_map, module) = self.item_scope(); - let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); + // This method resolves `path` just like import paths, so no expected macro subns is given. + let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None); if segment_index.is_some() { return PerNs::none(); } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 4000ba5c14c5..098b677b1501 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -24,6 +24,7 @@ use hir_def::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, lang_item::{lang_attr, LangItem}, + nameres::MacroSubNs, path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, @@ -378,9 +379,15 @@ impl<'a> TyLoweringContext<'a> { }; let ty = { let macro_call = macro_call.to_node(self.db.upcast()); - match expander.enter_expand::(self.db.upcast(), macro_call, |path| { - self.resolver.resolve_path_as_macro(self.db.upcast(), &path) - }) { + let resolver = |path| { + self.resolver.resolve_path_as_macro( + self.db.upcast(), + &path, + Some(MacroSubNs::Bang), + ) + }; + match expander.enter_expand::(self.db.upcast(), macro_call, resolver) + { Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { let ctx = expander.ctx(self.db.upcast()); // FIXME: Report syntax errors in expansion here diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index f747b63d75c2..b817937296d2 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -120,6 +120,7 @@ impl HasAttrs for AssocItem { } } +/// Resolves the item `link` points to in the scope of `def`. fn resolve_doc_path( db: &dyn HirDatabase, def: AttrDefId, diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 81ea99522f75..2d2b00b147e5 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -10,6 +10,7 @@ use hir_def::{ hir::Expr, lower::LowerCtx, macro_id_to_def_id, + nameres::MacroSubNs, resolver::{self, HasResolver, Resolver, TypeNs}, type_ref::Mutability, AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId, @@ -616,7 +617,7 @@ impl<'db> SemanticsImpl<'db> { let krate = resolver.krate(); let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { resolver - .resolve_path_as_macro(self.db.upcast(), &path) + .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang)) .map(|it| macro_id_to_def_id(self.db.upcast(), it)) })?; hir_expand::db::expand_speculative( diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 159601955f83..dae77fad2f37 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -17,6 +17,7 @@ use hir_def::{ lang_item::LangItem, lower::LowerCtx, macro_id_to_def_id, + nameres::MacroSubNs, path::{ModPath, Path, PathKind}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, type_ref::Mutability, @@ -484,7 +485,9 @@ impl SourceAnalyzer { ) -> Option { let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id); let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; - self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(|it| it.into()) + self.resolver + .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang)) + .map(|it| it.into()) } pub(crate) fn resolve_bind_pat_to_const( @@ -678,7 +681,7 @@ impl SourceAnalyzer { } } } - return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) { + return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) { Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))), // this labels any path that starts with a tool module as the tool itself, this is technically wrong // but there is no benefit in differentiating these two cases for the time being @@ -756,7 +759,7 @@ impl SourceAnalyzer { let krate = self.resolver.krate(); let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { self.resolver - .resolve_path_as_macro(db.upcast(), &path) + .resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang)) .map(|it| macro_id_to_def_id(db.upcast(), it)) })?; Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64) @@ -956,12 +959,14 @@ pub(crate) fn resolve_hir_path( } #[inline] -pub(crate) fn resolve_hir_path_as_macro( +pub(crate) fn resolve_hir_path_as_attr_macro( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, ) -> Option { - resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(Into::into) + resolver + .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr)) + .map(Into::into) } fn resolve_hir_path_( @@ -1060,7 +1065,7 @@ fn resolve_hir_path_( let macros = || { resolver - .resolve_path_as_macro(db.upcast(), path.mod_path()?) + .resolve_path_as_macro(db.upcast(), path.mod_path()?, None) .map(|def| PathResolution::Def(ModuleDef::Macro(def.into()))) };