Change:
This should print , but prints . The problem seems to be the pattern, since if this is replaced by aokok_` is not important.)
Confirmed. Bugs where we actually generate the wrong code are pretty bad, so fixing this is probably decently high priority. Not sure it actually fits for a milestone, though?
OK, I've figured out what is going on. The problem is that the matcher is too strict when deciding what patterns are included in some condition. Essentially the problem is that it decides that the condition that are relevant are "length 1" and "length 0" and decides that [2, .. ] is the only pattern that matches "length 1", which is obviously bogus. Fixing this seems a bit tricky, since we need to be able to properly expand out the patterns while still properly handling bindings. Note that this seems like a degenerate case, since the last pattern could just be replaced with a , but there are more complicated and interesting things where this happens too.
Oh, no, there is a pretty simple solution to this. The trick is, when checking submatches generated by a vector length check, set it up so that if none of the subpatterns match, it goes to the next vector length check. I'm explaining it poorly, but it is a really simple fix.
Simple fix has problems, though. So have a more complex fix. Which also has problems. Still investigating.
OK, have it all fixed. Just trying to document it well at this point.

Discussion:
} fn enter_default<'r>(bcx: @mut Block, <del> dm: DefMap, m: &[Match<'r>], col: uint, val: ValueRef) </del> <ins> dm: DefMap, m: &[Match<'r>], col: uint, val: ValueRef, chk: Option<mk_fail>) </ins> -> ~[Match<'r>] { debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)", bcx.to_str(),

bcx.val_to_str(val)); let _indenter = indenter(); <del> do enter_match(bcx, dm, m, col, val) |p| { </del> <ins> // Collect all of the matches that can match against anything. let matches = do enter_match(bcx, dm, m, col, val) |p| { </ins> match p.node { ast::pat_wild | ast::pat_tup(_) => Some(~[]), ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]), _ => None } <del> } </del> <ins> }; // 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 } </ins> } // <pcwalton> nmatsakis: what does enter_opt do?

C_int(ccx, 0) // Placeholder for when not using a switch }; <del> let defaults = enter_default(else_cx, dm, m, col, val); </del> <ins> let defaults = enter_default(else_cx, dm, m, col, val, chk); </ins> let exhaustive = chk.is_none() && defaults.len() == 0u; let len = opts.len();

// option. This file may not be copied, modified, or distributed // except according to those terms. <del> // xfail-test </del> enum side { mayo, catsup, vinegar } enum order { hamburger, fries(side), shake } enum meal { to_go(order), for_here(order) }