@@ -21,6 +21,38 @@ use syntax::ast_map::path;
2121use syntax:: ast_util;
2222use syntax:: ast_util:: local_def;
2323
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+
2456/// The main "translation" pass for automatically-derived impls. Generates
2557 /// code for monomorphic methods only. Other methods will be generated when
2658/// they are invoked with specific type parameters; see
@@ -36,15 +68,16 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
3668 impl_def_id) ;
3769
3870 for method_dids. each |method_did| {
71+ let kind = DerivingKind :: of_item ( ccx, * method_did) ;
3972 let llfn = get_item_val ( ccx, method_did. node ) ;
4073 match ty:: get ( self_ty. ty ) . sty {
4174 ty:: ty_class( * ) => {
4275 trans_deriving_struct_method ( ccx, llfn, impl_def_id,
43- self_ty. ty ) ;
76+ self_ty. ty , kind ) ;
4477 }
4578 ty:: ty_enum( * ) => {
4679 trans_deriving_enum_method ( ccx, llfn, impl_def_id,
47- self_ty. ty ) ;
80+ self_ty. ty , kind ) ;
4881 }
4982 _ => {
5083 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,
5487 }
5588}
5689
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 ) {
5995 let _icx = ccx. insn_ctxt ( "trans_deriving_struct_method" ) ;
6096 let fcx = new_fn_ctxt ( ccx, ~[ ] , llfn, None ) ;
6197 let top_bcx = top_scope_block ( fcx, None ) ;
@@ -64,7 +100,13 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
64100
65101 let llselfty = type_of ( ccx, self_ty) ;
66102 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+ }
68110
69111 let struct_field_tys;
70112 match ty:: get ( self_ty) . sty {
@@ -82,27 +124,43 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
82124 for ccx. tcx. deriving_struct_methods. get( impl_did) . eachi
83125 |i, derived_method_info| {
84126 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] ) ) ;
86130
87131 let self_ty = struct_field_tys[ i] . mt . ty ;
88132 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+ }
90147
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 => { }
96152 }
97153
98- Store ( bcx, C_bool ( true ) , fcx. llretptr ) ;
99154 Br ( bcx, fcx. llreturn ) ;
100155
101156 finish_fn ( fcx, lltop) ;
102157}
103158
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 ) {
106164 let _icx = ccx. insn_ctxt ( "trans_deriving_enum_method" ) ;
107165 let fcx = new_fn_ctxt ( ccx, ~[ ] , llfn, None ) ;
108166 let top_bcx = top_scope_block ( fcx, None ) ;
@@ -111,7 +169,12 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
111169
112170 let llselfty = type_of ( ccx, self_ty) ;
113171 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+ }
115178
116179 let enum_id, enum_substs, enum_variant_infos;
117180 match ty:: get ( self_ty) . sty {
@@ -127,11 +190,18 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
127190 }
128191 }
129192
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+ }
135205
136206 // Create the "unreachable" basic block.
137207 let unreachable_bcx = sub_block ( top_bcx, ~"unreachable") ;
@@ -144,11 +214,13 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
144214 if n_variants != 1 {
145215 // Grab the two discriminants.
146216 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 ] ) ) ) ;
148219
149220 // Skip over the discriminants and compute the address of the payload.
150221 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 ] ) ) ;
152224
153225 // Create basic blocks for the outer switch.
154226 let outer_bcxs = vec:: from_fn (
@@ -169,46 +241,71 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
169241 enum_variant_infos[ self_variant_index] . id ;
170242 let llselfval = GEP_enum ( match_bcx, llselfpayload, enum_id,
171243 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) ) ;
175248
176249 let self_ty = enum_variant_infos[ self_variant_index] . args [ i] ;
177250 match_bcx = call_substructure_method ( match_bcx,
178251 derived_method_info,
179252 self_ty,
180253 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 => { }
190280 }
191281
192282 // Finish up the matching block.
193- Store ( match_bcx, C_bool ( true ) , fcx. llretptr ) ;
194283 Br ( match_bcx, fcx. llreturn ) ;
195284
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+ }
212309 }
213310 }
214311 }
@@ -233,7 +330,7 @@ fn call_substructure_method(bcx: block,
233330 derived_field_info : & DerivedFieldInfo ,
234331 self_ty : ty:: t ,
235332 llselfval : ValueRef ,
236- llotherval : ValueRef ) -> block {
333+ llotherval_opt : Option < ValueRef > ) -> block {
237334 let fcx = bcx. fcx ;
238335 let ccx = fcx. ccx ;
239336
@@ -273,12 +370,18 @@ fn call_substructure_method(bcx: block,
273370 }
274371 } ;
275372
373+ let arg_values;
374+ match llotherval_opt {
375+ None => arg_values = ArgVals ( ~[ ] ) ,
376+ Some ( copy llotherval) => arg_values = ArgVals ( ~[ llotherval] )
377+ }
378+
276379 callee:: trans_call_inner ( bcx,
277380 None ,
278381 fn_expr_tpbt. ty ,
279382 ty:: mk_bool ( ccx. tcx ) ,
280383 cb,
281- ArgVals ( ~ [ llotherval ] ) ,
384+ move arg_values ,
282385 SaveIn ( fcx. llretptr ) ,
283386 DontAutorefArg )
284387}
0 commit comments