From 5d6a74f020dba8d25c21670bdcf7bdf8744bffaf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Nov 2011 11:49:29 +0100 Subject: [PATCH] Only warn about unreachable range patterns when appropriate Also simplifies the literal-munging, and moves it into ast_util Closes #1170 --- src/comp/middle/check_alt.rs | 15 +- src/comp/middle/trans_alt.rs | 3 +- src/comp/middle/tstate/auxiliary.rs | 1 - src/comp/middle/ty.rs | 4 +- src/comp/middle/typeck.rs | 27 +-- src/comp/syntax/ast_util.rs | 42 +++- src/comp/util/common.rs | 186 ------------------ .../compile-fail/alt-range-fail-dominate.rs | 12 +- 8 files changed, 59 insertions(+), 231 deletions(-) diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs index b79ded04c27..380fcff24b6 100644 --- a/src/comp/middle/check_alt.rs +++ b/src/comp/middle/check_alt.rs @@ -1,5 +1,5 @@ import syntax::ast::*; -import syntax::ast_util::{variant_def_ids, dummy_sp}; +import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit, lit_eq}; import syntax::visit; fn check_crate(tcx: ty::ctxt, crate: @crate) { @@ -66,11 +66,7 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { 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); - } + pat_lit(lb) { ret lit_eq(la, lb); } _ { ret false; } } } @@ -110,12 +106,11 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { 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); + ret compare_lit(begina, lb) <= 0 && compare_lit(enda, lb) >= 0; } pat_range(beginb, endb) { - ret util::common::lit_type_eq(begina, beginb) && - util::common::lit_ranges_overlap(begina, enda, beginb, endb); + ret compare_lit(begina, beginb) <= 0 && + compare_lit(enda, endb) >= 0; } _ { ret false; } } diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index af0a1890f3e..5b7b7a59294 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -7,10 +7,9 @@ import trans_build::*; import trans::{new_sub_block_ctxt, new_scope_block_ctxt, load_if_immediate}; import syntax::ast; import syntax::ast_util; -import syntax::ast_util::dummy_sp; +import syntax::ast_util::{dummy_sp, lit_eq}; import syntax::ast::def_id; import syntax::codemap::span; -import util::common::lit_eq; import trans_common::*; diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 6e35aabf032..e7c17665628 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -5,7 +5,6 @@ import syntax::ast_util::*; import syntax::codemap::span; import syntax::visit; import std::map::{new_int_hash}; -import util::common::{lit_eq}; import syntax::print::pprust::path_to_str; import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate, poststate, precond, postcond, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 9471c4e01c5..e950633284f 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1443,7 +1443,9 @@ fn arg_eq(eq: fn(T, T) -> bool, a: @sp_constr_arg, b: @sp_constr_arg) alt b.node { ast::carg_ident(t) { ret eq(s, t); } _ { ret false; } } } ast::carg_lit(l) { - alt b.node { ast::carg_lit(m) { ret lit_eq(l, m); } _ { ret false; } } + alt b.node { + ast::carg_lit(m) { ret ast_util::lit_eq(l, m); } _ { ret false; } + } } } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 156c1cf1138..0858833af6d 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1,6 +1,7 @@ import syntax::{ast, ast_util}; import ast::spanned; -import syntax::ast_util::{local_def, respan, ty_param_kind}; +import syntax::ast_util::{local_def, respan, ty_param_kind, lit_is_numeric, + lit_types_match}; import syntax::visit; import metadata::csearch; import driver::session; @@ -1252,24 +1253,7 @@ fn lit_as_float(l: @ast::lit) -> str { } 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 = std::float::from_str(s1); - let f2 = std::float::from_str(s2); - ret std::math::min(f1, f2) == f1 - } - ast::lit_uint(_) | ast::lit_char(_) { - let u1 = lit_as_uint(l1); - let u2 = lit_as_uint(l2); - ret std::math::min(u1, u2) == u1 - } - _ { - let i1 = lit_as_int(l1); - let i2 = lit_as_int(l2); - ret std::math::min(i1, i2) == i1 - } - } + ast_util::compare_lit(l1, l2) <= 0 } // Pattern checking is top-down rather than bottom-up so that bindings get @@ -1284,8 +1268,9 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat, 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) { + if !lit_types_match(begin, end) { + fcx.ccx.tcx.sess.span_err(pat.span, "mismatched types in range"); + } else if !lit_is_numeric(begin) || !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) { diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 2af904bdef0..c68092da90d 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -232,6 +232,47 @@ fn ret_by_ref(style: ret_style) -> bool { fn ty_param_kind(tp: ty_param) -> kind { tp.kind } +fn compare_lit(a: @lit, b: @lit) -> int { + fn cmp(a: T, b: T) -> int { a == b ? 0 : a < b ? -1 : 1 } + alt (a.node, b.node) { + (lit_int(a), lit_int(b)) | + (lit_mach_int(_, a), lit_mach_int(_, b)) { cmp(a, b) } + (lit_uint(a), lit_uint(b)) { cmp(a, b) } + (lit_char(a), lit_char(b)) { cmp(a, b) } + (lit_float(a), lit_float(b)) | + (lit_mach_float(_, a), lit_mach_float(_, b)) { + cmp(std::float::from_str(a), std::float::from_str(b)) + } + (lit_str(a), lit_str(b)) { cmp(a, b) } + (lit_nil., lit_nil.) { 0 } + (lit_bool(a), lit_bool(b)) { cmp(a, b) } + } +} + +fn lit_eq(a: @lit, b: @lit) -> bool { compare_lit(a, b) == 0 } + +fn lit_types_match(a: @lit, b: @lit) -> bool { + alt (a.node, b.node) { + (lit_int(_), lit_int(_)) | (lit_uint(_), lit_uint(_)) | + (lit_char(_), lit_char(_)) | (lit_float(_), lit_float(_)) | + (lit_str(_), lit_str(_)) | (lit_nil., lit_nil.) | + (lit_bool(_), lit_bool(_ )) { true } + (lit_mach_int(ta, _), lit_mach_int(tb, _)) | + (lit_mach_float(ta, _), lit_mach_float(tb, _)) { ta == tb } + _ { false } + } +} + +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 } + } +} + // Local Variables: // mode: rust // fill-column: 78; @@ -239,4 +280,3 @@ fn ty_param_kind(tp: ty_param) -> kind { tp.kind } // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: - diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs index 22c344e6200..f4f6f9cec24 100644 --- a/src/comp/util/common.rs +++ b/src/comp/util/common.rs @@ -81,192 +81,6 @@ 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) { - std::float::from_str(f3) >= min(f1, f2) && - std::float::from_str(f3) <= max(f1, f2) - } - _ { fail } - } - } - } -} - -fn ranges_overlap(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(std::float::from_str(f1), std::float::from_str(f2)) - } - _ { fail } } - } - _ { fail } - } -} - -fn lit_eq(l: @ast::lit, m: @ast::lit) -> bool { - alt l.node { - ast::lit_str(s) { - alt m.node { ast::lit_str(t) { ret s == t } _ { ret false; } } - } - ast::lit_char(c) { - alt m.node { ast::lit_char(d) { ret c == d; } _ { ret false; } } - } - ast::lit_int(i) { - alt m.node { ast::lit_int(j) { ret i == j; } _ { ret false; } } - } - ast::lit_uint(i) { - alt m.node { ast::lit_uint(j) { ret i == j; } _ { ret false; } } - } - ast::lit_mach_int(_, i) { - alt m.node { - ast::lit_mach_int(_, j) { ret i == j; } - _ { ret false; } - } - } - ast::lit_float(s) { - alt m.node { ast::lit_float(t) { ret s == t; } _ { ret false; } } - } - ast::lit_mach_float(_, s) { - alt m.node { - ast::lit_mach_float(_, t) { ret s == t; } - _ { ret false; } - } - } - ast::lit_nil. { - alt m.node { ast::lit_nil. { ret true; } _ { ret false; } } - } - ast::lit_bool(b) { - alt m.node { ast::lit_bool(c) { ret b == c; } _ { ret false; } } - } - } -} - fn is_main_name(path: [ast::ident]) -> bool { str::eq(option::get(std::vec::last(path)), "main") } diff --git a/src/test/compile-fail/alt-range-fail-dominate.rs b/src/test/compile-fail/alt-range-fail-dominate.rs index 51883e8f8dd..38ac1d76d98 100644 --- a/src/test/compile-fail/alt-range-fail-dominate.rs +++ b/src/test/compile-fail/alt-range-fail-dominate.rs @@ -3,7 +3,6 @@ //error-pattern: unreachable //error-pattern: unreachable //error-pattern: unreachable -//error-pattern: unreachable fn main() { alt 5u { @@ -12,13 +11,13 @@ fn main() { }; alt 5u { + 3u to 6u { } 4u to 6u { } - 3u to 5u { } }; alt 5u { 4u to 6u { } - 5u to 7u { } + 4u to 6u { } }; alt 'c' { @@ -27,12 +26,7 @@ fn main() { }; alt 1.0 { - -5.0 to 5.0 {} - 0.0 to 6.5 {} - }; - - alt 1.0 { - 0.02 {} 0.01 to 6.5 {} + 0.02 {} }; } \ No newline at end of file