]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | //! The compiler code necessary to implement the `#[derive]` extensions. |
223e47cc | 2 | |
3dfed10e | 3 | use rustc_ast as ast; |
74b04a01 | 4 | use rustc_ast::ptr::P; |
3c0e092e | 5 | use rustc_ast::{Impl, ItemKind, MetaItem}; |
ba9703b0 | 6 | use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; |
f9f354fc | 7 | use rustc_span::symbol::{sym, Ident, Symbol}; |
dfeec247 | 8 | use rustc_span::Span; |
223e47cc | 9 | |
ff7c6d11 | 10 | macro path_local($x:ident) { |
3dfed10e | 11 | generic::ty::Path::new_local(sym::$x) |
85aaf69f SL |
12 | } |
13 | ||
3dfed10e XL |
14 | macro pathvec_std($($rest:ident)::+) {{ |
15 | vec![ $( sym::$rest ),+ ] | |
ff7c6d11 | 16 | }} |
85aaf69f | 17 | |
ff7c6d11 XL |
18 | macro path_std($($x:tt)*) { |
19 | generic::ty::Path::new( pathvec_std!( $($x)* ) ) | |
85aaf69f SL |
20 | } |
21 | ||
1a4d82fc | 22 | pub mod bounds; |
223e47cc | 23 | pub mod clone; |
b039eaaf | 24 | pub mod debug; |
dfeec247 | 25 | pub mod decodable; |
1a4d82fc | 26 | pub mod default; |
dfeec247 XL |
27 | pub mod encodable; |
28 | pub mod hash; | |
970d7e83 | 29 | |
dfeec247 | 30 | #[path = "cmp/eq.rs"] |
970d7e83 | 31 | pub mod eq; |
dfeec247 | 32 | #[path = "cmp/ord.rs"] |
970d7e83 | 33 | pub mod ord; |
dfeec247 XL |
34 | #[path = "cmp/partial_eq.rs"] |
35 | pub mod partial_eq; | |
36 | #[path = "cmp/partial_ord.rs"] | |
37 | pub mod partial_ord; | |
223e47cc | 38 | |
970d7e83 LB |
39 | pub mod generic; |
40 | ||
416331ca | 41 | crate struct BuiltinDerive( |
dfeec247 | 42 | crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)), |
dc9dc135 XL |
43 | ); |
44 | ||
45 | impl MultiItemModifier for BuiltinDerive { | |
dfeec247 XL |
46 | fn expand( |
47 | &self, | |
48 | ecx: &mut ExtCtxt<'_>, | |
49 | span: Span, | |
50 | meta_item: &MetaItem, | |
51 | item: Annotatable, | |
ba9703b0 | 52 | ) -> ExpandResult<Vec<Annotatable>, Annotatable> { |
e1599b0c XL |
53 | // FIXME: Built-in derives often forget to give spans contexts, |
54 | // so we are doing it here in a centralized way. | |
55 | let span = ecx.with_def_site_ctxt(span); | |
dc9dc135 | 56 | let mut items = Vec::new(); |
fc512014 XL |
57 | match item { |
58 | Annotatable::Stmt(stmt) => { | |
59 | if let ast::StmtKind::Item(item) = stmt.into_inner().kind { | |
60 | (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| { | |
61 | // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' | |
62 | // to the function | |
63 | items.push(Annotatable::Stmt(P(ast::Stmt { | |
64 | id: ast::DUMMY_NODE_ID, | |
65 | kind: ast::StmtKind::Item(a.expect_item()), | |
66 | span, | |
67 | }))); | |
68 | }); | |
69 | } else { | |
70 | unreachable!("should have already errored on non-item statement") | |
71 | } | |
72 | } | |
73 | _ => { | |
74 | (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); | |
75 | } | |
76 | } | |
ba9703b0 | 77 | ExpandResult::Ready(items) |
dc9dc135 XL |
78 | } |
79 | } | |
80 | ||
54a0048b | 81 | /// Constructs an expression that calls an intrinsic |
dfeec247 XL |
82 | fn call_intrinsic( |
83 | cx: &ExtCtxt<'_>, | |
84 | span: Span, | |
3dfed10e | 85 | intrinsic: Symbol, |
dfeec247 XL |
86 | args: Vec<P<ast::Expr>>, |
87 | ) -> P<ast::Expr> { | |
e1599b0c | 88 | let span = cx.with_def_site_ctxt(span); |
3dfed10e | 89 | let path = cx.std_path(&[sym::intrinsics, intrinsic]); |
29967ef6 XL |
90 | cx.expr_call_global(span, path, args) |
91 | } | |
92 | ||
93 | /// Constructs an expression that calls the `unreachable` intrinsic. | |
94 | fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { | |
95 | let span = cx.with_def_site_ctxt(span); | |
96 | let path = cx.std_path(&[sym::intrinsics, sym::unreachable]); | |
97 | let call = cx.expr_call_global(span, path, vec![]); | |
54a0048b SL |
98 | |
99 | cx.expr_block(P(ast::Block { | |
3157f602 | 100 | stmts: vec![cx.stmt_expr(call)], |
54a0048b SL |
101 | id: ast::DUMMY_NODE_ID, |
102 | rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), | |
3b2f2976 | 103 | span, |
1b1a35ee | 104 | tokens: None, |
94222f64 | 105 | could_be_bare_literal: false, |
5bcae85e | 106 | })) |
54a0048b | 107 | } |
e74abb32 | 108 | |
e74abb32 XL |
109 | // Injects `impl<...> Structural for ItemType<...> { }`. In particular, |
110 | // does *not* add `where T: Structural` for parameters `T` in `...`. | |
111 | // (That's the main reason we cannot use TraitDef here.) | |
dfeec247 XL |
112 | fn inject_impl_of_structural_trait( |
113 | cx: &mut ExtCtxt<'_>, | |
114 | span: Span, | |
115 | item: &Annotatable, | |
3dfed10e | 116 | structural_path: generic::ty::Path, |
dfeec247 XL |
117 | push: &mut dyn FnMut(Annotatable), |
118 | ) { | |
ee023bcb FG |
119 | let Annotatable::Item(ref item) = *item else { |
120 | unreachable!(); | |
e74abb32 XL |
121 | }; |
122 | ||
123 | let generics = match item.kind { | |
dfeec247 | 124 | ItemKind::Struct(_, ref generics) | ItemKind::Enum(_, ref generics) => generics, |
e74abb32 XL |
125 | // Do not inject `impl Structural for Union`. (`PartialEq` does not |
126 | // support unions, so we will see error downstream.) | |
127 | ItemKind::Union(..) => return, | |
128 | _ => unreachable!(), | |
129 | }; | |
130 | ||
131 | // Create generics param list for where clauses and impl headers | |
132 | let mut generics = generics.clone(); | |
133 | ||
134 | // Create the type of `self`. | |
135 | // | |
5099ac24 | 136 | // in addition, remove defaults from generic params (impls cannot have them). |
dfeec247 XL |
137 | let self_params: Vec<_> = generics |
138 | .params | |
139 | .iter_mut() | |
140 | .map(|param| match &mut param.kind { | |
141 | ast::GenericParamKind::Lifetime => { | |
142 | ast::GenericArg::Lifetime(cx.lifetime(span, param.ident)) | |
143 | } | |
144 | ast::GenericParamKind::Type { default } => { | |
145 | *default = None; | |
146 | ast::GenericArg::Type(cx.ty_ident(span, param.ident)) | |
147 | } | |
5869c6ff XL |
148 | ast::GenericParamKind::Const { ty: _, kw_span: _, default } => { |
149 | *default = None; | |
dfeec247 XL |
150 | ast::GenericArg::Const(cx.const_ident(span, param.ident)) |
151 | } | |
152 | }) | |
153 | .collect(); | |
e74abb32 XL |
154 | |
155 | let type_ident = item.ident; | |
156 | ||
157 | let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics)); | |
158 | let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params)); | |
159 | ||
160 | // It would be nice to also encode constraint `where Self: Eq` (by adding it | |
161 | // onto `generics` cloned above). Unfortunately, that strategy runs afoul of | |
162 | // rust-lang/rust#48214. So we perform that additional check in the compiler | |
163 | // itself, instead of encoding it here. | |
164 | ||
165 | // Keep the lint and stability attributes of the original item, to control | |
166 | // how the generated implementation is linted. | |
167 | let mut attrs = Vec::new(); | |
dfeec247 XL |
168 | attrs.extend( |
169 | item.attrs | |
170 | .iter() | |
171 | .filter(|a| { | |
172 | [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] | |
173 | .contains(&a.name_or_empty()) | |
174 | }) | |
175 | .cloned(), | |
176 | ); | |
177 | ||
178 | let newitem = cx.item( | |
179 | span, | |
3c0e092e | 180 | Ident::empty(), |
dfeec247 | 181 | attrs, |
3c0e092e | 182 | ItemKind::Impl(Box::new(Impl { |
74b04a01 | 183 | unsafety: ast::Unsafe::No, |
dfeec247 XL |
184 | polarity: ast::ImplPolarity::Positive, |
185 | defaultness: ast::Defaultness::Final, | |
74b04a01 | 186 | constness: ast::Const::No, |
dfeec247 XL |
187 | generics, |
188 | of_trait: Some(trait_ref), | |
189 | self_ty: self_type, | |
190 | items: Vec::new(), | |
94222f64 | 191 | })), |
dfeec247 | 192 | ); |
e74abb32 XL |
193 | |
194 | push(Annotatable::Item(newitem)); | |
195 | } |