summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-03-24 21:24:47 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-03-24 21:38:43 -0700
commitbf9d714d469e595bdfa5b8b5fac61a90fc0db9e8 (patch)
treea487726376304f6299767b17b09f7ce414f8e615 /src/rustc
parentee5d0f5e3f1681a67452b5301958474343b90c51 (diff)
downloadrust-bf9d714d469e595bdfa5b8b5fac61a90fc0db9e8.tar.gz
rust-bf9d714d469e595bdfa5b8b5fac61a90fc0db9e8.zip
Avoid unifying vars when possible; handle bot (more) correctly
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/infer.rs39
-rw-r--r--src/rustc/middle/typeck.rs33
2 files changed, 48 insertions, 24 deletions
diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs
index abd44d6a851..6a246f6d4bc 100644
--- a/src/rustc/middle/infer.rs
+++ b/src/rustc/middle/infer.rs
@@ -293,14 +293,32 @@ impl unify_methods for infer_ctxt {
     }
 
     fn vars(a_id: uint, b_id: uint) -> ures {
-        #debug["vars(<T%u> <: <T%u>)",
-               a_id, b_id];
-
         // Need to make sub_id a subtype of sup_id.
         let {root: a_id, bounds: a_bounds} = self.get(a_id);
         let {root: b_id, bounds: b_bounds} = self.get(b_id);
 
+        #debug["vars(<T%u>=%s <: <T%u>=%s)",
+               a_id, self.bounds_to_str(a_bounds),
+               b_id, self.bounds_to_str(b_bounds)];
+
         if a_id == b_id { ret self.uok(); }
+
+        // If both A's UB and B's LB have already been bound to types,
+        // see if we can make those types subtypes.
+        alt (a_bounds.ub, b_bounds.lb) {
+          (some(a_ub), some(b_lb)) {
+            let r = self.try {|| self.tys(a_ub, b_lb) };
+            alt r {
+              result::ok(()) { ret result::ok(()); }
+              result::err(_) { /*fallthrough */ }
+            }
+          }
+          _ { /*fallthrough*/ }
+        }
+
+        // Otherwise, we need to merge A and B so as to guarantee that
+        // A remains a subtype of B.  Actually, there are other options,
+        // but that's the route we choose to take.
         self.merge(a_id, a_bounds, b_bounds).then {||
             // For max perf, we should consider the rank here.
             self.set(b_id, redirect(a_id));
@@ -309,18 +327,20 @@ impl unify_methods for infer_ctxt {
     }
 
     fn varty(a_id: uint, b: ty::t) -> ures {
-        #debug["varty(<T%u> <: %s)",
-               a_id, self.ty_to_str(b)];
         let {root: a_id, bounds: a_bounds} = self.get(a_id);
+        #debug["varty(<T%u>=%s <: %s)",
+               a_id, self.bounds_to_str(a_bounds),
+               self.ty_to_str(b)];
         let b_bounds = {lb: none, ub: some(b)};
         self.merge(a_id, a_bounds, b_bounds)
     }
 
     fn tyvar(a: ty::t, b_id: uint) -> ures {
-        #debug["tyvar(%s <: <T%u>)",
-               self.ty_to_str(a), b_id];
         let a_bounds = {lb: some(a), ub: none};
         let {root: b_id, bounds: b_bounds} = self.get(b_id);
+        #debug["tyvar(%s <: <T%u>=%s)",
+               self.ty_to_str(a),
+               b_id, self.bounds_to_str(b_bounds)];
         self.merge(b_id, a_bounds, b_bounds)
     }
 
@@ -532,6 +552,8 @@ impl unify_methods for infer_ctxt {
         if a == b { ret self.uok(); }
 
         alt (ty::get(a).struct, ty::get(b).struct) {
+          (ty::ty_bot, _) { self.uok() }
+
           (ty::ty_var(a_id), ty::ty_var(b_id)) {
             self.vars(a_id as uint, b_id as uint)
           }
@@ -542,9 +564,6 @@ impl unify_methods for infer_ctxt {
             self.tyvar(a, b_id as uint)
           }
 
-          (_, ty::ty_bot) { self.uok() }
-          (ty::ty_bot, _) { self.uok() }
-
           (ty::ty_nil, _) |
           (ty::ty_bool, _) |
           (ty::ty_int(_), _) |
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 5c512690c17..2dabc5b9faa 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -2483,15 +2483,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         let (if_t, if_bot) =
             alt elsopt {
               some(els) {
+                let if_t = next_ty_var(fcx);
                 let thn_bot = check_block(fcx, thn);
                 let thn_t = block_ty(fcx.ccx.tcx, thn);
-                let els_bot = check_expr_with(fcx, els, thn_t);
-                let els_t = expr_ty(fcx.ccx.tcx, els);
-                let if_t = if !ty::type_is_bot(els_t) {
-                    els_t
-                } else {
-                    thn_t
-                };
+                demand::simple(fcx, thn.span, if_t, thn_t);
+                let els_bot = check_expr_with(fcx, els, if_t);
                 (if_t, thn_bot & els_bot)
               }
               none {
@@ -2565,7 +2561,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
           }
 
           (_, _) if ty::is_binopable(tcx, lhs_t, op) {
-            let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
+            let tvar = next_ty_var(fcx);
+            demand::simple(fcx, expr.span, tvar, lhs_t);
+            let rhs_bot = check_expr_with(fcx, rhs, tvar);
             let rhs_t = alt op {
               ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
               ast::gt {
@@ -2646,9 +2644,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       ast::expr_binary(ast::gt, lhs, rhs) |
       ast::expr_binary(ast::ge, lhs, rhs) {
         let tcx = fcx.ccx.tcx;
-        bot |= check_expr(fcx, lhs);
-        let lhs_t = expr_ty(tcx, lhs);
-        bot |= check_expr_with(fcx, rhs, lhs_t);
+        let tvar = next_ty_var(fcx);
+        bot |= check_expr_with(fcx, lhs, tvar);
+        bot |= check_expr_with(fcx, rhs, tvar);
         write_ty(tcx, id, ty::mk_bool(tcx));
       }
       ast::expr_binary(op, lhs, rhs) {
@@ -2782,7 +2780,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       }
       ast::expr_log(_, lv, e) {
         bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
-        bot |= check_expr(fcx, e);
+        // Note: this does not always execute, so do not propagate bot:
+        check_expr(fcx, e);
         write_nil(tcx, id);
       }
       ast::expr_check(_, e) {
@@ -2850,13 +2849,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
           bot = !may_break(body);
       }
       ast::expr_alt(discrim, arms, _) {
-        bot = check_expr(fcx, discrim);
+        let pattern_ty = next_ty_var(fcx);
+        bot = check_expr_with(fcx, discrim, pattern_ty);
 
         let parent_block = tcx.region_map.rvalue_to_block.get(discrim.id);
 
         // Typecheck the patterns first, so that we get types for all the
         // bindings.
-        let pattern_ty = ty::expr_ty(tcx, discrim);
+        //let pattern_ty = ty::expr_ty(tcx, discrim);
         for arm: ast::arm in arms {
             let pcx = {
                 fcx: fcx,
@@ -3205,6 +3205,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     }
     if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); }
 
+    #debug("type of expr %s is %s, expected is %s",
+           syntax::print::pprust::expr_to_str(expr),
+           ty_to_str(tcx, expr_ty(tcx, expr)),
+           ty_to_str(tcx, expected));
+
     unify(fcx, expr.span, expected, expr_ty(tcx, expr));
     ret bot;
 }