about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2012-02-21 15:22:55 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2012-02-21 17:08:14 +0100
commit92a45f5582ed8ea4eb439ea2eada31e228d8fe6b (patch)
treee5f36ba47d8e3ba7272f2eaf505154a71b529343 /src
parentd85d4f55f7f7cf35dfbf39979a72062f4181f9ed (diff)
downloadrust-92a45f5582ed8ea4eb439ea2eada31e228d8fe6b.tar.gz
rust-92a45f5582ed8ea4eb439ea2eada31e228d8fe6b.zip
Move trans::type_of code into its own file
Slowly shrinking base.rs
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/trans/alt.rs2
-rw-r--r--src/comp/middle/trans/base.rs252
-rw-r--r--src/comp/middle/trans/closure.rs2
-rw-r--r--src/comp/middle/trans/common.rs13
-rw-r--r--src/comp/middle/trans/impl.rs1
-rw-r--r--src/comp/middle/trans/native.rs3
-rw-r--r--src/comp/middle/trans/shape.rs12
-rw-r--r--src/comp/middle/trans/tvec.rs10
-rw-r--r--src/comp/middle/trans/type_of.rs145
-rw-r--r--src/comp/middle/trans/uniq.rs2
-rw-r--r--src/comp/rustc.rc1
11 files changed, 223 insertions, 220 deletions
diff --git a/src/comp/middle/trans/alt.rs b/src/comp/middle/trans/alt.rs
index 19966559dcc..2057296d197 100644
--- a/src/comp/middle/trans/alt.rs
+++ b/src/comp/middle/trans/alt.rs
@@ -686,7 +686,7 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
       ast::pat_ident(_,inner) {
         if make_copy || ccx.copy_map.contains_key(pat.id) {
             let ty = node_id_type(bcx, pat.id);
-            let llty = type_of(ccx, ty);
+            let llty = type_of::type_of(ccx, ty);
             let alloc = alloca(bcx, llty);
             bcx = copy_val(bcx, INIT, alloc,
                                   load_if_immediate(bcx, val, ty), ty);
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index b426e193efb..eb25415357a 100644
--- a/src/comp/middle/trans/base.rs
+++ b/src/comp/middle/trans/base.rs
@@ -44,157 +44,80 @@ import util::ppaux::{ty_to_str, ty_to_short_str};
 import common::*;
 import build::*;
 import shape::*;
+import type_of::*;
+import type_of::type_of; // Issue #1873
 import ast_map::{path, path_mod, path_name};
 
-fn type_of_explicit_args(cx: crate_ctxt, inputs: [ty::arg]) -> [TypeRef] {
-    vec::map(inputs) {|arg|
-        let arg_ty = arg.ty;
-        let llty = type_of(cx, arg_ty);
-        alt ty::resolved_mode(cx.tcx, arg.mode) {
-          ast::by_val { llty }
-          _ { T_ptr(llty) }
-        }
-    }
-}
+// Destinations
 
+// These are passed around by the code generating functions to track the
+// destination of a computation's value.
 
-// NB: must keep 4 fns in sync:
-//
-//  - type_of_fn
-//  - create_llargs_for_fn_args.
-//  - new_fn_ctxt
-//  - trans_args
-fn type_of_fn(cx: crate_ctxt, inputs: [ty::arg],
-              output: ty::t, params: [ty::param_bounds]) -> TypeRef {
-    let atys: [TypeRef] = [];
+enum dest {
+    by_val(@mutable ValueRef),
+    save_in(ValueRef),
+    ignore,
+}
 
-    // Arg 0: Output pointer.
-    atys += [T_ptr(type_of(cx, output))];
+fn empty_dest_cell() -> @mutable ValueRef {
+    ret @mutable llvm::LLVMGetUndef(T_nil());
+}
 
-    // Arg 1: Environment
-    atys += [T_opaque_box_ptr(cx)];
+fn dup_for_join(dest: dest) -> dest {
+    alt dest {
+      by_val(_) { by_val(empty_dest_cell()) }
+      _ { dest }
+    }
+}
 
-    // Args >2: ty params, if not acquired via capture...
-    for bounds in params {
-        atys += [T_ptr(cx.tydesc_type)];
-        for bound in *bounds {
-            alt bound {
-              ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
+fn join_returns(parent_cx: block, in_cxs: [block],
+                in_ds: [dest], out_dest: dest) -> block {
+    let out = sub_block(parent_cx, "join");
+    let reachable = false, i = 0u, phi = none;
+    for cx in in_cxs {
+        if !cx.unreachable {
+            Br(cx, out.llbb);
+            reachable = true;
+            alt in_ds[i] {
+              by_val(cell) {
+                if option::is_none(phi) {
+                    phi = some(EmptyPhi(out, val_ty(*cell)));
+                }
+                AddIncomingToPhi(option::get(phi), *cell, cx.llbb);
+              }
               _ {}
             }
         }
+        i += 1u;
     }
-    // ... then explicit args.
-    atys += type_of_explicit_args(cx, inputs);
-    ret T_fn(atys, llvm::LLVMVoidType());
-}
-
-// Given a function type and a count of ty params, construct an llvm type
-fn type_of_fn_from_ty(cx: crate_ctxt, fty: ty::t,
-                      param_bounds: [ty::param_bounds]) -> TypeRef {
-    type_of_fn(cx, ty::ty_fn_args(fty), ty::ty_fn_ret(fty), param_bounds)
-}
-
-fn type_of(cx: crate_ctxt, t: ty::t) -> TypeRef {
-    assert !ty::type_has_vars(t);
-    // Check the cache.
-
-    if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); }
-    let llty = alt ty::get(t).struct {
-      ty::ty_nil | ty::ty_bot { T_nil() }
-      ty::ty_bool { T_bool() }
-      ty::ty_int(t) { T_int_ty(cx, t) }
-      ty::ty_uint(t) { T_uint_ty(cx, t) }
-      ty::ty_float(t) { T_float_ty(cx, t) }
-      ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
-      ty::ty_enum(did, _) { type_of_enum(cx, did, t) }
-      ty::ty_box(mt) {
-        let mt_ty = mt.ty;
-        T_ptr(T_box(cx, type_of(cx, mt_ty))) }
-      ty::ty_opaque_box { T_ptr(T_box(cx, T_i8())) }
-      ty::ty_uniq(mt) {
-        let mt_ty = mt.ty;
-        T_ptr(type_of(cx, mt_ty)) }
-      ty::ty_vec(mt) {
-        let mt_ty = mt.ty;
-        if ty::type_has_dynamic_size(cx.tcx, mt_ty) {
-            T_ptr(cx.opaque_vec_type)
-        } else {
-            T_ptr(T_vec(cx, type_of(cx, mt_ty))) }
-      }
-      ty::ty_ptr(mt) {
-        let mt_ty = mt.ty;
-        T_ptr(type_of(cx, mt_ty)) }
-      ty::ty_rec(fields) {
-        let tys: [TypeRef] = [];
-        for f: ty::field in fields {
-            let mt_ty = f.mt.ty;
-            tys += [type_of(cx, mt_ty)];
-        }
-        T_struct(tys)
-      }
-      ty::ty_fn(_) {
-        T_fn_pair(cx, type_of_fn_from_ty(cx, t, []))
-      }
-      ty::ty_iface(_, _) { T_opaque_iface(cx) }
-      ty::ty_res(_, sub, tps) {
-        let sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
-        ret T_struct([T_i8(), type_of(cx, sub1)]);
-      }
-      ty::ty_param(_, _) { T_typaram(cx.tn) }
-      ty::ty_send_type | ty::ty_type { T_ptr(cx.tydesc_type) }
-      ty::ty_tup(elts) {
-        let tys = [];
-        for elt in elts {
-            tys += [type_of(cx, elt)];
+    if !reachable {
+        Unreachable(out);
+    } else {
+        alt out_dest {
+          by_val(cell) { *cell = option::get(phi); }
+          _ {}
         }
-        T_struct(tys)
-      }
-      ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
-      ty::ty_constr(subt,_) { type_of(cx, subt) }
-
-      _ { fail "type_of not implemented for this kind of type"; }
-    };
-    cx.lltypes.insert(t, llty);
-    ret llty;
-}
-
-fn type_of_enum(cx: crate_ctxt, did: ast::def_id, t: ty::t)
-    -> TypeRef {
-    let degen = (*ty::enum_variants(cx.tcx, did)).len() == 1u;
-    if check type_has_static_size(cx, t) {
-        let size = static_size_of_enum(cx, t);
-        if !degen { T_enum(cx, size) }
-        else if size == 0u { T_struct([T_enum_variant(cx)]) }
-        else { T_array(T_i8(), size) }
-    }
-    else {
-        if degen { T_struct([T_enum_variant(cx)]) }
-        else { T_opaque_enum(cx) }
     }
+    ret out;
 }
 
-fn type_of_ty_param_bounds_and_ty
-    (ccx: crate_ctxt, tpt: ty::ty_param_bounds_and_ty) -> TypeRef {
-    let t = tpt.ty;
-    alt ty::get(t).struct {
-      ty::ty_fn(_) {
-        ret type_of_fn_from_ty(ccx, t, *tpt.bounds);
-      }
-      _ {
-        // fall through
-      }
+// Used to put an immediate value in a dest.
+fn store_in_dest(bcx: block, val: ValueRef, dest: dest) -> block {
+    alt dest {
+      ignore {}
+      by_val(cell) { *cell = val; }
+      save_in(addr) { Store(bcx, val, addr); }
     }
-    type_of(ccx, t)
+    ret bcx;
 }
 
-fn type_of_or_i8(ccx: crate_ctxt, typ: ty::t) -> TypeRef {
-    if check type_has_static_size(ccx, typ) {
-        type_of(ccx, typ)
-    } else { T_i8() }
+fn get_dest_addr(dest: dest) -> ValueRef {
+    alt dest {
+       save_in(a) { a }
+       _ { fail "get_dest_addr: not a save_in"; }
+    }
 }
 
-
 // Name sanitation. LLVM will happily accept identifiers with weird names, but
 // gas doesn't!
 fn sanitize(s: str) -> str {
@@ -1886,8 +1809,6 @@ fn trans_lazy_binop(bcx: block, op: lazy_binop_ty, a: @ast::expr,
     ret store_in_dest(join, phi, dest);
 }
 
-
-
 fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr,
                 rhs: @ast::expr, dest: dest, ex: @ast::expr) -> block {
     // User-defined operators
@@ -1921,71 +1842,6 @@ fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr,
     }
 }
 
-enum dest {
-    by_val(@mutable ValueRef),
-    save_in(ValueRef),
-    ignore,
-}
-
-fn empty_dest_cell() -> @mutable ValueRef {
-    ret @mutable llvm::LLVMGetUndef(T_nil());
-}
-
-fn dup_for_join(dest: dest) -> dest {
-    alt dest {
-      by_val(_) { by_val(empty_dest_cell()) }
-      _ { dest }
-    }
-}
-
-fn join_returns(parent_cx: block, in_cxs: [block],
-                in_ds: [dest], out_dest: dest) -> block {
-    let out = sub_block(parent_cx, "join");
-    let reachable = false, i = 0u, phi = none;
-    for cx in in_cxs {
-        if !cx.unreachable {
-            Br(cx, out.llbb);
-            reachable = true;
-            alt in_ds[i] {
-              by_val(cell) {
-                if option::is_none(phi) {
-                    phi = some(EmptyPhi(out, val_ty(*cell)));
-                }
-                AddIncomingToPhi(option::get(phi), *cell, cx.llbb);
-              }
-              _ {}
-            }
-        }
-        i += 1u;
-    }
-    if !reachable {
-        Unreachable(out);
-    } else {
-        alt out_dest {
-          by_val(cell) { *cell = option::get(phi); }
-          _ {}
-        }
-    }
-    ret out;
-}
-
-// Used to put an immediate value in a dest.
-fn store_in_dest(bcx: block, val: ValueRef, dest: dest) -> block {
-    alt dest {
-      ignore {}
-      by_val(cell) { *cell = val; }
-      save_in(addr) { Store(bcx, val, addr); }
-    }
-    ret bcx;
-}
-
-fn get_dest_addr(dest: dest) -> ValueRef {
-    alt dest {
-       save_in(a) { a }
-       _ { fail "get_dest_addr: not a save_in"; }
-    }
-}
-
 fn trans_if(cx: block, cond: @ast::expr, thn: ast::blk,
             els: option<@ast::expr>, dest: dest)
     -> block {
diff --git a/src/comp/middle/trans/closure.rs b/src/comp/middle/trans/closure.rs
index 4e915bc9b54..cde07aeedc4 100644
--- a/src/comp/middle/trans/closure.rs
+++ b/src/comp/middle/trans/closure.rs
@@ -6,6 +6,8 @@ import lib::llvm::{ValueRef, TypeRef};
 import common::*;
 import build::*;
 import base::*;
+import type_of::*;
+import type_of::type_of; // Issue #1873
 import middle::freevars::{get_freevars, freevar_info};
 import back::abi;
 import syntax::codemap::span;
diff --git a/src/comp/middle/trans/common.rs b/src/comp/middle/trans/common.rs
index c6b5f4f9c17..a5d83906749 100644
--- a/src/comp/middle/trans/common.rs
+++ b/src/comp/middle/trans/common.rs
@@ -20,9 +20,6 @@ import lib::llvm::{True, False, Bool};
 import metadata::csearch;
 import ast_map::path;
 
-// FIXME: These should probably be pulled in here too.
-import base::{type_of_fn, drop_ty};
-
 type namegen = fn@(str) -> str;
 fn new_namegen() -> namegen {
     let i = @mutable 0;
@@ -231,7 +228,7 @@ fn scope_clean_changed(info: scope_info) {
 fn add_clean(cx: block, val: ValueRef, ty: ty::t) {
     if !ty::type_needs_drop(cx.tcx(), ty) { ret; }
     in_scope_cx(cx) {|info|
-        info.cleanups += [clean(bind drop_ty(_, val, ty))];
+        info.cleanups += [clean(bind base::drop_ty(_, val, ty))];
         scope_clean_changed(info);
     }
 }
@@ -242,7 +239,7 @@ fn add_clean_temp(cx: block, val: ValueRef, ty: ty::t) {
         if ty::type_is_immediate(ty) {
             ret base::drop_ty_immediate(bcx, val, ty);
         } else {
-            ret drop_ty(bcx, val, ty);
+            ret base::drop_ty(bcx, val, ty);
         }
     }
     in_scope_cx(cx) {|info|
@@ -253,7 +250,7 @@ fn add_clean_temp(cx: block, val: ValueRef, ty: ty::t) {
 fn add_clean_temp_mem(cx: block, val: ValueRef, ty: ty::t) {
     if !ty::type_needs_drop(cx.tcx(), ty) { ret; }
     in_scope_cx(cx) {|info|
-        info.cleanups += [clean_temp(val, bind drop_ty(_, val, ty))];
+        info.cleanups += [clean_temp(val, bind base::drop_ty(_, val, ty))];
         scope_clean_changed(info);
     }
 }
@@ -301,8 +298,8 @@ fn get_res_dtor(ccx: crate_ctxt, did: ast::def_id, inner_t: ty::t)
     let param_bounds = ty::lookup_item_type(ccx.tcx, did).bounds;
     let nil_res = ty::mk_nil(ccx.tcx);
     let fn_mode = ast::expl(ast::by_ref);
-    let f_t = type_of_fn(ccx, [{mode: fn_mode, ty: inner_t}],
-                         nil_res, *param_bounds);
+    let f_t = type_of::type_of_fn(ccx, [{mode: fn_mode, ty: inner_t}],
+                                  nil_res, *param_bounds);
     ret base::get_extern_const(ccx.externs, ccx.llmod,
                                 csearch::get_symbol(ccx.sess.cstore,
                                                     did), f_t);
diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs
index 9cb686c5def..45c9499f197 100644
--- a/src/comp/middle/trans/impl.rs
+++ b/src/comp/middle/trans/impl.rs
@@ -1,6 +1,7 @@
 import ctypes::c_uint;
 import base::*;
 import common::*;
+import type_of::*;
 import build::*;
 import driver::session::session;
 import syntax::{ast, ast_util};
diff --git a/src/comp/middle/trans/native.rs b/src/comp/middle/trans/native.rs
index e2ab63302b7..22791047ef9 100644
--- a/src/comp/middle/trans/native.rs
+++ b/src/comp/middle/trans/native.rs
@@ -8,6 +8,7 @@ import back::link;
 import common::*;
 import build::*;
 import base::*;
+import type_of::*;
 
 export link_name, trans_native_mod, register_crust_fn, trans_crust_fn;
 
@@ -31,7 +32,7 @@ fn c_arg_and_ret_lltys(ccx: crate_ctxt,
     alt ty::get(ty::node_id_to_type(ccx.tcx, id)).struct {
       ty::ty_fn({inputs: arg_tys, output: ret_ty, _}) {
         let llargtys = type_of_explicit_args(ccx, arg_tys);
-        let llretty = type_of(ccx, ret_ty);
+        let llretty = type_of::type_of(ccx, ret_ty);
         (llargtys, llretty, ret_ty)
       }
       _ { ccx.sess.bug("c_arg_and_ret_lltys called on non-function type"); }
diff --git a/src/comp/middle/trans/shape.rs b/src/comp/middle/trans/shape.rs
index 8bdb6d63a4f..2805778e927 100644
--- a/src/comp/middle/trans/shape.rs
+++ b/src/comp/middle/trans/shape.rs
@@ -118,7 +118,7 @@ fn largest_variants(ccx: crate_ctxt, tag_id: ast::def_id) -> [uint] {
                 // when in fact it has minimum size sizeof(int).
                 bounded = false;
             } else {
-                let llty = base::type_of(ccx, elem_t);
+                let llty = type_of::type_of(ccx, elem_t);
                 min_size += llsize_of_real(ccx, llty);
                 min_align += llalign_of_real(ccx, llty);
             }
@@ -188,7 +188,7 @@ fn compute_static_enum_size(ccx: crate_ctxt, largest_variants: [uint],
         // We increment a "virtual data pointer" to compute the size.
         let lltys = [];
         for typ: ty::t in variants[vid].args {
-            lltys += [base::type_of(ccx, typ)];
+            lltys += [type_of::type_of(ccx, typ)];
         }
 
         let llty = trans::common::T_struct(lltys);
@@ -590,7 +590,7 @@ type tag_metrics = {
 fn size_of(bcx: block, t: ty::t) -> result {
     let ccx = bcx.ccx();
     if check type_has_static_size(ccx, t) {
-        rslt(bcx, llsize_of(ccx, base::type_of(ccx, t)))
+        rslt(bcx, llsize_of(ccx, type_of::type_of(ccx, t)))
     } else {
         let { bcx, sz, align: _ } = dynamic_metrics(bcx, t);
         rslt(bcx, sz)
@@ -600,7 +600,7 @@ fn size_of(bcx: block, t: ty::t) -> result {
 fn align_of(bcx: block, t: ty::t) -> result {
     let ccx = bcx.ccx();
     if check type_has_static_size(ccx, t) {
-        rslt(bcx, llalign_of(ccx, base::type_of(ccx, t)))
+        rslt(bcx, llalign_of(ccx, type_of::type_of(ccx, t)))
     } else {
         let { bcx, sz: _, align } = dynamic_metrics(bcx, t);
         rslt(bcx, align)
@@ -610,7 +610,7 @@ fn align_of(bcx: block, t: ty::t) -> result {
 fn metrics(bcx: block, t: ty::t) -> metrics {
     let ccx = bcx.ccx();
     if check type_has_static_size(ccx, t) {
-        let llty = base::type_of(ccx, t);
+        let llty = type_of::type_of(ccx, t);
         { bcx: bcx, sz: llsize_of(ccx, llty), align: llalign_of(ccx, llty) }
     } else {
         dynamic_metrics(bcx, t)
@@ -657,7 +657,7 @@ fn static_size_of_enum(cx: crate_ctxt, t: ty::t) -> uint {
             tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
             // Here we possibly do a recursive call.
             let this_size =
-                llsize_of_real(cx, base::type_of(cx, tup_ty));
+                llsize_of_real(cx, type_of::type_of(cx, tup_ty));
             if max_size < this_size { max_size = this_size; }
         }
         cx.enum_sizes.insert(t, max_size);
diff --git a/src/comp/middle/trans/tvec.rs b/src/comp/middle/trans/tvec.rs
index a48b5403d1e..ab9412263d2 100644
--- a/src/comp/middle/trans/tvec.rs
+++ b/src/comp/middle/trans/tvec.rs
@@ -2,7 +2,7 @@ import syntax::ast;
 import driver::session::session;
 import lib::llvm::{ValueRef, TypeRef};
 import back::abi;
-import base::{call_memmove, trans_shared_malloc, type_of_or_i8,
+import base::{call_memmove, trans_shared_malloc,
                INIT, copy_val, load_if_immediate, get_tydesc,
                sub_block, do_spill_noroot,
                dest};
@@ -46,7 +46,7 @@ type alloc_result =
 fn alloc(bcx: block, vec_ty: ty::t, elts: uint) -> alloc_result {
     let ccx = bcx.ccx();
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
-    let llunitty = type_of_or_i8(ccx, unit_ty);
+    let llunitty = type_of::type_of_or_i8(ccx, unit_ty);
     let llvecty = T_vec(ccx, llunitty);
     let {bcx: bcx, val: unit_sz} = size_of(bcx, unit_ty);
 
@@ -156,7 +156,7 @@ fn trans_append(cx: block, vec_ty: ty::t, lhsptr: ValueRef,
     };
 
     let {bcx: bcx, val: unit_sz} = size_of(cx, unit_ty);
-    let llunitty = type_of_or_i8(ccx, unit_ty);
+    let llunitty = type_of::type_of_or_i8(ccx, unit_ty);
 
     let lhs = Load(bcx, lhsptr);
     let self_append = ICmp(bcx, lib::llvm::IntEQ, lhs, rhs);
@@ -226,7 +226,7 @@ fn trans_add(bcx: block, vec_ty: ty::t, lhs: ValueRef,
       _ { false }
     };
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
-    let llunitty = type_of_or_i8(ccx, unit_ty);
+    let llunitty = type_of::type_of_or_i8(ccx, unit_ty);
     let {bcx: bcx, val: llunitsz} = size_of(bcx, unit_ty);
 
     let lhs_fill = get_fill(bcx, lhs);
@@ -268,7 +268,7 @@ fn iter_vec_raw(bcx: block, vptr: ValueRef, vec_ty: ty::t,
                 fill: ValueRef, f: iter_vec_block) -> block {
     let ccx = bcx.ccx();
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
-    let llunitty = type_of_or_i8(ccx, unit_ty);
+    let llunitty = type_of::type_of_or_i8(ccx, unit_ty);
     let {bcx: bcx, val: unit_sz} = size_of(bcx, unit_ty);
     let vptr = PointerCast(bcx, vptr, T_ptr(T_vec(ccx, llunitty)));
     let data_ptr = get_dataptr(bcx, vptr, llunitty);
diff --git a/src/comp/middle/trans/type_of.rs b/src/comp/middle/trans/type_of.rs
new file mode 100644
index 00000000000..f7095be55ff
--- /dev/null
+++ b/src/comp/middle/trans/type_of.rs
@@ -0,0 +1,145 @@
+import common::*;
+import lib::llvm::{TypeRef};
+import syntax::ast;
+import lib::llvm::llvm;
+
+fn type_of_explicit_args(cx: crate_ctxt, inputs: [ty::arg]) -> [TypeRef] {
+    vec::map(inputs) {|arg|
+        let arg_ty = arg.ty;
+        let llty = type_of(cx, arg_ty);
+        alt ty::resolved_mode(cx.tcx, arg.mode) {
+          ast::by_val { llty }
+          _ { T_ptr(llty) }
+        }
+    }
+}
+
+fn type_of_fn(cx: crate_ctxt, inputs: [ty::arg],
+              output: ty::t, params: [ty::param_bounds]) -> TypeRef {
+    let atys: [TypeRef] = [];
+
+    // Arg 0: Output pointer.
+    atys += [T_ptr(type_of(cx, output))];
+
+    // Arg 1: Environment
+    atys += [T_opaque_box_ptr(cx)];
+
+    // Args >2: ty params, if not acquired via capture...
+    for bounds in params {
+        atys += [T_ptr(cx.tydesc_type)];
+        for bound in *bounds {
+            alt bound {
+              ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
+              _ {}
+            }
+        }
+    }
+    // ... then explicit args.
+    atys += type_of_explicit_args(cx, inputs);
+    ret T_fn(atys, llvm::LLVMVoidType());
+}
+
+// Given a function type and a count of ty params, construct an llvm type
+fn type_of_fn_from_ty(cx: crate_ctxt, fty: ty::t,
+                      param_bounds: [ty::param_bounds]) -> TypeRef {
+    type_of_fn(cx, ty::ty_fn_args(fty), ty::ty_fn_ret(fty), param_bounds)
+}
+
+fn type_of(cx: crate_ctxt, t: ty::t) -> TypeRef {
+    assert !ty::type_has_vars(t);
+    // Check the cache.
+
+    if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); }
+    let llty = alt ty::get(t).struct {
+      ty::ty_nil | ty::ty_bot { T_nil() }
+      ty::ty_bool { T_bool() }
+      ty::ty_int(t) { T_int_ty(cx, t) }
+      ty::ty_uint(t) { T_uint_ty(cx, t) }
+      ty::ty_float(t) { T_float_ty(cx, t) }
+      ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
+      ty::ty_enum(did, _) { type_of_enum(cx, did, t) }
+      ty::ty_box(mt) {
+        let mt_ty = mt.ty;
+        T_ptr(T_box(cx, type_of(cx, mt_ty))) }
+      ty::ty_opaque_box { T_ptr(T_box(cx, T_i8())) }
+      ty::ty_uniq(mt) {
+        let mt_ty = mt.ty;
+        T_ptr(type_of(cx, mt_ty)) }
+      ty::ty_vec(mt) {
+        let mt_ty = mt.ty;
+        if ty::type_has_dynamic_size(cx.tcx, mt_ty) {
+            T_ptr(cx.opaque_vec_type)
+        } else {
+            T_ptr(T_vec(cx, type_of(cx, mt_ty))) }
+      }
+      ty::ty_ptr(mt) {
+        let mt_ty = mt.ty;
+        T_ptr(type_of(cx, mt_ty)) }
+      ty::ty_rec(fields) {
+        let tys: [TypeRef] = [];
+        for f: ty::field in fields {
+            let mt_ty = f.mt.ty;
+            tys += [type_of(cx, mt_ty)];
+        }
+        T_struct(tys)
+      }
+      ty::ty_fn(_) {
+        T_fn_pair(cx, type_of_fn_from_ty(cx, t, []))
+      }
+      ty::ty_iface(_, _) { T_opaque_iface(cx) }
+      ty::ty_res(_, sub, tps) {
+        let sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
+        ret T_struct([T_i8(), type_of(cx, sub1)]);
+      }
+      ty::ty_param(_, _) { T_typaram(cx.tn) }
+      ty::ty_send_type | ty::ty_type { T_ptr(cx.tydesc_type) }
+      ty::ty_tup(elts) {
+        let tys = [];
+        for elt in elts {
+            tys += [type_of(cx, elt)];
+        }
+        T_struct(tys)
+      }
+      ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
+      ty::ty_constr(subt,_) { type_of(cx, subt) }
+
+      _ { fail "type_of not implemented for this kind of type"; }
+    };
+    cx.lltypes.insert(t, llty);
+    ret llty;
+}
+
+fn type_of_enum(cx: crate_ctxt, did: ast::def_id, t: ty::t)
+    -> TypeRef {
+    let degen = (*ty::enum_variants(cx.tcx, did)).len() == 1u;
+    if check type_has_static_size(cx, t) {
+        let size = shape::static_size_of_enum(cx, t);
+        if !degen { T_enum(cx, size) }
+        else if size == 0u { T_struct([T_enum_variant(cx)]) }
+        else { T_array(T_i8(), size) }
+    }
+    else {
+        if degen { T_struct([T_enum_variant(cx)]) }
+        else { T_opaque_enum(cx) }
+    }
+}
+
+fn type_of_ty_param_bounds_and_ty
+    (ccx: crate_ctxt, tpt: ty::ty_param_bounds_and_ty) -> TypeRef {
+    let t = tpt.ty;
+    alt ty::get(t).struct {
+      ty::ty_fn(_) {
+        ret type_of_fn_from_ty(ccx, t, *tpt.bounds);
+      }
+      _ {
+        // fall through
+      }
+    }
+    type_of(ccx, t)
+}
+
+fn type_of_or_i8(ccx: crate_ctxt, typ: ty::t) -> TypeRef {
+    if check type_has_static_size(ccx, typ) {
+        type_of(ccx, typ)
+    } else { T_i8() }
+}
diff --git a/src/comp/middle/trans/uniq.rs b/src/comp/middle/trans/uniq.rs
index b2ff6577762..d6d32510858 100644
--- a/src/comp/middle/trans/uniq.rs
+++ b/src/comp/middle/trans/uniq.rs
@@ -24,7 +24,7 @@ fn alloc_uniq(cx: block, uniq_ty: ty::t) -> result {
     bcx = r.bcx;
     let llsz = r.val;
 
-    let llptrty = T_ptr(type_of(bcx.ccx(), contents_ty));
+    let llptrty = T_ptr(type_of::type_of(bcx.ccx(), contents_ty));
 
     r = trans_shared_malloc(bcx, llptrty, llsz);
     bcx = r.bcx;
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index 9c16479c13b..0b8ce111f1f 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -16,6 +16,7 @@ use std (name = "std",
 mod middle {
     mod trans {
         mod common;
+        mod type_of;
         mod build;
         mod base;
         mod alt;