about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/rustc/middle/trans/type_of.rs54
-rw-r--r--src/rustc/middle/ty.rs13
-rw-r--r--src/test/run-pass/classes-self-referential.rs10
3 files changed, 58 insertions, 19 deletions
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index e66ba7bc6c2..0d6ef8c6d12 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -76,10 +76,13 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
     // this then, e.g. `option<{myfield: bool}>` would be a different
     // type than `option<myrec>`.
     let t_norm = ty::normalize_ty(cx.tcx, t);
-    let llty = if t != t_norm {
-        type_of(cx, t_norm)
+
+    let mut llty;
+    if t != t_norm {
+        llty = type_of(cx, t_norm);
+        cx.lltypes.insert(t, llty);
     } else {
-        alt ty::get(t).struct {
+        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) }
@@ -149,30 +152,46 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
           }
           ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
           ty::ty_constr(subt,_) { type_of(cx, subt) }
+          ty::ty_class(*) {
+            // Only create the named struct, but don't fill it in. We fill it
+            // in *after* placing it into the type cache. This prevents
+            // infinite recursion with recursive class types.
+
+            common::T_named_struct(llvm_type_name(cx, t))
+          }
+          ty::ty_self { cx.tcx.sess.unimpl("type_of: ty_self"); }
+          ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
+          ty::ty_param(*) { cx.tcx.sess.bug("type_of with ty_param"); }
+          ty::ty_var_integral(_) {
+            cx.tcx.sess.bug("type_of shouldn't see a ty_var_integral");
+          }
+        };
+
+        cx.lltypes.insert(t, llty);
+
+        // If this was a class, fill in the type now.
+        alt ty::get(t).struct {
           ty::ty_class(did, ts) {
-            // only instance vars are record fields at runtime
+            // Only instance vars are record fields at runtime.
             let fields = lookup_class_fields(cx.tcx, did);
-            let tys = vec::map(fields) {|f|
+            let mut tys = vec::map(fields) {|f|
                 let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
                 type_of(cx, t)
             };
-            if ty::ty_dtor(cx.tcx, did) == none {
-              T_struct(tys)
-            }
-            else {
+
+            if ty::ty_dtor(cx.tcx, did) != none {
               // resource type
-              T_struct([T_i8(), T_struct(tys)])
+              tys = [T_i8(), T_struct(tys)];
             }
+
+            common::set_struct_body(llty, tys);
           }
-          ty::ty_self { cx.tcx.sess.unimpl("type_of: ty_self"); }
-          ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
-          ty::ty_param(*) { cx.tcx.sess.bug("type_of with ty_param"); }
-          ty::ty_var_integral(_) {
-            cx.tcx.sess.bug("type_of shouldn't see a ty_var_integral");
+          _ {
+            // Nothing more to do.
           }
         }
     };
-    cx.lltypes.insert(t, llty);
+
     ret llty;
 }
 
@@ -214,6 +233,9 @@ fn llvm_type_name(cx: @crate_ctxt, t: ty::t) -> str {
       ty::ty_enum(did, substs) {
         ("enum", did, substs.tps)
       }
+      ty::ty_class(did, substs) {
+        ("class", did, substs.tps)
+      }
     };
     ret #fmt(
         "%s %s[#%d]",
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 0d4cc92b1ef..421bbf38e14 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -3036,9 +3036,16 @@ fn normalize_ty(cx: ctxt, t: t) -> t {
             alt r.self_r {
               some(_) {
                 // This enum has a self region. Get rid of it
-                mk_enum(cx, did, {self_r: none,
-                                  self_ty: none,
-                                  tps: r.tps})
+                mk_enum(cx, did, {self_r: none, self_ty: none, tps: r.tps})
+              }
+              none { t }
+            }
+        }
+        ty_class(did, r) {
+            alt r.self_r {
+              some(_) {
+                // Ditto.
+                mk_class(cx, did, {self_r: none, self_ty: none, tps: r.tps})
               }
               none { t }
             }
diff --git a/src/test/run-pass/classes-self-referential.rs b/src/test/run-pass/classes-self-referential.rs
new file mode 100644
index 00000000000..7add8fec1b1
--- /dev/null
+++ b/src/test/run-pass/classes-self-referential.rs
@@ -0,0 +1,10 @@
+class kitten {
+    let cat: option<cat>;
+    new(cat: option<cat>) {
+       self.cat = cat;
+    }
+}
+
+type cat = @kitten;
+
+fn main() {}