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.
This commit is contained in:
parent
6acaa27fa6
commit
5d8a7daf2a
10 changed files with 211 additions and 101 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)| {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(¯o_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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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{}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -532,4 +532,5 @@ define_symbols! {
|
|||
CoerceUnsized,
|
||||
DispatchFromDyn,
|
||||
define_opaque,
|
||||
marker,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue