@@ -21,6 +21,38 @@ use syntax::ast_map::path;
21
21
use syntax:: ast_util;
22
22
use syntax:: ast_util:: local_def;
23
23
24
+ /// The kind of deriving method this is.
25
+ enum DerivingKind {
26
+ BoolKind , // fn f(&self, other: &other) -> bool
27
+ UnitKind , // fn f(&self) -> ()
28
+ }
29
+
30
+ impl DerivingKind {
31
+ static fn of_item( ccx: @crate_ctxt , method_did : ast:: def_id )
32
+ -> DerivingKind {
33
+ let item_type = ty:: lookup_item_type ( ccx. tcx , method_did) . ty ;
34
+ match ty:: get( item_type) . sty {
35
+ ty:: ty_fn( ref f) => {
36
+ match ty:: get( f. sig. output) . sty {
37
+ ty:: ty_bool => BoolKind ,
38
+ ty:: ty_nil => UnitKind ,
39
+ _ => {
40
+ // XXX: Report this earlier.
41
+ ccx. tcx. sess. fatal( ~"attempt to automatically derive \
42
+ derive an implementation of a \
43
+ function returning something \
44
+ other than bool or ( ) ") ;
45
+ }
46
+ }
47
+ }
48
+ _ => {
49
+ ccx. tcx. sess. bug( ~"DerivingKind :: of_item( ) : method def ID \
50
+ didn' t have a function type ") ;
51
+ }
52
+ }
53
+ }
54
+ }
55
+
24
56
/// The main "translation" pass for automatically-derived impls. Generates
25
57
/// code for monomorphic methods only. Other methods will be generated when
26
58
/// they are invoked with specific type parameters; see
@@ -36,15 +68,16 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
36
68
impl_def_id) ;
37
69
38
70
for method_dids. each |method_did| {
71
+ let kind = DerivingKind :: of_item ( ccx, * method_did) ;
39
72
let llfn = get_item_val ( ccx, method_did. node ) ;
40
73
match ty:: get ( self_ty. ty ) . sty {
41
74
ty:: ty_class( * ) => {
42
75
trans_deriving_struct_method ( ccx, llfn, impl_def_id,
43
- self_ty. ty ) ;
76
+ self_ty. ty , kind ) ;
44
77
}
45
78
ty:: ty_enum( * ) => {
46
79
trans_deriving_enum_method ( ccx, llfn, impl_def_id,
47
- self_ty. ty ) ;
80
+ self_ty. ty , kind ) ;
48
81
}
49
82
_ => {
50
83
ccx. tcx . sess . bug ( ~"translation of non-struct deriving \
@@ -54,8 +87,11 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
54
87
}
55
88
}
56
89
57
- fn trans_deriving_struct_method ( ccx : @crate_ctxt , llfn : ValueRef ,
58
- impl_did : def_id , self_ty : ty:: t ) {
90
+ fn trans_deriving_struct_method ( ccx : @crate_ctxt ,
91
+ llfn : ValueRef ,
92
+ impl_did : def_id ,
93
+ self_ty : ty:: t ,
94
+ kind : DerivingKind ) {
59
95
let _icx = ccx. insn_ctxt ( "trans_deriving_struct_method" ) ;
60
96
let fcx = new_fn_ctxt ( ccx, ~[ ] , llfn, None ) ;
61
97
let top_bcx = top_scope_block ( fcx, None ) ;
@@ -64,7 +100,13 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
64
100
65
101
let llselfty = type_of ( ccx, self_ty) ;
66
102
let llselfval = PointerCast ( bcx, fcx. llenv , T_ptr ( llselfty) ) ;
67
- let llotherval = llvm:: LLVMGetParam ( llfn, 2 ) ;
103
+
104
+ // If there is an "other" value, then get it.
105
+ let llotherval_opt;
106
+ match kind {
107
+ BoolKind => llotherval_opt = Some ( llvm:: LLVMGetParam ( llfn, 2 ) ) ,
108
+ UnitKind => llotherval_opt = None
109
+ }
68
110
69
111
let struct_field_tys;
70
112
match ty:: get ( self_ty) . sty {
@@ -82,27 +124,43 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
82
124
for ccx. tcx. deriving_struct_methods. get( impl_did) . eachi
83
125
|i, derived_method_info| {
84
126
let llselfval = GEPi ( bcx, llselfval, [ 0 , 0 , i] ) ;
85
- let llotherval = GEPi ( bcx, llotherval, [ 0 , 0 , i] ) ;
127
+
128
+ let llotherval_opt = llotherval_opt. map (
129
+ |llotherval| GEPi ( bcx, * llotherval, [ 0 , 0 , i] ) ) ;
86
130
87
131
let self_ty = struct_field_tys[ i] . mt . ty ;
88
132
bcx = call_substructure_method ( bcx, derived_method_info, self_ty,
89
- llselfval, llotherval) ;
133
+ llselfval, llotherval_opt) ;
134
+
135
+ // If this derived method is of boolean kind, return immediately if
136
+ // the call to the substructure method returned false.
137
+ match kind {
138
+ BoolKind => {
139
+ let next_block = sub_block ( top_bcx, ~"next") ;
140
+ let llcond = Load ( bcx, fcx. llretptr ) ;
141
+ CondBr ( bcx, llcond, next_block. llbb , fcx. llreturn ) ;
142
+ bcx = next_block;
143
+ }
144
+ UnitKind => { } // Unconditionally continue.
145
+ }
146
+ }
90
147
91
- // Return immediately if the call returned false.
92
- let next_block = sub_block ( top_bcx, ~"next") ;
93
- let llcond = Load ( bcx, fcx. llretptr ) ;
94
- CondBr ( bcx, llcond, next_block. llbb , fcx. llreturn ) ;
95
- bcx = next_block;
148
+ // Store true if necessary.
149
+ match kind {
150
+ BoolKind => Store ( bcx, C_bool ( true ) , fcx. llretptr ) ,
151
+ UnitKind => { }
96
152
}
97
153
98
- Store ( bcx, C_bool ( true ) , fcx. llretptr ) ;
99
154
Br ( bcx, fcx. llreturn ) ;
100
155
101
156
finish_fn ( fcx, lltop) ;
102
157
}
103
158
104
- fn trans_deriving_enum_method ( ccx : @crate_ctxt , llfn : ValueRef ,
105
- impl_did : def_id , self_ty : ty:: t ) {
159
+ fn trans_deriving_enum_method ( ccx : @crate_ctxt ,
160
+ llfn : ValueRef ,
161
+ impl_did : def_id ,
162
+ self_ty : ty:: t ,
163
+ kind : DerivingKind ) {
106
164
let _icx = ccx. insn_ctxt ( "trans_deriving_enum_method" ) ;
107
165
let fcx = new_fn_ctxt ( ccx, ~[ ] , llfn, None ) ;
108
166
let top_bcx = top_scope_block ( fcx, None ) ;
@@ -111,7 +169,12 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
111
169
112
170
let llselfty = type_of ( ccx, self_ty) ;
113
171
let llselfval = PointerCast ( bcx, fcx. llenv , T_ptr ( llselfty) ) ;
114
- let llotherval = llvm:: LLVMGetParam ( llfn, 2 ) ;
172
+
173
+ let llotherval_opt;
174
+ match kind {
175
+ UnitKind => llotherval_opt = None ,
176
+ BoolKind => llotherval_opt = Some ( llvm:: LLVMGetParam ( llfn, 2 ) )
177
+ }
115
178
116
179
let enum_id, enum_substs, enum_variant_infos;
117
180
match ty:: get ( self_ty) . sty {
@@ -127,11 +190,18 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
127
190
}
128
191
}
129
192
130
- // Create the "no match" basic block. This is a basic block that does
131
- // nothing more than return false.
132
- let nomatch_bcx = sub_block ( top_bcx, ~"no_match") ;
133
- Store ( nomatch_bcx, C_bool ( false ) , fcx. llretptr ) ;
134
- Br ( nomatch_bcx, fcx. llreturn ) ;
193
+ // Create the "no match" basic block, if necessary. This is a basic block
194
+ // that does nothing more than return false.
195
+ let nomatch_bcx_opt;
196
+ match kind {
197
+ BoolKind => {
198
+ let nomatch_bcx = sub_block ( top_bcx, ~"no_match") ;
199
+ Store ( nomatch_bcx, C_bool ( false ) , fcx. llretptr ) ;
200
+ Br ( nomatch_bcx, fcx. llreturn ) ;
201
+ nomatch_bcx_opt = Some ( nomatch_bcx) ;
202
+ }
203
+ UnitKind => nomatch_bcx_opt = None
204
+ }
135
205
136
206
// Create the "unreachable" basic block.
137
207
let unreachable_bcx = sub_block ( top_bcx, ~"unreachable") ;
@@ -144,11 +214,13 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
144
214
if n_variants != 1 {
145
215
// Grab the two discriminants.
146
216
let llselfdiscrim = Load ( bcx, GEPi ( bcx, llselfval, [ 0 , 0 ] ) ) ;
147
- let llotherdiscrim = Load ( bcx, GEPi ( bcx, llotherval, [ 0 , 0 ] ) ) ;
217
+ let llotherdiscrim_opt = llotherval_opt. map (
218
+ |llotherval| Load ( bcx, GEPi ( bcx, * llotherval, [ 0 , 0 ] ) ) ) ;
148
219
149
220
// Skip over the discriminants and compute the address of the payload.
150
221
let llselfpayload = GEPi ( bcx, llselfval, [ 0 , 1 ] ) ;
151
- let llotherpayload = GEPi ( bcx, llotherval, [ 0 , 1 ] ) ;
222
+ let llotherpayload_opt = llotherval_opt. map (
223
+ |llotherval| GEPi ( bcx, * llotherval, [ 0 , 1 ] ) ) ;
152
224
153
225
// Create basic blocks for the outer switch.
154
226
let outer_bcxs = vec:: from_fn (
@@ -169,46 +241,71 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
169
241
enum_variant_infos[ self_variant_index] . id ;
170
242
let llselfval = GEP_enum ( match_bcx, llselfpayload, enum_id,
171
243
variant_def_id, enum_substs. tps , i) ;
172
- let llotherval = GEP_enum ( match_bcx, llotherpayload,
173
- enum_id, variant_def_id,
174
- enum_substs. tps , i) ;
244
+
245
+ let llotherval_opt = llotherpayload_opt. map ( |llotherpayload|
246
+ GEP_enum ( match_bcx, * llotherpayload, enum_id,
247
+ variant_def_id, enum_substs. tps , i) ) ;
175
248
176
249
let self_ty = enum_variant_infos[ self_variant_index] . args [ i] ;
177
250
match_bcx = call_substructure_method ( match_bcx,
178
251
derived_method_info,
179
252
self_ty,
180
253
llselfval,
181
- llotherval) ;
182
-
183
- // Return immediately if the call to the substructure returned
184
- // false.
185
- let next_bcx = sub_block (
186
- top_bcx, fmt ! ( "next_%u_%u" , self_variant_index, i) ) ;
187
- let llcond = Load ( match_bcx, fcx. llretptr ) ;
188
- CondBr ( match_bcx, llcond, next_bcx. llbb , fcx. llreturn ) ;
189
- match_bcx = next_bcx;
254
+ llotherval_opt) ;
255
+
256
+ // If this is a boolean-kind deriving method, then return
257
+ // immediately if the call to the substructure returned false.
258
+ match kind {
259
+ BoolKind => {
260
+ let next_bcx = sub_block ( top_bcx,
261
+ fmt ! ( "next_%u_%u" ,
262
+ self_variant_index,
263
+ i) ) ;
264
+ let llcond = Load ( match_bcx, fcx. llretptr ) ;
265
+ CondBr ( match_bcx,
266
+ llcond,
267
+ next_bcx. llbb ,
268
+ fcx. llreturn ) ;
269
+ match_bcx = next_bcx;
270
+ }
271
+ UnitKind => { }
272
+ }
273
+ }
274
+
275
+ // Store true in the return pointer if this is a boolean-kind
276
+ // deriving method.
277
+ match kind {
278
+ BoolKind => Store ( match_bcx, C_bool ( true ) , fcx. llretptr ) ,
279
+ UnitKind => { }
190
280
}
191
281
192
282
// Finish up the matching block.
193
- Store ( match_bcx, C_bool ( true ) , fcx. llretptr ) ;
194
283
Br ( match_bcx, fcx. llreturn ) ;
195
284
196
- // Build the inner switch.
197
- let llswitch = Switch (
198
- * bcx, llotherdiscrim, unreachable_bcx. llbb , n_variants) ;
199
- for uint:: range( 0 , n_variants) |other_variant_index| {
200
- let discriminant =
201
- enum_variant_infos[ other_variant_index] . disr_val ;
202
- if self_variant_index == other_variant_index {
203
- // This is the potentially-matching case.
204
- AddCase ( llswitch,
205
- C_int ( ccx, discriminant) ,
206
- top_match_bcx. llbb ) ;
207
- } else {
208
- // This is always a non-matching case.
209
- AddCase ( llswitch,
210
- C_int ( ccx, discriminant) ,
211
- nomatch_bcx. llbb ) ;
285
+ // If this is a boolean-kind derived method, build the inner
286
+ // switch. Otherwise, just jump to the matching case.
287
+ match llotherdiscrim_opt {
288
+ None => Br ( * bcx, top_match_bcx. llbb ) ,
289
+ Some ( copy llotherdiscrim) => {
290
+ let llswitch = Switch ( * bcx,
291
+ llotherdiscrim,
292
+ unreachable_bcx. llbb ,
293
+ n_variants) ;
294
+ for uint:: range( 0 , n_variants) |other_variant_index| {
295
+ let discriminant =
296
+ enum_variant_infos[ other_variant_index] . disr_val ;
297
+ if self_variant_index == other_variant_index {
298
+ // This is the potentially-matching case.
299
+ AddCase ( llswitch,
300
+ C_int ( ccx, discriminant) ,
301
+ top_match_bcx. llbb ) ;
302
+ } else {
303
+ // This is always a non-matching case.
304
+ AddCase ( llswitch,
305
+ C_int ( ccx, discriminant) ,
306
+ nomatch_bcx_opt. get ( ) . llbb ) ;
307
+ }
308
+ }
212
309
}
213
310
}
214
311
}
@@ -233,7 +330,7 @@ fn call_substructure_method(bcx: block,
233
330
derived_field_info : & DerivedFieldInfo ,
234
331
self_ty : ty:: t ,
235
332
llselfval : ValueRef ,
236
- llotherval : ValueRef ) -> block {
333
+ llotherval_opt : Option < ValueRef > ) -> block {
237
334
let fcx = bcx. fcx ;
238
335
let ccx = fcx. ccx ;
239
336
@@ -273,12 +370,18 @@ fn call_substructure_method(bcx: block,
273
370
}
274
371
} ;
275
372
373
+ let arg_values;
374
+ match llotherval_opt {
375
+ None => arg_values = ArgVals ( ~[ ] ) ,
376
+ Some ( copy llotherval) => arg_values = ArgVals ( ~[ llotherval] )
377
+ }
378
+
276
379
callee:: trans_call_inner ( bcx,
277
380
None ,
278
381
fn_expr_tpbt. ty ,
279
382
ty:: mk_bool ( ccx. tcx ) ,
280
383
cb,
281
- ArgVals ( ~ [ llotherval ] ) ,
384
+ move arg_values ,
282
385
SaveIn ( fcx. llretptr ) ,
283
386
DontAutorefArg )
284
387
}
0 commit comments