1 use crate::deriving
::generic
::ty
::*;
2 use crate::deriving
::generic
::*;
3 use crate::deriving
::path_std
;
5 use rustc_ast
::ast
::{self, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData}
;
7 use rustc_expand
::base
::{Annotatable, ExtCtxt}
;
8 use rustc_span
::symbol
::{kw, sym, Symbol}
;
11 pub fn expand_deriving_clone(
16 push
: &mut dyn FnMut(Annotatable
),
18 // check if we can use a short form
20 // the short form is `fn clone(&self) -> Self { *self }`
22 // we can use the short form if:
23 // - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy)
24 // - there are no generic parameters (after specialization this limitation can be removed)
25 // if we used the short form with generics, we'd have to bound the generics with
26 // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
27 // that is Clone but not Copy. and until specialization we can't write both impls.
28 // - the item is a union with Copy fields
29 // Unions with generic parameters still can derive Clone because they require Copy
30 // for deriving, Clone alone is not enough.
31 // Whever Clone is implemented for fields is irrelevant so we don't assert it.
36 Annotatable
::Item(ref annitem
) => match annitem
.kind
{
37 ItemKind
::Struct(_
, Generics { ref params, .. }
)
38 | ItemKind
::Enum(_
, Generics { ref params, .. }
) => {
39 let container_id
= cx
.current_expansion
.id
.expn_data().parent
;
40 if cx
.resolver
.has_derive_copy(container_id
)
41 && !params
.iter().any(|param
| match param
.kind
{
42 ast
::GenericParamKind
::Type { .. }
=> true,
48 substructure
= combine_substructure(Box
::new(|c
, s
, sub
| {
49 cs_clone_shallow("Clone", c
, s
, sub
, false)
55 combine_substructure(Box
::new(|c
, s
, sub
| cs_clone("Clone", c
, s
, sub
)));
58 ItemKind
::Union(..) => {
59 bounds
= vec
![Literal(path_std
!(cx
, marker
::Copy
))];
61 substructure
= combine_substructure(Box
::new(|c
, s
, sub
| {
62 cs_clone_shallow("Clone", c
, s
, sub
, true)
69 combine_substructure(Box
::new(|c
, s
, sub
| cs_clone("Clone", c
, s
, sub
)));
73 _
=> cx
.span_bug(span
, "`#[derive(Clone)]` on trait item or impl item"),
76 let inline
= cx
.meta_word(span
, sym
::inline
);
77 let attrs
= vec
![cx
.attribute(inline
)];
78 let trait_def
= TraitDef
{
80 attributes
: Vec
::new(),
81 path
: path_std
!(cx
, clone
::Clone
),
82 additional_bounds
: bounds
,
83 generics
: LifetimeBounds
::empty(),
85 supports_unions
: true,
86 methods
: vec
![MethodDef
{
88 generics
: LifetimeBounds
::empty(),
89 explicit_self
: borrowed_explicit_self(),
94 unify_fieldless_variants
: false,
95 combine_substructure
: substructure
,
97 associated_types
: Vec
::new(),
100 trait_def
.expand_ext(cx
, mitem
, item
, push
, is_shallow
)
105 cx
: &mut ExtCtxt
<'_
>,
107 substr
: &Substructure
<'_
>,
111 cx
: &mut ExtCtxt
<'_
>,
112 stmts
: &mut Vec
<ast
::Stmt
>,
117 // Generate statement `let _: helper_name<ty>;`,
118 // set the expn ID so we can use the unstable struct.
119 let span
= cx
.with_def_site_ctxt(span
);
120 let assert_path
= cx
.path_all(
123 cx
.std_path(&[sym
::clone
, Symbol
::intern(helper_name
)]),
124 vec
![GenericArg
::Type(ty
)],
126 stmts
.push(cx
.stmt_let_type_only(span
, cx
.ty_path(assert_path
)));
128 fn process_variant(cx
: &mut ExtCtxt
<'_
>, stmts
: &mut Vec
<ast
::Stmt
>, variant
: &VariantData
) {
129 for field
in variant
.fields() {
130 // let _: AssertParamIsClone<FieldTy>;
131 assert_ty_bounds(cx
, stmts
, field
.ty
.clone(), field
.span
, "AssertParamIsClone");
135 let mut stmts
= Vec
::new();
137 // let _: AssertParamIsCopy<Self>;
139 cx
.ty_path(cx
.path_ident(trait_span
, ast
::Ident
::with_dummy_span(kw
::SelfUpper
)));
140 assert_ty_bounds(cx
, &mut stmts
, self_ty
, trait_span
, "AssertParamIsCopy");
142 match *substr
.fields
{
143 StaticStruct(vdata
, ..) => {
144 process_variant(cx
, &mut stmts
, vdata
);
146 StaticEnum(enum_def
, ..) => {
147 for variant
in &enum_def
.variants
{
148 process_variant(cx
, &mut stmts
, &variant
.data
);
154 "unexpected substructure in \
155 shallow `derive({})`",
161 stmts
.push(cx
.stmt_expr(cx
.expr_deref(trait_span
, cx
.expr_self(trait_span
))));
162 cx
.expr_block(cx
.block(trait_span
, stmts
))
167 cx
: &mut ExtCtxt
<'_
>,
169 substr
: &Substructure
<'_
>,
173 let fn_path
= cx
.std_path(&[sym
::clone
, sym
::Clone
, sym
::clone
]);
174 let subcall
= |cx
: &mut ExtCtxt
<'_
>, field
: &FieldInfo
<'_
>| {
175 let args
= vec
![cx
.expr_addr_of(field
.span
, field
.self_
.clone())];
176 cx
.expr_call_global(field
.span
, fn_path
.clone(), args
)
180 match *substr
.fields
{
181 Struct(vdata_
, ref af
) => {
182 ctor_path
= cx
.path(trait_span
, vec
![substr
.type_ident
]);
186 EnumMatching(.., variant
, ref af
) => {
187 ctor_path
= cx
.path(trait_span
, vec
![substr
.type_ident
, variant
.ident
]);
189 vdata
= &variant
.data
;
191 EnumNonMatchingCollapsed(..) => {
192 cx
.span_bug(trait_span
, &format
!("non-matching enum variants in `derive({})`", name
,))
194 StaticEnum(..) | StaticStruct(..) => {
195 cx
.span_bug(trait_span
, &format
!("associated function in `derive({})`", name
))
200 VariantData
::Struct(..) => {
201 let fields
= all_fields
204 let ident
= match field
.name
{
208 &format
!("unnamed field in normal struct in `derive({})`", name
,),
211 let call
= subcall(cx
, field
);
212 cx
.field_imm(field
.span
, ident
, call
)
214 .collect
::<Vec
<_
>>();
216 cx
.expr_struct(trait_span
, ctor_path
, fields
)
218 VariantData
::Tuple(..) => {
219 let subcalls
= all_fields
.iter().map(|f
| subcall(cx
, f
)).collect();
220 let path
= cx
.expr_path(ctor_path
);
221 cx
.expr_call(trait_span
, path
, subcalls
)
223 VariantData
::Unit(..) => cx
.expr_path(ctor_path
),