diff options
| -rw-r--r-- | src/librustc/middle/trans/_match.rs | 38 | ||||
| -rw-r--r-- | src/test/run-pass/issue-3121.rs | 1 |
2 files changed, 31 insertions, 8 deletions
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 9c2a77da149..a3164c6a848 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -521,10 +521,11 @@ fn enter_match<'r>(bcx: @mut Block, } fn enter_default<'r>(bcx: @mut Block, - dm: DefMap, - m: &[Match<'r>], - col: uint, - val: ValueRef) + dm: DefMap, + m: &[Match<'r>], + col: uint, + val: ValueRef, + chk: Option<mk_fail>) -> ~[Match<'r>] { debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)", bcx.to_str(), @@ -533,13 +534,36 @@ fn enter_default<'r>(bcx: @mut Block, bcx.val_to_str(val)); let _indenter = indenter(); - do enter_match(bcx, dm, m, col, val) |p| { + // Collect all of the matches that can match against anything. + let matches = do enter_match(bcx, dm, m, col, val) |p| { match p.node { ast::pat_wild | ast::pat_tup(_) => Some(~[]), ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]), _ => None } - } + }; + + // Ok, now, this is pretty subtle. A "default" match is a match + // that needs to be considered if none of the actual checks on the + // value being considered succeed. The subtlety lies in that sometimes + // identifier/wildcard matches are *not* default matches. Consider: + // "match x { _ if something => foo, true => bar, false => baz }". + // There is a wildcard match, but it is *not* a default case. The boolean + // case on the value being considered is exhaustive. If the case is + // exhaustive, then there are no defaults. + // + // We detect whether the case is exhaustive in the following + // somewhat kludgy way: if the last wildcard/binding match has a + // guard, then by non-redundancy, we know that there aren't any + // non guarded matches, and thus by exhaustiveness, we know that + // we don't need any default cases. If the check *isn't* nonexhaustive + // (because chk is Some), then we need the defaults anyways. + let is_exhaustive = match matches.last_opt() { + Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true, + _ => false + }; + + if is_exhaustive { ~[] } else { matches } } // <pcwalton> nmatsakis: what does enter_opt do? @@ -1575,7 +1599,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, C_int(ccx, 0) // Placeholder for when not using a switch }; - let defaults = enter_default(else_cx, dm, m, col, val); + let defaults = enter_default(else_cx, dm, m, col, val, chk); let exhaustive = chk.is_none() && defaults.len() == 0u; let len = opts.len(); diff --git a/src/test/run-pass/issue-3121.rs b/src/test/run-pass/issue-3121.rs index 522a68856b6..206dc383cb3 100644 --- a/src/test/run-pass/issue-3121.rs +++ b/src/test/run-pass/issue-3121.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test enum side { mayo, catsup, vinegar } enum order { hamburger, fries(side), shake } enum meal { to_go(order), for_here(order) } |
