Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #14865 #15004

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 12 additions & 42 deletions src/librustc/middle/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,7 @@ fn enter_default<'a, 'b>(
dm: &DefMap,
m: &'a [Match<'a, 'b>],
col: uint,
val: ValueRef,
chk: &FailureHandler)
val: ValueRef)
-> Vec<Match<'a, 'b>> {
debug!("enter_default(bcx={}, m={}, col={}, val={})",
bcx.to_str(),
Expand All @@ -529,35 +528,13 @@ fn enter_default<'a, 'b>(
let _indenter = indenter();

// Collect all of the matches that can match against anything.
let matches = enter_match(bcx, dm, m, col, val, |p| {
enter_match(bcx, dm, m, col, val, |p| {
match p.node {
ast::PatWild | ast::PatWildMulti => Some(Vec::new()),
ast::PatIdent(_, _, None) if pat_is_binding(dm, &*p) => Some(Vec::new()),
_ => 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() {
Some(m) if m.data.arm.guard.is_some() && chk.is_infallible() => true,
_ => false
};

if is_exhaustive { Vec::new() } else { matches }
})
}

// <pcwalton> nmatsakis: what does enter_opt do?
Expand Down Expand Up @@ -1448,15 +1425,12 @@ fn compile_submatch<'a, 'b>(
m.repr(bcx.tcx()),
vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
let _indenter = indenter();

/*
For an empty match, a fall-through case must exist
*/
assert!((m.len() > 0u || chk.is_fallible()));
let _icx = push_ctxt("match::compile_submatch");
let mut bcx = bcx;
if m.len() == 0u {
Br(bcx, chk.handle_fail());
if chk.is_fallible() {
Br(bcx, chk.handle_fail());
}
return;
}
if m[0].pats.len() == 0u {
Expand Down Expand Up @@ -1658,7 +1632,7 @@ fn compile_submatch_continue<'a, 'b>(
C_int(ccx, 0) // Placeholder for when not using a switch
};

let defaults = enter_default(else_cx, dm, m, col, val, chk);
let defaults = enter_default(else_cx, dm, m, col, val);
let exhaustive = chk.is_infallible() && defaults.len() == 0u;
let len = opts.len();

Expand Down Expand Up @@ -1947,18 +1921,14 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,

// `compile_submatch` works one column of arm patterns a time and
// then peels that column off. So as we progress, it may become
// impossible to know whether we have a genuine default arm, i.e.
// impossible to tell whether we have a genuine default arm, i.e.
// `_ => foo` or not. Sometimes it is important to know that in order
// to decide whether moving on to the next condition or falling back
// to the default arm.
let has_default = arms.len() > 0 && {
let ref pats = arms.last().unwrap().pats;

pats.len() == 1
&& match pats.last().unwrap().node {
ast::PatWild => true, _ => false
}
};
let has_default = arms.last().map_or(false, |arm| {
arm.pats.len() == 1
&& arm.pats.last().unwrap().node == ast::PatWild
});

compile_submatch(bcx, matches.as_slice(), [discr_datum.val], &chk, has_default);

Expand Down
30 changes: 30 additions & 0 deletions src/test/run-pass/issue-14865.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum X {
Foo(uint),
Bar(bool)
}

fn main() {
let x = match Foo(42) {
Foo(..) => 1,
_ if true => 0,
Bar(..) => fail!("Oh dear")
};
assert_eq!(x, 1);

let x = match Foo(42) {
_ if true => 0,
Foo(..) => 1,
Bar(..) => fail!("Oh dear")
};
assert_eq!(x, 0);
}