about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-06-30 14:46:17 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-06-30 18:36:12 +0200
commit86f16b90cd694cd706469bb42737e63b1d9c1fdc (patch)
treef81e107848cf5b8ba5488c6f4fbba20e38e0788e /src/comp
parent31ec26d46afe543508b4a11d33309afefa85b29a (diff)
downloadrust-86f16b90cd694cd706469bb42737e63b1d9c1fdc.tar.gz
rust-86f16b90cd694cd706469bb42737e63b1d9c1fdc.zip
Support type parameters in resources
Some rather dodgy code was added to trans in the process. I'd love to
discuss it with someone who knows more about types during translation.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/lib/llvm.rs7
-rw-r--r--src/comp/metadata/tydecode.rs6
-rw-r--r--src/comp/metadata/tyencode.rs6
-rw-r--r--src/comp/middle/alias.rs2
-rw-r--r--src/comp/middle/trans.rs76
-rw-r--r--src/comp/middle/ty.rs87
-rw-r--r--src/comp/middle/typeck.rs33
7 files changed, 151 insertions, 66 deletions
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index 460148ad1ee..b671b2485c0 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -1570,6 +1570,13 @@ fn type_to_str_inner(type_names names,
     }
 }
 
+fn fn_ty_param_tys(TypeRef fn_ty) -> vec[TypeRef] {
+    auto args = vec::init_elt(0 as TypeRef, llvm::LLVMCountParamTypes(fn_ty));
+    llvm::LLVMGetParamTypes(fn_ty, vec::buf(args));
+    ret args;
+}
+
+
 /* Memory-managed interface to target data. */
 
 obj target_data_dtor(TargetDataRef TD) {
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index 300fc2c6975..353eb0928c6 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -257,9 +257,13 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
             ret ty::mk_obj(st.tcx, methods);
         }
         case ('r') {
+            assert (next(st) as char == '[');
             auto def = parse_def(st, sd);
             auto inner = parse_ty(st, sd);
-            ret ty::mk_res(st.tcx, def, inner);
+            let vec[ty::t] params = [];
+            while (peek(st) as char != ']') { params += [parse_ty(st, sd)]; }
+            st.pos = st.pos + 1u;
+            ret ty::mk_res(st.tcx, def, inner, params);
         }
         case ('X') { ret ty::mk_var(st.tcx, parse_int(st)); }
         case ('E') { ret ty::mk_native(st.tcx); }
diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs
index 9ba314ccacc..51cd5fcc89a 100644
--- a/src/comp/metadata/tyencode.rs
+++ b/src/comp/metadata/tyencode.rs
@@ -172,11 +172,13 @@ fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
             }
             w.write_char(']');
         }
-        case (ty::ty_res(?def, ?ty)) {
-            w.write_char('r');
+        case (ty::ty_res(?def, ?ty, ?tps)) {
+            w.write_str("r[");
             w.write_str(cx.ds(def));
             w.write_char('|');
             enc_ty(w, cx, ty);
+            for (ty::t t in tps) { enc_ty(w, cx, t); }
+            w.write_char(']');
         }
         case (ty::ty_var(?id)) {
             w.write_char('X');
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index 87ad6096d33..b7f58dc4103 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -556,7 +556,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
                                               kind=unbox,
                                               outer_t=base_t));
                         }
-                        case (ty::ty_res(_, ?inner)) {
+                        case (ty::ty_res(_, ?inner, _)) {
                             vec::push(ds, rec(mut=false,
                                               kind=unbox,
                                               outer_t=base_t));
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 2f19de9230f..c14938a5b61 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -876,8 +876,9 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
             abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
             llty = abs_pair;
         }
-        case (ty::ty_res(_, ?sub)) {
-            ret T_struct([T_i32(), type_of_inner(cx, sp, sub)]);
+        case (ty::ty_res(_, ?sub, ?tps)) {
+            auto sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
+            ret T_struct([T_i32(), type_of_inner(cx, sp, sub1)]);
         }
         case (ty::ty_var(_)) {
             cx.tcx.sess.span_fatal(sp, "trans::type_of called on ty_var");
@@ -1220,9 +1221,10 @@ fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t {
                                     ty::mk_imm_box(ccx.tcx,
                                                    ty::mk_nil(ccx.tcx))]);
             }
-            case (ty::ty_res(_, ?sub)) {
+            case (ty::ty_res(_, ?sub, ?tps)) {
+                auto sub1 = ty::substitute_type_params(ccx.tcx, tps, sub);
                 ret ty::mk_imm_tup(ccx.tcx, [ty::mk_int(ccx.tcx),
-                                             simplify_type(ccx, sub)]);
+                                             simplify_type(ccx, sub1)]);
             }
             case (_) { ret typ; }
         }
@@ -1716,8 +1718,7 @@ fn get_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
     }
     // Otherwise, generate a tydesc if necessary, and return it.
 
-    let vec[uint] tps = [];
-    auto info = get_static_tydesc(cx, t, tps);
+    auto info = get_static_tydesc(cx, t, []);
     static_ti = some[@tydesc_info](info);
     ret rslt(cx, info.tydesc);
 }
@@ -2089,8 +2090,8 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
                 cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
             decr_refcnt_maybe_free(cx, box_cell, v0, t)
         }
-        case (ty::ty_res(?did, ?inner)) {
-            trans_res_drop(cx, v0, did, inner)
+        case (ty::ty_res(?did, ?inner, ?tps)) {
+            trans_res_drop(cx, v0, did, inner, tps)
         }
         case (ty::ty_fn(_, _, _, _, _)) {
             auto box_cell =
@@ -2108,9 +2109,11 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
 }
 
 fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
-                  ty::t inner_t) -> result {
+                  ty::t inner_t, &vec[ty::t] tps) -> result {
     auto ccx = cx.fcx.lcx.ccx;
-    auto tup_ty = ty::mk_imm_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t]);
+
+    auto inner_t_s = ty::substitute_type_params(ccx.tcx, tps, inner_t);
+    auto tup_ty = ty::mk_imm_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t_s]);
     auto drop_cx = new_sub_block_ctxt(cx, "drop res");
     auto next_cx = new_sub_block_ctxt(cx, "next");
 
@@ -2120,6 +2123,8 @@ fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
     cx.build.CondBr(null_test, next_cx.llbb, drop_cx.llbb);
     cx = drop_cx;
 
+    auto val = GEP_tup_like(cx, tup_ty, rs, [0, 1]);
+    cx = val.bcx;
     // Find and call the actual destructor.
     auto dtor_pair = if (did._0 == ast::local_crate) {
         ccx.fn_pairs.get(did._1)
@@ -2136,15 +2141,25 @@ fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
         (cx.build.GEP(dtor_pair, [C_int(0), C_int(abi::fn_field_code)]));
     auto dtor_env = cx.build.Load
         (cx.build.GEP(dtor_pair, [C_int(0), C_int(abi::fn_field_box)]));
-    auto val = GEP_tup_like(cx, tup_ty, rs, [0, 1]);
-    cx = val.bcx;
-    cx.build.FastCall(dtor_addr, [cx.fcx.llretptr, cx.fcx.lltaskptr, dtor_env]
-                      + cx.fcx.lltydescs + [val.val]);
-
-    cx = drop_slot(cx, val.val, inner_t).bcx;
+    auto args = [cx.fcx.llretptr, cx.fcx.lltaskptr, dtor_env];
+    for (ty::t tp in tps) {
+        let option::t[@tydesc_info] ti = none;
+        auto td = get_tydesc(cx, tp, false, ti);
+        args += [td.val];
+        cx = td.bcx;
+    }
+    // Kludge to work around the fact that we know the precise type of the
+    // value here, but the dtor expects a type that still has opaque pointers
+    // for type variables.
+    auto val_llty = lib::llvm::fn_ty_param_tys
+        (llvm::LLVMGetElementType(llvm::LLVMTypeOf(dtor_addr)))
+        .(vec::len(args));
+    auto val_cast = cx.build.BitCast(val.val, val_llty);
+    cx.build.FastCall(dtor_addr, args + [val_cast]);
+
+    cx = drop_slot(cx, val.val, inner_t_s).bcx;
     cx.build.Store(C_int(0), drop_flag.val);
     cx.build.Br(next_cx.llbb);
-
     ret rslt(next_cx, C_nil());
 }
 
@@ -2611,13 +2626,15 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv,
                 i += 1;
             }
         }
-        case (ty::ty_res(_, ?inner)) {
+        case (ty::ty_res(_, ?inner, ?tps)) {
+            auto inner1 = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx,
+                                                     tps, inner);
             r = GEP_tup_like(r.bcx, t, av, [0, 1]);
             auto llfld_a = r.val;
             r = GEP_tup_like(r.bcx, t, bv, [0, 1]);
             auto llfld_b = r.val;
-            f(r.bcx, load_if_immediate(r.bcx, llfld_a, inner),
-              load_if_immediate(r.bcx, llfld_b, inner), inner);
+            f(r.bcx, load_if_immediate(r.bcx, llfld_a, inner1),
+              load_if_immediate(r.bcx, llfld_b, inner1), inner1);
         }
         case (ty::ty_tag(?tid, ?tps)) {
             auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
@@ -2891,9 +2908,9 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field,
                                                  T_glue_fn(lcx.ccx.tn),
                                                  "drop");
                         ti.drop_glue = some[ValueRef](glue_fn);
-                        auto dg = make_drop_glue;
                         make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
-                                          mgghf_single(dg), ti.ty_params);
+                                          mgghf_single(make_drop_glue),
+                                          ti.ty_params);
                         log #fmt("--- lazily_emit_tydesc_glue DROP %s",
                                  ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
                     }
@@ -5026,7 +5043,7 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
             auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
             auto offset = alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
                 case (ty::ty_box(_)) { abi::box_rc_field_body }
-                case (ty::ty_res(_, _)) { 1 }
+                case (ty::ty_res(_, _, _)) { 1 }
             };
             auto val = sub.bcx.build.GEP(sub.val, [C_int(0), C_int(offset)]);
             ret lval_mem(sub.bcx, val);
@@ -7850,10 +7867,17 @@ fn trans_res_ctor(@local_ctxt cx, &span sp, &ast::_fn dtor,
     auto tup_t = ty::mk_imm_tup(cx.ccx.tcx, [ty::mk_int(cx.ccx.tcx), arg_t]);
     auto arg = load_if_immediate
         (bcx, fcx.llargs.get(dtor.decl.inputs.(0).id), arg_t);
-    auto dst = GEP_tup_like(bcx, tup_t, fcx.llretptr, [0, 1]);
+
+    auto llretptr = fcx.llretptr;
+    if (ty::type_has_dynamic_size(cx.ccx.tcx, ret_t)) {
+        auto llret_t = T_ptr(T_struct([T_i32(), llvm::LLVMTypeOf(arg)]));
+        llretptr = bcx.build.BitCast(llretptr, llret_t);
+    }
+
+    auto dst = GEP_tup_like(bcx, tup_t, llretptr, [0, 1]);
     bcx = dst.bcx;
     bcx = copy_val(bcx, INIT, dst.val, arg, arg_t).bcx;
-    auto flag = GEP_tup_like(bcx, tup_t, fcx.llretptr, [0, 0]);
+    auto flag = GEP_tup_like(bcx, tup_t, llretptr, [0, 0]);
     bcx = flag.bcx;
     bcx.build.Store(C_int(1), flag.val);
     bcx.build.RetVoid();
@@ -7973,7 +7997,7 @@ fn trans_item(@local_ctxt cx, &ast::item item) {
             trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
             // Create a function for the destructor
             auto lldtor_decl = cx.ccx.item_ids.get(item.id);
-            trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id);
+            trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id)
         }
         case (ast::item_mod(?m)) {
             auto sub_cx =
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index f669970898e..0d3be6b041d 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -268,7 +268,7 @@ tag sty {
     ty_fn(ast::proto, vec[arg], t, controlflow, vec[@constr_def]);
     ty_native_fn(ast::native_abi, vec[arg], t);
     ty_obj(vec[method]);
-    ty_res(def_id, t);
+    ty_res(def_id, t, vec[t]);
     ty_var(int); // type variable
     ty_param(uint); // fn/tag type param
     ty_type;
@@ -497,7 +497,12 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t {
                                  m.output);
             }
         }
-        case (ty_res(_, ?tt)) { derive_flags_t(cx, has_params, has_vars, tt);}
+        case (ty_res(_, ?tt, ?tps)) {
+            derive_flags_t(cx, has_params, has_vars, tt);
+            for (t tt in tps) {
+                derive_flags_t(cx, has_params, has_vars, tt);
+            }
+        }
     }
     ret rec(struct=st,
             cname=cname,
@@ -604,8 +609,8 @@ fn mk_obj(&ctxt cx, &vec[method] meths) -> t {
     ret gen_ty(cx, ty_obj(meths));
 }
 
-fn mk_res(&ctxt cx, &ast::def_id did, &t inner) -> t {
-    ret gen_ty(cx, ty_res(did, inner));
+fn mk_res(&ctxt cx, &ast::def_id did, &t inner, &vec[t] tps) -> t {
+    ret gen_ty(cx, ty_res(did, inner, tps));
 }
 
 fn mk_var(&ctxt cx, int v) -> t { ret gen_ty(cx, ty_var(v)); }
@@ -689,7 +694,10 @@ fn walk_ty(&ctxt cx, ty_walk walker, t ty) {
                 walk_ty(cx, walker, m.output);
             }
         }
-        case (ty_res(_, ?sub)) { walk_ty(cx, walker, sub); }
+        case (ty_res(_, ?sub, ?tps)) {
+            walk_ty(cx, walker, sub);
+            for (t tp in tps) { walk_ty(cx, walker, tp); }
+        }
         case (ty_var(_)) {/* no-op */ }
         case (ty_param(_)) {/* no-op */ }
     }
@@ -822,8 +830,11 @@ fn fold_ty(&ctxt cx, fold_mode fld, t ty_0) -> t {
             }
             ty = copy_cname(cx, mk_obj(cx, new_methods), ty);
         }
-        case (ty_res(?did, ?subty)) {
-            ty = copy_cname(cx, mk_res(cx, did, fold_ty(cx, fld, subty)), ty);
+        case (ty_res(?did, ?subty, ?tps)) {
+            auto new_tps = [];
+            for (t tp in tps) { new_tps += [fold_ty(cx, fld, tp)]; }
+            ty = copy_cname(cx, mk_res(cx, did, fold_ty(cx, fld, subty),
+                                       new_tps), ty);
         }
         case (ty_var(?id)) {
             alt (fld) {
@@ -894,7 +905,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
         case (ty_tag(_, _)) { ret true; }
         case (ty_fn(_, _, _, _, _)) { ret true; }
         case (ty_obj(_)) { ret true; }
-        case (ty_res(_, _)) { ret true; }
+        case (ty_res(_, _, _)) { ret true; }
         case (ty_ivec(_)) { ret true; }
         case (ty_istr) { ret true; }
         case (_) { ret false; }
@@ -903,7 +914,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
 
 fn type_is_copyable(&ctxt cx, &t ty) -> bool {
     ret alt (struct(cx, ty)) {
-        case (ty_res(_, _)) { false }
+        case (ty_res(_, _, _)) { false }
         case (_) { true }
     };
 }
@@ -1050,7 +1061,10 @@ fn type_has_pointers(&ctxt cx, &t ty) -> bool {
                 if (type_has_pointers(cx, tup_ty)) { result = true; }
             }
         }
-        case (ty_res(?did, ?inner)) { result = type_has_pointers(cx, inner); }
+        case (ty_res(?did, ?inner, ?tps)) {
+            result = type_has_pointers
+                (cx, substitute_type_params(cx, tps, inner));
+        }
         case (_) { result = true; }
     }
 
@@ -1114,7 +1128,12 @@ fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool {
         case (ty_fn(_,_,_,_,_)) { ret false; }
         case (ty_native_fn(_,_,_)) { ret false; }
         case (ty_obj(_)) { ret false; }
-        case (ty_res(_, ?sub)) { ret type_has_dynamic_size(cx, sub); }
+        case (ty_res(_, ?sub, ?tps)) {
+            for (t tp in tps) {
+                if (type_has_dynamic_size(cx, tp)) { ret true; }
+            }
+            ret type_has_dynamic_size(cx, sub);
+        }
         case (ty_var(_)) { fail "ty_var in type_has_dynamic_size()"; }
         case (ty_param(_)) { ret true; }
         case (ty_type) { ret false; }
@@ -1225,7 +1244,10 @@ fn type_owns_heap_mem(&ctxt cx, &t ty) -> bool {
                 if (type_owns_heap_mem(cx, f.mt.ty)) { result = true; }
             }
         }
-        case (ty_res(_, ?inner)) { result = type_owns_heap_mem(cx, inner); }
+        case (ty_res(_, ?inner, ?tps)) {
+            result = type_owns_heap_mem
+                (cx, substitute_type_params(cx, tps, inner));
+        }
 
         case (ty_ptr(_)) { result = false; }
         case (ty_port(_)) { result = false; }
@@ -1337,7 +1359,11 @@ fn hash_type_structure(&sty st) -> uint {
         case (ty_native) { ret 33u; }
         case (ty_bot) { ret 34u; }
         case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); }
-        case (ty_res(?did, ?sub)) { ret hash_subty(hash_def(18u, did), sub); }
+        case (ty_res(?did, ?sub, ?tps)) {
+            auto h = hash_subty(hash_def(18u, did), sub);
+            for (t tp in tps) { h += h << 5u + hash_ty(tp); }
+            ret h;
+        }
     }
 }
 
@@ -1598,10 +1624,18 @@ fn equal_type_structures(&sty a, &sty b) -> bool {
                 case (_) { ret false; }
             }
         }
-        case (ty_res(?id_a, ?inner_a)) {
+        case (ty_res(?id_a, ?inner_a, ?tps_a)) {
             alt (b) {
-                case (ty_res(?id_b, ?inner_b)) {
-                    ret equal_def(id_a, id_b) && ret eq_ty(inner_a, inner_b);
+                case (ty_res(?id_b, ?inner_b, ?tps_b)) {
+                    if (!equal_def(id_a, id_b) || !eq_ty(inner_a, inner_b)) {
+                        ret false;
+                    }
+                    auto i = 0u;
+                    for (t tp_a in tps_a) {
+                        if (!eq_ty(tp_a, tps_b.(i))) { ret false; }
+                        i += 1u;
+                    }
+                    ret true;
                 }
                 case (_) { ret false; }
             }
@@ -2394,17 +2428,30 @@ mod unify {
                     case (_) { ret ures_err(terr_mismatch); }
                 }
             }
-            case (ty::ty_res(?ex_id, ?ex_inner)) {
+            case (ty::ty_res(?ex_id, ?ex_inner, ?ex_tps)) {
                 alt (struct(cx.tcx, actual)) {
-                    case (ty::ty_res(?act_id, ?act_inner)) {
+                    case (ty::ty_res(?act_id, ?act_inner, ?act_tps)) {
                         if (ex_id._0 != act_id._0 || ex_id._1 != act_id._1) {
                             ret ures_err(terr_mismatch);
                         }
                         auto result = unify_step(cx, ex_inner, act_inner);
                         alt (result) {
                             case (ures_ok(?res_inner)) {
-                                ret ures_ok(mk_res(cx.tcx, act_id,
-                                                   res_inner));
+                                auto i = 0u;
+                                auto res_tps = [];
+                                for (t ex_tp in ex_tps) {
+                                    auto result =
+                                        unify_step(cx, ex_tp, act_tps.(i));
+                                    alt (result) {
+                                        case (ures_ok(?rty)) {
+                                            vec::push(res_tps, rty);
+                                        }
+                                        case (_) { ret result; }
+                                    }
+                                    i += 1u;
+                                }
+                                ret ures_ok(mk_res(cx.tcx, act_id, res_inner,
+                                                   res_tps));
                             }
                             case (_) { ret result; }
                         }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index ea5da34c773..4230a4967cd 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -439,6 +439,15 @@ mod write {
 mod collect {
     type ctxt = rec(ty::ctxt tcx);
 
+    fn mk_ty_params(&@ctxt cx, uint n) -> vec[ty::t] {
+        auto tps = [];
+        auto i = 0u;
+        while (i < n) {
+            tps += [ty::mk_param(cx.tcx, i)];
+            i += 1u;
+        }
+        ret tps;
+    }
     fn ty_of_fn_decl(&@ctxt cx, &fn(&@ast::ty) -> ty::t  convert,
                      &fn(&ast::arg) -> arg  ty_of_arg, &ast::fn_decl decl,
                      ast::proto proto, &vec[ast::ty_param] ty_params,
@@ -581,21 +590,17 @@ mod collect {
             case (ast::item_res(?f, _, ?tps, _)) {
                 auto t_arg = ty_of_arg(cx, f.decl.inputs.(0));
                 auto t_res = tup(vec::len(tps), ty::mk_res
-                                 (cx.tcx, local_def(it.id), t_arg.ty));
+                                 (cx.tcx, local_def(it.id), t_arg.ty,
+                                  mk_ty_params(cx, vec::len(tps))));
                 cx.tcx.tcache.insert(local_def(it.id), t_res);
                 ret t_res;
             }
             case (ast::item_tag(_, ?tps)) {
                 // Create a new generic polytype.
 
-                let vec[ty::t] subtys = [];
-                auto i = 0u;
-                for (ast::ty_param tp in tps) {
-                    subtys += [ty::mk_param(cx.tcx, i)];
-                    i += 1u;
-                }
-                auto t = ty::mk_tag(cx.tcx, local_def(it.id), subtys);
                 auto ty_param_count = vec::len[ast::ty_param](tps);
+                let vec[ty::t] subtys = mk_ty_params(cx, ty_param_count);
+                auto t = ty::mk_tag(cx.tcx, local_def(it.id), subtys);
                 auto tpt = tup(ty_param_count, t);
                 cx.tcx.tcache.insert(local_def(it.id), tpt);
                 ret tpt;
@@ -631,13 +636,8 @@ mod collect {
                              &vec[ast::ty_param] ty_params) {
         // Create a set of parameter types shared among all the variants.
 
-        let vec[ty::t] ty_param_tys = [];
-        auto i = 0u;
-        for (ast::ty_param tp in ty_params) {
-            ty_param_tys += [ty::mk_param(cx.tcx, i)];
-            i += 1u;
-        }
         auto ty_param_count = vec::len[ast::ty_param](ty_params);
+        let vec[ty::t] ty_param_tys = mk_ty_params(cx, ty_param_count);
         for (ast::variant variant in variants) {
             // Nullary tag constructors get turned into constants; n-ary tag
             // constructors get turned into functions.
@@ -737,7 +737,8 @@ mod collect {
             }
             case (ast::item_res(?f, ?dtor_id, ?tps, ?ctor_id)) {
                 auto t_arg = ty_of_arg(cx, f.decl.inputs.(0));
-                auto t_res = ty::mk_res(cx.tcx, local_def(it.id), t_arg.ty);
+                auto t_res = ty::mk_res(cx.tcx, local_def(it.id), t_arg.ty,
+                                        mk_ty_params(cx, vec::len(tps)));
                 auto t_ctor = ty::mk_fn(cx.tcx, ast::proto_fn, [t_arg],
                                         t_res, ast::return, []);
                 auto t_dtor = ty::mk_fn(cx.tcx, ast::proto_fn, [t_arg],
@@ -1527,7 +1528,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                 case (ast::deref) {
                     alt (structure_of(fcx, expr.span, oper_t)) {
                         case (ty::ty_box(?inner)) { oper_t = inner.ty; }
-                        case (ty::ty_res(_, ?inner)) { oper_t = inner; }
+                        case (ty::ty_res(_, ?inner, _)) { oper_t = inner; }
                         case (_) {
                             auto s = "dereferencing non-box type: " +
                                 ty_to_str(fcx.ccx.tcx, oper_t);