Skip to content

Commit 78fd20f

Browse files
Allow IDE layer to "see" fake builtin derive impls
It sees them as regular impls; the details are abstracted. It's beautiful for the IDE layer, and less beautiful for `hir`, so this is a big change. Some small differences still exist: - We show builtin derives impl (to the IDE layer) as if they have had no generic parameters. It is possible to show the parameters, but that means also having to handle fake impls in `TypeParam` etc., and the benefit is questionable. - Getting the fn *def* type of a method of a builtin derive impl is not supported, as there is no real `FunctionId`, therefore no `CallableDefId`. The trait method is returned instead. Note: getting the fn *ptr* type of the method is supported well. - Builtin derive impls and their methods do not fully support `HasSource`, because, well, they have no source (at least, not in the form of `ast::Impl` and `ast::Fn`). To support them, we use the derive's `TextRange` where possible, and the trait method's source when not. It's important to note that the def map still records the `MacroCallId`. I have doubts over this, as this means it's very easy to create the queries we don't want to create, but it does make things more convenient. In particular, a nicety of this setup is that even "Expand macro recursively" works (it creates the macro input/output query, but given that they will only be created when the user invokes the command, that does not seem to be a problem).
1 parent f1a7a46 commit 78fd20f

File tree

33 files changed

+2416
-1508
lines changed

33 files changed

+2416
-1508
lines changed

crates/hir-def/src/builtin_derive.rs

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,102 @@
33
//! To save time and memory, builtin derives are not really expanded. Instead, we record them
44
//! and create their impls based on lowered data, see crates/hir-ty/src/builtin_derive.rs.
55
6-
use hir_expand::builtin::BuiltinDeriveExpander;
6+
use hir_expand::{InFile, builtin::BuiltinDeriveExpander, name::Name};
7+
use intern::{Symbol, sym};
8+
use tt::TextRange;
9+
10+
use crate::{
11+
AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, db::DefDatabase,
12+
};
713

814
macro_rules! declare_enum {
9-
( $( $trait:ident ),* $(,)? ) => {
15+
( $( $trait:ident => [ $( $method:ident ),* ] ),* $(,)? ) => {
1016
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1117
pub enum BuiltinDeriveImplTrait {
1218
$( $trait, )*
1319
}
1420

21+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22+
#[allow(non_camel_case_types)]
23+
pub enum BuiltinDeriveImplMethod {
24+
$( $( $method, )* )*
25+
}
26+
1527
impl BuiltinDeriveImplTrait {
28+
#[inline]
29+
pub fn name(self) -> Symbol {
30+
match self {
31+
$( Self::$trait => sym::$trait, )*
32+
}
33+
}
34+
1635
#[inline]
1736
pub fn get_id(self, lang_items: &crate::lang_item::LangItems) -> Option<crate::TraitId> {
1837
match self {
1938
$( Self::$trait => lang_items.$trait, )*
2039
}
2140
}
41+
42+
#[inline]
43+
pub fn get_method(self, method_name: &Symbol) -> Option<BuiltinDeriveImplMethod> {
44+
match self {
45+
$(
46+
Self::$trait => {
47+
match method_name {
48+
$( _ if *method_name == sym::$method => Some(BuiltinDeriveImplMethod::$method), )*
49+
_ => None,
50+
}
51+
}
52+
)*
53+
}
54+
}
55+
56+
#[inline]
57+
pub fn all_methods(self) -> &'static [BuiltinDeriveImplMethod] {
58+
match self {
59+
$( Self::$trait => &[ $(BuiltinDeriveImplMethod::$method),* ], )*
60+
}
61+
}
62+
}
63+
64+
impl BuiltinDeriveImplMethod {
65+
#[inline]
66+
pub fn name(self) -> Symbol {
67+
match self {
68+
$( $( BuiltinDeriveImplMethod::$method => sym::$method, )* )*
69+
}
70+
}
2271
}
2372
};
2473
}
2574

2675
declare_enum!(
27-
Copy,
28-
Clone,
29-
Default,
30-
Debug,
31-
Hash,
32-
Ord,
33-
PartialOrd,
34-
Eq,
35-
PartialEq,
36-
CoerceUnsized,
37-
DispatchFromDyn,
76+
Copy => [],
77+
Clone => [clone],
78+
Default => [default],
79+
Debug => [fmt],
80+
Hash => [hash],
81+
Ord => [cmp],
82+
PartialOrd => [partial_cmp],
83+
Eq => [],
84+
PartialEq => [eq],
85+
CoerceUnsized => [],
86+
DispatchFromDyn => [],
3887
);
3988

89+
impl BuiltinDeriveImplMethod {
90+
pub fn trait_method(
91+
self,
92+
db: &dyn DefDatabase,
93+
impl_: BuiltinDeriveImplId,
94+
) -> Option<FunctionId> {
95+
let loc = impl_.loc(db);
96+
let lang_items = crate::lang_item::lang_items(db, loc.krate(db));
97+
let trait_ = impl_.loc(db).trait_.get_id(lang_items)?;
98+
trait_.trait_items(db).method_by_name(&Name::new_symbol_root(self.name()))
99+
}
100+
}
101+
40102
pub(crate) fn with_derive_traits(
41103
derive: BuiltinDeriveExpander,
42104
mut f: impl FnMut(BuiltinDeriveImplTrait),
@@ -59,3 +121,25 @@ pub(crate) fn with_derive_traits(
59121
};
60122
f(trait_);
61123
}
124+
125+
impl BuiltinDeriveImplLoc {
126+
pub fn source(&self, db: &dyn DefDatabase) -> InFile<TextRange> {
127+
let (adt_ast_id, module) = match self.adt {
128+
AdtId::StructId(adt) => {
129+
let adt_loc = adt.loc(db);
130+
(adt_loc.id.upcast(), adt_loc.container)
131+
}
132+
AdtId::UnionId(adt) => {
133+
let adt_loc = adt.loc(db);
134+
(adt_loc.id.upcast(), adt_loc.container)
135+
}
136+
AdtId::EnumId(adt) => {
137+
let adt_loc = adt.loc(db);
138+
(adt_loc.id.upcast(), adt_loc.container)
139+
}
140+
};
141+
let derive_range =
142+
self.derive_attr_id.find_derive_range(db, module.krate, adt_ast_id, self.derive_index);
143+
adt_ast_id.with_value(derive_range)
144+
}
145+
}

crates/hir-def/src/item_scope.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use indexmap::map::Entry;
99
use itertools::Itertools;
1010
use la_arena::Idx;
1111
use rustc_hash::{FxHashMap, FxHashSet};
12-
use smallvec::{SmallVec, smallvec};
12+
use smallvec::SmallVec;
1313
use span::Edition;
1414
use stdx::format_to;
1515
use syntax::ast;
@@ -536,12 +536,13 @@ impl ItemScope {
536536
adt: AstId<ast::Adt>,
537537
attr_id: AttrId,
538538
attr_call_id: MacroCallId,
539-
len: usize,
539+
mut derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
540540
) {
541+
derive_call_ids.shrink_to_fit();
541542
self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
542543
attr_id,
543544
attr_call_id,
544-
derive_call_ids: smallvec![None; len],
545+
derive_call_ids,
545546
});
546547
}
547548

crates/hir-def/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ use base_db::{Crate, impl_intern_key};
6464
use hir_expand::{
6565
AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallStyles,
6666
MacroDefId, MacroDefKind,
67+
attrs::AttrId,
6768
builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander},
6869
db::ExpandDatabase,
6970
eager::expand_eager_macro_input,
@@ -338,6 +339,8 @@ impl ImplId {
338339
pub struct BuiltinDeriveImplLoc {
339340
pub adt: AdtId,
340341
pub trait_: BuiltinDeriveImplTrait,
342+
pub derive_attr_id: AttrId,
343+
pub derive_index: u32,
341344
}
342345

343346
#[salsa::interned(debug, no_lifetime)]
@@ -768,6 +771,18 @@ impl_from!(
768771
for ModuleDefId
769772
);
770773

774+
impl From<DefWithBodyId> for ModuleDefId {
775+
#[inline]
776+
fn from(value: DefWithBodyId) -> Self {
777+
match value {
778+
DefWithBodyId::FunctionId(id) => id.into(),
779+
DefWithBodyId::StaticId(id) => id.into(),
780+
DefWithBodyId::ConstId(id) => id.into(),
781+
DefWithBodyId::VariantId(id) => id.into(),
782+
}
783+
}
784+
}
785+
771786
/// A constant, which might appears as a const item, an anonymous const block in expressions
772787
/// or patterns, or as a constant in types with const generics.
773788
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]

0 commit comments

Comments
 (0)