]> git.lizzy.rs Git - rust.git/commitdiff
Implement pattern ranges for all numeric types.
authorJosh Matthews <josh@joshmatthews.net>
Wed, 21 Sep 2011 07:00:32 +0000 (03:00 -0400)
committerMarijn Haverbeke <marijnh@gmail.com>
Wed, 21 Sep 2011 07:36:12 +0000 (09:36 +0200)
14 files changed:
src/comp/middle/alias.rs
src/comp/middle/check_alt.rs
src/comp/middle/trans_alt.rs
src/comp/middle/typeck.rs
src/comp/syntax/ast.rs
src/comp/syntax/ast_util.rs
src/comp/syntax/fold.rs
src/comp/syntax/parse/parser.rs
src/comp/syntax/print/pprust.rs
src/comp/util/common.rs
src/lib/int.rs
src/test/compile-fail/alt-range-fail-dominate.rs [new file with mode: 0644]
src/test/compile-fail/alt-range-fail.rs [new file with mode: 0644]
src/test/run-pass/alt-range.rs [new file with mode: 0644]

index f1788fda27e631f730e3f2badd333ae0c16aa46c..6d03bf5a7bb8af3559dff4f6d265d3b37fc22107 100644 (file)
@@ -645,7 +645,7 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
     fn walk(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat,
             &set: [pattern_root]) {
         alt pat.node {
-          ast::pat_wild. | ast::pat_lit(_) {}
+          ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {}
           ast::pat_bind(nm) {
             set += [{id: pat.id, name: nm, mut: mut, span: pat.span}];
           }
index 354d23f38f6f005024563d1d25ef8f423a27f67c..48279247f6bcd387f41cab3fc1a642535e6d67a9 100644 (file)
@@ -62,12 +62,15 @@ fn field_patterns_supersede(tcx: ty::ctxt, fas: [field_pat],
         ret true;
     }
 
-
     alt a.node {
       pat_wild. | pat_bind(_) { ret true; }
       pat_lit(la) {
         alt b.node {
           pat_lit(lb) { ret util::common::lit_eq(la, lb); }
+          pat_range(beginb, endb) {
+            ret util::common::lit_type_eq(la, beginb) &&
+                util::common::lit_in_range(la, beginb, endb);
+          }
           _ { ret false; }
         }
       }
@@ -98,6 +101,19 @@ fn field_patterns_supersede(tcx: ty::ctxt, fas: [field_pat],
           _ { ret pattern_supersedes(tcx, suba, b); }
         }
       }
+      pat_range(begina, enda) {
+        alt b.node {
+          pat_lit(lb) {
+            ret util::common::lit_type_eq(lb, begina) &&
+                util::common::lit_in_range(lb, begina, enda);
+          }
+          pat_range(beginb, endb) {
+            ret util::common::lit_type_eq(begina, beginb) &&
+                util::common::lit_ranges_overlap(begina, enda, beginb, endb);
+          }
+          _ { ret false; }
+        }
+      }
     }
 }
 
index eea4704c3d080aef1f25b046b0b9b5c7f33cb9e8..605ca0daeb35276bae112d0d728d312d0074e09f 100644 (file)
@@ -1,4 +1,4 @@
-import std::{str, vec, option};
+import std::{str, vec, option, int};
 import option::{some, none};
 import std::map::hashmap;
 
 
 import trans_common::*;
 
-// An option identifying a branch (either a literal or a tag variant)
+// An option identifying a branch (either a literal, a tag variant or a range)
 tag opt {
     lit(@ast::lit);
     var(/* variant id */uint, /* variant dids */{tg: def_id, var: def_id});
+    range(@ast::lit, @ast::lit);
 }
 fn opt_eq(a: opt, b: opt) -> bool {
     alt a {
       lit(la) {
-        ret alt b { lit(lb) { lit_eq(la, lb) } var(_, _) { false } };
+        ret alt b { lit(lb) { lit_eq(la, lb) } _ { false } };
       }
       var(ida, _) {
-        ret alt b { lit(_) { false } var(idb, _) { ida == idb } };
+        ret alt b { var(idb, _) { ida == idb } _ { false } };
+      }
+      range(la1, la2) {
+        ret alt b {
+          range(lb1, lb2) { lit_eq(la1, lb1) && lit_eq(la2, lb2) }
+          _ { false }
+        };
       }
     }
 }
-fn trans_opt(bcx: @block_ctxt, o: opt) -> result {
+
+tag opt_result {
+    single_result(result);
+    range_result(result, result);
+}
+fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
     alt o {
-      lit(l) { ret trans::trans_lit(bcx, *l); }
-      var(id, _) { ret rslt(bcx, C_int(id as int)); }
+      lit(l) { ret single_result(trans::trans_lit(bcx, *l)); }
+      var(id, _) { ret single_result(rslt(bcx, C_int(id as int))); }
+      range(l1, l2) {
+        let r1 = trans::trans_lit(bcx, *l1);
+        let r2 = trans::trans_lit(r1.bcx, *l2);
+        ret range_result(r1, r2);
+      }
     }
 }
 
@@ -124,6 +141,9 @@ fn e(ccx: @crate_ctxt, dummy: @ast::pat, opt: opt, size: uint,
           ast::pat_lit(l) {
             ret if opt_eq(lit(l), opt) { some([]) } else { none };
           }
+          ast::pat_range(l1, l2) {
+            ret if opt_eq(range(l1, l2), opt) { some([]) } else { none };
+          }
           _ { ret some(vec::init_elt(dummy, size)); }
         }
     }
@@ -186,6 +206,9 @@ fn add_to_set(&set: [opt], val: opt) {
     for br: match_branch in m {
         alt br.pats[col].node {
           ast::pat_lit(l) { add_to_set(found, lit(l)); }
+          ast::pat_range(l1, l2) {
+            add_to_set(found, range(l1, l2));
+          }
           ast::pat_tag(_, _) {
             add_to_set(found, variant_opt(ccx, br.pats[col].id));
           }
@@ -265,7 +288,9 @@ fn pick_col(m: match) -> uint {
         let i = 0u;
         for p: @ast::pat in br.pats {
             alt p.node {
-              ast::pat_lit(_) | ast::pat_tag(_, _) { scores[i] += 1u; }
+              ast::pat_lit(_) | ast::pat_tag(_, _) | ast::pat_range(_, _) {
+                scores[i] += 1u;
+              }
               _ { }
             }
             i += 1u;
@@ -410,6 +435,16 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
                   _ { test_val = Load(bcx, val); switch }
                 };
           }
+          range(_, _) {
+            test_val = Load(bcx, val);
+            kind = compare;
+          }
+        }
+    }
+    for o: opt in opts {
+        alt o {
+          range(_, _) { kind = compare; break; }
+          _ { }
         }
     }
     let else_cx =
@@ -428,22 +463,44 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
         alt kind {
           single. { Br(bcx, opt_cx.llbb); }
           switch. {
-            let r = trans_opt(bcx, opt);
-            bcx = r.bcx;
-            llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
+            let res = trans_opt(bcx, opt);
+            alt res {
+              single_result(r) {
+                llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
+                bcx = r.bcx;
+              }
+            }
           }
           compare. {
             let compare_cx = new_scope_block_ctxt(bcx, "compare_scope");
             Br(bcx, compare_cx.llbb);
             bcx = compare_cx;
-            let r = trans_opt(bcx, opt);
-            bcx = r.bcx;
             let t = ty::node_id_to_type(ccx.tcx, pat_id);
-            let eq =
-                trans::trans_compare(bcx, ast::eq, test_val, t, r.val, t);
-            let cleanup_cx = trans::trans_block_cleanups(bcx, compare_cx);
-            bcx = new_sub_block_ctxt(bcx, "compare_next");
-            CondBr(cleanup_cx, eq.val, opt_cx.llbb, bcx.llbb);
+            let res = trans_opt(bcx, opt);
+            alt res {
+              single_result(r) {
+                bcx = r.bcx;
+                let eq =
+                    trans::trans_compare(bcx, ast::eq, test_val, t, r.val, t);
+                /*let*/ bcx = eq.bcx; //XXX uncomment for assertion
+                let cleanup_cx = trans::trans_block_cleanups(bcx, compare_cx);
+                bcx = new_sub_block_ctxt(bcx, "compare_next");
+                CondBr(cleanup_cx, eq.val, opt_cx.llbb, bcx.llbb);
+              }
+              range_result(rbegin, rend) {
+                bcx = rend.bcx;
+                let ge = trans::trans_compare(bcx, ast::ge, test_val, t,
+                                              rbegin.val, t);
+                let le = trans::trans_compare(ge.bcx, ast::le, test_val, t,
+                                              rend.val, t);
+                let in_range = rslt(le.bcx, And(le.bcx, ge.val, le.val));
+                /*let*/ bcx = in_range.bcx; //XXX uncomment for assertion
+                let cleanup_cx =
+                    trans::trans_block_cleanups(bcx, compare_cx);
+                bcx = new_sub_block_ctxt(bcx, "compare_next");
+                CondBr(cleanup_cx, in_range.val, opt_cx.llbb, bcx.llbb);
+              }
+            }
           }
           _ { }
         }
@@ -456,7 +513,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
             unpacked = args.vals;
             opt_cx = args.bcx;
           }
-          lit(_) { }
+          lit(_) | range(_, _) { }
         }
         compile_submatch(opt_cx, enter_opt(ccx, m, opt, col, size, val),
                          unpacked + vals_left, f, exits);
@@ -631,12 +688,13 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
                         [C_int(0), C_int(back::abi::box_rc_field_body)]);
         bcx = bind_irrefutable_pat(bcx, inner, unboxed, table, true);
       }
-      ast::pat_wild. | ast::pat_lit(_) { }
+      ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) { }
     }
     ret bcx;
 }
 
 // Local Variables:
+// mode: rust
 // fill-column: 78;
 // indent-tabs-mode: nil
 // c-basic-offset: 4
index c6d24802ecd90c6ec0362596a256193a16d6b316..41fbe0f8e85c556de50476fa02f5ab329bf0bd01 100644 (file)
@@ -1266,6 +1266,44 @@ fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t {
     }
 }
 
+fn lit_as_uint(l: @ast::lit) -> uint {
+    alt l.node {
+      ast::lit_uint(u) { u }
+      ast::lit_char(c) { c as uint }
+    }
+}
+fn lit_as_int(l: @ast::lit) -> int {
+    alt l.node {
+      ast::lit_int(i) | ast::lit_mach_int(_, i) { i }
+    }
+}
+fn lit_as_float(l: @ast::lit) -> str {
+    alt l.node {
+      ast::lit_float(f) | ast::lit_mach_float(_, f) { f }
+    }
+}
+
+fn valid_range_bounds(l1: @ast::lit, l2: @ast::lit) -> bool {
+    alt l1.node {
+      ast::lit_float(s1) | ast::lit_mach_float(_, s1) {
+        let s2 = lit_as_float(l2);
+        let f1 = util::common::str_to_float(s1);
+        let f2 = util::common::str_to_float(s2);
+        ret *util::common::min(f1, f2) == f1
+      }
+      ast::lit_uint(_) | ast::lit_char(_) {
+        let u1 = lit_as_uint(l1);
+        let u2 = lit_as_uint(l2);
+        ret *util::common::min(u1, u2) == u1
+      }
+      _ {
+        let i1 = lit_as_int(l1);
+        let i2 = lit_as_int(l2);
+        ret *util::common::min(i1, i2) == i1
+      }
+    }
+}
+
 // Pattern checking is top-down rather than bottom-up so that bindings get
 // their types immediately.
 fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
@@ -1277,6 +1315,23 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
         typ = demand::simple(fcx, pat.span, expected, typ);
         write::ty_only_fixup(fcx, pat.id, typ);
       }
+      ast::pat_range(begin, end) {
+        if !util::common::lit_is_numeric(begin) ||
+           !util::common::lit_is_numeric(end) {
+            fcx.ccx.tcx.sess.span_err(pat.span,
+                                      "non-numeric type used in range");
+        } else if !valid_range_bounds(begin, end) {
+            fcx.ccx.tcx.sess.span_err(begin.span,
+                                      "lower range bound must be less \
+                                       than upper");
+        }
+        let typ1 = check_lit(fcx.ccx, begin);
+        typ1 = demand::simple(fcx, pat.span, expected, typ1);
+        write::ty_only_fixup(fcx, pat.id, typ1);
+        let typ2 = check_lit(fcx.ccx, end);
+        typ2 = demand::simple(fcx, pat.span, typ1, typ2);
+        write::ty_only_fixup(fcx, pat.id, typ2);
+      }
       ast::pat_bind(name) {
         let vid = lookup_local(fcx, pat.span, pat.id);
         let typ = ty::mk_var(fcx.ccx.tcx, vid);
index ad6aacb1549db507b855f103b870155e2299a069..a409f7c24379b4a551e10c3ab06a5ed01ed6285e 100644 (file)
@@ -92,6 +92,7 @@
     pat_rec([field_pat], bool);
     pat_tup([@pat]);
     pat_box(@pat);
+    pat_range(@lit, @lit);
 }
 
 tag mutability { mut; imm; maybe_mut; }
index 8350ce9a8bbde3b063d58c29ac8bd7f4ca9c3eb5..d94258a6ac78b38ea00f5138c0ad7e74a9329485 100644 (file)
@@ -69,7 +69,7 @@ fn pat_id_map(pat: @pat) -> pat_id_map {
         for elt in elts { for each b in pat_bindings(elt) { put b; } }
       }
       pat_box(sub) { for each b in pat_bindings(sub) { put b; } }
-      pat_wild. | pat_lit(_) { }
+      pat_wild. | pat_lit(_) | pat_range(_, _) { }
     }
 }
 
@@ -229,3 +229,4 @@ fn ret_by_ref(style: ret_style) -> bool {
 // buffer-file-coding-system: utf-8-unix
 // compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
 // End:
+
index c53176e24fb992ff791fe20ee53f163391ab505f..68c12153873de8ed7f1b52821c32f35e83c395bd 100644 (file)
@@ -291,6 +291,7 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
           }
           pat_tup(elts) { pat_tup(vec::map(fld.fold_pat, elts)) }
           pat_box(inner) { pat_box(fld.fold_pat(inner)) }
+          pat_range(_, _) { p }
         };
 }
 
index 6869dc6501d07ec0b66d92660f4ec94225000e13..efed1380a23645dde88dc1bfd7350c04f1412f2f 100644 (file)
@@ -1494,8 +1494,14 @@ fn parse_pat(p: parser) -> @ast::pat {
       tok {
         if !is_ident(tok) || is_word(p, "true") || is_word(p, "false") {
             let lit = parse_lit(p);
-            hi = lit.span.hi;
-            pat = ast::pat_lit(@lit);
+            if eat_word(p, "to") {
+                let end = parse_lit(p);
+                hi = end.span.hi;
+                pat = ast::pat_range(@lit, @end);
+            } else {
+                hi = lit.span.hi;
+                pat = ast::pat_lit(@lit);
+            }
         } else if is_plain_ident(p) &&
                       alt p.look_ahead(1u) {
                         token::DOT. | token::LPAREN. | token::LBRACKET. {
index 48031a295db96d1a2e3eb09c2a1d9b7ff44ff4b1..3bf5b0310c996a40a090ef922ff9ca4be7b9e726 100644 (file)
@@ -1113,6 +1113,12 @@ fn print_field(s: ps, f: ast::field_pat) {
         pclose(s);
       }
       ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); }
+      ast::pat_range(begin, end) {
+        print_literal(s, begin);
+        space(s.s);
+        word_space(s, "to");
+        print_literal(s, end);
+      }
     }
     s.ann.post(ann_node);
 }
index 355fcd934b4fea28be6e69a2e2cbfcce58372ef9..e73c2b511978ea6f5a689a7d7fd4c742bbde1906 100644 (file)
@@ -84,6 +84,162 @@ fn local_rhs_span(l: @ast::local, def: span) -> span {
     alt l.node.init { some(i) { ret i.expr.span; } _ { ret def; } }
 }
 
+fn lit_is_numeric(l: @ast::lit) -> bool {
+    alt l.node {
+      ast::lit_int(_) | ast::lit_char(_) | ast::lit_uint(_) |
+      ast::lit_mach_int(_, _) | ast::lit_float(_) | ast::lit_mach_float(_,_) {
+        true
+      }
+      _ { false }
+    }
+}
+
+fn lit_type_eq(l: @ast::lit, m: @ast::lit) -> bool {
+    alt l.node {
+      ast::lit_str(_) {
+        alt m.node { ast::lit_str(_) { true } _ { false } }
+      }
+      ast::lit_char(_) {
+        alt m.node { ast::lit_char(_) { true } _ { false } }
+      }
+      ast::lit_int(_) {
+        alt m.node { ast::lit_int(_) { true } _ { false } }
+      }
+      ast::lit_uint(_) {
+        alt m.node { ast::lit_uint(_) { true } _ { false } }
+      }
+      ast::lit_mach_int(_, _) {
+        alt m.node { ast::lit_mach_int(_, _) { true } _ { false } }
+      }
+      ast::lit_float(_) {
+        alt m.node { ast::lit_float(_) { true } _ { false } }
+      }
+      ast::lit_mach_float(_, _) {
+        alt m.node { ast::lit_mach_float(_, _) { true } _ { false } }
+      }
+      ast::lit_nil. {
+        alt m.node { ast::lit_nil. { true } _ { false } }
+      }
+      ast::lit_bool(_) {
+        alt m.node { ast::lit_bool(_) { true } _ { false } }
+      }
+    }
+}
+
+fn lit_in_range(l: @ast::lit, m1: @ast::lit, m2: @ast::lit) -> bool {
+    alt lits_to_range(m1, m2) {
+      irange(i1, i2) {
+        alt l.node {
+          ast::lit_int(i3) | ast::lit_mach_int(_, i3) {
+            i3 >= *min(i1, i2) && i3 <= *max(i1, i2)
+          }
+          _ { fail }
+        }
+      }
+      urange(u1, u2) {
+        alt l.node {
+          ast::lit_uint(u3) {
+            u3 >= *min(u1, u2) && u3 <= *max(u1, u2)
+          }
+          _ { fail }
+        }
+      }
+      crange(c1, c2) {
+        alt l.node {
+          ast::lit_char(c3) {
+            (c3 as uint) >= *min(c1 as uint, c2 as uint) &&
+            (c3 as uint) <= *max(c1 as uint, c2 as uint)
+          }
+          _ { fail }
+        }
+      }
+      frange(f1, f2) {
+        alt l.node {
+          ast::lit_float(f3) | ast::lit_mach_float(_, f3) {
+            str_to_float(f3) >= *min(f1, f2) &&
+            str_to_float(f3) <= *max(f1, f2)
+          }
+          _ { fail }
+        }
+      }
+    }
+}
+
+fn min<T>(x: T, y: T) -> @T {
+    ret @(if x > y { y } else { x });
+}
+
+fn max<T>(x: T, y: T) -> @T {
+    ret @(if x > y { x } else { y });
+}
+
+fn ranges_overlap<T>(a1: T, a2: T, b1: T, b2: T) -> bool {
+    let min1 = *min(a1, a2);
+    let max1 = *max(a1, a2);
+    let min2 = *min(b1, b2);
+    let max2 = *max(b1, b2);
+    ret (min1 >= min2 && max1 <= max2) || (min1 <= min2 && max1 >= min2) ||
+        (min1 >= min2 && min1 <= max2) || (max1 >= min2 && max1 <= max2);
+}
+
+fn lit_ranges_overlap(a1: @ast::lit, a2: @ast::lit,
+                      b1: @ast::lit, b2: @ast::lit) -> bool {
+    alt lits_to_range(a1, a2) {
+      irange(i1, i2) {
+        alt lits_to_range(b1, b2) {
+          irange(i3, i4) { ranges_overlap(i1, i2, i3, i4) }
+          _ { fail }
+        }
+      }
+      urange(u1, u2) {
+        alt lits_to_range(b1, b2) {
+          urange(u3, u4) { ranges_overlap(u1, u2, u3, u4) }
+          _ { fail }
+        }
+      }
+      crange(c1, c2) {
+        alt lits_to_range(b1, b2) {
+          crange(c3, c4) { ranges_overlap(c1, c2, c3, c4) }
+          _ { fail }
+        }
+      }
+      frange(f1, f2) {
+        alt lits_to_range(b1, b2) {
+          frange(f3, f4) { ranges_overlap(f1, f2, f3, f4) }
+          _ { fail }
+        }
+      }
+    }
+}
+
+tag range {
+    irange(int, int);
+    urange(uint, uint);
+    crange(char, char);
+    frange(float, float);
+}
+
+fn lits_to_range(l: @ast::lit, r: @ast::lit) -> range {
+    alt l.node {
+      ast::lit_int(i1) | ast::lit_mach_int(_, i1) {
+        alt r.node { ast::lit_int(i2) { irange(i1, i2) } _ { fail } }
+      }
+      ast::lit_uint(u1) {
+        alt r.node { ast::lit_uint(u2) { urange(u1, u2) } _ { fail } }
+      }
+      ast::lit_char(c1) {
+        alt r.node { ast::lit_char(c2) { crange(c1, c2) } _ { fail } }
+      }
+      ast::lit_float(f1) | ast::lit_mach_float(_, f1) {
+        alt r.node { ast::lit_float(f2) | ast::lit_mach_float(_, f2) {
+          frange(str_to_float(f1), str_to_float(f2))
+        }
+        _ { fail } }
+      }
+      _ { fail }
+    }
+}
+
 fn lit_eq(l: @ast::lit, m: @ast::lit) -> bool {
     alt l.node {
       ast::lit_str(s) {
@@ -156,6 +312,22 @@ fn float_to_str(num: float, digits: uint) -> str {
     ret accum;
 }
 
+fn str_to_float(num: str) -> float {
+    let digits = str::split(num, '.' as u8);
+    let total = int::from_str(digits[0]) as float;
+
+    fn dec_val(c: char) -> int { ret (c as int) - ('0' as int); }
+
+    let right = digits[1];
+    let len = str::char_len(digits[1]);
+    let i = 1u;
+    while (i < len) {
+        total += dec_val(str::pop_char(right)) as float /
+                 (int::pow(10, i) as float);
+        i += 1u;
+    }
+    ret total;
+}
 
 //
 // Local Variables:
index 98d8bb5e157e196618f48bdb05e35b9aac3d283e..0a6e69ceadc7e3ad32280c057e61fdf08b1e711f 100644 (file)
     while lo_ < hi { put lo_; lo_ += 1; }
 }
 
+fn parse_buf(buf: [u8], radix: uint) -> int {
+    if vec::len::<u8>(buf) == 0u {
+        log_err "parse_buf(): buf is empty";
+        fail;
+    }
+    let i = vec::len::<u8>(buf) - 1u;
+    let power = 1;
+    if buf[0] == ('-' as u8) {
+        power = -1;
+        i -= 1u;
+    }
+    let n = 0;
+    while true {
+        n += (buf[i] - ('0' as u8) as int) * power;
+        power *= radix as int;
+        if i == 0u { ret n; }
+        i -= 1u;
+    }
+    fail;
+}
+
+fn from_str(s: str) -> int { parse_buf(str::bytes(s), 10u) }
+
 fn to_str(n: int, radix: uint) -> str {
     assert (0u < radix && radix <= 16u);
     ret if n < 0 {
diff --git a/src/test/compile-fail/alt-range-fail-dominate.rs b/src/test/compile-fail/alt-range-fail-dominate.rs
new file mode 100644 (file)
index 0000000..51883e8
--- /dev/null
@@ -0,0 +1,38 @@
+//error-pattern: unreachable
+//error-pattern: unreachable
+//error-pattern: unreachable
+//error-pattern: unreachable
+//error-pattern: unreachable
+//error-pattern: unreachable
+
+fn main() {
+    alt 5u {
+      1u to 10u { }
+      5u to 6u { }
+    };
+
+    alt 5u {
+      4u to 6u { }
+      3u to 5u { }
+    };
+
+    alt 5u {
+      4u to 6u { }
+      5u to 7u { }
+    };
+
+    alt 'c' {
+      'A' to 'z' {}
+      'a' to 'z' {}
+    };
+
+    alt 1.0 {
+      -5.0 to 5.0 {}
+      0.0 to 6.5 {}
+    };
+
+    alt 1.0 {
+      0.02 {}
+      0.01 to 6.5 {}
+    };
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/alt-range-fail.rs b/src/test/compile-fail/alt-range-fail.rs
new file mode 100644 (file)
index 0000000..0a9acdc
--- /dev/null
@@ -0,0 +1,19 @@
+//error-pattern: lower range bound
+//error-pattern: non-numeric
+//error-pattern: mismatched types
+
+fn main() {
+    alt 5u {
+      6u to 1u { }
+      _ { }
+    };
+
+    alt "wow" {
+      "wow" to "woow" { }
+    };
+
+    alt 5u {
+      'c' to 100u { }
+      _ { }
+    };
+}
\ No newline at end of file
diff --git a/src/test/run-pass/alt-range.rs b/src/test/run-pass/alt-range.rs
new file mode 100644 (file)
index 0000000..1cd29cb
--- /dev/null
@@ -0,0 +1,30 @@
+fn main() {
+    alt 5u {
+      1u to 5u {}
+      _ { fail "should match range"; }
+    }
+    alt 5u {
+      6u to 7u { fail "shouldn't match range"; }
+      _ {}
+    }
+    alt 5u {
+      1u { fail "should match non-first range"; }
+      2u to 6u {}
+    }
+    alt 'c' {
+      'a' to 'z' {}
+      _ { fail "should suppport char ranges"; }
+    }
+    alt -3 {
+      -7 to 5 {}
+      _ { fail "should match signed range"; }
+    }
+    alt 3.0 {
+      1.0 to 5.0 {}
+      _ { fail "should match float range"; }
+    }
+    alt -1.5 {
+      -3.6 to 3.6 {}
+      _ { fail "should match negative float range"; }
+    }
+}