Skip to content

Commit 95a87ae

Browse files
committed
librustc: Implement deriving with a unit return type
1 parent 7e11b74 commit 95a87ae

File tree

5 files changed

+232
-67
lines changed

5 files changed

+232
-67
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,6 +2275,8 @@ fn register_deriving_method(ccx: @crate_ctxt,
22752275
}
22762276

22772277
let path = vec::append(*path, ~[
2278+
ast_map::path_mod(
2279+
ccx.sess.parse_sess.interner.intern(@fmt!("__derived%d__", id))),
22782280
ast_map::path_name(derived_method_info.method_info.ident)
22792281
]);
22802282
let mty = ty::lookup_item_type(ccx.tcx, local_def(id)).ty;

src/librustc/middle/trans/deriving.rs

Lines changed: 157 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,38 @@ use syntax::ast_map::path;
2121
use syntax::ast_util;
2222
use 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

Comments
 (0)