Skip to content

Commit 437a4c2

Browse files
committed
Fix interaction between default matches and guards. Closes #3121.
1 parent 8cefcc0 commit 437a4c2

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

src/librustc/middle/trans/_match.rs

+31-7
Original file line numberDiff line numberDiff line change
@@ -521,10 +521,11 @@ fn enter_match<'r>(bcx: @mut Block,
521521
}
522522

523523
fn enter_default<'r>(bcx: @mut Block,
524-
dm: DefMap,
525-
m: &[Match<'r>],
526-
col: uint,
527-
val: ValueRef)
524+
dm: DefMap,
525+
m: &[Match<'r>],
526+
col: uint,
527+
val: ValueRef,
528+
chk: Option<mk_fail>)
528529
-> ~[Match<'r>] {
529530
debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
530531
bcx.to_str(),
@@ -533,13 +534,36 @@ fn enter_default<'r>(bcx: @mut Block,
533534
bcx.val_to_str(val));
534535
let _indenter = indenter();
535536

536-
do enter_match(bcx, dm, m, col, val) |p| {
537+
// Collect all of the matches that can match against anything.
538+
let matches = do enter_match(bcx, dm, m, col, val) |p| {
537539
match p.node {
538540
ast::pat_wild | ast::pat_tup(_) => Some(~[]),
539541
ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]),
540542
_ => None
541543
}
542-
}
544+
};
545+
546+
// Ok, now, this is pretty subtle. A "default" match is a match
547+
// that needs to be considered if none of the actual checks on the
548+
// value being considered succeed. The subtlety lies in that sometimes
549+
// identifier/wildcard matches are *not* default matches. Consider:
550+
// "match x { _ if something => foo, true => bar, false => baz }".
551+
// There is a wildcard match, but it is *not* a default case. The boolean
552+
// case on the value being considered is exhaustive. If the case is
553+
// exhaustive, then there are no defaults.
554+
//
555+
// We detect whether the case is exhaustive in the following
556+
// somewhat kludgy way: if the last wildcard/binding match has a
557+
// guard, then by non-redundancy, we know that there aren't any
558+
// non guarded matches, and thus by exhaustiveness, we know that
559+
// we don't need any default cases. If the check *isn't* nonexhaustive
560+
// (because chk is Some), then we need the defaults anyways.
561+
let is_exhaustive = match matches.last_opt() {
562+
Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true,
563+
_ => false
564+
};
565+
566+
if is_exhaustive { ~[] } else { matches }
543567
}
544568

545569
// <pcwalton> nmatsakis: what does enter_opt do?
@@ -1575,7 +1599,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
15751599
C_int(ccx, 0) // Placeholder for when not using a switch
15761600
};
15771601

1578-
let defaults = enter_default(else_cx, dm, m, col, val);
1602+
let defaults = enter_default(else_cx, dm, m, col, val, chk);
15791603
let exhaustive = chk.is_none() && defaults.len() == 0u;
15801604
let len = opts.len();
15811605

src/test/run-pass/issue-3121.rs

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
1211
enum side { mayo, catsup, vinegar }
1312
enum order { hamburger, fries(side), shake }
1413
enum meal { to_go(order), for_here(order) }

0 commit comments

Comments
 (0)