Issue #2572: (trans) Fix self-referential classes.

This commit is contained in:
Patrick Walton 2012-06-14 18:47:44 -07:00
parent 6b16325f43
commit 6969f0f2fc
3 changed files with 60 additions and 21 deletions

View file

@ -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,20 +152,12 @@ 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(did, ts) {
// only instance vars are record fields at runtime
let fields = lookup_class_fields(cx.tcx, did);
let 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 {
// resource type
T_struct([T_i8(), T_struct(tys)])
}
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"); }
@ -170,9 +165,33 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
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.
let fields = lookup_class_fields(cx.tcx, did);
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 {
// resource type
tys = [T_i8(), T_struct(tys)];
}
common::set_struct_body(llty, tys);
}
_ {
// 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]",

View file

@ -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 }
}