Unnamed repository; edit this file 'description' to name the repository.
Fixes for builtin derive expansions
- Do not store the `MacroCallId` of the "real" expansion anywhere, so that the IDE layer could not expand it by mistake - Fix a stupid bug where we used the directive of the `derive` itself instead of of the macro, leading us to re-expand it again and again.
Chayim Refael Friedman 4 months ago
parent 87536b0 · commit 3389448
-rw-r--r--crates/hir-def/src/builtin_derive.rs22
-rw-r--r--crates/hir-def/src/dyn_map.rs10
-rw-r--r--crates/hir-def/src/item_scope.rs19
-rw-r--r--crates/hir-def/src/lang_item.rs54
-rw-r--r--crates/hir-def/src/nameres.rs10
-rw-r--r--crates/hir-def/src/nameres/collector.rs88
-rw-r--r--crates/hir/src/semantics.rs31
-rw-r--r--crates/hir/src/semantics/source_to_def.rs17
-rw-r--r--crates/ide/src/expand_macro.rs60
-rw-r--r--crates/intern/src/symbol/symbols.rs1
10 files changed, 211 insertions, 101 deletions
diff --git a/crates/hir-def/src/builtin_derive.rs b/crates/hir-def/src/builtin_derive.rs
index 32385516ab..946f08ec36 100644
--- a/crates/hir-def/src/builtin_derive.rs
+++ b/crates/hir-def/src/builtin_derive.rs
@@ -8,7 +8,8 @@ use intern::{Symbol, sym};
use tt::TextRange;
use crate::{
- AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, db::DefDatabase,
+ AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, MacroId,
+ db::DefDatabase, lang_item::LangItems,
};
macro_rules! declare_enum {
@@ -86,6 +87,25 @@ declare_enum!(
DispatchFromDyn => [],
);
+impl BuiltinDeriveImplTrait {
+ pub fn derive_macro(self, lang_items: &LangItems) -> Option<MacroId> {
+ match self {
+ BuiltinDeriveImplTrait::Copy => lang_items.CopyDerive,
+ BuiltinDeriveImplTrait::Clone => lang_items.CloneDerive,
+ BuiltinDeriveImplTrait::Default => lang_items.DefaultDerive,
+ BuiltinDeriveImplTrait::Debug => lang_items.DebugDerive,
+ BuiltinDeriveImplTrait::Hash => lang_items.HashDerive,
+ BuiltinDeriveImplTrait::Ord => lang_items.OrdDerive,
+ BuiltinDeriveImplTrait::PartialOrd => lang_items.PartialOrdDerive,
+ BuiltinDeriveImplTrait::Eq => lang_items.EqDerive,
+ BuiltinDeriveImplTrait::PartialEq => lang_items.PartialEqDerive,
+ BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
+ lang_items.CoercePointeeDerive
+ }
+ }
+ }
+}
+
impl BuiltinDeriveImplMethod {
pub fn trait_method(
self,
diff --git a/crates/hir-def/src/dyn_map.rs b/crates/hir-def/src/dyn_map.rs
index 7d3a94b038..4308d0ef1c 100644
--- a/crates/hir-def/src/dyn_map.rs
+++ b/crates/hir-def/src/dyn_map.rs
@@ -27,14 +27,15 @@
pub mod keys {
use std::marker::PhantomData;
+ use either::Either;
use hir_expand::{MacroCallId, attrs::AttrId};
use rustc_hash::FxHashMap;
use syntax::{AstNode, AstPtr, ast};
use crate::{
- BlockId, ConstId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId,
- ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitId,
- TypeAliasId, TypeOrConstParamId, UnionId, UseId,
+ BlockId, BuiltinDeriveImplId, ConstId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId,
+ FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId,
+ StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId,
dyn_map::{DynMap, Policy},
};
@@ -71,7 +72,8 @@ pub mod keys {
(
AttrId,
/* derive() */ MacroCallId,
- /* actual derive macros */ Box<[Option<MacroCallId>]>,
+ /* actual derive macros */
+ Box<[Option<Either<MacroCallId, BuiltinDeriveImplId>>]>,
),
> = Key::new();
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index a3278dd76c..9e1efb9777 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -4,6 +4,7 @@
use std::{fmt, sync::LazyLock};
use base_db::Crate;
+use either::Either;
use hir_expand::{AstId, MacroCallId, attrs::AttrId, name::Name};
use indexmap::map::Entry;
use itertools::Itertools;
@@ -199,7 +200,7 @@ struct DeriveMacroInvocation {
attr_id: AttrId,
/// The `#[derive]` call
attr_call_id: MacroCallId,
- derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
+ derive_call_ids: SmallVec<[Option<Either<MacroCallId, BuiltinDeriveImplId>>; 4]>,
}
pub(crate) static BUILTIN_SCOPE: LazyLock<FxIndexMap<Name, PerNs>> = LazyLock::new(|| {
@@ -345,7 +346,9 @@ impl ItemScope {
pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
self.derive_macros.values().flat_map(|it| {
- it.iter().flat_map(|it| it.derive_call_ids.iter().copied().flatten())
+ it.iter().flat_map(|it| {
+ it.derive_call_ids.iter().copied().flatten().flat_map(|it| it.left())
+ })
}),
)
}
@@ -379,6 +382,10 @@ impl ItemScope {
self.types.get(name).map(|item| (item.def, item.vis))
}
+ pub(crate) fn makro(&self, name: &Name) -> Option<MacroId> {
+ self.macros.get(name).map(|item| item.def)
+ }
+
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> {
match item {
@@ -519,7 +526,7 @@ impl ItemScope {
pub(crate) fn set_derive_macro_invoc(
&mut self,
adt: AstId<ast::Adt>,
- call: MacroCallId,
+ call: Either<MacroCallId, BuiltinDeriveImplId>,
id: AttrId,
idx: usize,
) {
@@ -539,7 +546,7 @@ impl ItemScope {
adt: AstId<ast::Adt>,
attr_id: AttrId,
attr_call_id: MacroCallId,
- mut derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
+ mut derive_call_ids: SmallVec<[Option<Either<MacroCallId, BuiltinDeriveImplId>>; 4]>,
) {
derive_call_ids.shrink_to_fit();
self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
@@ -554,7 +561,9 @@ impl ItemScope {
) -> impl Iterator<
Item = (
AstId<ast::Adt>,
- impl Iterator<Item = (AttrId, MacroCallId, &[Option<MacroCallId>])>,
+ impl Iterator<
+ Item = (AttrId, MacroCallId, &[Option<Either<MacroCallId, BuiltinDeriveImplId>>]),
+ >,
),
> + '_ {
self.derive_macros.iter().map(|(k, v)| {
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index eba4d87ec9..092ff6e486 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -7,8 +7,8 @@ use intern::{Symbol, sym};
use stdx::impl_from;
use crate::{
- AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
- StaticId, StructId, TraitId, TypeAliasId, UnionId,
+ AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, MacroId,
+ ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
attrs::AttrFlags,
db::DefDatabase,
nameres::{DefMap, assoc::TraitItems, crate_def_map, crate_local_def_map},
@@ -99,7 +99,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
}
if matches!(krate.data(db).origin, base_db::CrateOrigin::Lang(base_db::LangCrateOrigin::Core)) {
- lang_items.fill_non_lang_core_traits(db, crate_def_map);
+ lang_items.fill_non_lang_core_items(db, crate_def_map);
}
if lang_items.is_empty() { None } else { Some(Box::new(lang_items)) }
@@ -169,6 +169,27 @@ fn resolve_core_trait(
Some(trait_)
}
+fn resolve_core_macro(
+ db: &dyn DefDatabase,
+ core_def_map: &DefMap,
+ modules: &[Symbol],
+ name: Symbol,
+) -> Option<MacroId> {
+ let mut current = &core_def_map[core_def_map.root];
+ for module in modules {
+ let Some((ModuleDefId::ModuleId(cur), _)) =
+ current.scope.type_(&Name::new_symbol_root(module.clone()))
+ else {
+ return None;
+ };
+ if cur.krate(db) != core_def_map.krate() || cur.block(db) != core_def_map.block_id() {
+ return None;
+ }
+ current = &core_def_map[cur];
+ }
+ current.scope.makro(&Name::new_symbol_root(name))
+}
+
#[salsa::tracked(returns(as_deref))]
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> {
let mut traits = Vec::new();
@@ -195,7 +216,11 @@ macro_rules! language_item_table {
@non_lang_core_traits:
- $( core::$($non_lang_module:ident)::*, $non_lang_trait:ident; )*
+ $( core::$($non_lang_trait_module:ident)::*, $non_lang_trait:ident; )*
+
+ @non_lang_core_macros:
+
+ $( core::$($non_lang_macro_module:ident)::*, $non_lang_macro:ident, $non_lang_macro_field:ident; )*
) => {
#[allow(non_snake_case)] // FIXME: Should we remove this?
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
@@ -207,6 +232,9 @@ macro_rules! language_item_table {
$(
pub $non_lang_trait: Option<TraitId>,
)*
+ $(
+ pub $non_lang_macro_field: Option<MacroId>,
+ )*
}
impl LangItems {
@@ -218,6 +246,7 @@ macro_rules! language_item_table {
fn merge_prefer_self(&mut self, other: &Self) {
$( self.$lang_item = self.$lang_item.or(other.$lang_item); )*
$( self.$non_lang_trait = self.$non_lang_trait.or(other.$non_lang_trait); )*
+ $( self.$non_lang_macro_field = self.$non_lang_macro_field.or(other.$non_lang_macro_field); )*
}
fn assign_lang_item(&mut self, name: Symbol, target: LangItemTarget) {
@@ -233,8 +262,9 @@ macro_rules! language_item_table {
}
}
- fn fill_non_lang_core_traits(&mut self, db: &dyn DefDatabase, core_def_map: &DefMap) {
- $( self.$non_lang_trait = resolve_core_trait(db, core_def_map, &[ $(sym::$non_lang_module),* ], sym::$non_lang_trait); )*
+ fn fill_non_lang_core_items(&mut self, db: &dyn DefDatabase, core_def_map: &DefMap) {
+ $( self.$non_lang_trait = resolve_core_trait(db, core_def_map, &[ $(sym::$non_lang_trait_module),* ], sym::$non_lang_trait); )*
+ $( self.$non_lang_macro_field = resolve_core_macro(db, core_def_map, &[ $(sym::$non_lang_macro_module),* ], sym::$non_lang_macro); )*
}
}
@@ -479,4 +509,16 @@ language_item_table! { LangItems =>
core::hash, Hash;
core::cmp, Ord;
core::cmp, Eq;
+
+ @non_lang_core_macros:
+ core::default, Default, DefaultDerive;
+ core::fmt, Debug, DebugDerive;
+ core::hash, Hash, HashDerive;
+ core::cmp, PartialOrd, PartialOrdDerive;
+ core::cmp, Ord, OrdDerive;
+ core::cmp, PartialEq, PartialEqDerive;
+ core::cmp, Eq, EqDerive;
+ core::marker, CoercePointee, CoercePointeeDerive;
+ core::marker, Copy, CopyDerive;
+ core::clone, Clone, CloneDerive;
}
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 5f05cdb1e2..150372f1a0 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -61,6 +61,7 @@ mod tests;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use base_db::Crate;
+use either::Either;
use hir_expand::{
EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name,
proc_macro::ProcMacroKind,
@@ -75,8 +76,8 @@ use triomphe::Arc;
use tt::TextRange;
use crate::{
- AstId, BlockId, BlockLoc, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles,
- MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId,
+ AstId, BlockId, BlockLoc, BuiltinDeriveImplId, ExternCrateId, FunctionId, FxIndexMap, Lookup,
+ MacroCallStyles, MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId,
db::DefDatabase,
item_scope::{BuiltinShadowMode, ItemScope},
item_tree::TreeId,
@@ -192,7 +193,8 @@ pub struct DefMap {
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes.
// FIXME: Figure out a better way for the IDE layer to resolve these?
- derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
+ derive_helpers_in_scope:
+ FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, Either<MacroCallId, BuiltinDeriveImplId>)>>,
/// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
@@ -540,7 +542,7 @@ impl DefMap {
pub fn derive_helpers_in_scope(
&self,
id: AstId<ast::Adt>,
- ) -> Option<&[(Name, MacroId, MacroCallId)]> {
+ ) -> Option<&[(Name, MacroId, Either<MacroCallId, BuiltinDeriveImplId>)]> {
self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref)
}
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 87ade06517..323060f61d 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -3,7 +3,7 @@
//! `DefCollector::collect` contains the fixed-point iteration loop which
//! resolves imports and expands macros.
-use std::{iter, mem};
+use std::{iter, mem, ops::Range};
use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin};
use cfg::{CfgAtom, CfgExpr, CfgOptions};
@@ -226,6 +226,7 @@ struct DeferredBuiltinDerive {
container: ItemContainerId,
derive_attr_id: AttrId,
derive_index: u32,
+ helpers_range: Range<usize>,
}
/// Walks the tree of module recursively
@@ -1354,7 +1355,7 @@ impl<'db> DefCollector<'db> {
if let Ok((macro_id, def_id, call_id)) = id {
self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc(
ast_id.ast_id,
- call_id,
+ Either::Left(call_id),
*derive_attr,
*derive_pos,
);
@@ -1369,7 +1370,7 @@ impl<'db> DefCollector<'db> {
.extend(izip!(
helpers.iter().cloned(),
iter::repeat(macro_id),
- iter::repeat(call_id),
+ iter::repeat(Either::Left(call_id)),
));
}
}
@@ -1492,6 +1493,8 @@ impl<'db> DefCollector<'db> {
Interned::new(path),
);
+ derive_call_ids.push(None);
+
// Try to resolve the derive immediately. If we succeed, we can also use the fast path
// for builtin derives. If not, we cannot use it, as it can cause the ADT to become
// interned while the derive is still unresolved, which will cause it to get forgotten.
@@ -1506,23 +1509,42 @@ impl<'db> DefCollector<'db> {
call_id,
);
+ let ast_id_without_path = ast_id.ast_id;
+ let directive = MacroDirective {
+ module_id: directive.module_id,
+ depth: directive.depth + 1,
+ kind: MacroDirectiveKind::Derive {
+ ast_id,
+ derive_attr: *attr_id,
+ derive_pos: idx,
+ ctxt: call_site.ctx,
+ derive_macro_id: call_id,
+ },
+ container: directive.container,
+ };
+
if let Ok((macro_id, def_id, call_id)) = id {
- derive_call_ids.push(Some(call_id));
+ let (mut helpers_start, mut helpers_end) = (0, 0);
// Record its helper attributes.
if def_id.krate != self.def_map.krate {
let def_map = crate_def_map(self.db, def_id.krate);
if let Some(helpers) =
def_map.data.exported_derives.get(&macro_id)
{
- self.def_map
+ let derive_helpers = self
+ .def_map
.derive_helpers_in_scope
- .entry(ast_id.ast_id.map(|it| it.upcast()))
- .or_default()
- .extend(izip!(
- helpers.iter().cloned(),
- iter::repeat(macro_id),
- iter::repeat(call_id),
- ));
+ .entry(
+ ast_id_without_path.map(|it| it.upcast()),
+ )
+ .or_default();
+ helpers_start = derive_helpers.len();
+ derive_helpers.extend(izip!(
+ helpers.iter().cloned(),
+ iter::repeat(macro_id),
+ iter::repeat(Either::Left(call_id)),
+ ));
+ helpers_end = derive_helpers.len();
}
}
@@ -1531,7 +1553,7 @@ impl<'db> DefCollector<'db> {
def_id.kind
{
self.deferred_builtin_derives
- .entry(ast_id.ast_id.upcast())
+ .entry(ast_id_without_path.upcast())
.or_default()
.push(DeferredBuiltinDerive {
call_id,
@@ -1541,24 +1563,15 @@ impl<'db> DefCollector<'db> {
depth: directive.depth,
derive_attr_id: *attr_id,
derive_index: idx as u32,
+ helpers_range: helpers_start..helpers_end,
});
} else {
- push_resolved(&mut resolved, directive, call_id);
+ push_resolved(&mut resolved, &directive, call_id);
+ *derive_call_ids.last_mut().unwrap() =
+ Some(Either::Left(call_id));
}
} else {
- derive_call_ids.push(None);
- self.unresolved_macros.push(MacroDirective {
- module_id: directive.module_id,
- depth: directive.depth + 1,
- kind: MacroDirectiveKind::Derive {
- ast_id,
- derive_attr: *attr_id,
- derive_pos: idx,
- ctxt: call_site.ctx,
- derive_macro_id: call_id,
- },
- container: directive.container,
- });
+ self.unresolved_macros.push(directive);
}
}
@@ -1858,9 +1871,8 @@ impl ModCollector<'_, '_> {
ast_id: FileAstId<ast::Adt>,
id: AdtId,
def_map: &mut DefMap| {
- let Some(deferred_derives) =
- deferred_derives.remove(&InFile::new(file_id, ast_id.upcast()))
- else {
+ let ast_id = InFile::new(file_id, ast_id.upcast());
+ let Some(deferred_derives) = deferred_derives.remove(&ast_id.upcast()) else {
return;
};
let module = &mut def_map.modules[module_id];
@@ -1876,6 +1888,22 @@ impl ModCollector<'_, '_> {
},
);
module.scope.define_builtin_derive_impl(impl_id);
+ module.scope.set_derive_macro_invoc(
+ ast_id,
+ Either::Right(impl_id),
+ deferred_derive.derive_attr_id,
+ deferred_derive.derive_index as usize,
+ );
+ // Change its helper attributes to the new id.
+ if let Some(derive_helpers) =
+ def_map.derive_helpers_in_scope.get_mut(&ast_id.map(|it| it.upcast()))
+ {
+ for (_, _, call_id) in
+ &mut derive_helpers[deferred_derive.helpers_range.clone()]
+ {
+ *call_id = Either::Right(impl_id);
+ }
+ }
});
}
};
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index f4c42537de..e55b693ef0 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -13,7 +13,7 @@ use std::{
use base_db::FxIndexSet;
use either::Either;
use hir_def::{
- DefWithBodyId, MacroId, StructId, TraitId, VariantId,
+ BuiltinDeriveImplId, DefWithBodyId, HasModule, MacroId, StructId, TraitId, VariantId,
attrs::parse_extra_crate_attrs,
expr_store::{Body, ExprOrPatSource, HygieneId, path::Path},
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
@@ -622,7 +622,20 @@ impl<'db> SemanticsImpl<'db> {
Some(
calls
.into_iter()
- .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id }))
+ .map(|call| {
+ let call = call?;
+ match call {
+ Either::Left(call) => {
+ macro_call_to_macro_id(ctx, call).map(|id| Macro { id })
+ }
+ Either::Right(call) => {
+ let call = call.loc(self.db);
+ let krate = call.krate(self.db);
+ let lang_items = hir_def::lang_item::lang_items(self.db, krate);
+ call.trait_.derive_macro(lang_items).map(|id| Macro { id })
+ }
+ }
+ })
.collect(),
)
})
@@ -633,7 +646,7 @@ impl<'db> SemanticsImpl<'db> {
.derive_macro_calls(attr)?
.into_iter()
.flat_map(|call| {
- let file_id = call?;
+ let file_id = call?.left()?;
let ExpandResult { value, err } = self.db.parse_macro_expansion(file_id);
let root_node = value.0.syntax_node();
self.cache(root_node.clone(), file_id.into());
@@ -643,7 +656,10 @@ impl<'db> SemanticsImpl<'db> {
Some(res)
}
- fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroCallId>>> {
+ fn derive_macro_calls(
+ &self,
+ attr: &ast::Attr,
+ ) -> Option<Vec<Option<Either<MacroCallId, BuiltinDeriveImplId>>>> {
let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
let file_id = self.find_file(adt.syntax()).file_id;
let adt = InFile::new(file_id, &adt);
@@ -690,8 +706,9 @@ impl<'db> SemanticsImpl<'db> {
.derive_helpers_in_scope(InFile::new(sa.file_id, id))?
.iter()
.filter(|&(name, _, _)| *name == attr_name)
- .map(|&(_, macro_, call)| (macro_.into(), call))
+ .filter_map(|&(_, macro_, call)| Some((macro_.into(), call.left()?)))
.collect();
+ // FIXME: We filter our builtin derive "fake" expansions, is this correct? Should we still expose them somehow?
res.is_empty().not().then_some(res)
}
@@ -1338,6 +1355,7 @@ impl<'db> SemanticsImpl<'db> {
// FIXME: We need to call `f` for all of them as well though!
process_expansion_for_token(ctx, &mut stack, derive_attr);
for derive in derives.into_iter().flatten() {
+ let Either::Left(derive) = derive else { continue };
process_expansion_for_token(ctx, &mut stack, derive);
}
}
@@ -1467,11 +1485,12 @@ impl<'db> SemanticsImpl<'db> {
for (.., derive) in
helpers.iter().filter(|(helper, ..)| *helper == attr_name)
{
+ let Either::Left(derive) = *derive else { continue };
// as there may be multiple derives registering the same helper
// name, we gotta make sure to call this for all of them!
// FIXME: We need to call `f` for all of them as well though!
res = res
- .or(process_expansion_for_token(ctx, &mut stack, *derive));
+ .or(process_expansion_for_token(ctx, &mut stack, derive));
}
res
})
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 2574059927..d222c3dc7e 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -87,10 +87,10 @@
use either::Either;
use hir_def::{
- AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
- ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId,
- Lookup, MacroId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
- UseId, VariantId,
+ AdtId, BlockId, BuiltinDeriveImplId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+ EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId,
+ ImplId, LifetimeParamId, Lookup, MacroId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
+ TypeParamId, UnionId, UseId, VariantId,
dyn_map::{
DynMap,
keys::{self, Key},
@@ -394,7 +394,7 @@ impl SourceToDefCtx<'_, '_> {
&mut self,
item: InFile<&ast::Adt>,
src: InFile<ast::Attr>,
- ) -> Option<(AttrId, MacroCallId, &[Option<MacroCallId>])> {
+ ) -> Option<(AttrId, MacroCallId, &[Option<Either<MacroCallId, BuiltinDeriveImplId>>])> {
let map = self.dyn_map(item)?;
map[keys::DERIVE_MACRO_CALL]
.get(&AstPtr::new(&src.value))
@@ -409,8 +409,11 @@ impl SourceToDefCtx<'_, '_> {
pub(super) fn derive_macro_calls<'slf>(
&'slf mut self,
adt: InFile<&ast::Adt>,
- ) -> Option<impl Iterator<Item = (AttrId, MacroCallId, &'slf [Option<MacroCallId>])> + use<'slf>>
- {
+ ) -> Option<
+ impl Iterator<
+ Item = (AttrId, MacroCallId, &'slf [Option<Either<MacroCallId, BuiltinDeriveImplId>>]),
+ > + use<'slf>,
+ > {
self.dyn_map(adt).as_ref().map(|&map| {
let dyn_map = &map[keys::DERIVE_MACRO_CALL];
adt.value
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 7d02b80918..ba8b3aa9ca 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -583,26 +583,16 @@ fn main() {
fn macro_expand_derive() {
check(
r#"
-//- proc_macros: identity
-//- minicore: clone, derive
+//- proc_macros: identity, derive_identity
+//- minicore: derive
#[proc_macros::identity]
-#[derive(C$0lone)]
+#[derive(proc_macros::DeriveIde$0ntity)]
struct Foo {}
"#,
expect![[r#"
- Clone
- impl <>core::clone::Clone for Foo< >where {
- fn clone(&self) -> Self {
- match self {
- Foo{}
- => Foo{}
- ,
-
- }
- }
-
- }"#]],
+ proc_macros::DeriveIdentity
+ struct Foo{}"#]],
);
}
@@ -610,15 +600,17 @@ struct Foo {}
fn macro_expand_derive2() {
check(
r#"
-//- minicore: copy, clone, derive
+//- proc_macros: derive_identity
+//- minicore: derive
-#[derive(Cop$0y)]
-#[derive(Clone)]
+#[derive(proc_macros::$0DeriveIdentity)]
+#[derive(proc_macros::DeriveIdentity)]
struct Foo {}
"#,
expect![[r#"
- Copy
- impl <>core::marker::Copy for Foo< >where{}"#]],
+ proc_macros::DeriveIdentity
+ #[derive(proc_macros::DeriveIdentity)]
+ struct Foo{}"#]],
);
}
@@ -626,35 +618,27 @@ struct Foo {}
fn macro_expand_derive_multi() {
check(
r#"
-//- minicore: copy, clone, derive
+//- proc_macros: derive_identity
+//- minicore: derive
-#[derive(Cop$0y, Clone)]
+#[derive(proc_macros::DeriveIdent$0ity, proc_macros::DeriveIdentity)]
struct Foo {}
"#,
expect![[r#"
- Copy
- impl <>core::marker::Copy for Foo< >where{}"#]],
+ proc_macros::DeriveIdentity
+ struct Foo{}"#]],
);
check(
r#"
-//- minicore: copy, clone, derive
+//- proc_macros: derive_identity
+//- minicore: derive
-#[derive(Copy, Cl$0one)]
+#[derive(proc_macros::DeriveIdentity, proc_macros::De$0riveIdentity)]
struct Foo {}
"#,
expect![[r#"
- Clone
- impl <>core::clone::Clone for Foo< >where {
- fn clone(&self) -> Self {
- match self {
- Foo{}
- => Foo{}
- ,
-
- }
- }
-
- }"#]],
+ proc_macros::DeriveIdentity
+ struct Foo{}"#]],
);
}
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index b6efc599f1..3fadca29d1 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -532,4 +532,5 @@ define_symbols! {
CoerceUnsized,
DispatchFromDyn,
define_opaque,
+ marker,
}