hir_def/
builtin_derive.rs1use base_db::SourceDatabase;
7use hir_expand::{InFile, builtin::BuiltinDeriveExpander, name::Name};
8use intern::{Symbol, sym};
9use tt::TextRange;
10
11use crate::{
12 AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, MacroId,
13 lang_item::LangItems,
14};
15
16macro_rules! declare_enum {
17 ( $( $trait:ident => [ $( $method:ident ),* ] ),* $(,)? ) => {
18 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19 pub enum BuiltinDeriveImplTrait {
20 $( $trait, )*
21 }
22
23 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24 #[allow(non_camel_case_types)]
25 pub enum BuiltinDeriveImplMethod {
26 $( $( $method, )* )*
27 }
28
29 impl BuiltinDeriveImplTrait {
30 #[inline]
31 pub fn name(self) -> Symbol {
32 match self {
33 $( Self::$trait => sym::$trait, )*
34 }
35 }
36
37 #[inline]
38 pub fn get_id(self, lang_items: &crate::lang_item::LangItems) -> Option<crate::TraitId> {
39 match self {
40 $( Self::$trait => lang_items.$trait, )*
41 }
42 }
43
44 #[inline]
45 pub fn get_method(self, method_name: &Symbol) -> Option<BuiltinDeriveImplMethod> {
46 match self {
47 $(
48 Self::$trait => {
49 match method_name {
50 $( _ if *method_name == sym::$method => Some(BuiltinDeriveImplMethod::$method), )*
51 _ => None,
52 }
53 }
54 )*
55 }
56 }
57
58 #[inline]
59 pub fn all_methods(self) -> &'static [BuiltinDeriveImplMethod] {
60 match self {
61 $( Self::$trait => &[ $(BuiltinDeriveImplMethod::$method),* ], )*
62 }
63 }
64 }
65
66 impl BuiltinDeriveImplMethod {
67 #[inline]
68 pub fn name(self) -> Symbol {
69 match self {
70 $( $( BuiltinDeriveImplMethod::$method => sym::$method, )* )*
71 }
72 }
73 }
74 };
75}
76
77declare_enum!(
78 Copy => [],
79 Clone => [clone],
80 Default => [default],
81 Debug => [fmt],
82 Hash => [hash],
83 Ord => [cmp],
84 PartialOrd => [partial_cmp],
85 Eq => [],
86 PartialEq => [eq],
87 CoerceUnsized => [],
88 DispatchFromDyn => [],
89 Reborrow => [],
90);
91
92impl BuiltinDeriveImplTrait {
93 pub fn derive_macro(self, lang_items: &LangItems) -> Option<MacroId> {
94 match self {
95 BuiltinDeriveImplTrait::Copy => lang_items.CopyDerive,
96 BuiltinDeriveImplTrait::Clone => lang_items.CloneDerive,
97 BuiltinDeriveImplTrait::Default => lang_items.DefaultDerive,
98 BuiltinDeriveImplTrait::Debug => lang_items.DebugDerive,
99 BuiltinDeriveImplTrait::Hash => lang_items.HashDerive,
100 BuiltinDeriveImplTrait::Ord => lang_items.OrdDerive,
101 BuiltinDeriveImplTrait::PartialOrd => lang_items.PartialOrdDerive,
102 BuiltinDeriveImplTrait::Eq => lang_items.EqDerive,
103 BuiltinDeriveImplTrait::PartialEq => lang_items.PartialEqDerive,
104 BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
105 lang_items.CoercePointeeDerive
106 }
107 BuiltinDeriveImplTrait::Reborrow => lang_items.ReborrowDerive,
108 }
109 }
110}
111
112pub(crate) fn has_builtin_derive_impl(derive: BuiltinDeriveExpander) -> bool {
113 !matches!(derive, BuiltinDeriveExpander::CoerceShared)
114}
115
116impl BuiltinDeriveImplMethod {
117 pub fn trait_method(
118 self,
119 db: &dyn SourceDatabase,
120 impl_: BuiltinDeriveImplId,
121 ) -> Option<FunctionId> {
122 let loc = impl_.loc(db);
123 let lang_items = crate::lang_item::lang_items(db, loc.krate(db));
124 let trait_ = impl_.loc(db).trait_.get_id(lang_items)?;
125 trait_.trait_items(db).method_by_name(&Name::new_symbol_root(self.name()))
126 }
127}
128
129pub(crate) fn with_derive_traits(
130 derive: BuiltinDeriveExpander,
131 mut f: impl FnMut(BuiltinDeriveImplTrait),
132) {
133 debug_assert!(has_builtin_derive_impl(derive));
134 match derive {
135 BuiltinDeriveExpander::Copy => f(BuiltinDeriveImplTrait::Copy),
136 BuiltinDeriveExpander::Clone => f(BuiltinDeriveImplTrait::Clone),
137 BuiltinDeriveExpander::Default => f(BuiltinDeriveImplTrait::Default),
138 BuiltinDeriveExpander::Debug => f(BuiltinDeriveImplTrait::Debug),
139 BuiltinDeriveExpander::Hash => f(BuiltinDeriveImplTrait::Hash),
140 BuiltinDeriveExpander::Ord => f(BuiltinDeriveImplTrait::Ord),
141 BuiltinDeriveExpander::PartialOrd => f(BuiltinDeriveImplTrait::PartialOrd),
142 BuiltinDeriveExpander::Eq => f(BuiltinDeriveImplTrait::Eq),
143 BuiltinDeriveExpander::PartialEq => f(BuiltinDeriveImplTrait::PartialEq),
144 BuiltinDeriveExpander::CoercePointee => {
145 f(BuiltinDeriveImplTrait::CoerceUnsized);
146 f(BuiltinDeriveImplTrait::DispatchFromDyn);
147 }
148 BuiltinDeriveExpander::Reborrow => f(BuiltinDeriveImplTrait::Reborrow),
149 BuiltinDeriveExpander::CoerceShared => {}
150 }
151}
152
153impl BuiltinDeriveImplLoc {
154 pub fn source(&self, db: &dyn SourceDatabase) -> InFile<TextRange> {
155 let (adt_ast_id, module) = match self.adt {
156 AdtId::StructId(adt) => {
157 let adt_loc = adt.loc(db);
158 (adt_loc.id.upcast(), adt_loc.container)
159 }
160 AdtId::UnionId(adt) => {
161 let adt_loc = adt.loc(db);
162 (adt_loc.id.upcast(), adt_loc.container)
163 }
164 AdtId::EnumId(adt) => {
165 let adt_loc = adt.loc(db);
166 (adt_loc.id.upcast(), adt_loc.container)
167 }
168 };
169 let derive_range = self.derive_attr_id.find_derive_range(
170 db,
171 module.krate(db),
172 adt_ast_id,
173 self.derive_index,
174 );
175 adt_ast_id.with_value(derive_range)
176 }
177}