Use switches rather than chained conditionals to compile alt matches

This also moves the alt-related trans code into its own file.

Closes #467
This commit is contained in:
Marijn Haverbeke 2011-07-11 16:47:24 +02:00
parent 1ea449e2f6
commit 12d5532166
4 changed files with 433 additions and 219 deletions

View File

@ -32,7 +32,6 @@ import back::link;
import back::x86;
import back::abi;
import back::upcall;
import middle::ty::pat_ty;
import syntax::visit;
import visit::vt;
import util::common;
@ -3370,7 +3369,7 @@ fn move_val_if_temp(@block_ctxt cx, copy_action action, ValueRef dst,
}
}
fn trans_lit(&@crate_ctxt cx, &ast::lit lit, ast::node_id id) -> ValueRef {
fn trans_lit(&@crate_ctxt cx, &ast::lit lit) -> ValueRef {
alt (lit.node) {
case (ast::lit_int(?i)) { ret C_int(i); }
case (ast::lit_uint(?u)) { ret C_int(u as int); }
@ -4742,219 +4741,6 @@ fn trans_do_while(&@block_ctxt cx, &ast::block body, &@ast::expr cond) ->
ret rslt(next_cx, body_res.val);
}
// Pattern matching translation
fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
&@block_ctxt next_cx) -> result {
alt (pat.node) {
case (ast::pat_wild) { ret rslt(cx, llval); }
case (ast::pat_bind(_)) { ret rslt(cx, llval); }
case (ast::pat_lit(?lt)) {
auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, pat.id);
auto lltype = ty::node_id_to_type(cx.fcx.lcx.ccx.tcx, pat.id);
auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit);
auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
ret rslt(matched_cx, llval);
}
case (ast::pat_tag(?ident, ?subpats)) {
auto vdef;
alt (cx.fcx.lcx.ccx.tcx.def_map.find(pat.id)) {
case (some(?x)) { vdef = ast::variant_def_ids(x); }
case (_) {
cx.fcx.lcx.ccx.sess.span_fatal(pat.span,
"trans_pat_match: unbound var");
}
}
auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0);
auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
auto llblobptr = llval;
if (std::ivec::len(variants) == 1u) {
cx.build.Br(matched_cx.llbb);
} else {
auto lltagptr =
cx.build.PointerCast(llval,
T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
auto lldiscrimptr = cx.build.GEP(lltagptr,
~[C_int(0), C_int(0)]);
auto lldiscrim = cx.build.Load(lldiscrimptr);
auto variant_tag = 0;
auto i = 0;
for (ty::variant_info v in variants) {
auto this_variant_id = v.id;
if (vdef._1._0 == this_variant_id._0 &&
vdef._1._1 == this_variant_id._1) {
variant_tag = i;
}
i += 1;
}
auto lleq =
cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
C_int(variant_tag));
cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
if (std::ivec::len(subpats) > 0u) {
llblobptr =
matched_cx.build.GEP(lltagptr, ~[C_int(0), C_int(1)]);
}
}
auto ty_params = ty::node_id_to_type_params
(cx.fcx.lcx.ccx.tcx, pat.id);
if (std::ivec::len(subpats) > 0u) {
auto i = 0;
for (@ast::pat subpat in subpats) {
auto rslt =
GEP_tag(matched_cx, llblobptr, vdef._0, vdef._1,
ty_params, i);
auto llsubvalptr = rslt.val;
matched_cx = rslt.bcx;
auto llsubval =
load_if_immediate(matched_cx, llsubvalptr,
pat_ty(cx.fcx.lcx.ccx.tcx, subpat));
auto subpat_res =
trans_pat_match(matched_cx, subpat, llsubval,
next_cx);
matched_cx = subpat_res.bcx;
i += 1;
}
}
ret rslt(matched_cx, llval);
}
case (ast::pat_rec(?field_pats, _)) {
auto bcx = cx;
auto ccx = cx.fcx.lcx.ccx;
auto rec_ty = pat_ty(ccx.tcx, pat);
auto fields = alt (ty::struct(ccx.tcx, rec_ty)) {
ty::ty_rec(?fields) { fields }
};
for (ast::field_pat f in field_pats) {
let uint ix = ty::field_idx(ccx.sess, f.pat.span,
f.ident, fields);
auto r = GEP_tup_like(bcx, rec_ty, llval, ~[0, ix as int]);
auto v = load_if_immediate(r.bcx, r.val,
pat_ty(ccx.tcx, f.pat));
bcx = trans_pat_match(r.bcx, f.pat, v, next_cx).bcx;
}
ret rslt(bcx, llval);
}
}
}
type bind_map = hashmap[ast::ident, result];
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
bool is_mem, &bind_map bound) -> result {
alt (pat.node) {
case (ast::pat_wild) { ret rslt(cx, llval); }
case (ast::pat_lit(_)) { ret rslt(cx, llval); }
case (ast::pat_bind(?name)) {
auto val = llval;
if (!is_mem) {
val = spill_if_immediate
(cx, llval, node_id_type(cx.fcx.lcx.ccx, pat.id));
}
auto r = rslt(cx, val);
bound.insert(name, r);
ret r;
}
case (ast::pat_tag(_, ?subpats)) {
if (std::ivec::len[@ast::pat](subpats) == 0u) {
ret rslt(cx, llval);
}
// Get the appropriate variant for this tag.
auto vdef;
alt (cx.fcx.lcx.ccx.tcx.def_map.find(pat.id)) {
case (some(?x)) { vdef = ast::variant_def_ids(x); }
case (_) { cx.fcx.lcx.ccx.sess.span_fatal(pat.span,
"trans_pat_binding: internal error, unbound var"); }
}
auto llblobptr = llval;
if (std::ivec::len(ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0))
!= 1u) {
auto lltagptr = cx.build.PointerCast
(llval, T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
llblobptr = cx.build.GEP(lltagptr, ~[C_int(0), C_int(1)]);
}
auto ty_param_substs =
ty::node_id_to_type_params(cx.fcx.lcx.ccx.tcx, pat.id);
auto this_cx = cx;
auto i = 0;
for (@ast::pat subpat in subpats) {
auto rslt =
GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
ty_param_substs, i);
this_cx = rslt.bcx;
auto subpat_res =
trans_pat_binding(this_cx, subpat, rslt.val, true, bound);
this_cx = subpat_res.bcx;
i += 1;
}
ret rslt(this_cx, llval);
}
case (ast::pat_rec(?field_pats, _)) {
auto bcx = cx;
auto ccx = cx.fcx.lcx.ccx;
auto rec_ty = pat_ty(ccx.tcx, pat);
auto fields = alt (ty::struct(ccx.tcx, rec_ty)) {
ty::ty_rec(?fields) { fields }
};
for (ast::field_pat f in field_pats) {
let uint ix = ty::field_idx(ccx.sess, f.pat.span,
f.ident, fields);
auto r = GEP_tup_like(bcx, rec_ty, llval, ~[0, ix as int]);
bcx = trans_pat_binding(bcx, f.pat, r.val, true, bound).bcx;
}
ret rslt(bcx, llval);
}
}
}
fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &ast::arm[] arms,
ast::node_id id, &out_method output) -> result {
auto expr_res = trans_expr(cx, expr);
auto this_cx = expr_res.bcx;
let result[] arm_results = ~[];
for (ast::arm arm in arms) {
auto bind_maps = ~[];
auto block_cx = new_scope_block_ctxt(expr_res.bcx, "case block");
for (@ast::pat pat in arm.pats) {
auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
auto match_res =
trans_pat_match(this_cx, pat, expr_res.val, next_cx);
auto bind_map = new_str_hash[result]();
auto binding_res = trans_pat_binding
(match_res.bcx, pat, expr_res.val, false, bind_map);
bind_maps += ~[bind_map];
binding_res.bcx.build.Br(block_cx.llbb);
this_cx = next_cx;
}
// Go over the names and node_ids of the bound variables, add a Phi
// node for each and register the bindings.
for each (@tup(ast::ident, ast::node_id) item in
ast::pat_id_map(arm.pats.(0)).items()) {
auto vals = ~[]; auto llbbs = ~[];
for (bind_map map in bind_maps) {
auto rslt = map.get(item._0);
vals += ~[rslt.val];
llbbs += ~[rslt.bcx.llbb];
}
auto phi = block_cx.build.Phi(val_ty(vals.(0)), vals, llbbs);
block_cx.fcx.lllocals.insert(item._1, phi);
}
auto block_res = trans_block(block_cx, arm.block, output);
arm_results += ~[block_res];
}
auto default_cx = this_cx;
trans_fail(default_cx, some[span](expr.span),
"non-exhaustive match failure");
ret rslt(join_branches(cx, arm_results), C_nil());
}
type generic_info =
rec(ty::t item_type,
(option::t[@tydesc_info])[] static_tis,
@ -6224,10 +6010,9 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
result {
// FIXME Fill in cx.sp
alt (e.node) {
case (ast::expr_lit(?lit)) {
ret rslt(cx, trans_lit(cx.fcx.lcx.ccx, *lit, e.id));
ret rslt(cx, trans_lit(cx.fcx.lcx.ccx, *lit));
}
case (ast::expr_unary(?op, ?x)) {
if (op != ast::deref) { ret trans_unary(cx, op, x, e.id); }
@ -6259,7 +6044,8 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
ret trans_do_while(cx, body, cond);
}
case (ast::expr_alt(?expr, ?arms)) {
ret with_out_method(bind trans_alt(cx, expr, arms, e.id, _),
ret with_out_method(bind trans_alt::trans_alt(cx, expr,
arms, e.id, _),
cx, e.id, output);
}
case (ast::expr_fn(?f)) {
@ -8692,7 +8478,7 @@ fn trans_tag_variant(@local_ctxt cx, ast::node_id tag_id,
// that does so later on?
fn trans_const_expr(&@crate_ctxt cx, @ast::expr e) -> ValueRef {
alt (e.node) {
case (ast::expr_lit(?lit)) { ret trans_lit(cx, *lit, e.id); }
case (ast::expr_lit(?lit)) { ret trans_lit(cx, *lit); }
case (_) {
cx.sess.span_unimpl(e.span, "consts that's not a plain literal");
}

View File

@ -0,0 +1,426 @@
import std::str;
import std::ivec;
import std::option;
import option::some;
import option::none;
import std::map::hashmap;
import lib::llvm::llvm;
import lib::llvm::llvm::ValueRef;
import lib::llvm::llvm::TypeRef;
import lib::llvm::llvm::BasicBlockRef;
import trans::result;
import trans::rslt;
import trans::crate_ctxt;
import trans::block_ctxt;
import trans::new_sub_block_ctxt;
import trans::new_scope_block_ctxt;
import trans::load_if_immediate;
import trans::C_int;
import trans::C_uint;
import trans::C_nil;
import trans::val_ty;
import ty::pat_ty;
import syntax::ast;
import syntax::ast::def_id;
import syntax::codemap::span;
import util::common::lit_eq;
// An option identifying a branch (either a literal or a tag variant)
tag opt {
lit(@ast::lit);
var(uint /* variant id */, tup(def_id, def_id) /* variant def ids */);
}
fn opt_eq(&opt a, &opt b) -> bool {
alt (a) {
lit(?la) {
ret alt (b) { lit(?lb) { lit_eq(la, lb) } var(_, _) { false } };
}
var(?ida, _) {
ret alt (b) { lit(_) { false } var(?idb, _) { ida == idb } };
}
}
}
fn trans_opt(&@crate_ctxt ccx, &opt o) -> ValueRef {
alt (o) {
lit(?l) { ret trans::trans_lit(ccx, *l); }
var(?id, _) { ret C_int(id as int); }
}
}
fn variant_opt(&@crate_ctxt ccx, ast::node_id pat_id) -> opt {
auto vdef = ast::variant_def_ids(ccx.tcx.def_map.get(pat_id));
auto variants = ty::tag_variants(ccx.tcx, vdef._0);
auto i = 0u;
for (ty::variant_info v in variants) {
if (vdef._1 == v.id) { ret var(i, vdef); }
i += 1u;
}
fail;
}
type bind_map = tup(ast::ident, ValueRef)[];
type match_branch = @rec((@ast::pat)[] pats,
BasicBlockRef body,
mutable bind_map bound);
type match = match_branch[];
fn matches_always(&@ast::pat p) -> bool {
ret alt p.node {
ast::pat_wild { true }
ast::pat_bind(_) { true }
ast::pat_rec(_, _) { true }
_ { false }
};
}
fn bind_for_pat(&@ast::pat p, &match_branch br, ValueRef val) {
alt p.node {
ast::pat_bind(?name) {
br.bound += ~[tup(name, val)];
}
_ {}
}
}
fn enter_default(&match m, uint col, ValueRef val) -> match {
auto result = ~[];
for (match_branch br in m) {
if (matches_always(br.pats.(col))) {
auto pats = ivec::slice(br.pats, 0u, col) +
ivec::slice(br.pats, col + 1u, ivec::len(br.pats));
auto new_br = @rec(pats=pats with *br);
result += ~[new_br];
bind_for_pat(br.pats.(col), new_br, val);
}
}
ret result;
}
fn enter_opt(&@crate_ctxt ccx, &match m, &opt opt,
uint col, uint tag_size, ValueRef val) -> match {
auto result = ~[];
auto dummy = @rec(id=0, node=ast::pat_wild, span=rec(lo=0u, hi=0u));
for (match_branch br in m) {
auto pats = ivec::slice(br.pats, 0u, col);
auto include = true;
alt (br.pats.(col).node) {
ast::pat_tag(?ctor, _) {
include = opt_eq(variant_opt(ccx, br.pats.(col).id), opt);
}
ast::pat_lit(?l) {
include = opt_eq(lit(l), opt);
}
_ {}
}
if (include) {
alt (br.pats.(col).node) {
ast::pat_tag(_, ?subpats) {
assert ivec::len(subpats) == tag_size;
pats += subpats;
}
_ {
pats += ivec::init_elt(dummy, tag_size);
}
}
pats += ivec::slice(br.pats, col + 1u, ivec::len(br.pats));
auto new_br = @rec(pats=pats with *br);
result += ~[new_br];
bind_for_pat(br.pats.(col), new_br, val);
}
}
ret result;
}
fn enter_rec(&@crate_ctxt ccx, &match m, uint col, &ast::ident[] fields,
ValueRef val) -> match {
auto result = ~[];
auto dummy = @rec(id=0, node=ast::pat_wild, span=rec(lo=0u, hi=0u));
for (match_branch br in m) {
auto pats = ivec::slice(br.pats, 0u, col);
alt (br.pats.(col).node) {
ast::pat_rec(?fpats, _) {
for (ast::ident fname in fields) {
auto pat = dummy;
for (ast::field_pat fpat in fpats) {
if (str::eq(fpat.ident, fname)) {
pat = fpat.pat;
break;
}
}
pats += ~[pat];
}
}
_ {
pats += ivec::init_elt(dummy, ivec::len(fields));
}
}
pats += ivec::slice(br.pats, col + 1u, ivec::len(br.pats));
auto new_br = @rec(pats=pats with *br);
result += ~[new_br];
bind_for_pat(br.pats.(col), new_br, val);
}
ret result;
}
fn get_options(&@crate_ctxt ccx, &match m, uint col) -> opt[] {
fn add_to_set(&mutable opt[] set, &opt val) {
for (opt l in set) {
if (opt_eq(l, val)) { ret; }
}
set += ~[val];
}
auto found = ~[];
for (match_branch br in m) {
alt (br.pats.(col).node) {
ast::pat_lit(?l) { add_to_set(found, lit(l)); }
ast::pat_tag(_, _) {
add_to_set(found, variant_opt(ccx, br.pats.(col).id));
}
_ {}
}
}
ret found;
}
fn extract_variant_args(@block_ctxt bcx, ast::node_id pat_id,
&tup(def_id, def_id) vdefs, ValueRef val)
-> tup(ValueRef[], @block_ctxt) {
auto ccx = bcx.fcx.lcx.ccx;
auto ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id);
auto blobptr = val;
auto variants = ty::tag_variants(ccx.tcx, vdefs._0);
auto args = ~[];
auto size = ivec::len(ty::tag_variant_with_id
(ccx.tcx, vdefs._0, vdefs._1).args);
if (size > 0u && ivec::len(variants) != 1u) {
auto tagptr = bcx.build.PointerCast
(val, trans::T_opaque_tag_ptr(ccx.tn));
blobptr = bcx.build.GEP(tagptr, ~[C_int(0), C_int(1)]);
}
auto i = 0u;
while (i < size) {
auto r = trans::GEP_tag(bcx, blobptr, vdefs._0, vdefs._1,
ty_param_substs, i as int);
bcx = r.bcx;
args += ~[r.val];
i += 1u;
}
ret tup(args, bcx);
}
type exit_node = rec(bind_map bound,
BasicBlockRef from,
BasicBlockRef to);
type mk_fail = fn() -> BasicBlockRef;
fn compile_submatch(@block_ctxt bcx, &match m, ValueRef[] vals, &mk_fail f,
&mutable exit_node[] exits) {
if (ivec::len(m) == 0u) {
bcx.build.Br(f());
ret;
}
if (ivec::len(m.(0).pats) == 0u) {
exits += ~[rec(bound=m.(0).bound,
from=bcx.llbb,
to=m.(0).body)];
bcx.build.Br(m.(0).body);
ret;
}
// FIXME maybe be clever about picking a column.
auto col = 0u;
auto val = vals.(col);
auto vals_left = ivec::slice(vals, 1u, ivec::len(vals));
auto ccx = bcx.fcx.lcx.ccx;
auto pat_id = 0;
auto rec_fields = ~[];
for (match_branch br in m) {
// Find a real id (we're adding placeholder wildcard patterns, but
// each column is guaranteed to have at least one real pattern)
if (pat_id == 0) { pat_id = br.pats.(col).id; }
// Gather field names
alt (br.pats.(col).node) {
ast::pat_rec(?fs, _) {
for (ast::field_pat f in fs) {
if (!ivec::any(bind str::eq(f.ident, _), rec_fields)) {
rec_fields += ~[f.ident];
}
}
}
_ {}
}
}
// Separate path for extracting and binding record fields
if (ivec::len(rec_fields) > 0u) {
auto rec_ty = ty::node_id_to_monotype(ccx.tcx, pat_id);
auto fields = alt (ty::struct(ccx.tcx, rec_ty)) {
ty::ty_rec(?fields) { fields }
};
auto rec_vals = ~[];
for (ast::ident field_name in rec_fields) {
let uint ix = ty::field_idx(ccx.sess, rec(lo=0u, hi=0u),
field_name, fields);
auto r = trans::GEP_tup_like(bcx, rec_ty, val, ~[0, ix as int]);
rec_vals += ~[r.val];
bcx = r.bcx;
}
compile_submatch(bcx, enter_rec(ccx, m, col, rec_fields, val),
rec_vals + vals_left, f, exits);
ret;
}
// Decide what kind of branch we need
auto opts = get_options(ccx, m, col);
tag branch_kind { no_branch; single; switch; compare; }
auto kind = no_branch;
auto test_val = val;
if (ivec::len(opts) > 0u) {
alt (opts.(0)) {
var(_, ?vdef) {
if (ivec::len(ty::tag_variants(ccx.tcx, vdef._0)) == 1u) {
kind = single;
} else {
auto tagptr = bcx.build.PointerCast
(val, trans::T_opaque_tag_ptr(ccx.tn));
auto discrimptr = bcx.build.GEP
(tagptr, ~[C_int(0), C_int(0)]);
test_val = bcx.build.Load(discrimptr);
kind = switch;
}
}
lit(?l) {
test_val = bcx.build.Load(val);
kind = alt (l.node) {
ast::lit_str(_, _) { compare }
_ { switch }
};
}
}
}
auto else_cx = alt (kind) {
no_branch | single { bcx }
_ { new_sub_block_ctxt(bcx, "match_else") }
};
auto sw = if (kind == switch) {
bcx.build.Switch(test_val, else_cx.llbb, ivec::len(opts))
} else { C_int(0) }; // Placeholder for when not using a switch
// Compile subtrees for each option
for (opt opt in opts) {
auto opt_cx = new_sub_block_ctxt(bcx, "match_case");
alt (kind) {
single { bcx.build.Br(opt_cx.llbb); }
switch { llvm::LLVMAddCase(sw, trans_opt(ccx, opt), opt_cx.llbb);}
compare {
auto t = ty::node_id_to_type(ccx.tcx, pat_id);
auto eq = trans::trans_compare(bcx, ast::eq, t, test_val,
trans_opt(ccx, opt));
bcx = new_sub_block_ctxt(bcx, "next");
eq.bcx.build.CondBr(eq.val, opt_cx.llbb, bcx.llbb);
}
_ {}
}
auto size = 0u;
auto unpacked = ~[];
alt opt {
var(_, ?vdef) {
auto args = extract_variant_args(opt_cx, pat_id, vdef, val);
size = ivec::len(args._0);
unpacked = args._0;
opt_cx = args._1;
}
lit(_) { }
}
compile_submatch(opt_cx, enter_opt(ccx, m, opt, col, size, val),
unpacked + vals_left, f, exits);
}
// Compile the fall-through case
if (kind == compare) { bcx.build.Br(else_cx.llbb); }
if (kind != single) {
compile_submatch(else_cx, enter_default(m, col, val), vals_left,
f, exits);
}
}
// FIXME breaks on unreacheable cases
fn make_phi_bindings(&@block_ctxt bcx, &exit_node[] map,
&ast::pat_id_map ids) {
fn assoc(str key, &tup(str, ValueRef)[] list) -> ValueRef {
for (tup(str, ValueRef) elt in list) {
if (str::eq(elt._0, key)) { ret elt._1; }
}
fail;
}
auto our_block = bcx.llbb as uint;
for each (@tup(ast::ident, ast::node_id) item in ids.items()) {
auto llbbs = ~[];
auto vals = ~[];
for (exit_node ex in map) {
if (ex.to as uint == our_block) {
llbbs += ~[ex.from];
vals += ~[assoc(item._0, ex.bound)];
}
}
auto phi = bcx.build.Phi(val_ty(vals.(0)), vals, llbbs);
bcx.fcx.lllocals.insert(item._1, phi);
}
}
fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &ast::arm[] arms,
ast::node_id id, &trans::out_method output) -> result {
auto bodies = ~[];
let match match = ~[];
for (ast::arm a in arms) {
auto body = new_scope_block_ctxt(cx, "case_body");
bodies += ~[body];
for (@ast::pat p in a.pats) {
match += ~[@rec(pats=~[p], body=body.llbb, mutable bound=~[])];
}
}
// Cached fail-on-fallthrough block
auto fail_cx = @mutable none;
fn mk_fail(&@block_ctxt cx, &span sp,
@mutable option::t[BasicBlockRef] done) -> BasicBlockRef {
alt (*done) {
some(?bb) { ret bb; }
_ {}
}
auto fail_cx = new_sub_block_ctxt(cx, "case_fallthrough");
trans::trans_fail(fail_cx, some(sp), "non-exhaustive match failure");
*done = some(fail_cx.llbb);
ret fail_cx.llbb;
}
auto exit_map = ~[];
auto er = trans::trans_expr(cx, expr);
auto t = trans::node_id_type(cx.fcx.lcx.ccx, expr.id);
auto v = trans::spill_if_immediate(er.bcx, er.val, t);
compile_submatch(er.bcx, match, ~[v],
bind mk_fail(cx, expr.span, fail_cx), exit_map);
auto i = 0u;
auto arm_results = ~[];
for (ast::arm a in arms) {
auto body_cx = bodies.(i);
make_phi_bindings(body_cx, exit_map, ast::pat_id_map(a.pats.(0)));
auto block_res = trans::trans_block(body_cx, a.block, output);
arm_results += ~[block_res];
i += 1u;
}
ret rslt(trans::join_branches(cx, arm_results), C_nil());
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:

View File

@ -16,6 +16,7 @@ use std (name = "std",
mod middle {
mod trans;
mod trans_alt;
mod ty;
mod ast_map;
mod resolve;

View File

@ -195,6 +195,7 @@ fn call_kind_str(call_kind c) -> str {
case (kind_bind) { "Bind" }
}
}
//
// Local Variables:
// mode: rust