11
11
use deriving:: generic:: * ;
12
12
use deriving:: generic:: ty:: * ;
13
13
14
- use syntax:: ast:: { Expr , Generics , ItemKind , MetaItem , VariantData } ;
14
+ use syntax:: ast:: { self , Expr , Generics , ItemKind , MetaItem , VariantData } ;
15
15
use syntax:: attr;
16
16
use syntax:: ext:: base:: { Annotatable , ExtCtxt } ;
17
17
use syntax:: ext:: build:: AstBuilder ;
18
- use syntax:: parse:: token:: InternedString ;
18
+ use syntax:: parse:: token:: { keywords , InternedString } ;
19
19
use syntax:: ptr:: P ;
20
20
use syntax_pos:: Span ;
21
21
22
- #[ derive( PartialEq ) ]
23
- enum Mode {
24
- Deep ,
25
- Shallow ,
26
- }
27
-
28
22
pub fn expand_deriving_clone ( cx : & mut ExtCtxt ,
29
23
span : Span ,
30
24
mitem : & MetaItem ,
@@ -40,29 +34,38 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
40
34
// if we used the short form with generics, we'd have to bound the generics with
41
35
// Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
42
36
// that is Clone but not Copy. and until specialization we can't write both impls.
37
+ // - the item is a union with Copy fields
38
+ // Unions with generic parameters still can derive Clone because they require Copy
39
+ // for deriving, Clone alone is not enough.
40
+ // Whever Clone is implemented for fields is irrelevant so we don't assert it.
43
41
let bounds;
44
- let unify_fieldless_variants;
45
42
let substructure;
43
+ let is_shallow;
46
44
match * item {
47
45
Annotatable :: Item ( ref annitem) => {
48
46
match annitem. node {
49
47
ItemKind :: Struct ( _, Generics { ref ty_params, .. } ) |
50
48
ItemKind :: Enum ( _, Generics { ref ty_params, .. } )
51
- if ty_params. is_empty ( ) &&
52
- attr:: contains_name ( & annitem. attrs , "rustc_copy_clone_marker" ) => {
53
-
49
+ if attr:: contains_name ( & annitem. attrs , "rustc_copy_clone_marker" ) &&
50
+ ty_params. is_empty ( ) => {
51
+ bounds = vec ! [ ] ;
52
+ is_shallow = true ;
53
+ substructure = combine_substructure ( Box :: new ( |c, s, sub| {
54
+ cs_clone_shallow ( "Clone" , c, s, sub, false )
55
+ } ) ) ;
56
+ }
57
+ ItemKind :: Union ( ..) => {
54
58
bounds = vec ! [ Literal ( path_std!( cx, core:: marker:: Copy ) ) ] ;
55
- unify_fieldless_variants = true ;
59
+ is_shallow = true ;
56
60
substructure = combine_substructure ( Box :: new ( |c, s, sub| {
57
- cs_clone ( "Clone" , c, s, sub, Mode :: Shallow )
61
+ cs_clone_shallow ( "Clone" , c, s, sub, true )
58
62
} ) ) ;
59
63
}
60
-
61
64
_ => {
62
65
bounds = vec ! [ ] ;
63
- unify_fieldless_variants = false ;
66
+ is_shallow = false ;
64
67
substructure = combine_substructure ( Box :: new ( |c, s, sub| {
65
- cs_clone ( "Clone" , c, s, sub, Mode :: Deep )
68
+ cs_clone ( "Clone" , c, s, sub)
66
69
} ) ) ;
67
70
}
68
71
}
@@ -80,7 +83,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
80
83
additional_bounds : bounds,
81
84
generics : LifetimeBounds :: empty ( ) ,
82
85
is_unsafe : false ,
83
- supports_unions : false ,
86
+ supports_unions : true ,
84
87
methods : vec ! [ MethodDef {
85
88
name: "clone" ,
86
89
generics: LifetimeBounds :: empty( ) ,
@@ -89,37 +92,85 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
89
92
ret_ty: Self_ ,
90
93
attributes: attrs,
91
94
is_unsafe: false ,
92
- unify_fieldless_variants: unify_fieldless_variants ,
95
+ unify_fieldless_variants: false ,
93
96
combine_substructure: substructure,
94
97
} ] ,
95
98
associated_types : Vec :: new ( ) ,
96
99
} ;
97
100
98
- trait_def. expand ( cx, mitem, item, push)
101
+ trait_def. expand_ext ( cx, mitem, item, push, is_shallow)
102
+ }
103
+
104
+ fn cs_clone_shallow ( name : & str ,
105
+ cx : & mut ExtCtxt ,
106
+ trait_span : Span ,
107
+ substr : & Substructure ,
108
+ is_union : bool )
109
+ -> P < Expr > {
110
+ fn assert_ty_bounds ( cx : & mut ExtCtxt , stmts : & mut Vec < ast:: Stmt > ,
111
+ ty : P < ast:: Ty > , span : Span , helper_name : & str ) {
112
+ // Generate statement `let _: helper_name<ty>;`,
113
+ // set the expn ID so we can use the unstable struct.
114
+ let span = super :: allow_unstable ( cx, span, "derive(Clone)" ) ;
115
+ let assert_path = cx. path_all ( span, true ,
116
+ cx. std_path ( & [ "clone" , helper_name] ) ,
117
+ vec ! [ ] , vec ! [ ty] , vec ! [ ] ) ;
118
+ let local = P ( ast:: Local {
119
+ pat : cx. pat_wild ( span) ,
120
+ ty : Some ( cx. ty_path ( assert_path) ) ,
121
+ init : None ,
122
+ id : ast:: DUMMY_NODE_ID ,
123
+ span : span,
124
+ attrs : ast:: ThinVec :: new ( ) ,
125
+ } ) ;
126
+ let stmt = ast:: Stmt {
127
+ id : ast:: DUMMY_NODE_ID ,
128
+ node : ast:: StmtKind :: Local ( local) ,
129
+ span : span,
130
+ } ;
131
+ stmts. push ( stmt) ;
132
+ }
133
+ fn process_variant ( cx : & mut ExtCtxt , stmts : & mut Vec < ast:: Stmt > , variant : & VariantData ) {
134
+ for field in variant. fields ( ) {
135
+ // let _: AssertParamIsClone<FieldTy>;
136
+ assert_ty_bounds ( cx, stmts, field. ty . clone ( ) , field. span , "AssertParamIsClone" ) ;
137
+ }
138
+ }
139
+
140
+ let mut stmts = Vec :: new ( ) ;
141
+ if is_union {
142
+ // let _: AssertParamIsCopy<Self>;
143
+ let self_ty = cx. ty_path ( cx. path_ident ( trait_span, keywords:: SelfType . ident ( ) ) ) ;
144
+ assert_ty_bounds ( cx, & mut stmts, self_ty, trait_span, "AssertParamIsCopy" ) ;
145
+ } else {
146
+ match * substr. fields {
147
+ StaticStruct ( vdata, ..) => {
148
+ process_variant ( cx, & mut stmts, vdata) ;
149
+ }
150
+ StaticEnum ( enum_def, ..) => {
151
+ for variant in & enum_def. variants {
152
+ process_variant ( cx, & mut stmts, & variant. node . data ) ;
153
+ }
154
+ }
155
+ _ => cx. span_bug ( trait_span, & format ! ( "unexpected substructure in \
156
+ shallow `derive({})`", name) )
157
+ }
158
+ }
159
+ stmts. push ( cx. stmt_expr ( cx. expr_deref ( trait_span, cx. expr_self ( trait_span) ) ) ) ;
160
+ cx. expr_block ( cx. block ( trait_span, stmts) )
99
161
}
100
162
101
163
fn cs_clone ( name : & str ,
102
164
cx : & mut ExtCtxt ,
103
165
trait_span : Span ,
104
- substr : & Substructure ,
105
- mode : Mode )
166
+ substr : & Substructure )
106
167
-> P < Expr > {
107
168
let ctor_path;
108
169
let all_fields;
109
- let fn_path = match mode {
110
- Mode :: Shallow => cx. std_path ( & [ "clone" , "assert_receiver_is_clone" ] ) ,
111
- Mode :: Deep => cx. std_path ( & [ "clone" , "Clone" , "clone" ] ) ,
112
- } ;
170
+ let fn_path = cx. std_path ( & [ "clone" , "Clone" , "clone" ] ) ;
113
171
let subcall = |cx : & mut ExtCtxt , field : & FieldInfo | {
114
172
let args = vec ! [ cx. expr_addr_of( field. span, field. self_. clone( ) ) ] ;
115
-
116
- let span = if mode == Mode :: Shallow {
117
- // set the expn ID so we can call the unstable method
118
- super :: allow_unstable ( cx, field. span , "derive(Clone)" )
119
- } else {
120
- field. span
121
- } ;
122
- cx. expr_call_global ( span, fn_path. clone ( ) , args)
173
+ cx. expr_call_global ( field. span , fn_path. clone ( ) , args)
123
174
} ;
124
175
125
176
let vdata;
@@ -145,43 +196,31 @@ fn cs_clone(name: &str,
145
196
}
146
197
}
147
198
148
- match mode {
149
- Mode :: Shallow => {
150
- let mut stmts = all_fields. iter ( ) . map ( |f| {
151
- let call = subcall ( cx, f) ;
152
- cx. stmt_expr ( call)
153
- } ) . collect :: < Vec < _ > > ( ) ;
154
- stmts. push ( cx. stmt_expr ( cx. expr_deref ( trait_span, cx. expr_self ( trait_span) ) ) ) ;
155
- cx. expr_block ( cx. block ( trait_span, stmts) )
156
- }
157
- Mode :: Deep => {
158
- match * vdata {
159
- VariantData :: Struct ( ..) => {
160
- let fields = all_fields. iter ( )
161
- . map ( |field| {
162
- let ident = match field. name {
163
- Some ( i) => i,
164
- None => {
165
- cx. span_bug ( trait_span,
166
- & format ! ( "unnamed field in normal struct in \
167
- `derive({})`",
168
- name) )
169
- }
170
- } ;
171
- let call = subcall ( cx, field) ;
172
- cx. field_imm ( field. span , ident, call)
173
- } )
174
- . collect :: < Vec < _ > > ( ) ;
199
+ match * vdata {
200
+ VariantData :: Struct ( ..) => {
201
+ let fields = all_fields. iter ( )
202
+ . map ( |field| {
203
+ let ident = match field. name {
204
+ Some ( i) => i,
205
+ None => {
206
+ cx. span_bug ( trait_span,
207
+ & format ! ( "unnamed field in normal struct in \
208
+ `derive({})`",
209
+ name) )
210
+ }
211
+ } ;
212
+ let call = subcall ( cx, field) ;
213
+ cx. field_imm ( field. span , ident, call)
214
+ } )
215
+ . collect :: < Vec < _ > > ( ) ;
175
216
176
- cx. expr_struct ( trait_span, ctor_path, fields)
177
- }
178
- VariantData :: Tuple ( ..) => {
179
- let subcalls = all_fields. iter ( ) . map ( |f| subcall ( cx, f) ) . collect ( ) ;
180
- let path = cx. expr_path ( ctor_path) ;
181
- cx. expr_call ( trait_span, path, subcalls)
182
- }
183
- VariantData :: Unit ( ..) => cx. expr_path ( ctor_path) ,
184
- }
217
+ cx. expr_struct ( trait_span, ctor_path, fields)
218
+ }
219
+ VariantData :: Tuple ( ..) => {
220
+ let subcalls = all_fields. iter ( ) . map ( |f| subcall ( cx, f) ) . collect ( ) ;
221
+ let path = cx. expr_path ( ctor_path) ;
222
+ cx. expr_call ( trait_span, path, subcalls)
185
223
}
224
+ VariantData :: Unit ( ..) => cx. expr_path ( ctor_path) ,
186
225
}
187
226
}
0 commit comments