Rewrite exhaustiveness checker
Issue #352 Closes #1720 The old checker would happily accept things like 'alt x { @some(a) { a } }'. It now properly descends into patterns, checks exhaustiveness of booleans, and complains when number/string patterns aren't exhaustive.
This commit is contained in:
parent
4b63826050
commit
67cc89f38d
32 changed files with 193 additions and 125 deletions
|
@ -218,7 +218,7 @@ fn lookup_def(cnum: ast::crate_num, data: @[u8], did_: ast::def_id) ->
|
||||||
let fam_ch = item_family(item);
|
let fam_ch = item_family(item);
|
||||||
let did = {crate: cnum, node: did_.node};
|
let did = {crate: cnum, node: did_.node};
|
||||||
// We treat references to enums as references to types.
|
// We treat references to enums as references to types.
|
||||||
alt fam_ch {
|
alt check fam_ch {
|
||||||
'c' { ast::def_const(did) }
|
'c' { ast::def_const(did) }
|
||||||
'u' { ast::def_fn(did, ast::unsafe_fn) }
|
'u' { ast::def_fn(did, ast::unsafe_fn) }
|
||||||
'f' { ast::def_fn(did, ast::impure_fn) }
|
'f' { ast::def_fn(did, ast::impure_fn) }
|
||||||
|
@ -336,7 +336,7 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
||||||
_ { tcx.sess.bug("get_iface_methods: id has non-function type");
|
_ { tcx.sess.bug("get_iface_methods: id has non-function type");
|
||||||
} };
|
} };
|
||||||
result += [{ident: name, tps: bounds, fty: fty,
|
result += [{ident: name, tps: bounds, fty: fty,
|
||||||
purity: alt item_family(mth) {
|
purity: alt check item_family(mth) {
|
||||||
'u' { ast::unsafe_fn }
|
'u' { ast::unsafe_fn }
|
||||||
'f' { ast::impure_fn }
|
'f' { ast::impure_fn }
|
||||||
'p' { ast::pure_fn }
|
'p' { ast::pure_fn }
|
||||||
|
@ -346,7 +346,7 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn family_has_type_params(fam_ch: char) -> bool {
|
fn family_has_type_params(fam_ch: char) -> bool {
|
||||||
alt fam_ch {
|
alt check fam_ch {
|
||||||
'c' | 'T' | 'm' | 'n' { false }
|
'c' | 'T' | 'm' | 'n' { false }
|
||||||
'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' { true }
|
'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' { true }
|
||||||
}
|
}
|
||||||
|
@ -370,7 +370,7 @@ fn describe_def(items: ebml::doc, id: ast::def_id) -> str {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_family_to_str(fam: char) -> str {
|
fn item_family_to_str(fam: char) -> str {
|
||||||
alt fam {
|
alt check fam {
|
||||||
'c' { ret "const"; }
|
'c' { ret "const"; }
|
||||||
'f' { ret "fn"; }
|
'f' { ret "fn"; }
|
||||||
'u' { ret "unsafe fn"; }
|
'u' { ret "unsafe fn"; }
|
||||||
|
|
|
@ -177,7 +177,7 @@ fn parse_proto(c: char) -> ast::proto {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
||||||
alt next(st) {
|
alt check next(st) {
|
||||||
'n' { ret ty::mk_nil(st.tcx); }
|
'n' { ret ty::mk_nil(st.tcx); }
|
||||||
'z' { ret ty::mk_bot(st.tcx); }
|
'z' { ret ty::mk_bot(st.tcx); }
|
||||||
'b' { ret ty::mk_bool(st.tcx); }
|
'b' { ret ty::mk_bool(st.tcx); }
|
||||||
|
@ -185,7 +185,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
||||||
'u' { ret ty::mk_uint(st.tcx); }
|
'u' { ret ty::mk_uint(st.tcx); }
|
||||||
'l' { ret ty::mk_float(st.tcx); }
|
'l' { ret ty::mk_float(st.tcx); }
|
||||||
'M' {
|
'M' {
|
||||||
alt next(st) {
|
alt check next(st) {
|
||||||
'b' { ret ty::mk_mach_uint(st.tcx, ast::ty_u8); }
|
'b' { ret ty::mk_mach_uint(st.tcx, ast::ty_u8); }
|
||||||
'w' { ret ty::mk_mach_uint(st.tcx, ast::ty_u16); }
|
'w' { ret ty::mk_mach_uint(st.tcx, ast::ty_u16); }
|
||||||
'l' { ret ty::mk_mach_uint(st.tcx, ast::ty_u32); }
|
'l' { ret ty::mk_mach_uint(st.tcx, ast::ty_u32); }
|
||||||
|
@ -269,7 +269,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
||||||
'Y' { ret ty::mk_type(st.tcx); }
|
'Y' { ret ty::mk_type(st.tcx); }
|
||||||
'y' { ret ty::mk_send_type(st.tcx); }
|
'y' { ret ty::mk_send_type(st.tcx); }
|
||||||
'C' {
|
'C' {
|
||||||
let ck = alt next(st) {
|
let ck = alt check next(st) {
|
||||||
'&' { ty::ck_block }
|
'&' { ty::ck_block }
|
||||||
'@' { ty::ck_box }
|
'@' { ty::ck_box }
|
||||||
'~' { ty::ck_uniq }
|
'~' { ty::ck_uniq }
|
||||||
|
@ -355,7 +355,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
|
||||||
assert (next(st) == '[');
|
assert (next(st) == '[');
|
||||||
let inputs: [ty::arg] = [];
|
let inputs: [ty::arg] = [];
|
||||||
while peek(st) != ']' {
|
while peek(st) != ']' {
|
||||||
let mode = alt peek(st) {
|
let mode = alt check peek(st) {
|
||||||
'&' { ast::by_mut_ref }
|
'&' { ast::by_mut_ref }
|
||||||
'-' { ast::by_move }
|
'-' { ast::by_move }
|
||||||
'+' { ast::by_copy }
|
'+' { ast::by_copy }
|
||||||
|
@ -405,7 +405,7 @@ fn parse_bounds_data(data: @[u8], start: uint,
|
||||||
fn parse_bounds(st: @pstate, conv: conv_did) -> @[ty::param_bound] {
|
fn parse_bounds(st: @pstate, conv: conv_did) -> @[ty::param_bound] {
|
||||||
let bounds = [];
|
let bounds = [];
|
||||||
while true {
|
while true {
|
||||||
bounds += [alt next(st) {
|
bounds += [alt check next(st) {
|
||||||
'S' { ty::bound_send }
|
'S' { ty::bound_send }
|
||||||
'C' { ty::bound_copy }
|
'C' { ty::bound_copy }
|
||||||
'I' { ty::bound_iface(parse_ty(st, conv)) }
|
'I' { ty::bound_iface(parse_ty(st, conv)) }
|
||||||
|
|
|
@ -27,7 +27,7 @@ fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
|
||||||
/* Check for exhaustiveness */
|
/* Check for exhaustiveness */
|
||||||
if mode == alt_exhaustive {
|
if mode == alt_exhaustive {
|
||||||
let arms = vec::concat(vec::filter_map(arms, unguarded_pat));
|
let arms = vec::concat(vec::filter_map(arms, unguarded_pat));
|
||||||
check_exhaustive(tcx, ex.span, expr_ty(tcx, scrut), arms);
|
check_exhaustive(tcx, ex.span, arms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ { }
|
_ { }
|
||||||
|
@ -59,89 +59,136 @@ fn check_arms(tcx: ty::ctxt, arms: [arm]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn raw_pat(p: @pat) -> @pat {
|
||||||
|
alt p.node {
|
||||||
|
pat_ident(_, some(s)) { raw_pat(s) }
|
||||||
|
_ { p }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Precondition: patterns have been normalized
|
// Precondition: patterns have been normalized
|
||||||
// (not checked statically yet)
|
// (not checked statically yet)
|
||||||
fn check_exhaustive(tcx: ty::ctxt, sp:span, scrut_ty:ty::t, pats:[@pat]) {
|
fn check_exhaustive(tcx: ty::ctxt, sp: span, pats: [@pat]) {
|
||||||
let represented : [def_id] = [];
|
if pats.len() == 0u {
|
||||||
/* Determine the type of the scrutinee */
|
tcx.sess.span_err(sp, "non-exhaustive patterns");
|
||||||
/* If it's not an enum, exit (bailing out on checking non-enum alts
|
ret;
|
||||||
for now) */
|
}
|
||||||
/* Otherwise, get the list of variants and make sure each one is
|
// If there a non-refutable pattern in the set, we're okay.
|
||||||
represented. Then recurse on the columns. */
|
for pat in pats { if !is_refutable(tcx, pat) { ret; } }
|
||||||
|
|
||||||
let ty_def_id = alt ty::get(scrut_ty).struct {
|
alt ty::get(ty::node_id_to_type(tcx, pats[0].id)).struct {
|
||||||
ty_enum(id, _) { id }
|
ty::ty_enum(id, _) {
|
||||||
_ { ret; } };
|
check_exhaustive_enum(tcx, id, sp, pats);
|
||||||
|
}
|
||||||
|
ty::ty_box(_) {
|
||||||
|
check_exhaustive(tcx, sp, vec::filter_map(pats, {|p|
|
||||||
|
alt raw_pat(p).node { pat_box(sub) { some(sub) } _ { none } }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
ty::ty_uniq(_) {
|
||||||
|
check_exhaustive(tcx, sp, vec::filter_map(pats, {|p|
|
||||||
|
alt raw_pat(p).node { pat_uniq(sub) { some(sub) } _ { none } }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
ty::ty_tup(ts) {
|
||||||
|
let cols = vec::init_elt_mut(ts.len(), []);
|
||||||
|
for p in pats {
|
||||||
|
alt raw_pat(p).node {
|
||||||
|
pat_tup(sub) {
|
||||||
|
vec::iteri(sub) {|i, sp| cols[i] += [sp];}
|
||||||
|
}
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec::iter(cols) {|col| check_exhaustive(tcx, sp, col); }
|
||||||
|
}
|
||||||
|
ty::ty_rec(fs) {
|
||||||
|
let cols = vec::init_elt(fs.len(), {mutable wild: false,
|
||||||
|
mutable pats: []});
|
||||||
|
for p in pats {
|
||||||
|
alt raw_pat(p).node {
|
||||||
|
pat_rec(sub, _) {
|
||||||
|
vec::iteri(fs) {|i, field|
|
||||||
|
alt vec::find(sub, {|pf| pf.ident == field.ident }) {
|
||||||
|
some(pf) { cols[i].pats += [pf.pat]; }
|
||||||
|
none { cols[i].wild = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec::iter(cols) {|col|
|
||||||
|
if !col.wild { check_exhaustive(tcx, sp, copy col.pats); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::ty_bool {
|
||||||
|
let saw_true = false, saw_false = false;
|
||||||
|
for p in pats {
|
||||||
|
alt raw_pat(p).node {
|
||||||
|
pat_lit(@{node: expr_lit(@{node: lit_bool(b), _}), _}) {
|
||||||
|
if b { saw_true = true; }
|
||||||
|
else { saw_false = true; }
|
||||||
|
}
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !saw_true { tcx.sess.span_err(
|
||||||
|
sp, "non-exhaustive bool patterns: true not covered"); }
|
||||||
|
if !saw_false { tcx.sess.span_err(
|
||||||
|
sp, "non-exhaustive bool patterns: false not covered"); }
|
||||||
|
}
|
||||||
|
ty::ty_nil {
|
||||||
|
let seen = vec::any(pats, {|p|
|
||||||
|
alt raw_pat(p).node {
|
||||||
|
pat_lit(@{node: expr_lit(@{node: lit_nil, _}), _}) { true }
|
||||||
|
_ { false }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if !seen { tcx.sess.span_err(sp, "non-exhaustive patterns"); }
|
||||||
|
}
|
||||||
|
// Literal patterns are always considered non-exhaustive
|
||||||
|
_ {
|
||||||
|
tcx.sess.span_err(sp, "non-exhaustive literal patterns");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_exhaustive_enum(tcx: ty::ctxt, enum_id: def_id, sp: span,
|
||||||
|
pats: [@pat]) {
|
||||||
|
let variants = enum_variants(tcx, enum_id);
|
||||||
|
let columns_by_variant = vec::map(*variants, {|v|
|
||||||
|
{mutable seen: false,
|
||||||
|
cols: vec::init_elt_mut(v.args.len(), [])}
|
||||||
|
});
|
||||||
|
|
||||||
let variants = *enum_variants(tcx, ty_def_id);
|
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
if !is_refutable(tcx, pat) {
|
let pat = raw_pat(pat);
|
||||||
/* automatically makes this alt complete */ ret;
|
alt tcx.def_map.get(pat.id) {
|
||||||
}
|
def_variant(_, id) {
|
||||||
|
let variant_idx =
|
||||||
|
option::get(vec::position(*variants, {|v| v.id == id}));
|
||||||
|
columns_by_variant[variant_idx].seen = true;
|
||||||
alt pat.node {
|
alt pat.node {
|
||||||
// want the def_id for the constructor
|
pat_enum(_, args) {
|
||||||
pat_enum(id,_) {
|
vec::iteri(args) {|i, p|
|
||||||
alt tcx.def_map.find(pat.id) {
|
columns_by_variant[variant_idx].cols[i] += [p];
|
||||||
some(def_variant(_, variant_def_id)) {
|
|
||||||
represented += [variant_def_id];
|
|
||||||
}
|
|
||||||
_ { tcx.sess.span_bug(pat.span, "check_exhaustive:
|
|
||||||
pat_tag not bound to a variant"); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ { tcx.sess.span_bug(pat.span, "check_exhaustive: ill-typed \
|
|
||||||
pattern"); // we know this has enum type,
|
|
||||||
} // so anything else should be impossible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn not_represented(v: [def_id], &&vinfo: variant_info) -> bool {
|
|
||||||
!vec::contains(v, vinfo.id)
|
|
||||||
}
|
|
||||||
// Could be more efficient (bitvectors?)
|
|
||||||
alt vec::find(variants, bind not_represented(represented,_)) {
|
|
||||||
some(bad) {
|
|
||||||
// complain
|
|
||||||
// TODO: give examples of cases that aren't covered
|
|
||||||
tcx.sess.note("Patterns not covered include:");
|
|
||||||
tcx.sess.note(bad.name);
|
|
||||||
tcx.sess.span_err(sp, "Non-exhaustive pattern");
|
|
||||||
}
|
|
||||||
_ {}
|
|
||||||
}
|
|
||||||
// Otherwise, check subpatterns
|
|
||||||
// inefficient
|
|
||||||
for variant in variants {
|
|
||||||
// rows consists of the argument list for each pat that's an enum
|
|
||||||
let rows : [[@pat]] = [];
|
|
||||||
for pat in pats {
|
|
||||||
alt pat.node {
|
|
||||||
pat_enum(id, args) {
|
|
||||||
alt tcx.def_map.find(pat.id) {
|
|
||||||
some(def_variant(_,variant_id))
|
|
||||||
if variant_id == variant.id { rows += [args]; }
|
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if check vec::is_not_empty(rows) {
|
|
||||||
let i = 0u;
|
vec::iteri(columns_by_variant) {|i, cv|
|
||||||
for it in rows[0] {
|
if !cv.seen {
|
||||||
let column = [it];
|
tcx.sess.span_err(sp, "non-exhaustive patterns: variant `" +
|
||||||
// Annoying -- see comment in
|
variants[i].name + "` not covered");
|
||||||
// tstate::states::find_pre_post_state_loop
|
} else {
|
||||||
check vec::is_not_empty(rows);
|
vec::iter(cv.cols) {|col| check_exhaustive(tcx, sp, col); }
|
||||||
for row in vec::tail(rows) {
|
|
||||||
column += [row[i]];
|
|
||||||
}
|
}
|
||||||
check_exhaustive(tcx, sp, pat_ty(tcx, it), column);
|
|
||||||
i += 1u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This shouldn't actually happen, since there were no
|
|
||||||
// irrefutable patterns if we got here.
|
|
||||||
else { cont; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn time(do_it: bool, what: str, thunk: fn()) {
|
||||||
fn merge_opts(attrs: [ast::attribute], cmd_opts: [(option, bool)]) ->
|
fn merge_opts(attrs: [ast::attribute], cmd_opts: [(option, bool)]) ->
|
||||||
[(option, bool)] {
|
[(option, bool)] {
|
||||||
fn str_to_option(name: str) -> (option, bool) {
|
fn str_to_option(name: str) -> (option, bool) {
|
||||||
ret alt name {
|
ret alt check name {
|
||||||
"ctypes" { (ctypes, true) }
|
"ctypes" { (ctypes, true) }
|
||||||
"no_ctypes" { (ctypes, false) }
|
"no_ctypes" { (ctypes, false) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1023,7 +1023,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||||
}
|
}
|
||||||
ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); }
|
ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); }
|
||||||
ast::expr_log(lvl, lexp, expr) {
|
ast::expr_log(lvl, lexp, expr) {
|
||||||
alt lvl {
|
alt check lvl {
|
||||||
1 { word_nbsp(s, "log"); print_expr(s, expr); }
|
1 { word_nbsp(s, "log"); print_expr(s, expr); }
|
||||||
0 { word_nbsp(s, "log_err"); print_expr(s, expr); }
|
0 { word_nbsp(s, "log_err"); print_expr(s, expr); }
|
||||||
2 {
|
2 {
|
||||||
|
|
|
@ -68,7 +68,7 @@ fn run(lib_path: str, prog: str, args: [str],
|
||||||
let count = 2;
|
let count = 2;
|
||||||
while count > 0 {
|
while count > 0 {
|
||||||
let stream = comm::recv(p);
|
let stream = comm::recv(p);
|
||||||
alt stream {
|
alt check stream {
|
||||||
(1, s) {
|
(1, s) {
|
||||||
outs = s;
|
outs = s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,9 +60,10 @@ pure fn is_false(v: t) -> bool { !v }
|
||||||
brief = "Parse logic value from `s`"
|
brief = "Parse logic value from `s`"
|
||||||
)]
|
)]
|
||||||
pure fn from_str(s: str) -> t {
|
pure fn from_str(s: str) -> t {
|
||||||
alt s {
|
alt check s {
|
||||||
"true" { true }
|
"true" { true }
|
||||||
"false" { false }
|
"false" { false }
|
||||||
|
_ { fail "'" + s + "' is not a valid boolean string"; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2140,7 +2140,7 @@ mod tests {
|
||||||
fn test_chars_iter() {
|
fn test_chars_iter() {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
chars_iter("x\u03c0y") {|ch|
|
chars_iter("x\u03c0y") {|ch|
|
||||||
alt i {
|
alt check i {
|
||||||
0 { assert ch == 'x'; }
|
0 { assert ch == 'x'; }
|
||||||
1 { assert ch == '\u03c0'; }
|
1 { assert ch == '\u03c0'; }
|
||||||
2 { assert ch == 'y'; }
|
2 { assert ch == 'y'; }
|
||||||
|
@ -2156,7 +2156,7 @@ mod tests {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
bytes_iter("xyz") {|bb|
|
bytes_iter("xyz") {|bb|
|
||||||
alt i {
|
alt check i {
|
||||||
0 { assert bb == 'x' as u8; }
|
0 { assert bb == 'x' as u8; }
|
||||||
1 { assert bb == 'y' as u8; }
|
1 { assert bb == 'y' as u8; }
|
||||||
2 { assert bb == 'z' as u8; }
|
2 { assert bb == 'z' as u8; }
|
||||||
|
|
|
@ -166,7 +166,7 @@ Function: from_str
|
||||||
Parse logic value from `s`
|
Parse logic value from `s`
|
||||||
*/
|
*/
|
||||||
pure fn from_str(s: str) -> t {
|
pure fn from_str(s: str) -> t {
|
||||||
alt s {
|
alt check s {
|
||||||
"none" { none }
|
"none" { none }
|
||||||
"false" { four::false }
|
"false" { four::false }
|
||||||
"true" { four::true }
|
"true" { four::true }
|
||||||
|
@ -181,7 +181,7 @@ Convert `v` into a string
|
||||||
*/
|
*/
|
||||||
pure fn to_str(v: t) -> str {
|
pure fn to_str(v: t) -> str {
|
||||||
// FIXME replace with consts as soon as that works
|
// FIXME replace with consts as soon as that works
|
||||||
alt v {
|
alt check v {
|
||||||
0u8 { "none" }
|
0u8 { "none" }
|
||||||
1u8 { "true" }
|
1u8 { "true" }
|
||||||
2u8 { "false" }
|
2u8 { "false" }
|
||||||
|
@ -265,7 +265,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_tup(v: four::t) -> (bool, bool) {
|
fn to_tup(v: four::t) -> (bool, bool) {
|
||||||
alt v {
|
alt check v {
|
||||||
0u8 { (false, false) }
|
0u8 { (false, false) }
|
||||||
1u8 { (false, true) }
|
1u8 { (false, true) }
|
||||||
2u8 { (true, false) }
|
2u8 { (true, false) }
|
||||||
|
|
|
@ -241,7 +241,7 @@ fn test_option_int() {
|
||||||
fn deserialize_0<S: deserializer>(s: S) -> option<int> {
|
fn deserialize_0<S: deserializer>(s: S) -> option<int> {
|
||||||
s.read_enum("option") {||
|
s.read_enum("option") {||
|
||||||
s.read_enum_variant {|i|
|
s.read_enum_variant {|i|
|
||||||
alt i {
|
alt check i {
|
||||||
0u { none }
|
0u { none }
|
||||||
1u {
|
1u {
|
||||||
let v0 = s.read_enum_variant_arg(0u) {||
|
let v0 = s.read_enum_variant_arg(0u) {||
|
||||||
|
|
|
@ -52,8 +52,12 @@ fn insert<K: copy, V: copy>(m: treemap<K, V>, k: K, v: V) {
|
||||||
// We have to name left and right individually, because
|
// We have to name left and right individually, because
|
||||||
// otherwise the alias checker complains.
|
// otherwise the alias checker complains.
|
||||||
if k < kk {
|
if k < kk {
|
||||||
alt m { @node(_, _, left, _) { insert(left, k, v); } }
|
alt check m { @node(_, _, left, _) { insert(left, k, v); } }
|
||||||
} else { alt m { @node(_, _, _, right) { insert(right, k, v); } } }
|
} else {
|
||||||
|
alt check m {
|
||||||
|
@node(_, _, _, right) { insert(right, k, v); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ Function: from_str
|
||||||
Parse logic value from `s`
|
Parse logic value from `s`
|
||||||
*/
|
*/
|
||||||
pure fn from_str(s: str) -> t {
|
pure fn from_str(s: str) -> t {
|
||||||
alt s {
|
alt check s {
|
||||||
"unknown" { unknown }
|
"unknown" { unknown }
|
||||||
"true" { tri::true }
|
"true" { tri::true }
|
||||||
"false" { tri::false }
|
"false" { tri::false }
|
||||||
|
@ -151,7 +151,7 @@ Convert `v` into a string
|
||||||
*/
|
*/
|
||||||
pure fn to_str(v: t) -> str {
|
pure fn to_str(v: t) -> str {
|
||||||
// FIXME replace with consts as soon as that works
|
// FIXME replace with consts as soon as that works
|
||||||
alt v {
|
alt check v {
|
||||||
0u8 { "unknown" }
|
0u8 { "unknown" }
|
||||||
1u8 { "true" }
|
1u8 { "true" }
|
||||||
2u8 { "false" }
|
2u8 { "false" }
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
fn f() -> int {
|
fn f() -> int {
|
||||||
// Make sure typestate doesn't interpret this alt expression
|
// Make sure typestate doesn't interpret this alt expression
|
||||||
// as the function result
|
// as the function result
|
||||||
alt true { true { } };
|
alt check true { true { } };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
// error-pattern: Non-exhaustive pattern
|
// error-pattern: non-exhaustive patterns
|
||||||
enum t { a(u), b }
|
enum t { a(u), b }
|
||||||
enum u { c, d }
|
enum u { c, d }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
// -*- rust -*-
|
|
||||||
// error-pattern: Non-exhaustive pattern
|
|
||||||
enum t { a, b, }
|
enum t { a, b, }
|
||||||
|
|
||||||
fn main() { let x = a; alt x { b { } } }
|
fn main() {
|
||||||
|
let x = a;
|
||||||
|
alt x { b { } } //! ERROR non-exhaustive patterns
|
||||||
|
alt true { //! ERROR non-exhaustive bool patterns
|
||||||
|
true {}
|
||||||
|
}
|
||||||
|
alt @some(10) { //! ERROR non-exhaustive patterns
|
||||||
|
@none {}
|
||||||
|
}
|
||||||
|
alt (2, 3, 4) { //! ERROR non-exhaustive literal patterns
|
||||||
|
(_, _, 4) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn test2() -> int { let val = @0; { } *val }
|
||||||
|
|
||||||
fn test3() {
|
fn test3() {
|
||||||
let regs = @{mutable eax: 0};
|
let regs = @{mutable eax: 0};
|
||||||
alt true { true { } }
|
alt check true { true { } }
|
||||||
(*regs).eax = 1;
|
(*regs).eax = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,13 +20,13 @@ fn test6() -> bool { { } (true || false) && true }
|
||||||
|
|
||||||
fn test7() -> uint {
|
fn test7() -> uint {
|
||||||
let regs = @0;
|
let regs = @0;
|
||||||
alt true { true { } }
|
alt check true { true { } }
|
||||||
(*regs < 2) as uint
|
(*regs < 2) as uint
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test8() -> int {
|
fn test8() -> int {
|
||||||
let val = @0;
|
let val = @0;
|
||||||
alt true {
|
alt check true {
|
||||||
true { }
|
true { }
|
||||||
}
|
}
|
||||||
if *val < 1 {
|
if *val < 1 {
|
||||||
|
@ -36,11 +36,11 @@ fn test8() -> int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test9() { let regs = @mutable 0; alt true { true { } } *regs += 1; }
|
fn test9() { let regs = @mutable 0; alt check true { true { } } *regs += 1; }
|
||||||
|
|
||||||
fn test10() -> int {
|
fn test10() -> int {
|
||||||
let regs = @mutable [0];
|
let regs = @mutable [0];
|
||||||
alt true { true { } }
|
alt check true { true { } }
|
||||||
(*regs)[0]
|
(*regs)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ fn if_semi() -> int { if true { f() } else { f() }; -1 }
|
||||||
|
|
||||||
fn if_nosemi() -> int { (if true { 0 } else { 0 }) - 1 }
|
fn if_nosemi() -> int { (if true { 0 } else { 0 }) - 1 }
|
||||||
|
|
||||||
fn alt_semi() -> int { alt true { true { f() } }; -1 }
|
fn alt_semi() -> int { alt check true { true { f() } }; -1 }
|
||||||
|
|
||||||
fn alt_no_semi() -> int { (alt true { true { 0 } }) - 1 }
|
fn alt_no_semi() -> int { (alt check true { true { 0 } }) - 1 }
|
||||||
|
|
||||||
fn stmt() { { f() }; -1; }
|
fn stmt() { { f() }; -1; }
|
||||||
|
|
|
@ -4,7 +4,7 @@ fn test_box() {
|
||||||
@0;
|
@0;
|
||||||
}
|
}
|
||||||
fn test_str() {
|
fn test_str() {
|
||||||
let res = alt false { true { "happy" } };
|
let res = alt check false { true { "happy" } };
|
||||||
assert res == "happy";
|
assert res == "happy";
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
// n.b. This was only ever failing with optimization disabled.
|
// n.b. This was only ever failing with optimization disabled.
|
||||||
fn a() -> int { alt ret 1 { 2 { 3 } } }
|
fn a() -> int { alt check ret 1 { 2 { 3 } } }
|
||||||
fn main() { a(); }
|
fn main() { a(); }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
fn altlit(f: int) -> int {
|
fn altlit(f: int) -> int {
|
||||||
alt f {
|
alt check f {
|
||||||
10 { #debug("case 10"); ret 20; }
|
10 { #debug("case 10"); ret 20; }
|
||||||
11 { #debug("case 11"); ret 22; }
|
11 { #debug("case 11"); ret 22; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
||||||
6u to 7u { fail "shouldn't match range"; }
|
6u to 7u { fail "shouldn't match range"; }
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
alt 5u {
|
alt check 5u {
|
||||||
1u { fail "should match non-first range"; }
|
1u { fail "should match non-first range"; }
|
||||||
2u to 6u {}
|
2u to 6u {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Issue #53
|
// Issue #53
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
alt "test" { "not-test" { fail; } "test" { } _ { fail; } }
|
alt check "test" { "not-test" { fail; } "test" { } _ { fail; } }
|
||||||
|
|
||||||
enum t { tag1(str), tag2, }
|
enum t { tag1(str), tag2, }
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ fn main() {
|
||||||
_ { fail; }
|
_ { fail; }
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = alt "a" { "a" { 1 } "b" { 2 } };
|
let x = alt check "a" { "a" { 1 } "b" { 2 } };
|
||||||
assert (x == 1);
|
assert (x == 1);
|
||||||
|
|
||||||
alt "a" { "a" { } "b" { } }
|
alt check "a" { "a" { } "b" { } }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Check that issue #954 stays fixed
|
// Check that issue #954 stays fixed
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
alt -1 { -1 {} }
|
alt check -1 { -1 {} }
|
||||||
assert 1-1 == 0;
|
assert 1-1 == 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,13 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
|
|
||||||
// Tests for alt as expressions resulting in boxed types
|
// Tests for alt as expressions resulting in boxed types
|
||||||
fn test_box() { let res = alt true { true { @100 } }; assert (*res == 100); }
|
fn test_box() {
|
||||||
|
let res = alt check true { true { @100 } };
|
||||||
|
assert (*res == 100);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_str() {
|
fn test_str() {
|
||||||
let res = alt true { true { "happy" } };
|
let res = alt check true { true { "happy" } };
|
||||||
assert (res == "happy");
|
assert (res == "happy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
type compare<T> = fn@(@T, @T) -> bool;
|
type compare<T> = fn@(@T, @T) -> bool;
|
||||||
|
|
||||||
fn test_generic<T>(expected: @T, eq: compare<T>) {
|
fn test_generic<T>(expected: @T, eq: compare<T>) {
|
||||||
let actual: @T = alt true { true { expected } };
|
let actual: @T = alt check true { true { expected } };
|
||||||
assert (eq(expected, actual));
|
assert (eq(expected, actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
type compare<T> = fn@(T, T) -> bool;
|
type compare<T> = fn@(T, T) -> bool;
|
||||||
|
|
||||||
fn test_generic<T: copy>(expected: T, eq: compare<T>) {
|
fn test_generic<T: copy>(expected: T, eq: compare<T>) {
|
||||||
let actual: T = alt true { true { expected } };
|
let actual: T = alt check true { true { expected } };
|
||||||
assert (eq(expected, actual));
|
assert (eq(expected, actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
type compare<T> = fn@(~T, ~T) -> bool;
|
type compare<T> = fn@(~T, ~T) -> bool;
|
||||||
|
|
||||||
fn test_generic<T: copy>(expected: ~T, eq: compare<T>) {
|
fn test_generic<T: copy>(expected: ~T, eq: compare<T>) {
|
||||||
let actual: ~T = alt true { true { expected } };
|
let actual: ~T = alt check true { true { expected } };
|
||||||
assert (eq(expected, actual));
|
assert (eq(expected, actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
type compare<T> = fn@(T, T) -> bool;
|
type compare<T> = fn@(T, T) -> bool;
|
||||||
|
|
||||||
fn test_generic<T: copy>(expected: T, eq: compare<T>) {
|
fn test_generic<T: copy>(expected: T, eq: compare<T>) {
|
||||||
let actual: T = alt true { true { expected } };
|
let actual: T = alt check true { true { expected } };
|
||||||
assert (eq(expected, actual));
|
assert (eq(expected, actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
type compare<T> = fn@(T, T) -> bool;
|
type compare<T> = fn@(T, T) -> bool;
|
||||||
|
|
||||||
fn test_generic<T: copy>(expected: T, eq: compare<T>) {
|
fn test_generic<T: copy>(expected: T, eq: compare<T>) {
|
||||||
let actual: T = alt true { true { expected } };
|
let actual: T = alt check true { true { expected } };
|
||||||
assert (eq(expected, actual));
|
assert (eq(expected, actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
// Tests for alt as expressions resulting in structural types
|
// Tests for alt as expressions resulting in structural types
|
||||||
fn test_rec() {
|
fn test_rec() {
|
||||||
let rs = alt true { true { {i: 100} } };
|
let rs = alt check true { true { {i: 100} } };
|
||||||
assert (rs == {i: 100});
|
assert (rs == {i: 100});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
|
|
||||||
// Tests for alt as expressions resulting in boxed types
|
// Tests for alt as expressions resulting in boxed types
|
||||||
fn test_box() { let res = alt true { true { ~100 } }; assert (*res == 100); }
|
fn test_box() {
|
||||||
|
let res = alt check true { true { ~100 } };
|
||||||
|
assert (*res == 100);
|
||||||
|
}
|
||||||
|
|
||||||
fn main() { test_box(); }
|
fn main() { test_box(); }
|
||||||
|
|
|
@ -30,7 +30,7 @@ fn log_cont() { do { log(error, cont); } while false }
|
||||||
fn ret_ret() -> int { ret (ret 2) + 3; }
|
fn ret_ret() -> int { ret (ret 2) + 3; }
|
||||||
|
|
||||||
fn ret_guard() {
|
fn ret_guard() {
|
||||||
alt 2 {
|
alt check 2 {
|
||||||
x if (ret) { x; }
|
x if (ret) { x; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue