about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-06-08 18:39:34 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-06-08 18:42:34 -0700
commit6feb1dfd7672838fe3a621250a832f97c39f2260 (patch)
treedd108d12f3f8abac5a4f0afb4ad812bd504ac7dd
parent537d4ac65a49c4d9932cc8871ffdb9020b5ac05d (diff)
rustc: Don't eagerly resolve type variables after unification
-rw-r--r--src/comp/middle/ty.rs19
-rw-r--r--src/comp/middle/typeck.rs80
2 files changed, 59 insertions, 40 deletions
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 021f8e32b6c..3cd2602ed81 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -2126,6 +2126,25 @@ mod unify {
         ret fold_ty(tcx, bind folder(tcx, vb, _), typ);
     }
 
+    // If the given type is a variable, returns the structure of that type.
+    fn resolve_type_structure(&ty_ctxt tcx, &@var_bindings vb, t typ)
+            -> fixup_result {
+        alt (struct(tcx, typ)) {
+            case (ty_var(?vid)) {
+                if ((vid as uint) >= ufind::set_count(vb.sets)) {
+                    ret fix_err(vid);
+                }
+
+                auto root_id = ufind::find(vb.sets, vid as uint);
+                alt (smallintmap::find[t](vb.types, root_id)) {
+                    case (none[t]) { ret fix_err(vid); }
+                    case (some[t](?rt)) { ret fix_ok(rt); }
+                }
+            }
+            case (_) { ret fix_ok(typ); }
+        }
+    }
+
     fn unify_step(&@ctxt cx, &t expected, &t actual) -> result {
         // TODO: rewrite this using tuple pattern matching when available, to
         // avoid all this rightward drift and spikiness.
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 2f475b9a464..a76a377eae8 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -21,7 +21,6 @@ import middle::ty::mo_alias;
 import middle::ty::node_type_table;
 import middle::ty::pat_ty;
 import middle::ty::path_to_str;
-import middle::ty::struct;
 import middle::ty::ty_param_substs_opt_and_ty;
 import middle::ty::ty_to_str;
 import middle::ty::type_is_integral;
@@ -195,6 +194,19 @@ fn ast_mode_to_mode(ast::mode mode) -> ty::mode {
     ret ty_mode;
 }
 
+// Returns the one-level-deep structure of the given type.
+fn structure_of(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::sty {
+    auto r = ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings,
+                                               typ);
+    alt (r) {
+        case (fix_ok(?typ_s)) { ret ty::struct(fcx.ccx.tcx, typ_s); }
+        case (fix_err(_)) {
+            fcx.ccx.tcx.sess.span_err(sp, "the type of this value must be " +
+                "known in this context");
+        }
+    }
+}
+
 // Parses the programmer's textual representation of a type into our internal
 // notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
@@ -810,20 +822,11 @@ mod collect {
 
 // Type unification
 
+// TODO: rename to just "unify"
 mod unify {
     fn simple(&@fn_ctxt fcx, &ty::t expected, &ty::t actual)
             -> ty::unify::result {
-        auto result = ty::unify::unify(expected, actual, fcx.var_bindings,
-                                       fcx.ccx.tcx);
-
-        // FIXME: Shouldn't be necessary, but is until we remove pushdown.
-        alt (result) {
-            case (ures_ok(?typ)) {
-                ret ures_ok(ty::unify::resolve_all_vars(fcx.ccx.tcx,
-                    fcx.var_bindings, typ));
-            }
-            case (_) { ret result; }
-        }
+        ret ty::unify::unify(expected, actual, fcx.var_bindings, fcx.ccx.tcx);
     }
 }
 
@@ -833,10 +836,10 @@ tag autoderef_kind {
     NO_AUTODEREF;
 }
 
-fn strip_boxes(&ty::ctxt tcx, &ty::t t) -> ty::t {
+fn strip_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> ty::t {
     auto t1 = t;
     while (true) {
-        alt (struct(tcx, t1)) {
+        alt (structure_of(fcx, sp, t1)) {
             case (ty::ty_box(?inner)) { t1 = inner.ty; }
             case (_) { ret t1; }
         }
@@ -854,11 +857,11 @@ fn add_boxes(&@crate_ctxt ccx, uint n, &ty::t t) -> ty::t {
 }
 
 
-fn count_boxes(&ty::ctxt tcx, &ty::t t) -> uint {
+fn count_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> uint {
     auto n = 0u;
     auto t1 = t;
     while (true) {
-        alt (struct(tcx, t1)) {
+        alt (structure_of(fcx, sp, t1)) {
             case (ty::ty_box(?inner)) { n += 1u; t1 = inner.ty; }
             case (_) { ret n; }
         }
@@ -897,9 +900,9 @@ mod demand {
         auto implicit_boxes = 0u;
 
         if (adk == AUTODEREF_OK) {
-            expected_1 = strip_boxes(fcx.ccx.tcx, expected_1);
-            actual_1 = strip_boxes(fcx.ccx.tcx, actual_1);
-            implicit_boxes = count_boxes(fcx.ccx.tcx, actual);
+            expected_1 = strip_boxes(fcx, sp, expected_1);
+            actual_1 = strip_boxes(fcx, sp, actual_1);
+            implicit_boxes = count_boxes(fcx, sp, actual);
         }
 
         let vec[mutable ty::t] ty_param_substs = [mutable];
@@ -958,7 +961,7 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid,
     let vec[ty::t] result = [];
 
     auto tpt = ty::lookup_item_type(ccx.tcx, vid);
-    alt (struct(ccx.tcx, tpt._1)) {
+    alt (ty::struct(ccx.tcx, tpt._1)) {
         case (ty::ty_fn(_, ?ins, _, _)) {
             // N-ary variant.
             for (ty::arg arg in ins) {
@@ -1272,7 +1275,7 @@ fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) {
 
             // Take the tag type params out of `expected`.
             auto expected_tps;
-            alt (struct(fcx.ccx.tcx, expected)) {
+            alt (structure_of(fcx, pat.span, expected)) {
                 case (ty::ty_tag(_, ?tps)) { expected_tps = tps; }
                 case (_) {
                     // FIXME: Switch expected and actual in this message? I
@@ -1405,14 +1408,12 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
         // Check the function.
         check_expr(fcx, f);
 
-        // Get the function type. We need to have resolved it enough to know
-        // it's a ty_fn or ty_native_fn.
+        // Get the function type.
         auto fty = expr_ty(fcx.ccx.tcx, f);
-        fty = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, fty);
 
         // Grab the argument types and the return type.
         auto arg_tys;
-        alt (ty::struct(fcx.ccx.tcx, fty)) {
+        alt (structure_of(fcx, sp, fty)) {
             case (ty::ty_fn(_, ?arg_tys_0, _, _)) {
                 arg_tys = arg_tys_0;
             }
@@ -1508,7 +1509,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
             auto lhs_t = expr_ty(fcx.ccx.tcx, lhs);
 
             // FIXME: Binops have a bit more subtlety than this.
-            auto t = strip_boxes(fcx.ccx.tcx, lhs_t);
+            auto t = strip_boxes(fcx, expr.span, lhs_t);
             alt (binop) {
                 case (ast::eq) { t = ty::mk_bool(fcx.ccx.tcx); }
                 case (ast::lt) { t = ty::mk_bool(fcx.ccx.tcx); }
@@ -1532,7 +1533,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                                         rec(ty=oper_t, mut=mut));
                 }
                 case (ast::deref) {
-                    alt (struct(fcx.ccx.tcx, oper_t)) {
+                    alt (structure_of(fcx, expr.span, oper_t)) {
                         case (ty::ty_box(?inner)) { oper_t = inner.ty; }
                         case (_) {
                             fcx.ccx.tcx.sess.span_err
@@ -1542,7 +1543,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                         }
                     }
                 }
-                case (_) { oper_t = strip_boxes(fcx.ccx.tcx, oper_t); }
+                case (_) { oper_t = strip_boxes(fcx, expr.span, oper_t); }
             }
 
             write::ty_only_fixup(fcx, a.id, oper_t);
@@ -1721,7 +1722,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
 
             auto item_t;
             auto lhs_t = expr_ty(fcx.ccx.tcx, lhs);
-            alt (struct(fcx.ccx.tcx, lhs_t)) {
+            alt (structure_of(fcx, expr.span, lhs_t)) {
                 case (ty::ty_chan(?it)) { item_t = it; }
                 case (_) {
                     fcx.ccx.tcx.sess.span_err(expr.span,
@@ -1775,8 +1776,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
 
         case (ast::expr_for(?decl, ?seq, ?body, ?a)) {
             check_expr(fcx, seq);
-            alt (struct (fcx.ccx.tcx,
-                         expr_ty(fcx.ccx.tcx, seq))) {
+            alt (structure_of(fcx, expr.span, expr_ty(fcx.ccx.tcx, seq))) {
                 // FIXME: I include the check_for_or_each call in 
                 // each case because of a bug in typestate.
                 // The bug is fixed; once there's a new snapshot,
@@ -1877,7 +1877,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
             auto rt_1;
             auto fty = expr_ty(fcx.ccx.tcx, f);
             auto t_1;
-            alt (struct(fcx.ccx.tcx, fty)) {
+            alt (structure_of(fcx, expr.span, fty)) {
                 case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) {
                     proto_1 = proto;
                     rt_1 = rt;
@@ -1917,7 +1917,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
             // Pull the return type out of the type of the function.
             auto rt_1 = ty::mk_nil(fcx.ccx.tcx); // FIXME: typestate botch
             auto fty = ty::expr_ty(fcx.ccx.tcx, f);
-            alt (struct(fcx.ccx.tcx, fty)) {
+            alt (structure_of(fcx, expr.span, fty)) {
                 case (ty::ty_fn(_,_,?rt,_))         { rt_1 = rt; }
                 case (ty::ty_native_fn(_, _, ?rt))  { rt_1 = rt; }
                 case (_) {
@@ -1949,7 +1949,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
             }
 
             // Grab this method's type out of the current object type.
-            alt (struct(fcx.ccx.tcx, this_obj_ty)) {
+            alt (structure_of(fcx, expr.span, this_obj_ty)) {
                 case (ty::ty_obj(?methods)) {
                     for (ty::method method in methods) {
                         if (method.ident == id) {
@@ -2059,7 +2059,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
 
                     let vec[field] base_fields = [];
 
-                    alt (struct(fcx.ccx.tcx, bexpr_t)) {
+                    alt (structure_of(fcx, expr.span, bexpr_t)) {
                         case (ty::ty_rec(?flds)) { base_fields = flds; }
                         case (_) {
                             fcx.ccx.tcx.sess.span_err
@@ -2093,10 +2093,10 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
         case (ast::expr_field(?base, ?field, ?a)) {
             check_expr(fcx, base);
             auto base_t = expr_ty(fcx.ccx.tcx, base);
-            base_t = strip_boxes(fcx.ccx.tcx, base_t);
+            base_t = strip_boxes(fcx, expr.span, base_t);
             base_t = ty::unify::resolve_all_vars(fcx.ccx.tcx,
                 fcx.var_bindings, base_t);
-            alt (struct(fcx.ccx.tcx, base_t)) {
+            alt (structure_of(fcx, expr.span, base_t)) {
                 case (ty::ty_tup(?args)) {
                     let uint ix = ty::field_num(fcx.ccx.tcx.sess,
                                                 expr.span, field);
@@ -2142,11 +2142,11 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
         case (ast::expr_index(?base, ?idx, ?a)) {
             check_expr(fcx, base);
             auto base_t = expr_ty(fcx.ccx.tcx, base);
-            base_t = strip_boxes(fcx.ccx.tcx, base_t);
+            base_t = strip_boxes(fcx, expr.span, base_t);
 
             check_expr(fcx, idx);
             auto idx_t = expr_ty(fcx.ccx.tcx, idx);
-            alt (struct(fcx.ccx.tcx, base_t)) {
+            alt (structure_of(fcx, expr.span, base_t)) {
                 case (ty::ty_vec(?mt)) {
                     if (! type_is_integral(fcx.ccx.tcx, idx_t)) {
                         fcx.ccx.tcx.sess.span_err
@@ -2184,7 +2184,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
         case (ast::expr_chan(?x, ?a)) {
             check_expr(fcx, x);
             auto port_t = expr_ty(fcx.ccx.tcx, x);
-            alt (struct(fcx.ccx.tcx, port_t)) {
+            alt (structure_of(fcx, expr.span, port_t)) {
                 case (ty::ty_port(?subtype)) {
                     auto ct = ty::mk_chan(fcx.ccx.tcx, subtype);
                     write::ty_only_fixup(fcx, a.id, ct);