diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 7a81568117313..3717c6134726d 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -498,10 +498,27 @@ pub fn specialize(cx: @MatchCheckCtxt, lookup_const_by_id(cx.tcx, did).get(); let e_v = eval_const_expr(cx.tcx, const_expr); let match_ = match *ctor_id { - val(ref v) => compare_const_vals(&e_v, v) == 0, + val(ref v) => { + match compare_const_vals(&e_v, v) { + Some(val1) => (val1 == 0), + None => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between arms"); + false + } + } + }, range(ref c_lo, ref c_hi) => { - compare_const_vals(c_lo, &e_v) >= 0 && - compare_const_vals(c_hi, &e_v) <= 0 + let m1 = compare_const_vals(c_lo, &e_v), + m2 = compare_const_vals(c_hi, &e_v); + match (m1, m2) { + (Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0), + _ => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between ranges"); + false + } + } } single => true, _ => fail!("type error") @@ -529,10 +546,26 @@ pub fn specialize(cx: @MatchCheckCtxt, lookup_const_by_id(cx.tcx, did).get(); let e_v = eval_const_expr(cx.tcx, const_expr); let match_ = match *ctor_id { - val(ref v) => compare_const_vals(&e_v, v) == 0, + val(ref v) => + match compare_const_vals(&e_v, v) { + Some(val1) => (val1 == 0), + None => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between arms"); + false + } + }, range(ref c_lo, ref c_hi) => { - compare_const_vals(c_lo, &e_v) >= 0 && - compare_const_vals(c_hi, &e_v) <= 0 + let m1 = compare_const_vals(c_lo, &e_v), + m2 = compare_const_vals(c_hi, &e_v); + match (m1, m2) { + (Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0), + _ => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between ranges"); + false + } + } } single => true, _ => fail!("type error") @@ -619,10 +652,27 @@ pub fn specialize(cx: @MatchCheckCtxt, pat_lit(expr) => { let e_v = eval_const_expr(cx.tcx, expr); let match_ = match *ctor_id { - val(ref v) => compare_const_vals(&e_v, v) == 0, + val(ref v) => { + match compare_const_vals(&e_v, v) { + Some(val1) => val1 == 0, + None => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between arms"); + false + } + } + }, range(ref c_lo, ref c_hi) => { - compare_const_vals(c_lo, &e_v) >= 0 && - compare_const_vals(c_hi, &e_v) <= 0 + let m1 = compare_const_vals(c_lo, &e_v), + m2 = compare_const_vals(c_hi, &e_v); + match (m1, m2) { + (Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0), + _ => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between ranges"); + false + } + } } single => true, _ => fail!("type error") @@ -638,11 +688,22 @@ pub fn specialize(cx: @MatchCheckCtxt, _ => fail!("type error") }; let v_lo = eval_const_expr(cx.tcx, lo), - v_hi = eval_const_expr(cx.tcx, hi); - let match_ = compare_const_vals(&c_lo, &v_lo) >= 0 && - compare_const_vals(&c_hi, &v_hi) <= 0; - if match_ { Some(vec::to_owned(r.tail())) } else { None } - } + v_hi = eval_const_expr(cx.tcx, hi); + + let m1 = compare_const_vals(&c_lo, &v_lo), + m2 = compare_const_vals(&c_hi, &v_hi); + match (m1, m2) { + (Some(val1), Some(val2)) if val1 >= 0 && val2 <= 0 => { + Some(vec::to_owned(r.tail())) + }, + (Some(_), Some(_)) => None, + _ => { + cx.tcx.sess.span_err(pat_span, + "mismatched types between ranges"); + None + } + } + } pat_vec(before, slice, after) => { match *ctor_id { vec(_) => { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 6cc4409aee660..751767fb58c14 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -420,65 +420,73 @@ pub fn lit_to_const(lit: @lit) -> const_val { } } -pub fn compare_const_vals(a: &const_val, b: &const_val) -> int { +pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option { match (a, b) { (&const_int(a), &const_int(b)) => { if a == b { - 0 + Some(0) } else if a < b { - -1 + Some(-1) } else { - 1 + Some(1) } } (&const_uint(a), &const_uint(b)) => { if a == b { - 0 + Some(0) } else if a < b { - -1 + Some(-1) } else { - 1 + Some(1) } } (&const_float(a), &const_float(b)) => { if a == b { - 0 + Some(0) } else if a < b { - -1 + Some(-1) } else { - 1 + Some(1) } } (&const_str(ref a), &const_str(ref b)) => { if (*a) == (*b) { - 0 + Some(0) } else if (*a) < (*b) { - -1 + Some(-1) } else { - 1 + Some(1) } } (&const_bool(a), &const_bool(b)) => { if a == b { - 0 + Some(0) } else if a < b { - -1 + Some(-1) } else { - 1 + Some(1) } } - _ => fail!("compare_const_vals: ill-typed comparison") + _ => { + None + } } } -pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> int { - compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b)) +pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> Option { + compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b)) } -pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool { - compare_lit_exprs(tcx, a, b) == 0 +pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> Option { + match compare_lit_exprs(tcx, a, b) { + Some(val) => Some(val == 0), + None => None, + } } -pub fn lit_eq(a: @lit, b: @lit) -> bool { - compare_const_vals(&lit_to_const(a), &lit_to_const(b)) == 0 +pub fn lit_eq(a: @lit, b: @lit) -> Option { + match compare_const_vals(&lit_to_const(a), &lit_to_const(b)) { + Some(val) => Some(val == 0), + None => None, + } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index fa545f033a584..c7f2da9232961 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -193,48 +193,55 @@ pub enum Opt { pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { match (a, b) { - (&lit(a), &lit(b)) => { - match (a, b) { - (UnitLikeStructLit(a), UnitLikeStructLit(b)) => a == b, - _ => { - let a_expr; - match a { - ExprLit(existing_a_expr) => a_expr = existing_a_expr, - ConstLit(a_const) => { - let e = const_eval::lookup_const_by_id(tcx, a_const); - a_expr = e.get(); - } - UnitLikeStructLit(_) => { - fail!("UnitLikeStructLit should have been handled \ - above") + (&lit(a), &lit(b)) => { + match (a, b) { + (UnitLikeStructLit(a), UnitLikeStructLit(b)) => a == b, + _ => { + let a_expr; + match a { + ExprLit(existing_a_expr) => a_expr = existing_a_expr, + ConstLit(a_const) => { + let e = const_eval::lookup_const_by_id(tcx, a_const); + a_expr = e.get(); + } + UnitLikeStructLit(_) => { + fail!("UnitLikeStructLit should have been handled \ + above") + } } - } - let b_expr; - match b { - ExprLit(existing_b_expr) => b_expr = existing_b_expr, - ConstLit(b_const) => { - let e = const_eval::lookup_const_by_id(tcx, b_const); - b_expr = e.get(); + let b_expr; + match b { + ExprLit(existing_b_expr) => b_expr = existing_b_expr, + ConstLit(b_const) => { + let e = const_eval::lookup_const_by_id(tcx, b_const); + b_expr = e.get(); + } + UnitLikeStructLit(_) => { + fail!("UnitLikeStructLit should have been handled \ + above") + } } - UnitLikeStructLit(_) => { - fail!("UnitLikeStructLit should have been handled \ - above") + + match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) { + Some(val1) => val1 == 0, + None => fail!("compare_list_exprs: type mismatch"), } } - - const_eval::compare_lit_exprs(tcx, a_expr, b_expr) == 0 } } - } - (&range(a1, a2), &range(b1, b2)) => { - const_eval::compare_lit_exprs(tcx, a1, b1) == 0 && - const_eval::compare_lit_exprs(tcx, a2, b2) == 0 - } - (&var(a, _), &var(b, _)) => a == b, - (&vec_len_eq(a), &vec_len_eq(b)) => a == b, - (&vec_len_ge(a, _), &vec_len_ge(b, _)) => a == b, - _ => false + (&range(a1, a2), &range(b1, b2)) => { + let m1 = const_eval::compare_lit_exprs(tcx, a1, b1); + let m2 = const_eval::compare_lit_exprs(tcx, a2, b2); + match (m1, m2) { + (Some(val1), Some(val2)) => (val1 == 0 && val2 == 0), + _ => fail!("compare_list_exprs: type mismatch"), + } + } + (&var(a, _), &var(b, _)) => a == b, + (&vec_len_eq(a), &vec_len_eq(b)) => a == b, + (&vec_len_ge(a, _), &vec_len_ge(b, _)) => a == b, + _ => false } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 07083459020b1..d6ef27ab7ff0c 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -408,8 +408,18 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { // no-op } else if !ty::type_is_numeric(b_ty) { tcx.sess.span_err(pat.span, "non-numeric type used in range"); - } else if !valid_range_bounds(fcx.ccx, begin, end) { - tcx.sess.span_err(begin.span, "lower range bound must be less than upper"); + } else { + match valid_range_bounds(fcx.ccx, begin, end) { + Some(false) => { + tcx.sess.span_err(begin.span, + "lower range bound must be less than upper"); + }, + None => { + tcx.sess.span_err(begin.span, + "mismatched types in range"); + }, + _ => { }, + } } fcx.write_ty(pat.id, b_ty); } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index d45882cc17b05..cd58dc5fe48df 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -1044,8 +1044,11 @@ pub fn check_lit(fcx: @mut FnCtxt, lit: @ast::lit) -> ty::t { pub fn valid_range_bounds(ccx: @mut CrateCtxt, from: @ast::expr, to: @ast::expr) - -> bool { - const_eval::compare_lit_exprs(ccx.tcx, from, to) <= 0 + -> Option { + match const_eval::compare_lit_exprs(ccx.tcx, from, to) { + Some(val) => Some(val <= 0), + None => None + } } pub fn check_expr_has_type( diff --git a/src/test/compile-fail/match-ill-type1.rs b/src/test/compile-fail/match-ill-type1.rs new file mode 100644 index 0000000000000..4d2b95b61ea8d --- /dev/null +++ b/src/test/compile-fail/match-ill-type1.rs @@ -0,0 +1,6 @@ +fn main() { + match 1 { + 1..2u => 1, //~ ERROR mismatched types in range + _ => 2, + }; +} diff --git a/src/test/compile-fail/match-ill-type2.rs b/src/test/compile-fail/match-ill-type2.rs new file mode 100644 index 0000000000000..020ccde845246 --- /dev/null +++ b/src/test/compile-fail/match-ill-type2.rs @@ -0,0 +1,7 @@ +fn main() { + match 1 { + 1 => 1, //~ ERROR mismatched types between arms + 2u => 1, + _ => 2, + }; +}