Skip to content

Commit 1f892dc

Browse files
committed
Monomorphize class constructors, support generic classes and class methods
Allow class methods to have type parameters (this is a change from the original classes proposal). Add test cases for classes with type parameters, and classes with methods that have their own type parameters.
1 parent 4f4b7b1 commit 1f892dc

File tree

11 files changed

+217
-118
lines changed

11 files changed

+217
-118
lines changed

src/librustsyntax/parse/parser.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,11 +2062,24 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
20622062
attrs);
20632063
}
20642064

2065+
// Instantiates ident <i> with references to <typarams> as arguments
2066+
fn ident_to_path_tys(p: parser, i: ast::ident,
2067+
typarams: [ast::ty_param]) -> @ast::path {
2068+
let s = p.last_span;
2069+
let p_: ast::path_ = {global: false, idents: [i],
2070+
types: vec::map(typarams,
2071+
{|tp| @{id: p.get_id(),
2072+
node: ast::ty_path(ident_to_path(s, tp.ident),
2073+
p.get_id()),
2074+
span: s}})};
2075+
@spanned(s.lo, s.hi, p_)
2076+
}
2077+
20652078
fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
20662079
let lo = p.last_span.lo;
20672080
let class_name = parse_value_ident(p);
2068-
let class_path = ident_to_path(p.last_span, class_name);
20692081
let ty_params = parse_ty_params(p);
2082+
let class_path = ident_to_path_tys(p, class_name, ty_params);
20702083
expect(p, token::LBRACE);
20712084
let mut ms: [@ast::class_member] = [];
20722085
let ctor_id = p.get_id();
@@ -2104,15 +2117,16 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
21042117
enum class_contents { ctor_decl(ast::fn_decl, ast::blk, codemap::span),
21052118
members([@ast::class_member]) }
21062119

2107-
fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents {
2120+
fn parse_class_item(p:parser, class_name_with_tps:@ast::path)
2121+
-> class_contents {
21082122
if eat_word(p, "new") {
21092123
let lo = p.last_span.lo;
21102124
// Can ctors have attrs?
21112125
// result type is always the type of the class
21122126
let decl_ = parse_fn_decl(p, ast::impure_fn);
21132127
let decl = {output: @{id: p.get_id(),
2114-
node: ast::ty_path(class_name, p.get_id()),
2115-
span: decl_.output.span}
2128+
node: ast::ty_path(class_name_with_tps, p.get_id()),
2129+
span: decl_.output.span}
21162130
with decl_};
21172131
let body = parse_block(p);
21182132
ret ctor_decl(decl, body, ast_util::mk_sp(lo, p.last_span.hi));

src/rustc/middle/kind.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,26 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
189189
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id));
190190
ty::lookup_item_type(cx.tcx, did).bounds
191191
}
192-
expr_field(_, _, _) {
192+
expr_field(base, _, _) {
193193
alt cx.method_map.get(e.id) {
194194
typeck::method_static(did) {
195-
ty::lookup_item_type(cx.tcx, did).bounds
195+
/*
196+
If this is a class method, we want to use the
197+
class bounds plus the method bounds -- otherwise the
198+
indices come out wrong. So we check base's type...
199+
*/
200+
let mut bounds = ty::lookup_item_type(cx.tcx, did).bounds;
201+
alt ty::get(ty::node_id_to_type(cx.tcx, base.id)).struct {
202+
ty::ty_class(parent_id, ts) {
203+
/* ...and if it has a class type, prepend the
204+
class bounds onto the method bounds */
205+
bounds =
206+
@(*ty::lookup_item_type(cx.tcx, parent_id).bounds
207+
+ *bounds);
208+
}
209+
_ { }
210+
}
211+
bounds
196212
}
197213
typeck::method_param(ifce_id, n_mth, _, _) |
198214
typeck::method_iface(ifce_id, n_mth) {

src/rustc/middle/trans/base.rs

Lines changed: 73 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
950950
ty::ty_class(did, tps) {
951951
// a class is like a record type
952952
let mut i: int = 0;
953-
for vec::each(ty::class_items_as_fields(cx.tcx(), did)) {|fld|
953+
for vec::each(ty::class_items_as_fields(cx.tcx(), did, tps)) {|fld|
954954
let llfld_a = GEPi(cx, av, [0, i]);
955955
cx = f(cx, llfld_a, fld.mt.ty);
956956
i += 1;
@@ -1983,8 +1983,13 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
19831983
set_inline_hint(lldecl);
19841984
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
19851985
}
1986-
ast::item_class(_, _, ctor) {
1987-
ccx.sess.unimpl("monomorphic class constructor");
1986+
ast::item_class(tps, _, ctor) {
1987+
set_inline_hint_if_appr(i.attrs, lldecl);
1988+
let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps);
1989+
trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, lldecl,
1990+
option::get_or_default(psubsts,
1991+
{tys:tp_tys, vtables: none, bounds: @[]}),
1992+
fn_id.node, i.id, ctor.span);
19881993
}
19891994
}
19901995
}
@@ -2238,7 +2243,8 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
22382243
field: ast::ident, sp: span) -> lval_result {
22392244
let fields = alt ty::get(ty).struct {
22402245
ty::ty_rec(fs) { fs }
2241-
ty::ty_class(did,_) { ty::class_items_as_fields(bcx.tcx(), did) }
2246+
ty::ty_class(did,ts) {
2247+
ty::class_items_as_fields(bcx.tcx(), did, ts) }
22422248
// Constraint?
22432249
_ { bcx.tcx().sess.span_bug(sp, "trans_rec_field:\
22442250
base expr has non-record type"); }
@@ -4255,6 +4261,61 @@ fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
42554261
llvm::LLVMSetGlobalConstant(g, True);
42564262
}
42574263

4264+
fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
4265+
body: ast::blk, llctor_decl: ValueRef,
4266+
psubsts: param_substs, ctor_id: ast::node_id,
4267+
parent_id: ast::node_id, sp: span) {
4268+
// Add ctor to the ctor map
4269+
ccx.class_ctors.insert(ctor_id, parent_id);
4270+
// Translate the ctor
4271+
4272+
// Set up the type for the result of the ctor
4273+
// kludgy -- this wouldn't be necessary if the typechecker
4274+
// special-cased constructors, then we could just look up
4275+
// the ctor's return type.
4276+
let rslt_ty = ty::mk_class(ccx.tcx, local_def(parent_id),
4277+
psubsts.tys);
4278+
// Make the fn context
4279+
let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
4280+
some(psubsts), some(sp));
4281+
// FIXME: need to substitute into the fn arg types too?
4282+
create_llargs_for_fn_args(fcx, no_self, decl.inputs);
4283+
let mut bcx_top = top_scope_block(fcx, some(sp));
4284+
let lltop = bcx_top.llbb;
4285+
bcx_top = copy_args_to_allocas(fcx, bcx_top, decl.inputs,
4286+
ty::ty_fn_args(node_id_type(bcx_top, ctor_id)));
4287+
4288+
// We *don't* want self to be passed to the ctor -- that
4289+
// wouldn't make sense
4290+
// So we initialize it here
4291+
let selfptr = alloc_ty(bcx_top, rslt_ty);
4292+
// initialize fields to zero
4293+
let fields = ty::class_items_as_fields(bcx_top.tcx(),
4294+
local_def(parent_id),
4295+
psubsts.tys);
4296+
let mut bcx = bcx_top;
4297+
// Initialize fields to zero so init assignments can validly
4298+
// drop their LHS
4299+
for field in fields {
4300+
let ix = field_idx_strict(bcx.tcx(), sp, field.ident, fields);
4301+
bcx = zero_alloca(bcx, GEPi(bcx, selfptr, [0, ix]),
4302+
field.mt.ty);
4303+
}
4304+
4305+
// note we don't want to take *or* drop self.
4306+
fcx.llself = some({v: selfptr, t: rslt_ty});
4307+
4308+
// Translate the body of the ctor
4309+
bcx = trans_block(bcx_top, body, ignore);
4310+
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
4311+
// Generate the return expression
4312+
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
4313+
rslt_ty, true);
4314+
cleanup_and_leave(bcx, none, some(fcx.llreturn));
4315+
Unreachable(bcx);
4316+
finish_fn(fcx, lltop);
4317+
}
4318+
42584319
fn trans_item(ccx: @crate_ctxt, item: ast::item) {
42594320
let _icx = ccx.insn_ctxt("trans_item");
42604321
let path = alt check ccx.tcx.items.get(item.id) {
@@ -4322,62 +4383,15 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
43224383
native::trans_native_mod(ccx, native_mod, abi);
43234384
}
43244385
ast::item_class(tps, items, ctor) {
4325-
// FIXME factor our ctor translation, call from monomorphic_fn
4326-
let llctor_decl = get_item_val(ccx, ctor.node.id);
4327-
// Add ctor to the ctor map
4328-
ccx.class_ctors.insert(ctor.node.id, item.id);
4329-
// Translate the ctor
4330-
4331-
// Set up the type for the result of the ctor
4332-
// kludgy -- this wouldn't be necessary if the typechecker
4333-
// special-cased constructors, then we could just look up
4334-
// the ctor's return type.
4335-
let ty_args = vec::from_fn(tps.len(), {|i|
4336-
ty::mk_param(ccx.tcx, i, local_def(tps[i].id))
4337-
});
4338-
let rslt_ty = ty::mk_class(ccx.tcx,
4339-
local_def(item.id),
4340-
ty_args);
4341-
4342-
// Make the fn context
4343-
let fcx = new_fn_ctxt_w_id(ccx, *path, llctor_decl, ctor.node.id,
4344-
// substs?
4345-
none, some(ctor.span));
4346-
create_llargs_for_fn_args(fcx, no_self, ctor.node.dec.inputs);
4347-
let mut bcx_top = top_scope_block(fcx, some(ctor.span));
4348-
let lltop = bcx_top.llbb;
4349-
bcx_top = copy_args_to_allocas(fcx, bcx_top, ctor.node.dec.inputs,
4350-
ty::ty_fn_args(node_id_type(bcx_top, ctor.node.id)));
4351-
4352-
// We *don't* want self to be passed to the ctor -- that
4353-
// wouldn't make sense
4354-
// So we initialize it here
4355-
let selfptr = alloc_ty(bcx_top, rslt_ty);
4356-
// initialize fields to zero
4357-
let fields = ty::class_items_as_fields(bcx_top.tcx(),
4358-
local_def(item.id));
4359-
let mut bcx = bcx_top;
4360-
// Initialize fields to zero so init assignments can validly
4361-
// drop their LHS
4362-
for field in fields {
4363-
let ix = field_idx_strict(bcx.tcx(), ctor.span, field.ident,
4364-
fields);
4365-
bcx = zero_alloca(bcx, GEPi(bcx, selfptr, [0, ix]),
4366-
field.mt.ty);
4386+
if tps.len() == 0u {
4387+
let psubsts = {tys: ty::ty_params_to_tys(ccx.tcx, tps),
4388+
vtables: none,
4389+
bounds: @[]};
4390+
trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
4391+
get_item_val(ccx, ctor.node.id), psubsts,
4392+
ctor.node.id, item.id, ctor.span);
43674393
}
4368-
4369-
// note we don't want to take *or* drop self.
4370-
fcx.llself = some({v: selfptr, t: rslt_ty});
4371-
4372-
// Translate the body of the ctor
4373-
bcx = trans_block(bcx_top, ctor.node.body, ignore);
4374-
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
4375-
// Generate the return expression
4376-
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
4377-
rslt_ty, true);
4378-
cleanup_and_leave(bcx, none, some(fcx.llreturn));
4379-
Unreachable(bcx);
4380-
finish_fn(fcx, lltop);
4394+
// If there are ty params, the ctor will get monomorphized
43814395

43824396
// Translate methods
43834397
let (_, ms) = ast_util::split_class_items(items);

src/rustc/middle/trans/shape.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,10 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
369369
s
370370
}
371371
ty::ty_iface(_, _) { [shape_box_fn] }
372-
ty::ty_class(did, _) {
372+
ty::ty_class(did, ts) {
373373
// same as records
374374
let mut s = [shape_struct], sub = [];
375-
for f:field in ty::class_items_as_fields(ccx.tcx, did) {
375+
for f:field in ty::class_items_as_fields(ccx.tcx, did, ts) {
376376
sub += shape_of(ccx, f.mt.ty, ty_param_map);
377377
}
378378
add_substr(s, sub);

src/rustc/middle/trans/type_of.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
8181
}
8282
ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
8383
ty::ty_constr(subt,_) { type_of(cx, subt) }
84-
ty::ty_class(did, _) {
84+
ty::ty_class(did, ts) {
8585
// only instance vars are record fields at runtime
8686
let fields = lookup_class_fields(cx.tcx, did);
8787
let tys = vec::map(fields) {|f|
88-
let t = ty::lookup_field_type(cx.tcx, did, f.id);
88+
let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
8989
type_of(cx, t)
9090
};
9191
T_struct(tys)

src/rustc/middle/trans/type_use.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Determines the ways in which a generic function body is dependant
1+
// Determines the ways in which a generic function body depends
22
// on its type parameters. Used to aggressively reuse compiled
33
// function bodies for different types.
44

@@ -80,7 +80,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
8080
}
8181
}
8282
ast_map::node_ctor(@{node: item_class(_, _, ctor), _}, _) {
83-
ccx.sess.unimpl("type uses in class constructor");
83+
handle_body(cx, ctor.node.body);
8484
}
8585
}
8686
let uses = vec::from_mut(cx.uses);

src/rustc/middle/tstate/auxiliary.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,20 @@ type pred_args = spanned<pred_args_>;
197197
// for this local.
198198
type constr_arg_use = spanned<constr_arg_general_<inst>>;
199199

200+
/*
201+
A constraint is either an init constraint, referring to the initialization
202+
state of a variable (not initialized, definitely initialized, or maybe
203+
initialized) or a predicate constraint, referring to the truth value of a
204+
predicate on variables (definitely false, maybe true, or definitely true).
205+
206+
cinit and ninit represent init constraints, while cpred and npred
207+
represent predicate constraints.
208+
209+
In a predicate constraint, the <path> field (and the <def_id> field
210+
in the npred constructor) names a user-defined function that may
211+
be the operator in a "check" expression in the source.
212+
*/
213+
200214
enum constraint {
201215
cinit(uint, span, ident),
202216

0 commit comments

Comments
 (0)