about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJihyun Yu <yjh0502@gmail.com>2013-05-21 18:04:55 +0900
committerJihyun Yu <yjh0502@gmail.com>2013-05-22 14:06:25 +0900
commitf8af2b50eee70ea912c18e5acb510789e59dd535 (patch)
treef23043bbb999fd3a57a6fea7a8e7364b03ecc5f0
parent15e44381af4f6d89fc62111a8425087ccab40665 (diff)
downloadrust-f8af2b50eee70ea912c18e5acb510789e59dd535.tar.gz
rust-f8af2b50eee70ea912c18e5acb510789e59dd535.zip
fix issue #6209
-rw-r--r--src/librustc/middle/check_match.rs91
-rw-r--r--src/librustc/middle/const_eval.rs54
-rw-r--r--src/librustc/middle/trans/_match.rs77
-rw-r--r--src/librustc/middle/typeck/check/_match.rs16
-rw-r--r--src/librustc/middle/typeck/check/mod.rs9
-rw-r--r--src/test/compile-fail/match-ill-type1.rs6
-rw-r--r--src/test/compile-fail/match-ill-type2.rs7
7 files changed, 181 insertions, 79 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 7a815681173..3717c613472 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 6cc4409aee6..751767fb58c 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<int> {
   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<int> {
+    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<bool> {
+    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<bool> {
+    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 fa545f033a5..c7f2da92329 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 07083459020..d6ef27ab7ff 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 d45882cc17b..cd58dc5fe48 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<bool> {
+    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 00000000000..4d2b95b61ea
--- /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 00000000000..020ccde8452
--- /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,
+    };
+}