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 did = {crate: cnum, node: did_.node};
|
||||
// We treat references to enums as references to types.
|
||||
alt fam_ch {
|
||||
alt check fam_ch {
|
||||
'c' { ast::def_const(did) }
|
||||
'u' { ast::def_fn(did, ast::unsafe_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");
|
||||
} };
|
||||
result += [{ident: name, tps: bounds, fty: fty,
|
||||
purity: alt item_family(mth) {
|
||||
purity: alt check item_family(mth) {
|
||||
'u' { ast::unsafe_fn }
|
||||
'f' { ast::impure_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 {
|
||||
alt fam_ch {
|
||||
alt check fam_ch {
|
||||
'c' | 'T' | 'm' | 'n' { false }
|
||||
'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 {
|
||||
alt fam {
|
||||
alt check fam {
|
||||
'c' { ret "const"; }
|
||||
'f' { ret "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 {
|
||||
alt next(st) {
|
||||
alt check next(st) {
|
||||
'n' { ret ty::mk_nil(st.tcx); }
|
||||
'z' { ret ty::mk_bot(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); }
|
||||
'l' { ret ty::mk_float(st.tcx); }
|
||||
'M' {
|
||||
alt next(st) {
|
||||
alt check next(st) {
|
||||
'b' { ret ty::mk_mach_uint(st.tcx, ast::ty_u8); }
|
||||
'w' { ret ty::mk_mach_uint(st.tcx, ast::ty_u16); }
|
||||
'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_send_type(st.tcx); }
|
||||
'C' {
|
||||
let ck = alt next(st) {
|
||||
let ck = alt check next(st) {
|
||||
'&' { ty::ck_block }
|
||||
'@' { ty::ck_box }
|
||||
'~' { ty::ck_uniq }
|
||||
|
@ -355,7 +355,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
|
|||
assert (next(st) == '[');
|
||||
let inputs: [ty::arg] = [];
|
||||
while peek(st) != ']' {
|
||||
let mode = alt peek(st) {
|
||||
let mode = alt check peek(st) {
|
||||
'&' { ast::by_mut_ref }
|
||||
'-' { ast::by_move }
|
||||
'+' { 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] {
|
||||
let bounds = [];
|
||||
while true {
|
||||
bounds += [alt next(st) {
|
||||
bounds += [alt check next(st) {
|
||||
'S' { ty::bound_send }
|
||||
'C' { ty::bound_copy }
|
||||
'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 */
|
||||
if mode == alt_exhaustive {
|
||||
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
|
||||
// (not checked statically yet)
|
||||
fn check_exhaustive(tcx: ty::ctxt, sp:span, scrut_ty:ty::t, pats:[@pat]) {
|
||||
let represented : [def_id] = [];
|
||||
/* Determine the type of the scrutinee */
|
||||
/* If it's not an enum, exit (bailing out on checking non-enum alts
|
||||
for now) */
|
||||
/* Otherwise, get the list of variants and make sure each one is
|
||||
represented. Then recurse on the columns. */
|
||||
fn check_exhaustive(tcx: ty::ctxt, sp: span, pats: [@pat]) {
|
||||
if pats.len() == 0u {
|
||||
tcx.sess.span_err(sp, "non-exhaustive patterns");
|
||||
ret;
|
||||
}
|
||||
// If there a non-refutable pattern in the set, we're okay.
|
||||
for pat in pats { if !is_refutable(tcx, pat) { ret; } }
|
||||
|
||||
let ty_def_id = alt ty::get(scrut_ty).struct {
|
||||
ty_enum(id, _) { id }
|
||||
_ { ret; } };
|
||||
|
||||
let variants = *enum_variants(tcx, ty_def_id);
|
||||
for pat in pats {
|
||||
if !is_refutable(tcx, pat) {
|
||||
/* automatically makes this alt complete */ ret;
|
||||
alt ty::get(ty::node_id_to_type(tcx, pats[0].id)).struct {
|
||||
ty::ty_enum(id, _) {
|
||||
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];}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
alt pat.node {
|
||||
// want the def_id for the constructor
|
||||
pat_enum(id,_) {
|
||||
alt tcx.def_map.find(pat.id) {
|
||||
some(def_variant(_, variant_def_id)) {
|
||||
represented += [variant_def_id];
|
||||
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; }
|
||||
}
|
||||
_ { 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");
|
||||
}
|
||||
_ {}
|
||||
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");
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
}
|
||||
|
||||
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(), [])}
|
||||
});
|
||||
|
||||
for pat in pats {
|
||||
let pat = raw_pat(pat);
|
||||
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 {
|
||||
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;
|
||||
for it in rows[0] {
|
||||
let column = [it];
|
||||
// Annoying -- see comment in
|
||||
// tstate::states::find_pre_post_state_loop
|
||||
check vec::is_not_empty(rows);
|
||||
for row in vec::tail(rows) {
|
||||
column += [row[i]];
|
||||
pat_enum(_, args) {
|
||||
vec::iteri(args) {|i, p|
|
||||
columns_by_variant[variant_idx].cols[i] += [p];
|
||||
}
|
||||
check_exhaustive(tcx, sp, pat_ty(tcx, it), column);
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
vec::iteri(columns_by_variant) {|i, cv|
|
||||
if !cv.seen {
|
||||
tcx.sess.span_err(sp, "non-exhaustive patterns: variant `" +
|
||||
variants[i].name + "` not covered");
|
||||
} else {
|
||||
vec::iter(cv.cols) {|col| check_exhaustive(tcx, sp, col); }
|
||||
}
|
||||
// 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)]) ->
|
||||
[(option, bool)] {
|
||||
fn str_to_option(name: str) -> (option, bool) {
|
||||
ret alt name {
|
||||
ret alt check name {
|
||||
"ctypes" { (ctypes, true) }
|
||||
"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_log(lvl, lexp, expr) {
|
||||
alt lvl {
|
||||
alt check lvl {
|
||||
1 { word_nbsp(s, "log"); print_expr(s, expr); }
|
||||
0 { word_nbsp(s, "log_err"); print_expr(s, expr); }
|
||||
2 {
|
||||
|
|
|
@ -68,7 +68,7 @@ fn run(lib_path: str, prog: str, args: [str],
|
|||
let count = 2;
|
||||
while count > 0 {
|
||||
let stream = comm::recv(p);
|
||||
alt stream {
|
||||
alt check stream {
|
||||
(1, s) {
|
||||
outs = s;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,10 @@ pure fn is_false(v: t) -> bool { !v }
|
|||
brief = "Parse logic value from `s`"
|
||||
)]
|
||||
pure fn from_str(s: str) -> t {
|
||||
alt s {
|
||||
alt check s {
|
||||
"true" { true }
|
||||
"false" { false }
|
||||
_ { fail "'" + s + "' is not a valid boolean string"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2140,7 +2140,7 @@ mod tests {
|
|||
fn test_chars_iter() {
|
||||
let i = 0;
|
||||
chars_iter("x\u03c0y") {|ch|
|
||||
alt i {
|
||||
alt check i {
|
||||
0 { assert ch == 'x'; }
|
||||
1 { assert ch == '\u03c0'; }
|
||||
2 { assert ch == 'y'; }
|
||||
|
@ -2156,7 +2156,7 @@ mod tests {
|
|||
let i = 0;
|
||||
|
||||
bytes_iter("xyz") {|bb|
|
||||
alt i {
|
||||
alt check i {
|
||||
0 { assert bb == 'x' as u8; }
|
||||
1 { assert bb == 'y' as u8; }
|
||||
2 { assert bb == 'z' as u8; }
|
||||
|
|
|
@ -166,7 +166,7 @@ Function: from_str
|
|||
Parse logic value from `s`
|
||||
*/
|
||||
pure fn from_str(s: str) -> t {
|
||||
alt s {
|
||||
alt check s {
|
||||
"none" { none }
|
||||
"false" { four::false }
|
||||
"true" { four::true }
|
||||
|
@ -181,7 +181,7 @@ Convert `v` into a string
|
|||
*/
|
||||
pure fn to_str(v: t) -> str {
|
||||
// FIXME replace with consts as soon as that works
|
||||
alt v {
|
||||
alt check v {
|
||||
0u8 { "none" }
|
||||
1u8 { "true" }
|
||||
2u8 { "false" }
|
||||
|
@ -265,7 +265,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn to_tup(v: four::t) -> (bool, bool) {
|
||||
alt v {
|
||||
alt check v {
|
||||
0u8 { (false, false) }
|
||||
1u8 { (false, true) }
|
||||
2u8 { (true, false) }
|
||||
|
|
|
@ -241,7 +241,7 @@ fn test_option_int() {
|
|||
fn deserialize_0<S: deserializer>(s: S) -> option<int> {
|
||||
s.read_enum("option") {||
|
||||
s.read_enum_variant {|i|
|
||||
alt i {
|
||||
alt check i {
|
||||
0u { none }
|
||||
1u {
|
||||
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
|
||||
// otherwise the alias checker complains.
|
||||
if k < kk {
|
||||
alt m { @node(_, _, left, _) { insert(left, k, v); } }
|
||||
} else { alt m { @node(_, _, _, right) { insert(right, k, v); } } }
|
||||
alt check m { @node(_, _, left, _) { insert(left, k, v); } }
|
||||
} else {
|
||||
alt check m {
|
||||
@node(_, _, _, right) { insert(right, k, v); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ Function: from_str
|
|||
Parse logic value from `s`
|
||||
*/
|
||||
pure fn from_str(s: str) -> t {
|
||||
alt s {
|
||||
alt check s {
|
||||
"unknown" { unknown }
|
||||
"true" { tri::true }
|
||||
"false" { tri::false }
|
||||
|
@ -151,7 +151,7 @@ Convert `v` into a string
|
|||
*/
|
||||
pure fn to_str(v: t) -> str {
|
||||
// FIXME replace with consts as soon as that works
|
||||
alt v {
|
||||
alt check v {
|
||||
0u8 { "unknown" }
|
||||
1u8 { "true" }
|
||||
2u8 { "false" }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
fn f() -> int {
|
||||
// Make sure typestate doesn't interpret this alt expression
|
||||
// as the function result
|
||||
alt true { true { } };
|
||||
alt check true { true { } };
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// -*- rust -*-
|
||||
// error-pattern: Non-exhaustive pattern
|
||||
// error-pattern: non-exhaustive patterns
|
||||
enum t { a(u), b }
|
||||
enum u { c, d }
|
||||
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
// -*- rust -*-
|
||||
// error-pattern: Non-exhaustive pattern
|
||||
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() {
|
||||
let regs = @{mutable eax: 0};
|
||||
alt true { true { } }
|
||||
alt check true { true { } }
|
||||
(*regs).eax = 1;
|
||||
}
|
||||
|
||||
|
@ -20,13 +20,13 @@ fn test6() -> bool { { } (true || false) && true }
|
|||
|
||||
fn test7() -> uint {
|
||||
let regs = @0;
|
||||
alt true { true { } }
|
||||
alt check true { true { } }
|
||||
(*regs < 2) as uint
|
||||
}
|
||||
|
||||
fn test8() -> int {
|
||||
let val = @0;
|
||||
alt true {
|
||||
alt check true {
|
||||
true { }
|
||||
}
|
||||
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 {
|
||||
let regs = @mutable [0];
|
||||
alt true { true { } }
|
||||
alt check true { true { } }
|
||||
(*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 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; }
|
||||
|
|
|
@ -4,7 +4,7 @@ fn test_box() {
|
|||
@0;
|
||||
}
|
||||
fn test_str() {
|
||||
let res = alt false { true { "happy" } };
|
||||
let res = alt check false { true { "happy" } };
|
||||
assert res == "happy";
|
||||
}
|
||||
fn main() {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// 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(); }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
|
||||
fn altlit(f: int) -> int {
|
||||
alt f {
|
||||
alt check f {
|
||||
10 { #debug("case 10"); ret 20; }
|
||||
11 { #debug("case 11"); ret 22; }
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
|||
6u to 7u { fail "shouldn't match range"; }
|
||||
_ {}
|
||||
}
|
||||
alt 5u {
|
||||
alt check 5u {
|
||||
1u { fail "should match non-first range"; }
|
||||
2u to 6u {}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Issue #53
|
||||
|
||||
fn main() {
|
||||
alt "test" { "not-test" { fail; } "test" { } _ { fail; } }
|
||||
alt check "test" { "not-test" { fail; } "test" { } _ { fail; } }
|
||||
|
||||
enum t { tag1(str), tag2, }
|
||||
|
||||
|
@ -13,9 +13,9 @@ fn main() {
|
|||
_ { fail; }
|
||||
}
|
||||
|
||||
let x = alt "a" { "a" { 1 } "b" { 2 } };
|
||||
let x = alt check "a" { "a" { 1 } "b" { 2 } };
|
||||
assert (x == 1);
|
||||
|
||||
alt "a" { "a" { } "b" { } }
|
||||
alt check "a" { "a" { } "b" { } }
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Check that issue #954 stays fixed
|
||||
|
||||
fn main() {
|
||||
alt -1 { -1 {} }
|
||||
alt check -1 { -1 {} }
|
||||
assert 1-1 == 0;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
// -*- rust -*-
|
||||
|
||||
// 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() {
|
||||
let res = alt true { true { "happy" } };
|
||||
let res = alt check true { true { "happy" } };
|
||||
assert (res == "happy");
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
type compare<T> = fn@(@T, @T) -> bool;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
type compare<T> = fn@(T, T) -> bool;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
type compare<T> = fn@(~T, ~T) -> bool;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
type compare<T> = fn@(T, T) -> bool;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
type compare<T> = fn@(T, T) -> bool;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
// Tests for alt as expressions resulting in structural types
|
||||
fn test_rec() {
|
||||
let rs = alt true { true { {i: 100} } };
|
||||
let rs = alt check true { true { {i: 100} } };
|
||||
assert (rs == {i: 100});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
// -*- rust -*-
|
||||
|
||||
// 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(); }
|
||||
|
|
|
@ -30,7 +30,7 @@ fn log_cont() { do { log(error, cont); } while false }
|
|||
fn ret_ret() -> int { ret (ret 2) + 3; }
|
||||
|
||||
fn ret_guard() {
|
||||
alt 2 {
|
||||
alt check 2 {
|
||||
x if (ret) { x; }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue