1 use crate::deriving
::path_std
;
2 use crate::deriving
::generic
::*;
3 use crate::deriving
::generic
::ty
::*;
5 use syntax
::ast
::{self, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData}
;
7 use syntax
::ext
::base
::{Annotatable, ExtCtxt}
;
8 use syntax
::ext
::build
::AstBuilder
;
10 use syntax
::symbol
::{Symbol, keywords}
;
13 pub fn expand_deriving_clone(cx
: &mut ExtCtxt
<'_
>,
17 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
) => {
38 ItemKind
::Struct(_
, Generics { ref params, .. }
) |
39 ItemKind
::Enum(_
, Generics { ref params, .. }
) => {
40 if attr
::contains_name(&annitem
.attrs
, "rustc_copy_clone_marker") &&
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)
54 substructure
= combine_substructure(Box
::new(|c
, s
, sub
| {
55 cs_clone("Clone", c
, s
, sub
)
59 ItemKind
::Union(..) => {
60 bounds
= vec
![Literal(path_std
!(cx
, marker
::Copy
))];
62 substructure
= combine_substructure(Box
::new(|c
, s
, sub
| {
63 cs_clone_shallow("Clone", c
, s
, sub
, true)
69 substructure
= combine_substructure(Box
::new(|c
, s
, sub
| {
70 cs_clone("Clone", c
, s
, sub
)
76 _
=> cx
.span_bug(span
, "#[derive(Clone)] on trait item or impl item"),
79 let inline
= cx
.meta_word(span
, Symbol
::intern("inline"));
80 let attrs
= vec
![cx
.attribute(span
, inline
)];
81 let trait_def
= TraitDef
{
83 attributes
: Vec
::new(),
84 path
: path_std
!(cx
, clone
::Clone
),
85 additional_bounds
: bounds
,
86 generics
: LifetimeBounds
::empty(),
88 supports_unions
: true,
89 methods
: vec
![MethodDef
{
91 generics
: LifetimeBounds
::empty(),
92 explicit_self
: borrowed_explicit_self(),
97 unify_fieldless_variants
: false,
98 combine_substructure
: substructure
,
100 associated_types
: Vec
::new(),
103 trait_def
.expand_ext(cx
, mitem
, item
, push
, is_shallow
)
106 fn cs_clone_shallow(name
: &str,
107 cx
: &mut ExtCtxt
<'_
>,
109 substr
: &Substructure
<'_
>,
112 fn assert_ty_bounds(cx
: &mut ExtCtxt
<'_
>, stmts
: &mut Vec
<ast
::Stmt
>,
113 ty
: P
<ast
::Ty
>, span
: Span
, helper_name
: &str) {
114 // Generate statement `let _: helper_name<ty>;`,
115 // set the expn ID so we can use the unstable struct.
116 let span
= span
.with_ctxt(cx
.backtrace());
117 let assert_path
= cx
.path_all(span
, true,
118 cx
.std_path(&["clone", helper_name
]),
119 vec
![GenericArg
::Type(ty
)], vec
![]);
120 stmts
.push(cx
.stmt_let_type_only(span
, cx
.ty_path(assert_path
)));
122 fn process_variant(cx
: &mut ExtCtxt
<'_
>, stmts
: &mut Vec
<ast
::Stmt
>, variant
: &VariantData
) {
123 for field
in variant
.fields() {
124 // let _: AssertParamIsClone<FieldTy>;
125 assert_ty_bounds(cx
, stmts
, field
.ty
.clone(), field
.span
, "AssertParamIsClone");
129 let mut stmts
= Vec
::new();
131 // let _: AssertParamIsCopy<Self>;
132 let self_ty
= cx
.ty_path(cx
.path_ident(trait_span
, keywords
::SelfUpper
.ident()));
133 assert_ty_bounds(cx
, &mut stmts
, self_ty
, trait_span
, "AssertParamIsCopy");
135 match *substr
.fields
{
136 StaticStruct(vdata
, ..) => {
137 process_variant(cx
, &mut stmts
, vdata
);
139 StaticEnum(enum_def
, ..) => {
140 for variant
in &enum_def
.variants
{
141 process_variant(cx
, &mut stmts
, &variant
.node
.data
);
144 _
=> cx
.span_bug(trait_span
, &format
!("unexpected substructure in \
145 shallow `derive({})`", name
))
148 stmts
.push(cx
.stmt_expr(cx
.expr_deref(trait_span
, cx
.expr_self(trait_span
))));
149 cx
.expr_block(cx
.block(trait_span
, stmts
))
152 fn cs_clone(name
: &str,
153 cx
: &mut ExtCtxt
<'_
>,
155 substr
: &Substructure
<'_
>)
159 let fn_path
= cx
.std_path(&["clone", "Clone", "clone"]);
160 let subcall
= |cx
: &mut ExtCtxt
<'_
>, field
: &FieldInfo
<'_
>| {
161 let args
= vec
![cx
.expr_addr_of(field
.span
, field
.self_
.clone())];
162 cx
.expr_call_global(field
.span
, fn_path
.clone(), args
)
166 match *substr
.fields
{
167 Struct(vdata_
, ref af
) => {
168 ctor_path
= cx
.path(trait_span
, vec
![substr
.type_ident
]);
172 EnumMatching(.., variant
, ref af
) => {
173 ctor_path
= cx
.path(trait_span
, vec
![substr
.type_ident
, variant
.node
.ident
]);
175 vdata
= &variant
.node
.data
;
177 EnumNonMatchingCollapsed(..) => {
178 cx
.span_bug(trait_span
,
179 &format
!("non-matching enum variants in \
183 StaticEnum(..) | StaticStruct(..) => {
184 cx
.span_bug(trait_span
, &format
!("static method in `derive({})`", name
))
189 VariantData
::Struct(..) => {
190 let fields
= all_fields
.iter()
192 let ident
= match field
.name
{
195 cx
.span_bug(trait_span
,
196 &format
!("unnamed field in normal struct in \
201 let call
= subcall(cx
, field
);
202 cx
.field_imm(field
.span
, ident
, call
)
204 .collect
::<Vec
<_
>>();
206 cx
.expr_struct(trait_span
, ctor_path
, fields
)
208 VariantData
::Tuple(..) => {
209 let subcalls
= all_fields
.iter().map(|f
| subcall(cx
, f
)).collect();
210 let path
= cx
.expr_path(ctor_path
);
211 cx
.expr_call(trait_span
, path
, subcalls
)
213 VariantData
::Unit(..) => cx
.expr_path(ctor_path
),