Skip to content

Commit 463cf83

Browse files
committed
rustc: Teach trans::alt.rs about exhaustive alts
Closes #1971
1 parent 1598527 commit 463cf83

File tree

2 files changed

+82
-72
lines changed

2 files changed

+82
-72
lines changed

src/rustc/middle/trans/alt.rs

Lines changed: 80 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,10 @@ fn pick_col(m: match) -> uint {
354354
ret best_col;
355355
}
356356

357-
fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
358-
&exits: [exit_node]) {
357+
fn compile_submatch(bcx: block, m: match, vals: [ValueRef],
358+
chk: option<mk_fail>, &exits: [exit_node]) {
359359
let bcx = bcx, tcx = bcx.tcx(), dm = tcx.def_map;
360-
if m.len() == 0u { Br(bcx, f()); ret; }
360+
if m.len() == 0u { Br(bcx, option::get(chk)()); ret; }
361361
if m[0].pats.len() == 0u {
362362
let data = m[0].data;
363363
alt data.guard {
@@ -372,7 +372,7 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
372372
trans_temp_expr(bcx, e)
373373
};
374374
bcx = with_cond(guard_cx, Not(guard_cx, val)) {|bcx|
375-
compile_submatch(bcx, vec::tail(m), vals, f, exits);
375+
compile_submatch(bcx, vec::tail(m), vals, chk, exits);
376376
bcx
377377
};
378378
}
@@ -389,13 +389,10 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
389389
let val = vals[col];
390390
let m = if has_nested_bindings(m, col) {
391391
expand_nested_bindings(m, col, val)
392-
} else {
393-
m
394-
};
392+
} else { m };
395393

396-
let vals_left =
397-
vec::slice(vals, 0u, col) +
398-
vec::slice(vals, col + 1u, vals.len());
394+
let vals_left = vec::slice(vals, 0u, col) +
395+
vec::slice(vals, col + 1u, vals.len());
399396
let ccx = bcx.fcx.ccx;
400397
let pat_id = 0;
401398
for br: match_branch in m {
@@ -417,7 +414,7 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
417414
bcx = r.bcx;
418415
}
419416
compile_submatch(bcx, enter_rec(dm, m, col, rec_fields, val),
420-
rec_vals + vals_left, f, exits);
417+
rec_vals + vals_left, chk, exits);
421418
ret;
422419
}
423420

@@ -435,7 +432,7 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
435432
i += 1u;
436433
}
437434
compile_submatch(bcx, enter_tup(dm, m, col, val, n_tup_elts),
438-
tup_vals + vals_left, f, exits);
435+
tup_vals + vals_left, chk, exits);
439436
ret;
440437
}
441438

@@ -444,14 +441,14 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
444441
let box = Load(bcx, val);
445442
let unboxed = GEPi(bcx, box, [0, abi::box_field_body]);
446443
compile_submatch(bcx, enter_box(dm, m, col, val), [unboxed]
447-
+ vals_left, f, exits);
444+
+ vals_left, chk, exits);
448445
ret;
449446
}
450447

451448
if any_uniq_pat(m, col) {
452449
let unboxed = Load(bcx, val);
453450
compile_submatch(bcx, enter_uniq(dm, m, col, val),
454-
[unboxed] + vals_left, f, exits);
451+
[unboxed] + vals_left, chk, exits);
455452
ret;
456453
}
457454

@@ -499,42 +496,48 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
499496
Switch(bcx, test_val, else_cx.llbb, opts.len())
500497
} else { C_int(ccx, 0) }; // Placeholder for when not using a switch
501498

502-
// Compile subtrees for each option
503-
for opt: opt in opts {
504-
let opt_cx = sub_block(bcx, "match_case");
505-
alt kind {
506-
single { Br(bcx, opt_cx.llbb); }
507-
switch {
508-
let res = trans_opt(bcx, opt);
509-
alt check res {
510-
single_result(r) {
511-
llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
512-
bcx = r.bcx;
513-
}
514-
}
515-
}
516-
compare {
517-
let t = node_id_type(bcx, pat_id);
518-
let {bcx: after_cx, val: matches} =
519-
with_scope_result(bcx, "compare_scope") {|bcx|
520-
alt trans_opt(bcx, opt) {
521-
single_result({bcx, val}) {
522-
trans_compare(bcx, ast::eq, test_val, t, val, t)
523-
}
524-
range_result({val: vbegin, _}, {bcx, val: vend}) {
525-
let {bcx, val: ge} = trans_compare(bcx, ast::ge, test_val,
526-
t, vbegin, t);
527-
let {bcx, val: le} = trans_compare(bcx, ast::le, test_val,
528-
t, vend, t);
529-
{bcx: bcx, val: And(bcx, ge, le)}
499+
let defaults = enter_default(dm, m, col, val);
500+
let exhaustive = option::is_none(chk) && defaults.len() == 0u;
501+
let len = opts.len(), i = 0u;
502+
// Compile subtrees for each option
503+
for opt in opts {
504+
i += 1u;
505+
let opt_cx = else_cx;
506+
if !exhaustive || i < len {
507+
opt_cx = sub_block(bcx, "match_case");
508+
alt kind {
509+
single { Br(bcx, opt_cx.llbb); }
510+
switch {
511+
alt check trans_opt(bcx, opt) {
512+
single_result(r) {
513+
llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
514+
bcx = r.bcx;
530515
}
531516
}
532-
};
533-
bcx = sub_block(after_cx, "compare_next");
534-
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
535-
}
536-
_ { }
537-
}
517+
}
518+
compare {
519+
let t = node_id_type(bcx, pat_id);
520+
let {bcx: after_cx, val: matches} =
521+
with_scope_result(bcx, "compare_scope") {|bcx|
522+
alt trans_opt(bcx, opt) {
523+
single_result({bcx, val}) {
524+
trans_compare(bcx, ast::eq, test_val, t, val, t)
525+
}
526+
range_result({val: vbegin, _}, {bcx, val: vend}) {
527+
let {bcx, val: ge} = trans_compare(
528+
bcx, ast::ge, test_val, t, vbegin, t);
529+
let {bcx, val: le} = trans_compare(
530+
bcx, ast::le, test_val, t, vend, t);
531+
{bcx: bcx, val: And(bcx, ge, le)}
532+
}
533+
}
534+
};
535+
bcx = sub_block(after_cx, "compare_next");
536+
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
537+
}
538+
_ { }
539+
}
540+
} else if kind == compare { Br(bcx, else_cx.llbb); }
538541
let size = 0u;
539542
let unpacked = [];
540543
alt opt {
@@ -547,14 +550,15 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
547550
lit(_) | range(_, _) { }
548551
}
549552
compile_submatch(opt_cx, enter_opt(tcx, m, opt, col, size, val),
550-
unpacked + vals_left, f, exits);
553+
unpacked + vals_left, chk, exits);
551554
}
552555

553-
// Compile the fall-through case
554-
if kind == compare { Br(bcx, else_cx.llbb); }
555-
if kind != single {
556-
compile_submatch(else_cx, enter_default(dm, m, col, val), vals_left,
557-
f, exits);
556+
// Compile the fall-through case, if any
557+
if !exhaustive {
558+
if kind == compare { Br(bcx, else_cx.llbb); }
559+
if kind != single {
560+
compile_submatch(else_cx, defaults, vals_left, chk, exits);
561+
}
558562
}
559563
}
560564

@@ -605,12 +609,14 @@ fn make_phi_bindings(bcx: block, map: [exit_node],
605609
}
606610

607611
fn trans_alt(bcx: block, expr: @ast::expr, arms: [ast::arm],
608-
dest: dest) -> block {
609-
with_scope(bcx, "alt") {|bcx| trans_alt_inner(bcx, expr, arms, dest)}
612+
mode: ast::alt_mode, dest: dest) -> block {
613+
with_scope(bcx, "alt") {|bcx|
614+
trans_alt_inner(bcx, expr, arms, mode, dest)
615+
}
610616
}
611617

612618
fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: [ast::arm],
613-
dest: dest) -> block {
619+
mode: ast::alt_mode, dest: dest) -> block {
614620
let bcx = scope_cx, tcx = bcx.tcx();
615621
let bodies = [], match = [];
616622

@@ -630,22 +636,26 @@ fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: [ast::arm],
630636
}
631637
}
632638

633-
// Cached fail-on-fallthrough block
634-
let fail_cx = @mutable none;
635-
fn mk_fail(bcx: block, sp: span,
636-
done: @mutable option<BasicBlockRef>) -> BasicBlockRef {
637-
alt *done { some(bb) { ret bb; } _ { } }
638-
let fail_cx = sub_block(bcx, "case_fallthrough");
639-
trans_fail(fail_cx, some(sp), "non-exhaustive match failure");;
640-
*done = some(fail_cx.llbb);
641-
ret fail_cx.llbb;
642-
}
643-
639+
let mk_fail = alt mode {
640+
ast::alt_check {
641+
// Cached fail-on-fallthrough block
642+
let fail_cx = @mutable none;
643+
fn mk_fail(bcx: block, sp: span,
644+
done: @mutable option<BasicBlockRef>) -> BasicBlockRef {
645+
alt *done { some(bb) { ret bb; } _ { } }
646+
let fail_cx = sub_block(bcx, "case_fallthrough");
647+
trans_fail(fail_cx, some(sp), "non-exhaustive match failure");;
648+
*done = some(fail_cx.llbb);
649+
ret fail_cx.llbb;
650+
}
651+
some(bind mk_fail(scope_cx, expr.span, fail_cx))
652+
}
653+
ast::alt_exhaustive { none }
654+
};
644655
let exit_map = [];
645656
let t = node_id_type(bcx, expr.id);
646657
let {bcx, val: spilled} = spill_if_immediate(bcx, val, t);
647-
compile_submatch(bcx, match, [spilled],
648-
bind mk_fail(scope_cx, expr.span, fail_cx), exit_map);
658+
compile_submatch(bcx, match, [spilled], mk_fail, exit_map);
649659

650660
let arm_cxs = [], arm_dests = [], i = 0u;
651661
for a in arms {

src/rustc/middle/trans/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3141,8 +3141,8 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
31413141
ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) {
31423142
ret trans_if(bcx, cond, thn, els, dest);
31433143
}
3144-
ast::expr_alt(expr, arms, _) {
3145-
ret alt::trans_alt(bcx, expr, arms, dest);
3144+
ast::expr_alt(expr, arms, mode) {
3145+
ret alt::trans_alt(bcx, expr, arms, mode, dest);
31463146
}
31473147
ast::expr_block(blk) {
31483148
ret with_scope(bcx, "block-expr body") {|bcx|

0 commit comments

Comments
 (0)