about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-06-19 18:35:56 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-07-10 15:16:48 -0700
commit0a4a602a235c868a7f740ed09a8fc4c83c0c6dad (patch)
tree658f07f41c582049ade16430ada19b735837e58e /src/rustc
parentef9a64709efafbcf692a80413ba71fd37733ceb5 (diff)
Modify reflect interface to pass tydescs back to client, stop on false return.
These changes are required to prune type-recursion and admit early
returns in the visitor code. Changes to visitors in subsequent csets.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/front/intrinsic.rs83
-rw-r--r--src/rustc/middle/trans/base.rs4
-rw-r--r--src/rustc/middle/trans/foreign.rs19
-rw-r--r--src/rustc/middle/trans/reflect.rs155
-rw-r--r--src/rustc/middle/trans/type_use.rs3
-rw-r--r--src/rustc/middle/ty.rs4
-rw-r--r--src/rustc/middle/typeck/check.rs18
-rw-r--r--src/rustc/middle/typeck/collect.rs19
8 files changed, 172 insertions, 133 deletions
diff --git a/src/rustc/front/intrinsic.rs b/src/rustc/front/intrinsic.rs
index 214d0aa0bee..21d8777e22d 100644
--- a/src/rustc/front/intrinsic.rs
+++ b/src/rustc/front/intrinsic.rs
@@ -3,8 +3,21 @@
 
 mod intrinsic {
 
-    import rusti::visit_ty;
-    export ty_visitor, visit_ty;
+    import rusti::visit_tydesc;
+    export ty_visitor, get_tydesc, visit_tydesc, tydesc;
+
+    // FIXME (#2712): remove this when the interface has settled and the
+    // version in sys is no longer present.
+    fn get_tydesc<T>() -> *tydesc {
+        rusti::get_tydesc::<T>() as *tydesc
+    }
+
+    enum tydesc = {
+        first_param: **u8,
+        size: uint,
+        align: uint
+        // Remaining fields not listed
+    };
 
     iface ty_visitor {
         fn visit_bot() -> bool;
@@ -35,50 +48,37 @@ mod intrinsic {
         fn visit_estr_slice() -> bool;
         fn visit_estr_fixed(sz: uint) -> bool;
 
-        fn visit_enter_box(mtbl: uint) -> bool;
-        fn visit_leave_box(mtbl: uint) -> bool;
-        fn visit_enter_uniq(mtbl: uint) -> bool;
-        fn visit_leave_uniq(mtbl: uint) -> bool;
-        fn visit_enter_ptr(mtbl: uint) -> bool;
-        fn visit_leave_ptr(mtbl: uint) -> bool;
-        fn visit_enter_rptr(mtbl: uint) -> bool;
-        fn visit_leave_rptr(mtbl: uint) -> bool;
-
-        fn visit_enter_vec(mtbl: uint) -> bool;
-        fn visit_leave_vec(mtbl: uint) -> bool;
-        fn visit_enter_evec_box(mtbl: uint) -> bool;
-        fn visit_leave_evec_box(mtbl: uint) -> bool;
-        fn visit_enter_evec_uniq(mtbl: uint) -> bool;
-        fn visit_leave_evec_uniq(mtbl: uint) -> bool;
-        fn visit_enter_evec_slice(mtbl: uint) -> bool;
-        fn visit_leave_evec_slice(mtbl: uint) -> bool;
-        fn visit_enter_evec_fixed(mtbl: uint, n: uint,
-                                  sz: uint, align: uint) -> bool;
-        fn visit_leave_evec_fixed(mtbl: uint, n: uint,
-                                  sz: uint, align: uint) -> bool;
+        fn visit_box(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_uniq(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_ptr(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_rptr(mtbl: uint, inner: *tydesc) -> bool;
+
+        fn visit_vec(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_unboxed_vec(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_evec_box(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_evec_uniq(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_evec_slice(mtbl: uint, inner: *tydesc) -> bool;
+        fn visit_evec_fixed(n: uint, mtbl: uint,
+                            sz: uint, align: uint,
+                            inner: *tydesc) -> bool;
 
         fn visit_enter_rec(n_fields: uint,
                            sz: uint, align: uint) -> bool;
-        fn visit_enter_rec_field(mtbl: uint, i: uint,
-                                 name: str/&) -> bool;
-        fn visit_leave_rec_field(mtbl: uint, i: uint,
-                                 name: str/&) -> bool;
+        fn visit_rec_field(i: uint, name: str/&,
+                           mtbl: uint, inner: *tydesc) -> bool;
         fn visit_leave_rec(n_fields: uint,
                            sz: uint, align: uint) -> bool;
 
         fn visit_enter_class(n_fields: uint,
                              sz: uint, align: uint) -> bool;
-        fn visit_enter_class_field(mtbl: uint, i: uint,
-                                   name: str/&) -> bool;
-        fn visit_leave_class_field(mtbl: uint, i: uint,
-                                   name: str/&) -> bool;
+        fn visit_class_field(i: uint, name: str/&,
+                             mtbl: uint, inner: *tydesc) -> bool;
         fn visit_leave_class(n_fields: uint,
                              sz: uint, align: uint) -> bool;
 
         fn visit_enter_tup(n_fields: uint,
                            sz: uint, align: uint) -> bool;
-        fn visit_enter_tup_field(i: uint) -> bool;
-        fn visit_leave_tup_field(i: uint) -> bool;
+        fn visit_tup_field(i: uint, inner: *tydesc) -> bool;
         fn visit_leave_tup(n_fields: uint,
                            sz: uint, align: uint) -> bool;
 
@@ -88,8 +88,7 @@ mod intrinsic {
                                     disr_val: int,
                                     n_fields: uint,
                                     name: str/&) -> bool;
-        fn visit_enter_enum_variant_field(i: uint) -> bool;
-        fn visit_leave_enum_variant_field(i: uint) -> bool;
+        fn visit_enum_variant_field(i: uint, inner: *tydesc) -> bool;
         fn visit_leave_enum_variant(variant: uint,
                                     disr_val: int,
                                     n_fields: uint,
@@ -99,29 +98,25 @@ mod intrinsic {
 
         fn visit_enter_fn(purity: uint, proto: uint,
                           n_inputs: uint, retstyle: uint) -> bool;
-        fn visit_enter_fn_input(i: uint, mode: uint) -> bool;
-        fn visit_leave_fn_input(i: uint, mode: uint) -> bool;
-        fn visit_enter_fn_output(retstyle: uint) -> bool;
-        fn visit_leave_fn_output(retstyle: uint) -> bool;
+        fn visit_fn_input(i: uint, mode: uint, inner: *tydesc) -> bool;
+        fn visit_fn_output(retstyle: uint, inner: *tydesc) -> bool;
         fn visit_leave_fn(purity: uint, proto: uint,
                           n_inputs: uint, retstyle: uint) -> bool;
 
         fn visit_trait() -> bool;
-        fn visit_enter_res() -> bool;
-        fn visit_leave_res() -> bool;
         fn visit_var() -> bool;
         fn visit_var_integral() -> bool;
         fn visit_param(i: uint) -> bool;
         fn visit_self() -> bool;
         fn visit_type() -> bool;
         fn visit_opaque_box() -> bool;
-        fn visit_enter_constr() -> bool;
-        fn visit_leave_constr() -> bool;
+        fn visit_constr(inner: *tydesc) -> bool;
         fn visit_closure_ptr(ck: uint) -> bool;
     }
 
     #[abi = "rust-intrinsic"]
     extern mod rusti {
-        fn visit_ty<T>(&&tv: ty_visitor);
+        fn get_tydesc<T>() -> *();
+        fn visit_tydesc(td: *tydesc, &&tv: ty_visitor);
     }
 }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 08c05527645..d17c4ba2ca2 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -671,8 +671,8 @@ fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
 fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
     let _icx = bcx.insn_ctxt("make_visit_glue");
     let mut bcx = bcx;
-    assert bcx.ccx().tcx.intrinsic_traits.contains_key(@"ty_visitor");
-    let (iid, ty) = bcx.ccx().tcx.intrinsic_traits.get(@"ty_visitor");
+    assert bcx.ccx().tcx.intrinsic_defs.contains_key(@"ty_visitor");
+    let (iid, ty) = bcx.ccx().tcx.intrinsic_defs.get(@"ty_visitor");
     let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), ty)));
     bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, iid);
     build_return(bcx);
diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs
index 3da69f9b778..d46779d4fe7 100644
--- a/src/rustc/middle/trans/foreign.rs
+++ b/src/rustc/middle/trans/foreign.rs
@@ -910,8 +910,13 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
       }
       "get_tydesc" {
         let tp_ty = substs.tys[0];
-        let td = get_tydesc_simple(ccx, tp_ty);
-        Store(bcx, PointerCast(bcx, td, T_ptr(T_nil())), fcx.llretptr);
+        let mut static_ti = none;
+        let lltydesc = get_tydesc(ccx, tp_ty, static_ti);
+        lazily_emit_all_tydesc_glue(ccx, copy static_ti);
+        // FIXME (#2712): change this to T_ptr(ccx.tydesc_ty) when the
+        // core::sys copy of the get_tydesc interface dies off.
+        let td = PointerCast(bcx, lltydesc, T_ptr(T_nil()));
+        Store(bcx, td, fcx.llretptr);
       }
       "init" {
         let tp_ty = substs.tys[0];
@@ -951,10 +956,12 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
         Store(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)),
               fcx.llretptr);
       }
-      "visit_ty" {
-        let tp_ty = substs.tys[0];
-        let visitor = get_param(decl, first_real_arg);
-        call_tydesc_glue(bcx, visitor, tp_ty, abi::tydesc_field_visit_glue);
+      "visit_tydesc" {
+        let td = get_param(decl, first_real_arg);
+        let visitor = get_param(decl, first_real_arg + 1u);
+        let td = PointerCast(bcx, td, T_ptr(ccx.tydesc_type));
+        call_tydesc_glue_full(bcx, visitor, td,
+                              abi::tydesc_field_visit_glue, none);
       }
       "frame_address" {
         let frameaddress = ccx.intrinsics.get("llvm.frameaddress");
diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs
index 3d5304f5f5c..e77b60db39c 100644
--- a/src/rustc/middle/trans/reflect.rs
+++ b/src/rustc/middle/trans/reflect.rs
@@ -13,6 +13,8 @@ import util::ppaux::ty_to_str;
 enum reflector = {
     visitor_val: ValueRef,
     visitor_methods: @~[ty::method],
+    final_bcx: block,
+    tydesc_ty: TypeRef,
     mut bcx: block
 };
 
@@ -39,6 +41,19 @@ impl methods for reflector {
              self.c_uint(a)];
     }
 
+    fn c_tydesc(t: ty::t) -> ValueRef {
+        let bcx = self.bcx;
+        let mut static_ti = none;
+        let lltydesc = get_tydesc(bcx.ccx(), t, static_ti);
+        lazily_emit_all_tydesc_glue(bcx.ccx(), copy static_ti);
+        PointerCast(bcx, lltydesc, T_ptr(self.tydesc_ty))
+    }
+
+    fn c_mt(mt: ty::mt) -> ~[ValueRef] {
+        ~[self.c_uint(mt.mutbl as uint),
+          self.c_tydesc(mt.ty)]
+    }
+
     fn visit(ty_name: str, args: ~[ValueRef]) {
         let tcx = self.bcx.tcx();
         let mth_idx = option::get(ty::method_idx(@("visit_" + ty_name),
@@ -58,29 +73,22 @@ impl methods for reflector {
         for args.eachi |i, a| {
             #debug("arg %u: %s", i, val_str(bcx.ccx().tn, a));
         }
-        self.bcx =
+        let d = empty_dest_cell();
+        let bcx =
             trans_call_inner(self.bcx, none, mth_ty, ty::mk_bool(tcx),
-                             get_lval, arg_vals(args), ignore);
-    }
-
-    fn visit_tydesc(t: ty::t) {
-        self.bcx =
-            call_tydesc_glue(self.bcx, self.visitor_val, t,
-                             abi::tydesc_field_visit_glue);
+                             get_lval, arg_vals(args), by_val(d));
+        let next_bcx = sub_block(bcx, "next");
+        CondBr(bcx, *d, next_bcx.llbb, self.final_bcx.llbb);
+        self.bcx = next_bcx
     }
 
-    fn bracketed_t(bracket_name: str, t: ty::t, extra: ~[ValueRef]) {
+    fn bracketed(bracket_name: str, extra: ~[ValueRef],
+                 inner: fn()) {
         self.visit("enter_" + bracket_name, extra);
-        self.visit_tydesc(t);
+        inner();
         self.visit("leave_" + bracket_name, extra);
     }
 
-    fn bracketed_mt(bracket_name: str, mt: ty::mt, extra: ~[ValueRef]) {
-        self.bracketed_t(bracket_name, mt.ty,
-                         vec::append(~[self.c_uint(mt.mutbl as uint)],
-                                     extra));
-    }
-
     fn vstore_name_and_extra(t: ty::t,
                              vstore: ty::vstore,
                              f: fn(str,~[ValueRef])) {
@@ -127,7 +135,8 @@ impl methods for reflector {
           ty::ty_float(ast::ty_f64) { self.leaf("f64") }
           ty::ty_str { self.leaf("str") }
 
-          ty::ty_vec(mt) { self.bracketed_mt("vec", mt, ~[]) }
+          ty::ty_vec(mt) { self.visit("vec", self.c_mt(mt)) }
+          ty::ty_unboxed_vec(mt) { self.visit("vec", self.c_mt(mt)) }
           ty::ty_estr(vst) {
             do self.vstore_name_and_extra(t, vst) |name, extra| {
                 self.visit("estr_" + name, extra)
@@ -135,34 +144,38 @@ impl methods for reflector {
           }
           ty::ty_evec(mt, vst) {
             do self.vstore_name_and_extra(t, vst) |name, extra| {
-                self.bracketed_mt("evec_" + name, mt, extra)
+                self.visit("evec_" + name, extra +
+                           self.c_mt(mt))
             }
           }
-          ty::ty_box(mt) { self.bracketed_mt("box", mt, ~[]) }
-          ty::ty_uniq(mt) { self.bracketed_mt("uniq", mt, ~[]) }
-          ty::ty_ptr(mt) { self.bracketed_mt("ptr", mt, ~[]) }
-          ty::ty_rptr(_, mt) { self.bracketed_mt("rptr", mt, ~[]) }
+          ty::ty_box(mt) { self.visit("box", self.c_mt(mt)) }
+          ty::ty_uniq(mt) { self.visit("uniq", self.c_mt(mt)) }
+          ty::ty_ptr(mt) { self.visit("ptr", self.c_mt(mt)) }
+          ty::ty_rptr(_, mt) { self.visit("rptr", self.c_mt(mt)) }
 
           ty::ty_rec(fields) {
-            let extra = (vec::append(~[self.c_uint(vec::len(fields))],
-                                     self.c_size_and_align(t)));
-            self.visit("enter_rec", extra);
-            for fields.eachi |i, field| {
-                self.bracketed_mt("rec_field", field.mt,
-                                  ~[self.c_uint(i),
-                                   self.c_slice(*field.ident)]);
+            do self.bracketed("rec",
+                              ~[self.c_uint(vec::len(fields))]
+                              + self.c_size_and_align(t)) {
+                for fields.eachi |i, field| {
+                    self.visit("rec_field",
+                               ~[self.c_uint(i),
+                                 self.c_slice(*field.ident)]
+                               + self.c_mt(field.mt));
+                }
             }
-            self.visit("leave_rec", extra);
           }
 
           ty::ty_tup(tys) {
-            let extra = (vec::append(~[self.c_uint(vec::len(tys))],
-                                     self.c_size_and_align(t)));
-            self.visit("enter_tup", extra);
-            for tys.eachi |i, t| {
-                self.bracketed_t("tup_field", t, ~[self.c_uint(i)]);
+            do self.bracketed("tup",
+                              ~[self.c_uint(vec::len(tys))]
+                              + self.c_size_and_align(t)) {
+                for tys.eachi |i, t| {
+                    self.visit("tup_field",
+                               ~[self.c_uint(i),
+                                 self.c_tydesc(t)]);
+                }
             }
-            self.visit("leave_tup", extra);
           }
 
           // FIXME (#2594): fetch constants out of intrinsic:: for the
@@ -203,12 +216,14 @@ impl methods for reflector {
                     }
                   }
                 };
-                self.bracketed_t("fn_input", arg.ty,
-                                 ~[self.c_uint(i),
-                                  self.c_uint(modeval)]);
+                self.visit("fn_input",
+                           ~[self.c_uint(i),
+                             self.c_uint(modeval),
+                             self.c_tydesc(arg.ty)]);
             }
-            self.bracketed_t("fn_output", fty.output,
-                             ~[self.c_uint(retval)]);
+            self.visit("fn_output",
+                       ~[self.c_uint(retval),
+                         self.c_tydesc(fty.output)]);
             self.visit("leave_fn", extra);
           }
 
@@ -216,16 +231,16 @@ impl methods for reflector {
             let bcx = self.bcx;
             let tcx = bcx.ccx().tcx;
             let fields = ty::class_items_as_fields(tcx, did, substs);
-            let extra = vec::append(~[self.c_uint(vec::len(fields))],
-                                    self.c_size_and_align(t));
 
-            self.visit("enter_class", extra);
-            for fields.eachi |i, field| {
-                self.bracketed_mt("class_field", field.mt,
-                                  ~[self.c_uint(i),
-                                   self.c_slice(*field.ident)]);
+            do self.bracketed("class", ~[self.c_uint(vec::len(fields))]
+                              + self.c_size_and_align(t)) {
+                for fields.eachi |i, field| {
+                    self.visit("class_field",
+                               ~[self.c_uint(i),
+                                self.c_slice(*field.ident)]
+                               + self.c_mt(field.mt));
+                }
             }
-            self.visit("leave_class", extra);
           }
 
           // FIXME (#2595): visiting all the variants in turn is probably
@@ -236,23 +251,24 @@ impl methods for reflector {
             let bcx = self.bcx;
             let tcx = bcx.ccx().tcx;
             let variants = ty::substd_enum_variants(tcx, did, substs);
-            let extra = vec::append(~[self.c_uint(vec::len(variants))],
-                                    self.c_size_and_align(t));
 
-            self.visit("enter_enum", extra);
-            for variants.eachi |i, v| {
-                let extra = ~[self.c_uint(i),
-                             self.c_int(v.disr_val),
-                             self.c_uint(vec::len(v.args)),
-                             self.c_slice(*v.name)];
-                self.visit("enter_enum_variant", extra);
-                for v.args.eachi |j, a| {
-                    self.bracketed_t("enum_variant_field", a,
-                                     ~[self.c_uint(j)]);
+            do self.bracketed("enum",
+                              ~[self.c_uint(vec::len(variants))]
+                              + self.c_size_and_align(t)) {
+                for variants.eachi |i, v| {
+                    do self.bracketed("enum_variant",
+                                      ~[self.c_uint(i),
+                                        self.c_int(v.disr_val),
+                                        self.c_uint(vec::len(v.args)),
+                                        self.c_slice(*v.name)]) {
+                        for v.args.eachi |j, a| {
+                            self.visit("enum_variant_field",
+                                       ~[self.c_uint(j),
+                                         self.c_tydesc(a)]);
+                        }
+                    }
                 }
-                self.visit("leave_enum_variant", extra);
             }
-            self.visit("leave_enum", extra);
           }
 
           // Miscallaneous extra types
@@ -263,7 +279,7 @@ impl methods for reflector {
           ty::ty_self { self.leaf("self") }
           ty::ty_type { self.leaf("type") }
           ty::ty_opaque_box { self.leaf("opaque_box") }
-          ty::ty_constr(t, _) { self.bracketed_t("constr", t, ~[]) }
+          ty::ty_constr(t, _) { self.visit("constr", ~[self.c_tydesc(t)]) }
           ty::ty_opaque_closure_ptr(ck) {
             let ckval = alt ck {
               ty::ck_block { 0u }
@@ -272,7 +288,6 @@ impl methods for reflector {
             };
             self.visit("closure_ptr", ~[self.c_uint(ckval)])
           }
-          ty::ty_unboxed_vec(mt) { self.bracketed_mt("vec", mt, ~[]) }
         }
     }
 }
@@ -282,12 +297,18 @@ fn emit_calls_to_trait_visit_ty(bcx: block, t: ty::t,
                                 visitor_val: ValueRef,
                                 visitor_iid: def_id) -> block {
 
+    let final = sub_block(bcx, "final");
+    assert bcx.ccx().tcx.intrinsic_defs.contains_key(@"tydesc");
+    let (_, tydesc_ty) = bcx.ccx().tcx.intrinsic_defs.get(@"tydesc");
+    let tydesc_ty = type_of::type_of(bcx.ccx(), tydesc_ty);
     let r = reflector({
         visitor_val: visitor_val,
         visitor_methods: ty::trait_methods(bcx.tcx(), visitor_iid),
+        final_bcx: final,
+        tydesc_ty: tydesc_ty,
         mut bcx: bcx
     });
-
     r.visit_ty(t);
-    ret r.bcx;
+    Br(r.bcx, final.llbb);
+    ret final;
 }
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index 386bf06ef14..ef2a95005da 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -76,7 +76,6 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
                                  abi, _) {
         if abi == foreign_abi_rust_intrinsic {
             let flags = alt check *i.ident {
-              "visit_ty" { use_repr | use_tydesc }
               "size_of" |  "pref_align_of" | "min_align_of" |
               "init" |  "reinterpret_cast" | "move_val" | "move_val_init" {
                 use_repr
@@ -87,7 +86,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
               "atomic_xchng_rel" | "atomic_add_rel" | "atomic_sub_rel" {
                 0u
               }
-              "forget" | "addr_of" { 0u }
+              "visit_tydesc" | "forget" | "addr_of" { 0u }
             };
             for uint::range(0u, n_tps) |n| { cx.uses[n] |= flags;}
         }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 56e0c39c566..f4febfa0512 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -247,7 +247,7 @@ type ctxt =
       node_type_substs: hashmap<node_id, ~[t]>,
 
       items: ast_map::map,
-      intrinsic_traits: hashmap<ast::ident, (ast::def_id, t)>,
+      intrinsic_defs: hashmap<ast::ident, (ast::def_id, t)>,
       freevars: freevars::freevar_map,
       tcache: type_cache,
       rcache: creader_cache,
@@ -526,7 +526,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
       node_types: @smallintmap::mk(),
       node_type_substs: map::int_hash(),
       items: amap,
-      intrinsic_traits: map::box_str_hash(),
+      intrinsic_defs: map::box_str_hash(),
       freevars: freevars,
       tcache: ast_util::new_def_hash(),
       rcache: mk_rcache(),
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index b4a8c02f3b7..bd9230613d3 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -2254,7 +2254,6 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
     let (n_tps, inputs, output) = alt *it.ident {
       "size_of" |
       "pref_align_of" | "min_align_of" { (1u, ~[], ty::mk_uint(ccx.tcx)) }
-      "get_tydesc" { (1u, ~[], ty::mk_nil_ptr(tcx)) }
       "init" { (1u, ~[], param(ccx, 0u)) }
       "forget" { (1u, ~[arg(ast::by_move, param(ccx, 0u))],
                   ty::mk_nil(tcx)) }
@@ -2277,10 +2276,19 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
          ty::mk_int(tcx))
       }
 
-      "visit_ty" {
-        assert ccx.tcx.intrinsic_traits.contains_key(@"ty_visitor");
-        let (_, visitor_trait) = ccx.tcx.intrinsic_traits.get(@"ty_visitor");
-        (1u, ~[arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx))
+      "get_tydesc" {
+        // FIXME (#2712): return *intrinsic::tydesc, not *()
+        (1u, ~[], ty::mk_nil_ptr(tcx))
+      }
+      "visit_tydesc" {
+        assert ccx.tcx.intrinsic_defs.contains_key(@"tydesc");
+        assert ccx.tcx.intrinsic_defs.contains_key(@"ty_visitor");
+        let (_, tydesc_ty) = ccx.tcx.intrinsic_defs.get(@"tydesc");
+        let (_, visitor_trait) = ccx.tcx.intrinsic_defs.get(@"ty_visitor");
+        let td_ptr = ty::mk_ptr(ccx.tcx, {ty: tydesc_ty,
+                                          mutbl: ast::m_imm});
+        (0u, ~[arg(ast::by_val, td_ptr),
+               arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx))
       }
       "frame_address" {
         let fty = ty::mk_fn(ccx.tcx, {
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index 4bae90d2214..b1d0f026957 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -33,16 +33,25 @@ fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
             alt crate_item.node {
               ast::item_mod(m) {
                 for m.items.each |intrinsic_item| {
+                    let def_id = { crate: ast::local_crate,
+                                  node: intrinsic_item.id };
+                    let substs = {self_r: none, self_ty: none, tps: ~[]};
+
                     alt intrinsic_item.node {
+
                       ast::item_trait(_, _, _) {
-                        let def_id = { crate: ast::local_crate,
-                                      node: intrinsic_item.id };
-                        let substs = {self_r: none, self_ty: none, tps: ~[]};
                         let ty = ty::mk_trait(ccx.tcx, def_id, substs);
-                        ccx.tcx.intrinsic_traits.insert
+                        ccx.tcx.intrinsic_defs.insert
+                            (intrinsic_item.ident, (def_id, ty));
+                      }
+
+                      ast::item_enum(_, _, _) {
+                        let ty = ty::mk_enum(ccx.tcx, def_id, substs);
+                        ccx.tcx.intrinsic_defs.insert
                             (intrinsic_item.ident, (def_id, ty));
                       }
-                      _ { }
+
+                     _ { }
                     }
                 }
               }