mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
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.
This commit is contained in:
parent
4f4b7b10bb
commit
1f892dcb01
@ -2062,11 +2062,24 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||
attrs);
|
||||
}
|
||||
|
||||
// Instantiates ident <i> with references to <typarams> as arguments
|
||||
fn ident_to_path_tys(p: parser, i: ast::ident,
|
||||
typarams: [ast::ty_param]) -> @ast::path {
|
||||
let s = p.last_span;
|
||||
let p_: ast::path_ = {global: false, idents: [i],
|
||||
types: vec::map(typarams,
|
||||
{|tp| @{id: p.get_id(),
|
||||
node: ast::ty_path(ident_to_path(s, tp.ident),
|
||||
p.get_id()),
|
||||
span: s}})};
|
||||
@spanned(s.lo, s.hi, p_)
|
||||
}
|
||||
|
||||
fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||
let lo = p.last_span.lo;
|
||||
let class_name = parse_value_ident(p);
|
||||
let class_path = ident_to_path(p.last_span, class_name);
|
||||
let ty_params = parse_ty_params(p);
|
||||
let class_path = ident_to_path_tys(p, class_name, ty_params);
|
||||
expect(p, token::LBRACE);
|
||||
let mut ms: [@ast::class_member] = [];
|
||||
let ctor_id = p.get_id();
|
||||
@ -2104,15 +2117,16 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||
enum class_contents { ctor_decl(ast::fn_decl, ast::blk, codemap::span),
|
||||
members([@ast::class_member]) }
|
||||
|
||||
fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents {
|
||||
fn parse_class_item(p:parser, class_name_with_tps:@ast::path)
|
||||
-> class_contents {
|
||||
if eat_word(p, "new") {
|
||||
let lo = p.last_span.lo;
|
||||
// Can ctors have attrs?
|
||||
// result type is always the type of the class
|
||||
let decl_ = parse_fn_decl(p, ast::impure_fn);
|
||||
let decl = {output: @{id: p.get_id(),
|
||||
node: ast::ty_path(class_name, p.get_id()),
|
||||
span: decl_.output.span}
|
||||
node: ast::ty_path(class_name_with_tps, p.get_id()),
|
||||
span: decl_.output.span}
|
||||
with decl_};
|
||||
let body = parse_block(p);
|
||||
ret ctor_decl(decl, body, ast_util::mk_sp(lo, p.last_span.hi));
|
||||
|
@ -189,10 +189,26 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id));
|
||||
ty::lookup_item_type(cx.tcx, did).bounds
|
||||
}
|
||||
expr_field(_, _, _) {
|
||||
expr_field(base, _, _) {
|
||||
alt cx.method_map.get(e.id) {
|
||||
typeck::method_static(did) {
|
||||
ty::lookup_item_type(cx.tcx, did).bounds
|
||||
/*
|
||||
If this is a class method, we want to use the
|
||||
class bounds plus the method bounds -- otherwise the
|
||||
indices come out wrong. So we check base's type...
|
||||
*/
|
||||
let mut bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
||||
alt ty::get(ty::node_id_to_type(cx.tcx, base.id)).struct {
|
||||
ty::ty_class(parent_id, ts) {
|
||||
/* ...and if it has a class type, prepend the
|
||||
class bounds onto the method bounds */
|
||||
bounds =
|
||||
@(*ty::lookup_item_type(cx.tcx, parent_id).bounds
|
||||
+ *bounds);
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
bounds
|
||||
}
|
||||
typeck::method_param(ifce_id, n_mth, _, _) |
|
||||
typeck::method_iface(ifce_id, n_mth) {
|
||||
|
@ -950,7 +950,7 @@ fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
|
||||
ty::ty_class(did, tps) {
|
||||
// a class is like a record type
|
||||
let mut i: int = 0;
|
||||
for vec::each(ty::class_items_as_fields(cx.tcx(), did)) {|fld|
|
||||
for vec::each(ty::class_items_as_fields(cx.tcx(), did, tps)) {|fld|
|
||||
let llfld_a = GEPi(cx, av, [0, i]);
|
||||
cx = f(cx, llfld_a, fld.mt.ty);
|
||||
i += 1;
|
||||
@ -1983,8 +1983,13 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
|
||||
set_inline_hint(lldecl);
|
||||
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
|
||||
}
|
||||
ast::item_class(_, _, ctor) {
|
||||
ccx.sess.unimpl("monomorphic class constructor");
|
||||
ast::item_class(tps, _, ctor) {
|
||||
set_inline_hint_if_appr(i.attrs, lldecl);
|
||||
let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps);
|
||||
trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, lldecl,
|
||||
option::get_or_default(psubsts,
|
||||
{tys:tp_tys, vtables: none, bounds: @[]}),
|
||||
fn_id.node, i.id, ctor.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2238,7 +2243,8 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
|
||||
field: ast::ident, sp: span) -> lval_result {
|
||||
let fields = alt ty::get(ty).struct {
|
||||
ty::ty_rec(fs) { fs }
|
||||
ty::ty_class(did,_) { ty::class_items_as_fields(bcx.tcx(), did) }
|
||||
ty::ty_class(did,ts) {
|
||||
ty::class_items_as_fields(bcx.tcx(), did, ts) }
|
||||
// Constraint?
|
||||
_ { bcx.tcx().sess.span_bug(sp, "trans_rec_field:\
|
||||
base expr has non-record type"); }
|
||||
@ -4255,6 +4261,61 @@ fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
}
|
||||
|
||||
fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
|
||||
body: ast::blk, llctor_decl: ValueRef,
|
||||
psubsts: param_substs, ctor_id: ast::node_id,
|
||||
parent_id: ast::node_id, sp: span) {
|
||||
// Add ctor to the ctor map
|
||||
ccx.class_ctors.insert(ctor_id, parent_id);
|
||||
// Translate the ctor
|
||||
|
||||
// Set up the type for the result of the ctor
|
||||
// kludgy -- this wouldn't be necessary if the typechecker
|
||||
// special-cased constructors, then we could just look up
|
||||
// the ctor's return type.
|
||||
let rslt_ty = ty::mk_class(ccx.tcx, local_def(parent_id),
|
||||
psubsts.tys);
|
||||
// Make the fn context
|
||||
let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
|
||||
some(psubsts), some(sp));
|
||||
// FIXME: need to substitute into the fn arg types too?
|
||||
create_llargs_for_fn_args(fcx, no_self, decl.inputs);
|
||||
let mut bcx_top = top_scope_block(fcx, some(sp));
|
||||
let lltop = bcx_top.llbb;
|
||||
bcx_top = copy_args_to_allocas(fcx, bcx_top, decl.inputs,
|
||||
ty::ty_fn_args(node_id_type(bcx_top, ctor_id)));
|
||||
|
||||
// We *don't* want self to be passed to the ctor -- that
|
||||
// wouldn't make sense
|
||||
// So we initialize it here
|
||||
let selfptr = alloc_ty(bcx_top, rslt_ty);
|
||||
// initialize fields to zero
|
||||
let fields = ty::class_items_as_fields(bcx_top.tcx(),
|
||||
local_def(parent_id),
|
||||
psubsts.tys);
|
||||
let mut bcx = bcx_top;
|
||||
// Initialize fields to zero so init assignments can validly
|
||||
// drop their LHS
|
||||
for field in fields {
|
||||
let ix = field_idx_strict(bcx.tcx(), sp, field.ident, fields);
|
||||
bcx = zero_alloca(bcx, GEPi(bcx, selfptr, [0, ix]),
|
||||
field.mt.ty);
|
||||
}
|
||||
|
||||
// note we don't want to take *or* drop self.
|
||||
fcx.llself = some({v: selfptr, t: rslt_ty});
|
||||
|
||||
// Translate the body of the ctor
|
||||
bcx = trans_block(bcx_top, body, ignore);
|
||||
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
|
||||
// Generate the return expression
|
||||
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
|
||||
rslt_ty, true);
|
||||
cleanup_and_leave(bcx, none, some(fcx.llreturn));
|
||||
Unreachable(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
}
|
||||
|
||||
fn trans_item(ccx: @crate_ctxt, item: ast::item) {
|
||||
let _icx = ccx.insn_ctxt("trans_item");
|
||||
let path = alt check ccx.tcx.items.get(item.id) {
|
||||
@ -4322,62 +4383,15 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
|
||||
native::trans_native_mod(ccx, native_mod, abi);
|
||||
}
|
||||
ast::item_class(tps, items, ctor) {
|
||||
// FIXME factor our ctor translation, call from monomorphic_fn
|
||||
let llctor_decl = get_item_val(ccx, ctor.node.id);
|
||||
// Add ctor to the ctor map
|
||||
ccx.class_ctors.insert(ctor.node.id, item.id);
|
||||
// Translate the ctor
|
||||
|
||||
// Set up the type for the result of the ctor
|
||||
// kludgy -- this wouldn't be necessary if the typechecker
|
||||
// special-cased constructors, then we could just look up
|
||||
// the ctor's return type.
|
||||
let ty_args = vec::from_fn(tps.len(), {|i|
|
||||
ty::mk_param(ccx.tcx, i, local_def(tps[i].id))
|
||||
});
|
||||
let rslt_ty = ty::mk_class(ccx.tcx,
|
||||
local_def(item.id),
|
||||
ty_args);
|
||||
|
||||
// Make the fn context
|
||||
let fcx = new_fn_ctxt_w_id(ccx, *path, llctor_decl, ctor.node.id,
|
||||
// substs?
|
||||
none, some(ctor.span));
|
||||
create_llargs_for_fn_args(fcx, no_self, ctor.node.dec.inputs);
|
||||
let mut bcx_top = top_scope_block(fcx, some(ctor.span));
|
||||
let lltop = bcx_top.llbb;
|
||||
bcx_top = copy_args_to_allocas(fcx, bcx_top, ctor.node.dec.inputs,
|
||||
ty::ty_fn_args(node_id_type(bcx_top, ctor.node.id)));
|
||||
|
||||
// We *don't* want self to be passed to the ctor -- that
|
||||
// wouldn't make sense
|
||||
// So we initialize it here
|
||||
let selfptr = alloc_ty(bcx_top, rslt_ty);
|
||||
// initialize fields to zero
|
||||
let fields = ty::class_items_as_fields(bcx_top.tcx(),
|
||||
local_def(item.id));
|
||||
let mut bcx = bcx_top;
|
||||
// Initialize fields to zero so init assignments can validly
|
||||
// drop their LHS
|
||||
for field in fields {
|
||||
let ix = field_idx_strict(bcx.tcx(), ctor.span, field.ident,
|
||||
fields);
|
||||
bcx = zero_alloca(bcx, GEPi(bcx, selfptr, [0, ix]),
|
||||
field.mt.ty);
|
||||
if tps.len() == 0u {
|
||||
let psubsts = {tys: ty::ty_params_to_tys(ccx.tcx, tps),
|
||||
vtables: none,
|
||||
bounds: @[]};
|
||||
trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
|
||||
get_item_val(ccx, ctor.node.id), psubsts,
|
||||
ctor.node.id, item.id, ctor.span);
|
||||
}
|
||||
|
||||
// note we don't want to take *or* drop self.
|
||||
fcx.llself = some({v: selfptr, t: rslt_ty});
|
||||
|
||||
// Translate the body of the ctor
|
||||
bcx = trans_block(bcx_top, ctor.node.body, ignore);
|
||||
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
|
||||
// Generate the return expression
|
||||
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
|
||||
rslt_ty, true);
|
||||
cleanup_and_leave(bcx, none, some(fcx.llreturn));
|
||||
Unreachable(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
// If there are ty params, the ctor will get monomorphized
|
||||
|
||||
// Translate methods
|
||||
let (_, ms) = ast_util::split_class_items(items);
|
||||
|
@ -369,10 +369,10 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
||||
s
|
||||
}
|
||||
ty::ty_iface(_, _) { [shape_box_fn] }
|
||||
ty::ty_class(did, _) {
|
||||
ty::ty_class(did, ts) {
|
||||
// same as records
|
||||
let mut s = [shape_struct], sub = [];
|
||||
for f:field in ty::class_items_as_fields(ccx.tcx, did) {
|
||||
for f:field in ty::class_items_as_fields(ccx.tcx, did, ts) {
|
||||
sub += shape_of(ccx, f.mt.ty, ty_param_map);
|
||||
}
|
||||
add_substr(s, sub);
|
||||
|
@ -81,11 +81,11 @@ 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, _) {
|
||||
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);
|
||||
let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
|
||||
type_of(cx, t)
|
||||
};
|
||||
T_struct(tys)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Determines the ways in which a generic function body is dependant
|
||||
// Determines the ways in which a generic function body depends
|
||||
// on its type parameters. Used to aggressively reuse compiled
|
||||
// function bodies for different types.
|
||||
|
||||
@ -80,7 +80,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
|
||||
}
|
||||
}
|
||||
ast_map::node_ctor(@{node: item_class(_, _, ctor), _}, _) {
|
||||
ccx.sess.unimpl("type uses in class constructor");
|
||||
handle_body(cx, ctor.node.body);
|
||||
}
|
||||
}
|
||||
let uses = vec::from_mut(cx.uses);
|
||||
|
@ -197,6 +197,20 @@ type pred_args = spanned<pred_args_>;
|
||||
// for this local.
|
||||
type constr_arg_use = spanned<constr_arg_general_<inst>>;
|
||||
|
||||
/*
|
||||
A constraint is either an init constraint, referring to the initialization
|
||||
state of a variable (not initialized, definitely initialized, or maybe
|
||||
initialized) or a predicate constraint, referring to the truth value of a
|
||||
predicate on variables (definitely false, maybe true, or definitely true).
|
||||
|
||||
cinit and ninit represent init constraints, while cpred and npred
|
||||
represent predicate constraints.
|
||||
|
||||
In a predicate constraint, the <path> field (and the <def_id> field
|
||||
in the npred constructor) names a user-defined function that may
|
||||
be the operator in a "check" expression in the source.
|
||||
*/
|
||||
|
||||
enum constraint {
|
||||
cinit(uint, span, ident),
|
||||
|
||||
|
@ -82,7 +82,7 @@ export ty_vec, mk_vec, type_is_vec;
|
||||
export ty_nil, mk_nil, type_is_nil;
|
||||
export ty_iface, mk_iface;
|
||||
export ty_res, mk_res;
|
||||
export ty_param, mk_param;
|
||||
export ty_param, mk_param, ty_params_to_tys;
|
||||
export ty_ptr, mk_ptr, mk_mut_ptr, mk_imm_ptr, mk_nil_ptr, type_is_unsafe_ptr;
|
||||
export ty_rptr, mk_rptr;
|
||||
export ty_rec, mk_rec;
|
||||
@ -742,6 +742,10 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
|
||||
ty_constr(subty, cs) {
|
||||
ty = mk_constr(cx, do_fold(cx, fld, subty, under_rptr), cs);
|
||||
}
|
||||
ty_class(did, ts) {
|
||||
ty = mk_class(cx, did, vec::map(ts, {|t|
|
||||
do_fold(cx, fld, t, under_rptr)}));
|
||||
}
|
||||
_ {
|
||||
cx.sess.bug("unsupported sort of type in fold_ty");
|
||||
}
|
||||
@ -886,8 +890,8 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
|
||||
for f in flds { if type_needs_drop(cx, f.mt.ty) { accum = true; } }
|
||||
accum
|
||||
}
|
||||
ty_class(did,_) {
|
||||
for f in ty::class_items_as_fields(cx, did)
|
||||
ty_class(did, ts) {
|
||||
for f in ty::class_items_as_fields(cx, did, ts)
|
||||
{ if type_needs_drop(cx, f.mt.ty) { accum = true; } }
|
||||
accum
|
||||
}
|
||||
@ -1996,7 +2000,8 @@ fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
|
||||
|
||||
fn def_has_ty_params(def: ast::def) -> bool {
|
||||
alt def {
|
||||
ast::def_fn(_, _) | ast::def_variant(_, _) { true }
|
||||
ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_)
|
||||
{ true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
@ -2166,9 +2171,6 @@ fn enum_variant_with_id(cx: ctxt, enum_id: ast::def_id,
|
||||
// If the given item is in an external crate, looks up its type and adds it to
|
||||
// the type cache. Returns the type parameters and type.
|
||||
fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
|
||||
/*
|
||||
Are we putting class ids in the tcache (where does that happen?)
|
||||
*/
|
||||
alt cx.tcache.find(did) {
|
||||
some(tpt) { ret tpt; }
|
||||
none {
|
||||
@ -2184,23 +2186,26 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
|
||||
}
|
||||
|
||||
// Look up a field ID, whether or not it's local
|
||||
fn lookup_field_type(tcx: ctxt, class_id: def_id, id: def_id) -> ty::t {
|
||||
if id.crate == ast::local_crate {
|
||||
// Takes a list of type substs in case the class is generic
|
||||
fn lookup_field_type(tcx: ctxt, class_id: def_id, id: def_id,
|
||||
substs: [ty::t]) -> ty::t {
|
||||
let t = if id.crate == ast::local_crate {
|
||||
node_id_to_type(tcx, id.node)
|
||||
}
|
||||
else {
|
||||
alt tcx.tcache.find(id) {
|
||||
some(tpt) { ret tpt.ty; }
|
||||
some(tpt) { tpt.ty }
|
||||
none {
|
||||
let tpt = csearch::get_field_type(tcx, class_id, id);
|
||||
// ok b/c fields are monomorphic
|
||||
// TODO: Comment might be a lie, what if it mentions
|
||||
// class-bound ty params?
|
||||
tcx.tcache.insert(id, tpt);
|
||||
ret tpt.ty;
|
||||
tpt.ty
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
substitute_type_params(tcx, substs, t)
|
||||
}
|
||||
|
||||
// Look up the list of field names and IDs for a given class
|
||||
@ -2298,13 +2303,16 @@ fn class_field_tys(items: [@class_member]) -> [field_ty] {
|
||||
|
||||
// Return a list of fields corresponding to the class's items
|
||||
// (as if the class was a record). trans uses this
|
||||
fn class_items_as_fields(cx:ctxt, did: ast::def_id) -> [field] {
|
||||
// Takes a list of substs with which to instantiate field types
|
||||
fn class_items_as_fields(cx:ctxt, did: ast::def_id, substs: [ty::t])
|
||||
-> [field] {
|
||||
let mut rslt = [];
|
||||
for f in lookup_class_fields(cx, did) {
|
||||
// consider all instance vars mut, because the
|
||||
// constructor may mutate all vars
|
||||
rslt += [{ident: f.ident, mt: {ty: lookup_field_type(cx, did, f.id),
|
||||
mutbl: m_mutbl}}];
|
||||
rslt += [{ident: f.ident, mt:
|
||||
{ty: lookup_field_type(cx, did, f.id, substs),
|
||||
mutbl: m_mutbl}}];
|
||||
}
|
||||
rslt
|
||||
}
|
||||
@ -2408,7 +2416,11 @@ fn ast_constr_to_constr<T>(tcx: ctxt, c: @ast::constr_general<T>) ->
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn ty_params_to_tys(tcx: ty::ctxt, tps: [ast::ty_param]) -> [t] {
|
||||
vec::from_fn(tps.len(), {|i|
|
||||
ty::mk_param(tcx, i, ast_util::local_def(tps[i].id))
|
||||
})
|
||||
}
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
@ -218,7 +218,7 @@ fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path,
|
||||
(sp, "this item does not take type parameters");
|
||||
} else if ty_substs_len > ty_param_count {
|
||||
fcx.ccx.tcx.sess.span_fatal
|
||||
(sp, "too many type parameter provided for this item");
|
||||
(sp, "too many type parameters provided for this item");
|
||||
} else if ty_substs_len < ty_param_count {
|
||||
fcx.ccx.tcx.sess.span_fatal
|
||||
(sp, "not enough type parameters provided for this item");
|
||||
@ -399,7 +399,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
|
||||
path_to_str(path))); }
|
||||
some(d) { d }};
|
||||
alt a_def {
|
||||
ast::def_ty(did) {
|
||||
ast::def_ty(did) | ast::def_class(did) {
|
||||
instantiate(tcx, ast_ty.span, mode, did,
|
||||
id, path.node.types)
|
||||
}
|
||||
@ -433,28 +433,6 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::def_class(class_id) {
|
||||
if class_id.crate == ast::local_crate {
|
||||
alt tcx.items.find(class_id.node) {
|
||||
some(ast_map::node_item(
|
||||
@{node: ast::item_class(tps, _, _), _}, _)) {
|
||||
if vec::len(tps) != vec::len(path.node.types) {
|
||||
tcx.sess.span_err(ast_ty.span, "incorrect number \
|
||||
of type parameters to object type");
|
||||
}
|
||||
ty::mk_class(tcx, class_id, vec::map(path.node.types,
|
||||
{|ast_ty| ast_ty_to_ty(tcx, mode, ast_ty)}))
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_bug(ast_ty.span, #fmt("class id is \
|
||||
unbound in items"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
getter(tcx, mode, class_id).ty
|
||||
}
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
"found type name used as a variable");
|
||||
@ -2196,7 +2174,8 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
|
||||
tcx.sess.span_fatal(
|
||||
sp, "can not call a method that contains a \
|
||||
self type through a boxed iface");
|
||||
} else if (*m.tps).len() > 0u {
|
||||
} else if (*m.tps).len() > 0u &&
|
||||
alt parent { an_iface(_) { true } cls(_) { false } } {
|
||||
tcx.sess.span_fatal(
|
||||
sp, "can not call a generic method through a \
|
||||
boxed iface");
|
||||
@ -2276,8 +2255,10 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
|
||||
}
|
||||
}
|
||||
ty::ty_class(did, tps) {
|
||||
alt lookup_method_inner_(tcx, *ty::iface_methods(tcx, did), tps,
|
||||
cls(did), name, expr.span, include_private) {
|
||||
alt lookup_method_inner_(tcx, *ty::iface_methods(tcx, did),
|
||||
/* Need to include class tps so that the
|
||||
indices for ty params work out right */
|
||||
tps, cls(did), name, expr.span, include_private) {
|
||||
some(r) { ret some(r); }
|
||||
none { }
|
||||
}
|
||||
@ -2361,9 +2342,10 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
|
||||
// Only for fields! Returns <none> for methods>
|
||||
// FIXME: privacy flags
|
||||
fn lookup_field_ty(tcx: ty::ctxt, class_id: ast::def_id,
|
||||
items:[ty::field_ty], fieldname: ast::ident) -> option<ty::t> {
|
||||
items:[ty::field_ty], fieldname: ast::ident, substs: [ty::t])
|
||||
-> option<ty::t> {
|
||||
option::map(vec::find(items, {|f| f.ident == fieldname}),
|
||||
{|f| ty::lookup_field_type(tcx, class_id, f.id) })
|
||||
{|f| ty::lookup_field_type(tcx, class_id, f.id, substs) })
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3236,7 +3218,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
ty::ty_class(base_id, _params) {
|
||||
ty::ty_class(base_id, params) {
|
||||
// This is just for fields -- the same code handles
|
||||
// methods in both classes and ifaces
|
||||
|
||||
@ -3255,7 +3237,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||
else {
|
||||
lookup_public_fields(tcx, base_id)
|
||||
};
|
||||
alt lookup_field_ty(tcx, base_id, cls_items, field) {
|
||||
alt lookup_field_ty(tcx, base_id, cls_items, field, params) {
|
||||
some(field_ty) {
|
||||
// (2) look up what field's type is, and return it
|
||||
// FIXME: actually instantiate any type params
|
||||
|
28
src/test/run-pass/class-poly-methods.rs
Normal file
28
src/test/run-pass/class-poly-methods.rs
Normal file
@ -0,0 +1,28 @@
|
||||
class cat<U> {
|
||||
priv {
|
||||
let mut info : [U];
|
||||
let mut meows : uint;
|
||||
}
|
||||
|
||||
let how_hungry : int;
|
||||
|
||||
new(in_x : uint, in_y : int, -in_info: [U])
|
||||
{ self.meows = in_x; self.how_hungry = in_y;
|
||||
self.info <- in_info; }
|
||||
|
||||
fn speak<T>(stuff: [T]) {
|
||||
self.meows += stuff.len();
|
||||
}
|
||||
fn meow_count() -> uint { self.meows }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let nyan : cat<int> = cat::<int>(52u, 99, [9]);
|
||||
let kitty = cat(1000u, 2, ["tabby"]);
|
||||
assert(nyan.how_hungry == 99);
|
||||
assert(kitty.how_hungry == 2);
|
||||
nyan.speak([1,2,3]);
|
||||
assert(nyan.meow_count() == 55u);
|
||||
kitty.speak(["meow", "mew", "purr", "chirp"]);
|
||||
assert(kitty.meow_count() == 1004u);
|
||||
}
|
19
src/test/run-pass/class-typarams.rs
Normal file
19
src/test/run-pass/class-typarams.rs
Normal file
@ -0,0 +1,19 @@
|
||||
class cat<U> {
|
||||
priv {
|
||||
let mut meows : uint;
|
||||
}
|
||||
|
||||
let how_hungry : int;
|
||||
|
||||
new(in_x : uint, in_y : int) { self.meows = in_x; self.how_hungry = in_y; }
|
||||
|
||||
fn speak() {
|
||||
self.meows += 1u;
|
||||
}
|
||||
fn meow_count() -> uint { self.meows }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _nyan : cat<int> = cat::<int>(52u, 99);
|
||||
// let kitty = cat(1000u, 2);
|
||||
}
|
Loading…
Reference in New Issue
Block a user