Skip to content

Commit 4991cc5

Browse files
committed
rustc: Translate by-value pattern bindings
1 parent 7f60c56 commit 4991cc5

File tree

1 file changed

+120
-35
lines changed

1 file changed

+120
-35
lines changed

src/rustc/middle/trans/alt.rs

Lines changed: 120 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,24 @@ fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> opt {
7979
core::unreachable();
8080
}
8181

82+
struct binding {
83+
val: ValueRef;
84+
mode: ast::binding_mode;
85+
ty: ty::t;
86+
}
87+
8288
type bind_map = ~[{
8389
ident: ast::ident,
84-
val: ValueRef,
85-
mode: ast::binding_mode
90+
binding: binding
8691
}];
8792

88-
fn assoc(key: ast::ident, list: bind_map) -> option<ValueRef> {
93+
fn assoc(key: ast::ident, list: bind_map) -> option<binding> {
8994
for vec::each(list) |elt| {
90-
if str::eq(*elt.ident, *key) { ret some(elt.val); }
95+
if str::eq(*elt.ident, *key) {
96+
return some(elt.binding);
97+
}
9198
}
92-
ret none;
99+
return none;
93100
}
94101

95102
type match_branch =
@@ -110,7 +117,9 @@ fn has_nested_bindings(m: match_, col: uint) -> bool {
110117
ret false;
111118
}
112119

113-
fn expand_nested_bindings(m: match_, col: uint, val: ValueRef) -> match_ {
120+
fn expand_nested_bindings(bcx: block, m: match_, col: uint, val: ValueRef)
121+
-> match_ {
122+
114123
let mut result = ~[];
115124
for vec::each(m) |br| {
116125
alt br.pats[col].node {
@@ -123,8 +132,12 @@ fn expand_nested_bindings(m: match_, col: uint, val: ValueRef) -> match_ {
123132
@{pats: pats,
124133
bound: vec::append(
125134
br.bound, ~[{ident: path_to_ident(name),
126-
val: val,
127-
mode: mode}])
135+
binding: binding {
136+
val: val,
137+
mode: mode,
138+
ty: node_id_type(bcx,
139+
br.pats[col].id)
140+
}}])
128141
with *br});
129142
}
130143
_ { vec::push(result, br); }
@@ -135,7 +148,7 @@ fn expand_nested_bindings(m: match_, col: uint, val: ValueRef) -> match_ {
135148

136149
type enter_pat = fn(@ast::pat) -> option<~[@ast::pat]>;
137150

138-
fn enter_match(dm: DefMap, m: match_, col: uint, val: ValueRef,
151+
fn enter_match(bcx: block, dm: DefMap, m: match_, col: uint, val: ValueRef,
139152
e: enter_pat) -> match_ {
140153
let mut result = ~[];
141154
for vec::each(m) |br| {
@@ -149,8 +162,11 @@ fn enter_match(dm: DefMap, m: match_, col: uint, val: ValueRef,
149162
ast::pat_ident(mode, name, none) if !pat_is_variant(dm, self) {
150163
vec::append(br.bound,
151164
~[{ident: path_to_ident(name),
152-
val: val,
153-
mode: mode}])
165+
binding: binding {
166+
val: val,
167+
mode: mode,
168+
ty: node_id_type(bcx, br.pats[col].id)
169+
}}])
154170
}
155171
_ { br.bound }
156172
};
@@ -162,8 +178,10 @@ fn enter_match(dm: DefMap, m: match_, col: uint, val: ValueRef,
162178
ret result;
163179
}
164180

165-
fn enter_default(dm: DefMap, m: match_, col: uint, val: ValueRef) -> match_ {
166-
do enter_match(dm, m, col, val) |p| {
181+
fn enter_default(bcx: block, dm: DefMap, m: match_, col: uint, val: ValueRef)
182+
-> match_ {
183+
184+
do enter_match(bcx, dm, m, col, val) |p| {
167185
alt p.node {
168186
ast::pat_wild | ast::pat_rec(_, _) | ast::pat_tup(_) { some(~[]) }
169187
ast::pat_ident(_, _, none) if !pat_is_variant(dm, p) {
@@ -174,10 +192,11 @@ fn enter_default(dm: DefMap, m: match_, col: uint, val: ValueRef) -> match_ {
174192
}
175193
}
176194

177-
fn enter_opt(tcx: ty::ctxt, m: match_, opt: opt, col: uint,
195+
fn enter_opt(bcx: block, m: match_, opt: opt, col: uint,
178196
variant_size: uint, val: ValueRef) -> match_ {
197+
let tcx = bcx.tcx();
179198
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
180-
do enter_match(tcx.def_map, m, col, val) |p| {
199+
do enter_match(bcx, tcx.def_map, m, col, val) |p| {
181200
alt p.node {
182201
ast::pat_enum(_, subpats) {
183202
if opt_eq(tcx, variant_opt(tcx, p.id), opt) {
@@ -200,10 +219,10 @@ fn enter_opt(tcx: ty::ctxt, m: match_, opt: opt, col: uint,
200219
}
201220
}
202221

203-
fn enter_rec(dm: DefMap, m: match_, col: uint, fields: ~[ast::ident],
204-
val: ValueRef) -> match_ {
222+
fn enter_rec(bcx: block, dm: DefMap, m: match_, col: uint,
223+
fields: ~[ast::ident], val: ValueRef) -> match_ {
205224
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
206-
do enter_match(dm, m, col, val) |p| {
225+
do enter_match(bcx, dm, m, col, val) |p| {
207226
alt p.node {
208227
ast::pat_rec(fpats, _) {
209228
let mut pats = ~[];
@@ -221,30 +240,32 @@ fn enter_rec(dm: DefMap, m: match_, col: uint, fields: ~[ast::ident],
221240
}
222241
}
223242

224-
fn enter_tup(dm: DefMap, m: match_, col: uint, val: ValueRef,
243+
fn enter_tup(bcx: block, dm: DefMap, m: match_, col: uint, val: ValueRef,
225244
n_elts: uint) -> match_ {
226245
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
227-
do enter_match(dm, m, col, val) |p| {
246+
do enter_match(bcx, dm, m, col, val) |p| {
228247
alt p.node {
229248
ast::pat_tup(elts) { some(elts) }
230249
_ { some(vec::from_elem(n_elts, dummy)) }
231250
}
232251
}
233252
}
234253

235-
fn enter_box(dm: DefMap, m: match_, col: uint, val: ValueRef) -> match_ {
254+
fn enter_box(bcx: block, dm: DefMap, m: match_, col: uint, val: ValueRef)
255+
-> match_ {
236256
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
237-
do enter_match(dm, m, col, val) |p| {
257+
do enter_match(bcx, dm, m, col, val) |p| {
238258
alt p.node {
239259
ast::pat_box(sub) { some(~[sub]) }
240260
_ { some(~[dummy]) }
241261
}
242262
}
243263
}
244264

245-
fn enter_uniq(dm: DefMap, m: match_, col: uint, val: ValueRef) -> match_ {
265+
fn enter_uniq(bcx: block, dm: DefMap, m: match_, col: uint, val: ValueRef)
266+
-> match_ {
246267
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
247-
do enter_match(dm, m, col, val) |p| {
268+
do enter_match(bcx, dm, m, col, val) |p| {
248269
alt p.node {
249270
ast::pat_uniq(sub) { some(~[sub]) }
250271
_ { some(~[dummy]) }
@@ -407,9 +428,24 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
407428
some(e) {
408429
// Temporarily set bindings. They'll be rewritten to PHI nodes
409430
// for the actual arm block.
431+
//
432+
// Also, in the case of by-value, do the copy now.
433+
410434
for data.id_map.each |key, val| {
411-
let loc = local_mem(option::get(assoc(key, m[0].bound)));
412-
bcx.fcx.lllocals.insert(val, loc);
435+
let binding = assoc(key, m[0].bound).get();
436+
let (llval, mode) = (binding.val, binding.mode);
437+
let ty = binding.ty;
438+
439+
if mode == ast::bind_by_value {
440+
let llty = type_of::type_of(bcx.fcx.ccx, ty);
441+
let alloc = alloca(bcx, llty);
442+
bcx = copy_val(bcx, INIT, alloc,
443+
load_if_immediate(bcx, llval, ty), ty);
444+
bcx.fcx.lllocals.insert(val, local_mem(alloc));
445+
add_clean(bcx, alloc, ty);
446+
} else {
447+
bcx.fcx.lllocals.insert(val, local_mem(llval));
448+
}
413449
};
414450
let {bcx: guard_cx, val} = {
415451
do with_scope_result(bcx, e.info(), ~"guard") |bcx| {
@@ -434,7 +470,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
434470
let col = pick_col(m);
435471
let val = vals[col];
436472
let m = if has_nested_bindings(m, col) {
437-
expand_nested_bindings(m, col, val)
473+
expand_nested_bindings(bcx, m, col, val)
438474
} else { m };
439475

440476
let vals_left = vec::append(vec::slice(vals, 0u, col),
@@ -458,7 +494,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
458494
let ix = option::get(ty::field_idx(field_name, fields));
459495
vec::push(rec_vals, GEPi(bcx, val, ~[0u, ix]));
460496
}
461-
compile_submatch(bcx, enter_rec(dm, m, col, rec_fields, val),
497+
compile_submatch(bcx, enter_rec(bcx, dm, m, col, rec_fields, val),
462498
vec::append(rec_vals, vals_left), chk, exits);
463499
ret;
464500
}
@@ -474,7 +510,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
474510
vec::push(tup_vals, GEPi(bcx, val, ~[0u, i]));
475511
i += 1u;
476512
}
477-
compile_submatch(bcx, enter_tup(dm, m, col, val, n_tup_elts),
513+
compile_submatch(bcx, enter_tup(bcx, dm, m, col, val, n_tup_elts),
478514
vec::append(tup_vals, vals_left), chk, exits);
479515
ret;
480516
}
@@ -485,7 +521,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
485521
let box_no_addrspace = non_gc_box_cast(bcx, llbox);
486522
let unboxed =
487523
GEPi(bcx, box_no_addrspace, ~[0u, abi::box_field_body]);
488-
compile_submatch(bcx, enter_box(dm, m, col, val),
524+
compile_submatch(bcx, enter_box(bcx, dm, m, col, val),
489525
vec::append(~[unboxed], vals_left), chk, exits);
490526
ret;
491527
}
@@ -495,7 +531,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
495531
let box_no_addrspace = non_gc_box_cast(bcx, llbox);
496532
let unboxed =
497533
GEPi(bcx, box_no_addrspace, ~[0u, abi::box_field_body]);
498-
compile_submatch(bcx, enter_uniq(dm, m, col, val),
534+
compile_submatch(bcx, enter_uniq(bcx, dm, m, col, val),
499535
vec::append(~[unboxed], vals_left), chk, exits);
500536
ret;
501537
}
@@ -544,7 +580,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
544580
Switch(bcx, test_val, else_cx.llbb, opts.len())
545581
} else { C_int(ccx, 0) }; // Placeholder for when not using a switch
546582

547-
let defaults = enter_default(dm, m, col, val);
583+
let defaults = enter_default(bcx, dm, m, col, val);
548584
let exhaustive = option::is_none(chk) && defaults.len() == 0u;
549585
let len = opts.len();
550586
let mut i = 0u;
@@ -599,7 +635,7 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
599635
}
600636
lit(_) | range(_, _) { }
601637
}
602-
compile_submatch(opt_cx, enter_opt(tcx, m, opt, col, size, val),
638+
compile_submatch(opt_cx, enter_opt(bcx, m, opt, col, size, val),
603639
vec::append(unpacked, vals_left), chk, exits);
604640
}
605641

@@ -624,9 +660,9 @@ fn make_phi_bindings(bcx: block, map: ~[exit_node],
624660
for vec::each(map) |ex| {
625661
if ex.to as uint == our_block {
626662
alt assoc(name, ex.bound) {
627-
some(val) {
663+
some(binding) {
628664
vec::push(llbbs, ex.from);
629-
vec::push(vals, val);
665+
vec::push(vals, binding.val);
630666
}
631667
none { }
632668
}
@@ -643,6 +679,54 @@ fn make_phi_bindings(bcx: block, map: ~[exit_node],
643679
ret success;
644680
}
645681

682+
// Copies by-value bindings into their homes.
683+
fn copy_by_value_bindings(bcx: block,
684+
exit_node_map: &[exit_node],
685+
pat_ids: pat_util::pat_id_map)
686+
-> block {
687+
let mut bcx = bcx;
688+
let our_block = bcx.llbb as uint;
689+
for pat_ids.each |name, node_id| {
690+
let bindings = dvec::dvec();
691+
for exit_node_map.each |exit_node| {
692+
if exit_node.to as uint == our_block {
693+
match assoc(name, exit_node.bound) {
694+
none => {}
695+
some(binding) => bindings.push(binding)
696+
}
697+
}
698+
}
699+
700+
if bindings.len() == 0 {
701+
again;
702+
}
703+
704+
let binding = bindings[0];
705+
match binding.mode {
706+
ast::bind_by_ref => {}
707+
ast::bind_by_value => {
708+
let llvalue;
709+
match bcx.fcx.lllocals.get(node_id) {
710+
local_mem(llval) =>
711+
llvalue = llval,
712+
local_imm(_) =>
713+
bcx.sess().bug(~"local_imm unexpected here")
714+
}
715+
716+
let lltype = type_of::type_of(bcx.fcx.ccx, binding.ty);
717+
let allocation = alloca(bcx, lltype);
718+
let ty = binding.ty;
719+
bcx = copy_val(bcx, INIT, allocation,
720+
load_if_immediate(bcx, llvalue, ty), ty);
721+
bcx.fcx.lllocals.insert(node_id, local_mem(allocation));
722+
add_clean(bcx, allocation, ty);
723+
}
724+
}
725+
}
726+
727+
return bcx;
728+
}
729+
646730
fn trans_alt(bcx: block,
647731
alt_expr: @ast::expr,
648732
expr: @ast::expr,
@@ -713,6 +797,7 @@ fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: ~[ast::arm],
713797
let body_cx = bodies[i];
714798
let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]);
715799
if make_phi_bindings(body_cx, exit_map, id_map) {
800+
let body_cx = copy_by_value_bindings(body_cx, exit_map, id_map);
716801
let arm_dest = dup_for_join(dest);
717802
vec::push(arm_dests, arm_dest);
718803
let mut arm_cx = trans_block(body_cx, a.body, arm_dest);

0 commit comments

Comments
 (0)