1
Fork 0

Generic classes and generic class methods work cross-crate

Classes can have ty params now. So can methods inside classes.
That was probably true before, but now it should still work if you
call methods in a class that's defined in a different crate. Yay!
This commit is contained in:
Tim Chevalier 2012-04-10 10:52:06 -07:00
parent b2ec26c152
commit fd26743bed
19 changed files with 216 additions and 82 deletions

View file

@ -643,7 +643,7 @@ enum item_ {
item_native_mod(native_mod), item_native_mod(native_mod),
item_ty(@ty, [ty_param]), item_ty(@ty, [ty_param]),
item_enum([variant], [ty_param]), item_enum([variant], [ty_param]),
item_res(fn_decl /* dtor */, [ty_param], blk, item_res(fn_decl /* dtor */, [ty_param], blk /* dtor body */,
node_id /* dtor id */, node_id /* ctor id */), node_id /* dtor id */, node_id /* ctor id */),
item_class([ty_param], /* ty params for class */ item_class([ty_param], /* ty params for class */
[@class_member], /* methods, etc. */ [@class_member], /* methods, etc. */
@ -703,6 +703,7 @@ enum inlined_item {
ii_item(@item), ii_item(@item),
ii_method(def_id /* impl id */, @method), ii_method(def_id /* impl id */, @method),
ii_native(@native_item), ii_native(@native_item),
ii_ctor(class_ctor, ident, [ty_param], def_id /* parent id */)
} }
// //

View file

@ -302,6 +302,7 @@ impl inlined_item_methods for inlined_item {
ii_item(i) { i.ident } ii_item(i) { i.ident }
ii_native(i) { i.ident } ii_native(i) { i.ident }
ii_method(_, m) { m.ident } ii_method(_, m) { m.ident }
ii_ctor(_, nm, _, _) { nm }
} }
} }
@ -310,6 +311,7 @@ impl inlined_item_methods for inlined_item {
ii_item(i) { i.id } ii_item(i) { i.id }
ii_native(i) { i.id } ii_native(i) { i.id }
ii_method(_, m) { m.id } ii_method(_, m) { m.id }
ii_ctor(ctor, _, _, _) { ctor.node.id }
} }
} }
@ -318,6 +320,9 @@ impl inlined_item_methods for inlined_item {
ii_item(i) { v.visit_item(i, e, v) } ii_item(i) { v.visit_item(i, e, v) }
ii_native(i) { v.visit_native_item(i, e, v) } ii_native(i) { v.visit_native_item(i, e, v) }
ii_method(_, m) { visit::visit_method_helper(m, e, v) } ii_method(_, m) { visit::visit_method_helper(m, e, v) }
ii_ctor(ctor, nm, tps, parent_id) {
visit::visit_class_ctor_helper(ctor, nm, tps, parent_id, e, v);
}
} }
} }
} }

View file

@ -14,6 +14,8 @@ export noop_fold_ty;
export noop_fold_block; export noop_fold_block;
export wrap; export wrap;
export fold_ty_param; export fold_ty_param;
export fold_ty_params;
export fold_fn_decl;
type ast_fold = @mut a_f; type ast_fold = @mut a_f;
@ -270,10 +272,12 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
item_class(typms, items, ctor) { item_class(typms, items, ctor) {
let ctor_body = fld.fold_block(ctor.node.body); let ctor_body = fld.fold_block(ctor.node.body);
let ctor_decl = fold_fn_decl(ctor.node.dec, fld); let ctor_decl = fold_fn_decl(ctor.node.dec, fld);
let ctor_id = fld.new_id(ctor.node.id);
item_class(typms, item_class(typms,
vec::map(items, fld.fold_class_item), vec::map(items, fld.fold_class_item),
{node: {body: ctor_body, {node: {body: ctor_body,
dec: ctor_decl with ctor.node} dec: ctor_decl,
id: ctor_id with ctor.node}
with ctor}) with ctor})
} }
item_impl(tps, ifce, ty, methods) { item_impl(tps, ifce, ty, methods) {

View file

@ -18,13 +18,14 @@ enum fn_kind {
fk_res(ident, [ty_param]), fk_res(ident, [ty_param]),
fk_anon(proto), //< an anonymous function like fn@(...) fk_anon(proto), //< an anonymous function like fn@(...)
fk_fn_block, //< a block {||...} fk_fn_block, //< a block {||...}
fk_ctor(ident, [ty_param]) // class constructor fk_ctor(ident, [ty_param], node_id /* self id */,
def_id /* parent class id */) // class constructor
} }
fn name_of_fn(fk: fn_kind) -> ident { fn name_of_fn(fk: fn_kind) -> ident {
alt fk { alt fk {
fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _) fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _)
| fk_ctor(name, _) { name } | fk_ctor(name, _, _, _) { name }
fk_anon(_) | fk_fn_block { "anon" } fk_anon(_) | fk_fn_block { "anon" }
} }
} }
@ -32,7 +33,7 @@ fn name_of_fn(fk: fn_kind) -> ident {
fn tps_of_fn(fk: fn_kind) -> [ty_param] { fn tps_of_fn(fk: fn_kind) -> [ty_param] {
alt fk { alt fk {
fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps) fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps)
| fk_ctor(_, tps) { tps } | fk_ctor(_, tps, _, _) { tps }
fk_anon(_) | fk_fn_block { [] } fk_anon(_) | fk_fn_block { [] }
} }
} }
@ -141,9 +142,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
for members.each {|m| for members.each {|m|
v.visit_class_item(m, e, v); v.visit_class_item(m, e, v);
} }
// make up a fake fn so as to call visit_fn on the ctor visit_class_ctor_helper(ctor, i.ident, tps,
v.visit_fn(fk_ctor(i.ident, tps), ctor.node.dec, ast_util::local_def(i.id), e, v);
ctor.node.body, ctor.span, ctor.node.id, e, v);
} }
item_iface(tps, methods) { item_iface(tps, methods) {
v.visit_ty_params(tps, e, v); v.visit_ty_params(tps, e, v);
@ -270,6 +270,15 @@ fn visit_method_helper<E>(m: @method, e: E, v: vt<E>) {
m.id, e, v); m.id, e, v);
} }
// Similar logic to the comment on visit_method_helper - Tim
fn visit_class_ctor_helper<E>(ctor: class_ctor, nm: ident, tps: [ty_param],
parent_id: def_id, e: E, v: vt<E>) {
v.visit_fn(visit::fk_ctor(nm, tps, ctor.node.self_id,
parent_id), ctor.node.dec,
ctor.node.body, ctor.span, ctor.node.id, e, v)
}
fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span, fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span,
_id: node_id, e: E, v: vt<E>) { _id: node_id, e: E, v: vt<E>) {
visit_fn_decl(decl, e, v); visit_fn_decl(decl, e, v);

View file

@ -1,3 +1,5 @@
import util::ppaux::ty_to_str;
import syntax::ast; import syntax::ast;
import syntax::fold; import syntax::fold;
import syntax::visit; import syntax::visit;
@ -200,8 +202,14 @@ fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
vfn(id); vfn(id);
alt fk { alt fk {
visit::fk_ctor(nm, tps, self_id, parent_id) {
vec::iter(tps) {|tp| vfn(tp.id)}
vfn(id);
vfn(self_id);
vfn(parent_id.node);
}
visit::fk_item_fn(_, tps) | visit::fk_item_fn(_, tps) |
visit::fk_res(_, tps) | visit::fk_ctor(_, tps) { visit::fk_res(_, tps) {
vec::iter(tps) {|tp| vfn(tp.id)} vec::iter(tps) {|tp| vfn(tp.id)}
} }
visit::fk_method(_, tps, m) { visit::fk_method(_, tps, m) {
@ -376,6 +384,13 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
ast::ii_native(i) { ast::ii_native(i) {
ast::ii_native(fld.fold_native_item(i)) ast::ii_native(fld.fold_native_item(i))
} }
ast::ii_ctor(ctor, nm, tps, parent_id) {
let ctor_body = fld.fold_block(ctor.node.body);
let ctor_decl = fold::fold_fn_decl(ctor.node.dec, fld);
ast::ii_ctor({node: {body: ctor_body, dec: ctor_decl
with ctor.node}
with ctor}, nm, tps, parent_id)
}
} }
} }
@ -403,6 +418,16 @@ fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
ast::ii_native(i) { ast::ii_native(i) {
ast::ii_native(fld.fold_native_item(i)) ast::ii_native(fld.fold_native_item(i))
} }
ast::ii_ctor(ctor, nm, tps, parent_id) {
let ctor_body = fld.fold_block(ctor.node.body);
let ctor_decl = fold::fold_fn_decl(ctor.node.dec, fld);
let new_params = fold::fold_ty_params(tps, fld);
let ctor_id = fld.new_id(ctor.node.id);
let new_parent = xcx.tr_def_id(parent_id);
ast::ii_ctor({node: {body: ctor_body, dec: ctor_decl, id: ctor_id
with ctor.node}
with ctor}, nm, new_params, new_parent)
}
} }
} }

View file

@ -368,6 +368,7 @@ fn encode_privacy(ebml_w: ebml::writer, privacy: privacy) {
/* Returns an index of items in this class */ /* Returns an index of items in this class */
fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer, fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
id: node_id, path: ast_map::path, id: node_id, path: ast_map::path,
class_tps: [ty_param],
items: [@class_member], items: [@class_member],
global_index: @mut[entry<int>]) global_index: @mut[entry<int>])
-> [entry<int>] { -> [entry<int>] {
@ -397,13 +398,10 @@ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
but it works for now -- tjc */ but it works for now -- tjc */
*global_index += [{val: m.id, pos: ebml_w.writer.tell()}]; *global_index += [{val: m.id, pos: ebml_w.writer.tell()}];
let impl_path = path + [ast_map::path_name(m.ident)]; let impl_path = path + [ast_map::path_name(m.ident)];
/*
Recall methods are (currently) monomorphic, and we don't
repeat the class's ty params in the method decl
*/
#debug("encode_info_for_class: doing %s %d", m.ident, m.id); #debug("encode_info_for_class: doing %s %d", m.ident, m.id);
encode_info_for_method(ecx, ebml_w, impl_path, encode_info_for_method(ecx, ebml_w, impl_path,
should_inline(m.attrs), id, m, []); should_inline(m.attrs), id, m,
class_tps + m.tps);
} }
_ { /* don't encode private methods */ } _ { /* don't encode private methods */ }
} }
@ -415,7 +413,8 @@ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer, fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer,
id: node_id, ident: ident, path: ast_map::path, id: node_id, ident: ident, path: ast_map::path,
item: option<@item>, tps: [ty_param], decl: fn_decl) { item: option<inlined_item>, tps: [ty_param],
decl: fn_decl) {
ebml_w.start_tag(tag_items_data_item); ebml_w.start_tag(tag_items_data_item);
encode_name(ebml_w, ident); encode_name(ebml_w, ident);
encode_def_id(ebml_w, local_def(id)); encode_def_id(ebml_w, local_def(id));
@ -428,7 +427,7 @@ fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer,
encode_path(ebml_w, path, ast_map::path_name(ident)); encode_path(ebml_w, path, ast_map::path_name(ident));
alt item { alt item {
some(it) { some(it) {
astencode::encode_inlined_item(ecx, ebml_w, path, ii_item(it)); astencode::encode_inlined_item(ecx, ebml_w, path, it);
} }
none { none {
encode_symbol(ecx, ebml_w, id); encode_symbol(ecx, ebml_w, id);
@ -441,7 +440,7 @@ fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::writer,
impl_path: ast_map::path, should_inline: bool, impl_path: ast_map::path, should_inline: bool,
parent_id: node_id, parent_id: node_id,
m: @method, all_tps: [ty_param]) { m: @method, all_tps: [ty_param]) {
#debug("encode_info_for_method: %d %s", m.id, m.ident); #debug("encode_info_for_method: %d %s %u", m.id, m.ident, all_tps.len());
ebml_w.start_tag(tag_items_data_item); ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(m.id)); encode_def_id(ebml_w, local_def(m.id));
encode_family(ebml_w, purity_fn_family(m.decl.purity)); encode_family(ebml_w, purity_fn_family(m.decl.purity));
@ -562,8 +561,8 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
These come first because we need to write them to make These come first because we need to write them to make
the index, and the index needs to be in the item for the the index, and the index needs to be in the item for the
class itself */ class itself */
let idx = encode_info_for_class(ecx, ebml_w, item.id, path, items, let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps,
index); items, index);
/* Index the class*/ /* Index the class*/
add_to_index(); add_to_index();
/* Now, make an item for the class itself */ /* Now, make an item for the class itself */
@ -594,6 +593,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
#debug("Writing %s %d", m.ident, m.id); #debug("Writing %s %d", m.ident, m.id);
encode_family(ebml_w, purity_fn_family(m.decl.purity)); encode_family(ebml_w, purity_fn_family(m.decl.purity));
encode_name(ebml_w, m.ident); encode_name(ebml_w, m.ident);
encode_type_param_bounds(ebml_w, ecx, tps + m.tps);
encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id)); encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
encode_def_id(ebml_w, local_def(m.id)); encode_def_id(ebml_w, local_def(m.id));
ebml_w.end_tag(); ebml_w.end_tag();
@ -727,7 +727,6 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
alt check ecx.ccx.tcx.items.get(i.id) { alt check ecx.ccx.tcx.items.get(i.id) {
ast_map::node_item(_, pt) { ast_map::node_item(_, pt) {
encode_info_for_item(ecx, ebml_w, i, index, *pt); encode_info_for_item(ecx, ebml_w, i, index, *pt);
/* TODO: encode info for class items! */
/* encode ctor, then encode items */ /* encode ctor, then encode items */
alt i.node { alt i.node {
item_class(tps,_,ctor) { item_class(tps,_,ctor) {
@ -737,7 +736,10 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
ctor.node.id); ctor.node.id);
*index += [{val: ctor.node.id, pos: ebml_w.writer.tell()}]; *index += [{val: ctor.node.id, pos: ebml_w.writer.tell()}];
encode_info_for_fn(ecx, ebml_w, ctor.node.id, i.ident, encode_info_for_fn(ecx, ebml_w, ctor.node.id, i.ident,
*pt, none, tps, ctor.node.dec) *pt, if tps.len() > 0u {
some(ii_ctor(ctor, i.ident, tps,
local_def(i.id))) }
else { none }, tps, ctor.node.dec)
} }
_ {} _ {}
} }

View file

@ -44,10 +44,16 @@ enum ast_node {
// order they are introduced. // order they are introduced.
node_arg(arg, uint), node_arg(arg, uint),
node_local(uint), node_local(uint),
node_ctor(@item, @path), // Constructor for either a resource or a class
node_ctor(ident, [ty_param], a_ctor, @path),
node_block(blk), node_block(blk),
} }
enum a_ctor {
res_ctor(fn_decl, node_id, codemap::span),
class_ctor(@class_ctor, def_id /* ID for parent class */),
}
type map = std::map::hashmap<node_id, ast_node>; type map = std::map::hashmap<node_id, ast_node>;
type ctx = {map: map, mut path: path, type ctx = {map: map, mut path: path,
mut local_id: uint, sess: session}; mut local_id: uint, sess: session};
@ -99,7 +105,7 @@ fn map_decoded_item(sess: session, map: map, path: path, ii: inlined_item) {
// don't decode and instantiate the impl, but just the method, we have to // don't decode and instantiate the impl, but just the method, we have to
// add it to the table now: // add it to the table now:
alt ii { alt ii {
ii_item(i) { /* fallthrough */ } ii_item(_) | ii_ctor(_,_,_,_) { /* fallthrough */ }
ii_native(i) { ii_native(i) {
cx.map.insert(i.id, node_native_item(i, native_abi_rust_intrinsic, cx.map.insert(i.id, node_native_item(i, native_abi_rust_intrinsic,
@path)); @path));
@ -119,6 +125,16 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
cx.map.insert(a.id, node_arg(a, cx.local_id)); cx.map.insert(a.id, node_arg(a, cx.local_id));
cx.local_id += 1u; cx.local_id += 1u;
} }
alt fk {
visit::fk_ctor(nm, tps, self_id, parent_id) {
let ct = @{node: {id: id, self_id: self_id,
dec: decl, body: body},
span: sp};
cx.map.insert(id, node_ctor(nm, tps, class_ctor(ct, parent_id),
@cx.path));
}
_ {}
}
visit::visit_fn(fk, decl, body, sp, id, cx, v); visit::visit_fn(fk, decl, body, sp, id, cx, v);
} }
@ -166,8 +182,10 @@ fn map_item(i: @item, cx: ctx, v: vt) {
map_method(impl_did, extend(cx, i.ident), m, cx); map_method(impl_did, extend(cx, i.ident), m, cx);
} }
} }
item_res(_, _, _, dtor_id, ctor_id) { item_res(decl, tps, _, dtor_id, ctor_id) {
cx.map.insert(ctor_id, node_ctor(i, item_path)); cx.map.insert(ctor_id, node_ctor(i.ident, tps,
res_ctor(decl, ctor_id, i.span),
item_path));
cx.map.insert(dtor_id, node_item(i, item_path)); cx.map.insert(dtor_id, node_item(i, item_path));
} }
item_enum(vs, _) { item_enum(vs, _) {
@ -186,7 +204,6 @@ fn map_item(i: @item, cx: ctx, v: vt) {
} }
} }
item_class(_, items, ctor) { item_class(_, items, ctor) {
cx.map.insert(ctor.node.id, node_ctor(i, item_path));
let d_id = ast_util::local_def(i.id); let d_id = ast_util::local_def(i.id);
let p = extend(cx, i.ident); let p = extend(cx, i.ident);
for items.each {|ci| for items.each {|ci|
@ -267,7 +284,7 @@ fn node_id_to_str(map: map, id: node_id) -> str {
some(node_local(_)) { // FIXME: add more info here some(node_local(_)) { // FIXME: add more info here
#fmt["local (id=%?)", id] #fmt["local (id=%?)", id]
} }
some(node_ctor(_, _)) { // FIXME: add more info here some(node_ctor(_, _, _, _)) { // FIXME: add more info here
#fmt["node_ctor (id=%?)", id] #fmt["node_ctor (id=%?)", id]
} }
some(node_block(_)) { some(node_block(_)) {

View file

@ -218,8 +218,8 @@ fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) {
v.visit_ty_params(tps, cx, v); v.visit_ty_params(tps, cx, v);
vec::map::<@class_member, ()>(items, vec::map::<@class_member, ()>(items,
{|i| v.visit_class_item(i, cx, v); }); {|i| v.visit_class_item(i, cx, v); });
v.visit_fn(visit::fk_ctor(item.ident, tps), ctor.node.dec, visit::visit_class_ctor_helper(ctor, item.ident, tps,
ctor.node.body, ctor.span, ctor.node.id, ast_util::local_def(item.id),
@{in_ctor: some(ctor.node.self_id) with *cx}, v); @{in_ctor: some(ctor.node.self_id) with *cx}, v);
} }
_ { visit::visit_item(item, cx, v); } _ { visit::visit_item(item, cx, v); }

View file

@ -572,7 +572,7 @@ fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
for decl.constraints.each {|c| resolve_constr(e, c, sc, v); } for decl.constraints.each {|c| resolve_constr(e, c, sc, v); }
let scope = alt fk { let scope = alt fk {
visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) | visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) |
visit::fk_method(_, tps, _) | visit::fk_ctor(_, tps) visit::fk_method(_, tps, _) | visit::fk_ctor(_, tps, _, _)
{ scope_bare_fn(decl, id, tps) } { scope_bare_fn(decl, id, tps) }
visit::fk_anon(ast::proto_bare) { scope_bare_fn(decl, id, []) } visit::fk_anon(ast::proto_bare) { scope_bare_fn(decl, id, []) }
visit::fk_anon(_) | visit::fk_fn_block { scope_fn_expr(decl, id, []) } visit::fk_anon(_) | visit::fk_fn_block { scope_fn_expr(decl, id, []) }

View file

@ -1906,11 +1906,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
ret {val: get_item_val(ccx, fn_id.node), ret {val: get_item_val(ccx, fn_id.node),
must_cast: true}; must_cast: true};
} }
ast_map::node_ctor(i, _) { ast_map::node_ctor(nm, _, _, pt) { (pt, nm) }
alt check ccx.tcx.items.get(i.id) {
ast_map::node_item(i, pt) { (pt, i.ident) }
}
}
_ { fail "unexpected node type"; } _ { fail "unexpected node type"; }
}; };
let mono_ty = ty::substitute_type_params(ccx.tcx, substs, item_ty); let mono_ty = ty::substitute_type_params(ccx.tcx, substs, item_ty);
@ -1950,19 +1946,19 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
trans_fn(ccx, pt, mth.decl, mth.body, lldecl, trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
impl_self(selfty), psubsts, fn_id.node); impl_self(selfty), psubsts, fn_id.node);
} }
ast_map::node_ctor(i, _) { ast_map::node_ctor(nm, tps, ct, _) {
alt check i.node { alt ct {
ast::item_res(decl, _, _, _, _) { ast_map::res_ctor(decl,_, _) {
set_inline_hint(lldecl); set_inline_hint(lldecl);
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl); trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
} }
ast::item_class(tps, _, ctor) { ast_map::class_ctor(ctor, parent_id) {
set_inline_hint_if_appr(i.attrs, lldecl); // ctors don't have attrs, at least not right now
let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps); 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, trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, lldecl,
option::get_or_default(psubsts, option::get_or_default(psubsts,
{tys:tp_tys, vtables: none, bounds: @[]}), {tys:tp_tys, vtables: none, bounds: @[]}),
fn_id.node, i.id, ctor.span); fn_id.node, parent_id, ctor.span);
} }
} }
} }
@ -1992,6 +1988,10 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
trans_item(ccx, *item); trans_item(ccx, *item);
local_def(item.id) local_def(item.id)
} }
csearch::found(ast::ii_ctor(ctor, nm, tps, parent_id)) {
ccx.external.insert(fn_id, some(ctor.node.id));
local_def(ctor.node.id)
}
csearch::found(ast::ii_native(item)) { csearch::found(ast::ii_native(item)) {
ccx.external.insert(fn_id, some(item.id)); ccx.external.insert(fn_id, some(item.id));
local_def(item.id) local_def(item.id)
@ -4256,17 +4256,17 @@ fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl, fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
body: ast::blk, llctor_decl: ValueRef, body: ast::blk, llctor_decl: ValueRef,
psubsts: param_substs, ctor_id: ast::node_id, psubsts: param_substs, ctor_id: ast::node_id,
parent_id: ast::node_id, sp: span) { parent_id: ast::def_id, sp: span) {
// Add ctor to the ctor map // Add ctor to the ctor map
ccx.class_ctors.insert(ctor_id, parent_id); ccx.class_ctors.insert(ctor_id, parent_id);
// Translate the ctor // Translate the ctor
// Set up the type for the result of the ctor // Set up the type for the result of the ctor
// kludgy -- this wouldn't be necessary if the typechecker // kludgy -- this wouldn't be necessary if the typechecker
// special-cased constructors, then we could just look up // special-cased constructors, then we could just look up
// the ctor's return type. // the ctor's return type.
let rslt_ty = ty::mk_class(ccx.tcx, local_def(parent_id), let rslt_ty = ty::mk_class(ccx.tcx, parent_id, psubsts.tys);
psubsts.tys);
// Make the fn context // Make the fn context
let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id, let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
some(psubsts), some(sp)); some(psubsts), some(sp));
@ -4280,10 +4280,10 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
// We *don't* want self to be passed to the ctor -- that // We *don't* want self to be passed to the ctor -- that
// wouldn't make sense // wouldn't make sense
// So we initialize it here // So we initialize it here
let selfptr = alloc_ty(bcx_top, rslt_ty); let selfptr = alloc_ty(bcx_top, rslt_ty);
// initialize fields to zero // initialize fields to zero
let fields = ty::class_items_as_fields(bcx_top.tcx(), let fields = ty::class_items_as_fields(bcx_top.tcx(), parent_id,
local_def(parent_id),
psubsts.tys); psubsts.tys);
let mut bcx = bcx_top; let mut bcx = bcx_top;
// Initialize fields to zero so init assignments can validly // Initialize fields to zero so init assignments can validly
@ -4381,7 +4381,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
bounds: @[]}; bounds: @[]};
trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body, trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
get_item_val(ccx, ctor.node.id), psubsts, get_item_val(ccx, ctor.node.id), psubsts,
ctor.node.id, item.id, ctor.span); ctor.node.id, local_def(item.id), ctor.span);
} }
// If there are ty params, the ctor will get monomorphized // If there are ty params, the ctor will get monomorphized
@ -4542,6 +4542,7 @@ fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
} }
fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef { fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
#debug("get_item_val: %d", id);
alt ccx.item_vals.find(id) { alt ccx.item_vals.find(id) {
some(v) { v } some(v) { v }
none { none {
@ -4593,16 +4594,16 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
exprt = true; exprt = true;
register_fn(ccx, ni.span, *pth + [path_name(ni.ident)], ni.id) register_fn(ccx, ni.span, *pth + [path_name(ni.ident)], ni.id)
} }
ast_map::node_ctor(i, _) { ast_map::node_ctor(nm, tps, ct, pt) {
alt check i.node { let my_path = *pt + [path_name(nm)];
ast::item_res(_, _, _, _, _) { alt ct {
let my_path = item_path(ccx, i); ast_map::res_ctor(_,_,sp) {
let llctor = register_fn(ccx, i.span, my_path, id); let llctor = register_fn(ccx, sp, my_path, id);
set_inline_hint(llctor); set_inline_hint(llctor);
llctor llctor
} }
ast::item_class(_, _, ctor) { ast_map::class_ctor(ctor, _) {
register_fn(ccx, i.span, item_path(ccx, i), id) register_fn(ccx, ctor.span, my_path, ctor.node.id)
} }
} }
} }
@ -4923,7 +4924,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
shape_cx: mk_ctxt(llmod), shape_cx: mk_ctxt(llmod),
crate_map: crate_map, crate_map: crate_map,
dbg_cx: dbg_cx, dbg_cx: dbg_cx,
class_ctors: int_hash::<int>(), class_ctors: int_hash::<ast::def_id>(),
mut do_not_commit_warning_issued: false}; mut do_not_commit_warning_issued: false};

View file

@ -121,7 +121,9 @@ type crate_ctxt = {
dbg_cx: option<debuginfo::debug_ctxt>, dbg_cx: option<debuginfo::debug_ctxt>,
// Mapping from class constructors to parent class -- // Mapping from class constructors to parent class --
// used in base::trans_closure // used in base::trans_closure
class_ctors: hashmap<ast::node_id, ast::node_id>, // parent_class must be a def_id because ctors can be
// inlined, so the parent may be in a different crate
class_ctors: hashmap<ast::node_id, ast::def_id>,
mut do_not_commit_warning_issued: bool}; mut do_not_commit_warning_issued: bool};
// Types used for llself. // Types used for llself.

View file

@ -757,13 +757,14 @@ fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
ast_map::node_method(method, _, _) { ast_map::node_method(method, _, _) {
(method.ident, method.decl.output, method.id) (method.ident, method.decl.output, method.id)
} }
ast_map::node_ctor(item, _) { ast_map::node_ctor(nm, _, ct, _) {
alt item.node { alt ct {
ast::item_res(decl, _, _, _, ctor_id) { ast_map::res_ctor(decl, ctor_id, _) {
(item.ident, decl.output, ctor_id) (nm, decl.output, ctor_id)
} }
_ { fcx.ccx.sess.span_bug(item.span, "create_function: \ ast_map::class_ctor(ctor,_) {
expected an item_res here"); } fcx.ccx.sess.span_bug(ctor.span, "create_function: \
expected a resource ctor here"); }
} }
} }
ast_map::node_expr(expr) { ast_map::node_expr(expr) {

View file

@ -58,13 +58,18 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
ccx.type_use_cache.insert(fn_id, uses); ccx.type_use_cache.insert(fn_id, uses);
ret uses; ret uses;
} }
alt check ccx.tcx.items.get(fn_id_loc.node) { let map_node = alt ccx.tcx.items.find(fn_id_loc.node) {
some(x) { x }
none { ccx.sess.bug(#fmt("type_uses_for: unbound item ID %?",
fn_id_loc)); }
};
alt check map_node {
ast_map::node_item(@{node: item_fn(_, _, body), _}, _) | ast_map::node_item(@{node: item_fn(_, _, body), _}, _) |
ast_map::node_item(@{node: item_res(_, _, body, _, _), _}, _) | ast_map::node_item(@{node: item_res(_, _, body, _, _), _}, _) |
ast_map::node_method(@{body, _}, _, _) { ast_map::node_method(@{body, _}, _, _) {
handle_body(cx, body); handle_body(cx, body);
} }
ast_map::node_ctor(@{node: item_res(_, _, _, _, _), _},_) | ast_map::node_ctor(_, _, ast_map::res_ctor(_, _, _), _) |
ast_map::node_variant(_, _, _) { ast_map::node_variant(_, _, _) {
uint::range(0u, n_tps) {|n| cx.uses[n] |= use_repr;} uint::range(0u, n_tps) {|n| cx.uses[n] |= use_repr;}
} }
@ -79,7 +84,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
uint::range(0u, n_tps) {|n| cx.uses[n] |= flags;} uint::range(0u, n_tps) {|n| cx.uses[n] |= flags;}
} }
} }
ast_map::node_ctor(@{node: item_class(_, _, ctor), _}, _) { ast_map::node_ctor(_, _, ast_map::class_ctor(ctor, _), _){
handle_body(cx, ctor.node.body); handle_body(cx, ctor.node.body);
} }
} }

View file

@ -111,7 +111,7 @@ fn check_states_against_conditions(fcx: fn_ctxt,
/* Check that the return value is initialized */ /* Check that the return value is initialized */
let post = aux::block_poststate(fcx.ccx, f_body); let post = aux::block_poststate(fcx.ccx, f_body);
let is_ctor = alt fk { visit::fk_ctor(_,_) { true } _ { false } }; let is_ctor = alt fk { visit::fk_ctor(_,_,_,_) { true } _ { false } };
if !is_ctor && !promises(fcx, post, fcx.enclosing.i_return) && if !is_ctor && !promises(fcx, post, fcx.enclosing.i_return) &&
!ty::type_is_nil(ty::ty_fn_ret(ty::node_id_to_type( !ty::type_is_nil(ty::ty_fn_ret(ty::node_id_to_type(
fcx.ccx.tcx, id))) && fcx.ccx.tcx, id))) &&

View file

@ -2043,8 +2043,8 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
vec::init(*path) + [ast_map::path_name(variant.node.name)] vec::init(*path) + [ast_map::path_name(variant.node.name)]
} }
ast_map::node_ctor(i, path) { ast_map::node_ctor(nm, _, _, path) {
*path + [ast_map::path_name(i.ident)] *path + [ast_map::path_name(nm)]
} }
ast_map::node_expr(_) | ast_map::node_arg(_, _) | ast_map::node_expr(_) | ast_map::node_arg(_, _) |
@ -2121,7 +2121,6 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
alt cx.tcache.find(did) { alt cx.tcache.find(did) {
some(tpt) { ret tpt; } some(tpt) { ret tpt; }
none { none {
#debug("lookup_item_type: looking up %?", did);
// The item is in this crate. The caller should have added it to the // The item is in this crate. The caller should have added it to the
// type cache already // type cache already
assert did.crate != ast::local_crate; assert did.crate != ast::local_crate;
@ -2168,7 +2167,10 @@ fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] {
_ { cx.sess.bug("class ID bound to non-class"); } _ { cx.sess.bug("class ID bound to non-class"); }
} }
} }
_ { cx.sess.bug("class ID not bound to an item"); } _ {
cx.sess.bug(#fmt("class ID not bound to an item: %s",
ast_map::node_id_to_str(cx.items, did.node)));
}
} }
} }
else { else {

View file

@ -2149,6 +2149,20 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
} }
} }
/*
Takes arguments describing a method, and returns either its origin,
or <none> if it's unbound.
expr: the entire method reference
node_id: the method's ID
name: the method's name
ty: the type of the base expression
tps: the ty substitutions that are part of the field expr
(for example: in foo.bar<int,char>(), tps would be
[int, char])
include_private: true if we're inside the same class and should
search private methods
*/
fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
name: ast::ident, ty: ty::t, tps: [ty::t], name: ast::ident, ty: ty::t, tps: [ty::t],
include_private: bool) include_private: bool)
@ -2159,7 +2173,12 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
let mut substs = substs; let mut substs = substs;
let n_tps = vec::len(substs), n_tys = vec::len(tps); let n_tps = vec::len(substs), n_tys = vec::len(tps);
let has_self = ty::type_has_vars(fty); let has_self = ty::type_has_vars(fty);
/* If either the method was declared to have ty params,
or ty arguments were provided, or both... */
if method_n_tps + n_tps > 0u { if method_n_tps + n_tps > 0u {
/* If no type arguments were given,
or a different number of them were given than the
method's declared types... */
if n_tys == 0u || n_tys != method_n_tps { if n_tys == 0u || n_tys != method_n_tps {
if n_tys != 0u { if n_tys != 0u {
tcx.sess.span_err tcx.sess.span_err
@ -2167,12 +2186,18 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
parameters given for this method"); parameters given for this method");
} }
/* If not enough types were given, make some ty vars */
substs += vec::from_fn(method_n_tps, {|_i| substs += vec::from_fn(method_n_tps, {|_i|
ty::mk_var(tcx, next_ty_var_id(fcx)) ty::mk_var(tcx, next_ty_var_id(fcx))
}); });
} else { } else {
/* If the right number of types were given, just add them on */
substs += tps; substs += tps;
} }
/*
For a class method, "substs" here begins with the class ty
params
*/
fcx.write_ty_substs(node_id, fty, substs); fcx.write_ty_substs(node_id, fty, substs);
} else { } else {
if n_tys > 0u { if n_tys > 0u {
@ -2209,7 +2234,6 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
include_private: bool) include_private: bool)
-> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t], -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
origin: method_origin, self_sub: option<self_subst>}> { origin: method_origin, self_sub: option<self_subst>}> {
#debug("lookup_method_inner_: %? %? %s", ms, parent, name);
let mut i = 0u; let mut i = 0u;
for ms.each {|m| for ms.each {|m|
if m.ident == name { if m.ident == name {
@ -2228,6 +2252,8 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
sp, "Call to private method not allowed outside \ sp, "Call to private method not allowed outside \
its defining class"); its defining class");
} }
#debug("lookup_method_inner_: %s has %u ty params, by its \
declaration", name, vec::len(*m.tps));
ret some({method_ty: fty, ret some({method_ty: fty,
n_tps: vec::len(*m.tps), n_tps: vec::len(*m.tps),
substs: tps, substs: tps,

View file

@ -0,0 +1,21 @@
mod kitties {
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 }
}
}

View file

@ -0,0 +1,15 @@
// xfail-fast
// aux-build:cci_class_6.rs
use cci_class_6;
import cci_class_6::kitties::*;
fn main() {
let nyan : cat<char> = cat::<char>(52u, 99, ['p']);
let kitty = cat(1000u, 2, ["tabby"]);
assert(nyan.how_hungry == 99);
assert(kitty.how_hungry == 2);
nyan.speak([1u,2u,3u]);
assert(nyan.meow_count() == 55u);
kitty.speak(["meow", "mew", "purr", "chirp"]);
assert(kitty.meow_count() == 1004u);
}

View file

@ -1,5 +1,3 @@
// xfail-test
// needs metadata encoding on Windows
class cat<U> { class cat<U> {
priv { priv {
let mut info : [U]; let mut info : [U];