From 6d45afd8d8a27b835045fe75035336f7d42fe195 Mon Sep 17 00:00:00 2001 From: tamasfe Date: Fri, 17 Nov 2023 15:25:20 +0100 Subject: [PATCH 1/3] feat: ignored and disabled macro expansion --- crates/base-db/src/input.rs | 1 + crates/hir-def/src/data.rs | 11 +++++++- crates/hir-def/src/nameres/collector.rs | 34 ++++++++++++++++++++++--- crates/hir-expand/src/lib.rs | 3 +++ crates/hir-expand/src/proc_macro.rs | 25 ++++++++++++++++++ crates/load-cargo/src/lib.rs | 14 +++++++--- crates/rust-analyzer/src/config.rs | 2 +- crates/rust-analyzer/src/reload.rs | 27 +++++++++++++++++--- 8 files changed, 105 insertions(+), 12 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 9560826e373..1db8c2f29d3 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -243,6 +243,7 @@ pub fn from_canonical_name(canonical_name: String) -> CrateDisplayName { CrateDisplayName { crate_name, canonical_name } } } + pub type TargetLayoutLoadResult = Result, Arc>; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 7ce05b64d02..d6aab11afd5 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -634,7 +634,6 @@ fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[Asso attr, ) { Ok(ResolvedAttr::Macro(call_id)) => { - self.attr_calls.push((ast_id, call_id)); // If proc attribute macro expansion is disabled, skip expanding it here if !self.db.expand_proc_attr_macros() { continue 'attrs; @@ -647,10 +646,20 @@ fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[Asso // disabled. This is analogous to the handling in // `DefCollector::collect_macros`. if exp.is_dummy() { + self.diagnostics.push(DefDiagnostic::unresolved_proc_macro( + self.module_id.local_id, + loc.kind, + loc.def.krate, + )); + + continue 'attrs; + } else if exp.is_disabled() { continue 'attrs; } } + self.attr_calls.push((ast_id, call_id)); + let res = self.expander.enter_expand_id::(self.db, call_id); self.collect_macro_items(res, &|| loc.kind.clone()); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 21cc28f1b3d..d3c8c813640 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -98,9 +98,13 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI }; ( name.as_name(), - CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId( - idx as u32, - )), + if it.expander.should_expand() { + CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId( + idx as u32, + )) + } else { + CustomProcMacroExpander::disabled() + }, ) }) .collect()) @@ -1156,6 +1160,28 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { self.def_map.modules[directive.module_id] .scope .add_macro_invoc(ast_id.ast_id, call_id); + + let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id); + + if let MacroDefKind::ProcMacro(expander, _, _) = loc.def.kind { + if expander.is_dummy() || expander.is_disabled() { + // If there's no expander for the proc macro (e.g. + // because proc macros are disabled, or building the + // proc macro crate failed), report this and skip + // expansion like we would if it was disabled + self.def_map.diagnostics.push( + DefDiagnostic::unresolved_proc_macro( + directive.module_id, + loc.kind, + loc.def.krate, + ), + ); + + res = ReachedFixedPoint::No; + return false; + } + } + push_resolved(directive, call_id); res = ReachedFixedPoint::No; @@ -1348,6 +1374,8 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { def.krate, )); + return recollect_without(self); + } else if exp.is_disabled() { return recollect_without(self); } } diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index fd028182faf..42a8864c6a7 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -129,6 +129,8 @@ pub trait Lookup { #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum ExpandError { UnresolvedProcMacro(CrateId), + /// The macro expansion is disabled. + MacroDisabled, Mbe(mbe::ExpandError), RecursionOverflowPoisoned, Other(Box>), @@ -160,6 +162,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(it) } ExpandError::Other(it) => f.write_str(it), + ExpandError::MacroDisabled => f.write_str("macro disabled"), } } } diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index 70b47fc54b1..f745ff23efb 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -31,6 +31,16 @@ fn expand( call_site: Span, mixed_site: Span, ) -> Result; + + /// If this returns `false`, expansions via [`expand`](ProcMacroExpander::expand) will always + /// return the input subtree or will always return an error. + /// + /// This is used to skip any additional expansion-related work, + /// e.g. to make sure we do not touch the syntax tree in any way + /// if a proc macro will never be expanded. + fn should_expand(&self) -> bool { + true + } } #[derive(Debug)] @@ -57,6 +67,7 @@ pub struct CustomProcMacroExpander { } const DUMMY_ID: u32 = !0; +const DISABLED_ID: u32 = !1; impl CustomProcMacroExpander { pub fn new(proc_macro_id: ProcMacroId) -> Self { @@ -68,10 +79,20 @@ pub fn dummy() -> Self { Self { proc_macro_id: ProcMacroId(DUMMY_ID) } } + /// The macro was not yet resolved. pub fn is_dummy(&self) -> bool { self.proc_macro_id.0 == DUMMY_ID } + pub fn disabled() -> Self { + Self { proc_macro_id: ProcMacroId(DISABLED_ID) } + } + + /// The macro is explicitly disabled and cannot be expanded. + pub fn is_disabled(&self) -> bool { + self.proc_macro_id.0 == DISABLED_ID + } + pub fn expand( self, db: &dyn ExpandDatabase, @@ -88,6 +109,10 @@ pub fn expand( tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), ExpandError::UnresolvedProcMacro(def_crate), ), + ProcMacroId(DISABLED_ID) => ExpandResult::new( + tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), + ExpandError::MacroDisabled, + ), ProcMacroId(id) => { let proc_macros = db.proc_macros(); let proc_macros = match proc_macros.get(&def_crate) { diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index c6dc071c394..dc9005f5838 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -273,7 +273,7 @@ pub fn partition(&self, vfs: &vfs::Vfs) -> Vec { pub fn load_proc_macro( server: &ProcMacroServer, path: &AbsPath, - dummy_replace: &[Box], + ignored_macros: &[Box], ) -> ProcMacroLoadResult { let res: Result, String> = (|| { let dylib = MacroDylib::new(path.to_path_buf()); @@ -283,7 +283,7 @@ pub fn load_proc_macro( } Ok(vec .into_iter() - .map(|expander| expander_to_proc_macro(expander, dummy_replace)) + .map(|expander| expander_to_proc_macro(expander, ignored_macros)) .collect()) })(); match res { @@ -349,7 +349,7 @@ fn load_crate_graph( fn expander_to_proc_macro( expander: proc_macro_api::ProcMacro, - dummy_replace: &[Box], + ignored_macros: &[Box], ) -> ProcMacro { let name = From::from(expander.name()); let kind = match expander.kind() { @@ -358,7 +358,7 @@ fn expander_to_proc_macro( proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, }; let expander: sync::Arc = - if dummy_replace.iter().any(|replace| **replace == name) { + if ignored_macros.iter().any(|replace| &**replace == name) { match kind { ProcMacroKind::Attr => sync::Arc::new(IdentityExpander), _ => sync::Arc::new(EmptyExpander), @@ -407,6 +407,9 @@ fn expand( ) -> Result, ProcMacroExpansionError> { Ok(subtree.clone()) } + fn should_expand(&self) -> bool { + false + } } /// Empty expander, used for proc-macros that are deliberately ignored by the user. @@ -425,6 +428,9 @@ fn expand( ) -> Result, ProcMacroExpansionError> { Ok(tt::Subtree::empty(DelimSpan { open: call_site, close: call_site })) } + fn should_expand(&self) -> bool { + false + } } #[cfg(test)] diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 7bdd9ec866a..bf3e71a6bdb 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1202,7 +1202,7 @@ pub fn proc_macro_srv(&self) -> Option { Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path))) } - pub fn dummy_replacements(&self) -> &FxHashMap, Box<[Box]>> { + pub fn ignored_proc_macros(&self) -> &FxHashMap, Box<[Box]>> { &self.data.procMacro_ignored } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 5a5d26e0b05..14d622abfe2 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -299,13 +299,13 @@ pub(crate) fn fetch_build_data(&mut self, cause: Cause) { pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec) { tracing::info!(%cause, "will load proc macros"); - let dummy_replacements = self.config.dummy_replacements().clone(); + let ignored_proc_macros = self.config.ignored_proc_macros().clone(); let proc_macro_clients = self.proc_macro_clients.clone(); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { sender.send(Task::LoadProcMacros(ProcMacroProgress::Begin)).unwrap(); - let dummy_replacements = &dummy_replacements; + let ignored_proc_macros = &ignored_proc_macros; let progress = { let sender = sender.clone(); &move |msg| { @@ -333,7 +333,13 @@ pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec bool { + if s1.len() != s2.len() { + return false; + } + + s1.as_bytes().iter().zip(s2.as_bytes()).all(|(c1, c2)| { + let c1_underscore = c1 == &b'_' || c1 == &b'-'; + let c2_underscore = c2 == &b'_' || c2 == &b'-'; + + c1 == c2 || (c1_underscore && c2_underscore) + }) +} From ab50ec9863689524f2b8bb44b3e20e73ff27aafd Mon Sep 17 00:00:00 2001 From: tamasfe Date: Fri, 17 Nov 2023 15:55:55 +0100 Subject: [PATCH 2/3] fix(macros): no diagnostics for disabled macro --- crates/hir-def/src/nameres/collector.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index d3c8c813640..7a957e86942 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -1164,7 +1164,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id); if let MacroDefKind::ProcMacro(expander, _, _) = loc.def.kind { - if expander.is_dummy() || expander.is_disabled() { + if expander.is_dummy() { // If there's no expander for the proc macro (e.g. // because proc macros are disabled, or building the // proc macro crate failed), report this and skip @@ -1177,6 +1177,9 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { ), ); + res = ReachedFixedPoint::No; + return false; + } else if expander.is_disabled() { res = ReachedFixedPoint::No; return false; } From e2a985e93f0320120aa00bce376c95c49a66531d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 12 Feb 2024 13:34:38 +0100 Subject: [PATCH 3/3] Encode disabled proc-macros via boolean flag, not special Expander --- crates/hir-def/src/data.rs | 3 +- .../hir-def/src/macro_expansion_tests/mod.rs | 1 + crates/hir-def/src/nameres/collector.rs | 114 ++++++++---------- crates/hir-def/src/nameres/diagnostics.rs | 3 + crates/hir-expand/src/proc_macro.rs | 45 +++---- crates/load-cargo/src/lib.rs | 55 +-------- crates/rust-analyzer/src/reload.rs | 13 +- crates/test-fixture/src/lib.rs | 5 + 8 files changed, 91 insertions(+), 148 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index d6aab11afd5..f506864902c 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -653,7 +653,8 @@ fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[Asso )); continue 'attrs; - } else if exp.is_disabled() { + } + if exp.is_disabled() { continue 'attrs; } } diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index fc5a6e80a42..23b10cfd8e6 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -58,6 +58,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream name: "identity_when_valid".into(), kind: ProcMacroKind::Attr, expander: sync::Arc::new(IdentityWhenValidProcMacroExpander), + disabled: false, }, )]; let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 7a957e86942..8f64df280c1 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -11,7 +11,7 @@ use hir_expand::{ ast_id_map::FileAstId, attrs::{Attr, AttrId}, - builtin_attr_macro::find_builtin_attr, + builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander}, builtin_derive_macro::find_builtin_derive, builtin_fn_macro::find_builtin_macro, name::{name, AsName, Name}, @@ -98,12 +98,12 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI }; ( name.as_name(), - if it.expander.should_expand() { + if it.disabled { + CustomProcMacroExpander::disabled() + } else { CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId( idx as u32, )) - } else { - CustomProcMacroExpander::disabled() }, ) }) @@ -608,9 +608,6 @@ fn export_proc_macro( id: ItemTreeId, fn_id: FunctionId, ) { - if self.def_map.block.is_some() { - return; - } let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) { @@ -1124,9 +1121,16 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { let mut push_resolved = |directive: &MacroDirective, call_id| { resolved.push((directive.module_id, directive.depth, directive.container, call_id)); }; + + #[derive(PartialEq, Eq)] + enum Resolved { + Yes, + No, + } + let mut res = ReachedFixedPoint::Yes; // Retain unresolved macros after this round of resolution. - macros.retain(|directive| { + let mut retain = |directive: &MacroDirective| { let subns = match &directive.kind { MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang, MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => { @@ -1161,34 +1165,10 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { .scope .add_macro_invoc(ast_id.ast_id, call_id); - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id); - - if let MacroDefKind::ProcMacro(expander, _, _) = loc.def.kind { - if expander.is_dummy() { - // If there's no expander for the proc macro (e.g. - // because proc macros are disabled, or building the - // proc macro crate failed), report this and skip - // expansion like we would if it was disabled - self.def_map.diagnostics.push( - DefDiagnostic::unresolved_proc_macro( - directive.module_id, - loc.kind, - loc.def.krate, - ), - ); - - res = ReachedFixedPoint::No; - return false; - } else if expander.is_disabled() { - res = ReachedFixedPoint::No; - return false; - } - } - push_resolved(directive, call_id); res = ReachedFixedPoint::No; - return false; + return Resolved::Yes; } } MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site } => { @@ -1227,7 +1207,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { push_resolved(directive, call_id); res = ReachedFixedPoint::No; - return false; + return Resolved::Yes; } } MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => { @@ -1250,7 +1230,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { } .collect(&[*mod_item], directive.container); res = ReachedFixedPoint::No; - false + Resolved::Yes }; if let Some(ident) = path.as_ident() { @@ -1266,13 +1246,18 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { let def = match resolver_def_id(path.clone()) { Some(def) if def.is_attribute() => def, - _ => return true, + _ => return Resolved::No, }; - if matches!( - def, - MacroDefId { kind: MacroDefKind::BuiltInAttr(expander, _),.. } - if expander.is_derive() - ) { + + if let MacroDefId { + kind: + MacroDefKind::BuiltInAttr( + BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst, + _, + ), + .. + } = def + { // Resolved to `#[derive]`, we don't actually expand this attribute like // normal (as that would just be an identity expansion with extra output) // Instead we treat derive attributes special and apply them separately. @@ -1345,16 +1330,6 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { let call_id = attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def); - // If proc attribute macro expansion is disabled, skip expanding it here - if !self.db.expand_proc_attr_macros() { - self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( - directive.module_id, - self.db.lookup_intern_macro_call(call_id).kind, - def.krate, - )); - return recollect_without(self); - } - // Skip #[test]/#[bench] expansion, which would merely result in more memory usage // due to duplicating functions into macro expansions if matches!( @@ -1366,19 +1341,29 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { } if let MacroDefKind::ProcMacro(exp, ..) = def.kind { - if exp.is_dummy() { - // If there's no expander for the proc macro (e.g. - // because proc macros are disabled, or building the - // proc macro crate failed), report this and skip - // expansion like we would if it was disabled + // If proc attribute macro expansion is disabled, skip expanding it here + if !self.db.expand_proc_attr_macros() { self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( directive.module_id, self.db.lookup_intern_macro_call(call_id).kind, def.krate, )); - return recollect_without(self); - } else if exp.is_disabled() { + } + + // If there's no expander for the proc macro (e.g. + // because proc macros are disabled, or building the + // proc macro crate failed), report this and skip + // expansion like we would if it was disabled + if exp.is_dummy() { + self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( + directive.module_id, + self.db.lookup_intern_macro_call(call_id).kind, + def.krate, + )); + return recollect_without(self); + } + if exp.is_disabled() { return recollect_without(self); } } @@ -1389,12 +1374,13 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { push_resolved(directive, call_id); res = ReachedFixedPoint::No; - return false; + return Resolved::Yes; } } - true - }); + Resolved::No + }; + macros.retain(|it| retain(it) == Resolved::No); // Attribute resolution can add unresolved macro invocations, so concatenate the lists. macros.extend(mem::take(&mut self.unresolved_macros)); self.unresolved_macros = macros; @@ -1704,7 +1690,11 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) { FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT { + + if self.def_collector.def_map.block.is_none() + && self.def_collector.is_proc_macro + && self.module_id == DefMap::ROOT + { if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { self.def_collector.export_proc_macro( proc_macro, diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 0a3f7bf7ec3..161b2c05990 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -103,6 +103,9 @@ pub fn unconfigured_code( } // FIXME: Whats the difference between this and unresolved_macro_call + // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc + // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this + // struct loses all that information! pub(crate) fn unresolved_proc_macro( container: LocalModuleId, ast: MacroCallKind, diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index f745ff23efb..7c4de2f1b87 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -31,16 +31,6 @@ fn expand( call_site: Span, mixed_site: Span, ) -> Result; - - /// If this returns `false`, expansions via [`expand`](ProcMacroExpander::expand) will always - /// return the input subtree or will always return an error. - /// - /// This is used to skip any additional expansion-related work, - /// e.g. to make sure we do not touch the syntax tree in any way - /// if a proc macro will never be expanded. - fn should_expand(&self) -> bool { - true - } } #[derive(Debug)] @@ -59,6 +49,7 @@ pub struct ProcMacro { pub name: SmolStr, pub kind: ProcMacroKind, pub expander: sync::Arc, + pub disabled: bool, } #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] @@ -66,31 +57,35 @@ pub struct CustomProcMacroExpander { proc_macro_id: ProcMacroId, } -const DUMMY_ID: u32 = !0; -const DISABLED_ID: u32 = !1; - impl CustomProcMacroExpander { + const DUMMY_ID: u32 = !0; + const DISABLED_ID: u32 = !1; + pub fn new(proc_macro_id: ProcMacroId) -> Self { - assert_ne!(proc_macro_id.0, DUMMY_ID); + assert_ne!(proc_macro_id.0, Self::DUMMY_ID); + assert_ne!(proc_macro_id.0, Self::DISABLED_ID); Self { proc_macro_id } } - pub fn dummy() -> Self { - Self { proc_macro_id: ProcMacroId(DUMMY_ID) } + /// A dummy expander that always errors. This is used for proc-macros that are missing, usually + /// due to them not being built yet. + pub const fn dummy() -> Self { + Self { proc_macro_id: ProcMacroId(Self::DUMMY_ID) } } /// The macro was not yet resolved. - pub fn is_dummy(&self) -> bool { - self.proc_macro_id.0 == DUMMY_ID + pub const fn is_dummy(&self) -> bool { + self.proc_macro_id.0 == Self::DUMMY_ID } - pub fn disabled() -> Self { - Self { proc_macro_id: ProcMacroId(DISABLED_ID) } + /// A dummy expander that always errors. This expander is used for macros that have been disabled. + pub const fn disabled() -> Self { + Self { proc_macro_id: ProcMacroId(Self::DISABLED_ID) } } /// The macro is explicitly disabled and cannot be expanded. - pub fn is_disabled(&self) -> bool { - self.proc_macro_id.0 == DISABLED_ID + pub const fn is_disabled(&self) -> bool { + self.proc_macro_id.0 == Self::DISABLED_ID } pub fn expand( @@ -105,11 +100,11 @@ pub fn expand( mixed_site: Span, ) -> ExpandResult { match self.proc_macro_id { - ProcMacroId(DUMMY_ID) => ExpandResult::new( + ProcMacroId(Self::DUMMY_ID) => ExpandResult::new( tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), ExpandError::UnresolvedProcMacro(def_crate), ), - ProcMacroId(DISABLED_ID) => ExpandResult::new( + ProcMacroId(Self::DISABLED_ID) => ExpandResult::new( tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), ExpandError::MacroDisabled, ), @@ -135,7 +130,7 @@ pub fn expand( ); return ExpandResult::new( tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), - ExpandError::other("Internal error"), + ExpandError::other("Internal error: proc-macro index out of bounds"), ); } }; diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index dc9005f5838..a52cc19650f 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -18,7 +18,6 @@ use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; -use tt::DelimSpan; use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath}; pub struct LoadCargoConfig { @@ -357,16 +356,8 @@ fn expander_to_proc_macro( proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike, proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, }; - let expander: sync::Arc = - if ignored_macros.iter().any(|replace| &**replace == name) { - match kind { - ProcMacroKind::Attr => sync::Arc::new(IdentityExpander), - _ => sync::Arc::new(EmptyExpander), - } - } else { - sync::Arc::new(Expander(expander)) - }; - ProcMacro { name, kind, expander } + let disabled = ignored_macros.iter().any(|replace| **replace == name); + ProcMacro { name, kind, expander: sync::Arc::new(Expander(expander)), disabled } } #[derive(Debug)] @@ -391,48 +382,6 @@ fn expand( } } -/// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user. -#[derive(Debug)] -struct IdentityExpander; - -impl ProcMacroExpander for IdentityExpander { - fn expand( - &self, - subtree: &tt::Subtree, - _: Option<&tt::Subtree>, - _: &Env, - _: Span, - _: Span, - _: Span, - ) -> Result, ProcMacroExpansionError> { - Ok(subtree.clone()) - } - fn should_expand(&self) -> bool { - false - } -} - -/// Empty expander, used for proc-macros that are deliberately ignored by the user. -#[derive(Debug)] -struct EmptyExpander; - -impl ProcMacroExpander for EmptyExpander { - fn expand( - &self, - _: &tt::Subtree, - _: Option<&tt::Subtree>, - _: &Env, - call_site: Span, - _: Span, - _: Span, - ) -> Result, ProcMacroExpansionError> { - Ok(tt::Subtree::empty(DelimSpan { open: call_site, close: call_site })) - } - fn should_expand(&self) -> bool { - false - } -} - #[cfg(test)] mod tests { use ide_db::base_db::SourceDatabase; diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 14d622abfe2..3c2ba2f115a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -333,13 +333,12 @@ pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec TokenStream { name: "identity".into(), kind: ProcMacroKind::Attr, expander: sync::Arc::new(IdentityProcMacroExpander), + disabled: false, }, ), ( @@ -388,6 +389,7 @@ pub fn derive_identity(item: TokenStream) -> TokenStream { name: "DeriveIdentity".into(), kind: ProcMacroKind::CustomDerive, expander: sync::Arc::new(IdentityProcMacroExpander), + disabled: false, }, ), ( @@ -402,6 +404,7 @@ pub fn input_replace(attr: TokenStream, _item: TokenStream) -> TokenStream { name: "input_replace".into(), kind: ProcMacroKind::Attr, expander: sync::Arc::new(AttributeInputReplaceProcMacroExpander), + disabled: false, }, ), ( @@ -416,6 +419,7 @@ pub fn mirror(input: TokenStream) -> TokenStream { name: "mirror".into(), kind: ProcMacroKind::FuncLike, expander: sync::Arc::new(MirrorProcMacroExpander), + disabled: false, }, ), ( @@ -430,6 +434,7 @@ pub fn shorten(input: TokenStream) -> TokenStream { name: "shorten".into(), kind: ProcMacroKind::FuncLike, expander: sync::Arc::new(ShortenProcMacroExpander), + disabled: false, }, ), ]