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