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:
parent
b2ec26c152
commit
fd26743bed
19 changed files with 216 additions and 82 deletions
|
@ -643,7 +643,7 @@ enum item_ {
|
|||
item_native_mod(native_mod),
|
||||
item_ty(@ty, [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 */),
|
||||
item_class([ty_param], /* ty params for class */
|
||||
[@class_member], /* methods, etc. */
|
||||
|
@ -703,6 +703,7 @@ enum inlined_item {
|
|||
ii_item(@item),
|
||||
ii_method(def_id /* impl id */, @method),
|
||||
ii_native(@native_item),
|
||||
ii_ctor(class_ctor, ident, [ty_param], def_id /* parent id */)
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -302,6 +302,7 @@ impl inlined_item_methods for inlined_item {
|
|||
ii_item(i) { i.ident }
|
||||
ii_native(i) { i.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_native(i) { i.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_native(i) { v.visit_native_item(i, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ export noop_fold_ty;
|
|||
export noop_fold_block;
|
||||
export wrap;
|
||||
export fold_ty_param;
|
||||
export fold_ty_params;
|
||||
export fold_fn_decl;
|
||||
|
||||
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) {
|
||||
let ctor_body = fld.fold_block(ctor.node.body);
|
||||
let ctor_decl = fold_fn_decl(ctor.node.dec, fld);
|
||||
let ctor_id = fld.new_id(ctor.node.id);
|
||||
item_class(typms,
|
||||
vec::map(items, fld.fold_class_item),
|
||||
{node: {body: ctor_body,
|
||||
dec: ctor_decl with ctor.node}
|
||||
dec: ctor_decl,
|
||||
id: ctor_id with ctor.node}
|
||||
with ctor})
|
||||
}
|
||||
item_impl(tps, ifce, ty, methods) {
|
||||
|
|
|
@ -18,13 +18,14 @@ enum fn_kind {
|
|||
fk_res(ident, [ty_param]),
|
||||
fk_anon(proto), //< an anonymous function like fn@(...)
|
||||
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 {
|
||||
alt fk {
|
||||
fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _)
|
||||
| fk_ctor(name, _) { name }
|
||||
| fk_ctor(name, _, _, _) { name }
|
||||
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] {
|
||||
alt fk {
|
||||
fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps)
|
||||
| fk_ctor(_, tps) { tps }
|
||||
| fk_ctor(_, tps, _, _) { tps }
|
||||
fk_anon(_) | fk_fn_block { [] }
|
||||
}
|
||||
}
|
||||
|
@ -141,9 +142,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
|||
for members.each {|m|
|
||||
v.visit_class_item(m, e, v);
|
||||
}
|
||||
// make up a fake fn so as to call visit_fn on the ctor
|
||||
v.visit_fn(fk_ctor(i.ident, tps), ctor.node.dec,
|
||||
ctor.node.body, ctor.span, ctor.node.id, e, v);
|
||||
visit_class_ctor_helper(ctor, i.ident, tps,
|
||||
ast_util::local_def(i.id), e, v);
|
||||
}
|
||||
item_iface(tps, methods) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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,
|
||||
_id: node_id, e: E, v: vt<E>) {
|
||||
visit_fn_decl(decl, e, v);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import util::ppaux::ty_to_str;
|
||||
|
||||
import syntax::ast;
|
||||
import syntax::fold;
|
||||
import syntax::visit;
|
||||
|
@ -200,8 +202,14 @@ fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
|
|||
vfn(id);
|
||||
|
||||
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_res(_, tps) | visit::fk_ctor(_, tps) {
|
||||
visit::fk_res(_, tps) {
|
||||
vec::iter(tps) {|tp| vfn(tp.id)}
|
||||
}
|
||||
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(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,7 +418,17 @@ fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
|
|||
ast::ii_native(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
|
|
|
@ -368,6 +368,7 @@ fn encode_privacy(ebml_w: ebml::writer, privacy: privacy) {
|
|||
/* Returns an index of items in this class */
|
||||
fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
||||
id: node_id, path: ast_map::path,
|
||||
class_tps: [ty_param],
|
||||
items: [@class_member],
|
||||
global_index: @mut[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 */
|
||||
*global_index += [{val: m.id, pos: ebml_w.writer.tell()}];
|
||||
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);
|
||||
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 */ }
|
||||
}
|
||||
|
@ -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,
|
||||
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);
|
||||
encode_name(ebml_w, ident);
|
||||
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));
|
||||
alt item {
|
||||
some(it) {
|
||||
astencode::encode_inlined_item(ecx, ebml_w, path, ii_item(it));
|
||||
astencode::encode_inlined_item(ecx, ebml_w, path, it);
|
||||
}
|
||||
none {
|
||||
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,
|
||||
parent_id: node_id,
|
||||
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);
|
||||
encode_def_id(ebml_w, local_def(m.id));
|
||||
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
|
||||
the index, and the index needs to be in the item for the
|
||||
class itself */
|
||||
let idx = encode_info_for_class(ecx, ebml_w, item.id, path, items,
|
||||
index);
|
||||
let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps,
|
||||
items, index);
|
||||
/* Index the class*/
|
||||
add_to_index();
|
||||
/* 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);
|
||||
encode_family(ebml_w, purity_fn_family(m.decl.purity));
|
||||
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_def_id(ebml_w, local_def(m.id));
|
||||
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) {
|
||||
ast_map::node_item(_, pt) {
|
||||
encode_info_for_item(ecx, ebml_w, i, index, *pt);
|
||||
/* TODO: encode info for class items! */
|
||||
/* encode ctor, then encode items */
|
||||
alt i.node {
|
||||
item_class(tps,_,ctor) {
|
||||
|
@ -737,7 +736,10 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
|||
ctor.node.id);
|
||||
*index += [{val: ctor.node.id, pos: ebml_w.writer.tell()}];
|
||||
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)
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
|
|
|
@ -44,10 +44,16 @@ enum ast_node {
|
|||
// order they are introduced.
|
||||
node_arg(arg, 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),
|
||||
}
|
||||
|
||||
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 ctx = {map: map, mut path: path,
|
||||
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
|
||||
// add it to the table now:
|
||||
alt ii {
|
||||
ii_item(i) { /* fallthrough */ }
|
||||
ii_item(_) | ii_ctor(_,_,_,_) { /* fallthrough */ }
|
||||
ii_native(i) {
|
||||
cx.map.insert(i.id, node_native_item(i, native_abi_rust_intrinsic,
|
||||
@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.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);
|
||||
}
|
||||
|
||||
|
@ -166,8 +182,10 @@ fn map_item(i: @item, cx: ctx, v: vt) {
|
|||
map_method(impl_did, extend(cx, i.ident), m, cx);
|
||||
}
|
||||
}
|
||||
item_res(_, _, _, dtor_id, ctor_id) {
|
||||
cx.map.insert(ctor_id, node_ctor(i, item_path));
|
||||
item_res(decl, tps, _, dtor_id, ctor_id) {
|
||||
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));
|
||||
}
|
||||
item_enum(vs, _) {
|
||||
|
@ -186,7 +204,6 @@ fn map_item(i: @item, cx: ctx, v: vt) {
|
|||
}
|
||||
}
|
||||
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 p = extend(cx, i.ident);
|
||||
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
|
||||
#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]
|
||||
}
|
||||
some(node_block(_)) {
|
||||
|
|
|
@ -214,15 +214,15 @@ fn visit_expr(ex: @expr, &&cx: @ctx, v: visit::vt<@ctx>) {
|
|||
|
||||
fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) {
|
||||
alt item.node {
|
||||
item_class(tps, items, ctor) {
|
||||
v.visit_ty_params(tps, cx, v);
|
||||
vec::map::<@class_member, ()>(items,
|
||||
{|i| v.visit_class_item(i, cx, v); });
|
||||
v.visit_fn(visit::fk_ctor(item.ident, tps), ctor.node.dec,
|
||||
ctor.node.body, ctor.span, ctor.node.id,
|
||||
@{in_ctor: some(ctor.node.self_id) with *cx}, v);
|
||||
}
|
||||
_ { visit::visit_item(item, cx, v); }
|
||||
item_class(tps, items, ctor) {
|
||||
v.visit_ty_params(tps, cx, v);
|
||||
vec::map::<@class_member, ()>(items,
|
||||
{|i| v.visit_class_item(i, cx, v); });
|
||||
visit::visit_class_ctor_helper(ctor, item.ident, tps,
|
||||
ast_util::local_def(item.id),
|
||||
@{in_ctor: some(ctor.node.self_id) with *cx}, v);
|
||||
}
|
||||
_ { visit::visit_item(item, cx, v); }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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); }
|
||||
let scope = alt fk {
|
||||
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) }
|
||||
visit::fk_anon(ast::proto_bare) { scope_bare_fn(decl, id, []) }
|
||||
visit::fk_anon(_) | visit::fk_fn_block { scope_fn_expr(decl, id, []) }
|
||||
|
|
|
@ -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),
|
||||
must_cast: true};
|
||||
}
|
||||
ast_map::node_ctor(i, _) {
|
||||
alt check ccx.tcx.items.get(i.id) {
|
||||
ast_map::node_item(i, pt) { (pt, i.ident) }
|
||||
}
|
||||
}
|
||||
ast_map::node_ctor(nm, _, _, pt) { (pt, nm) }
|
||||
_ { fail "unexpected node type"; }
|
||||
};
|
||||
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,
|
||||
impl_self(selfty), psubsts, fn_id.node);
|
||||
}
|
||||
ast_map::node_ctor(i, _) {
|
||||
alt check i.node {
|
||||
ast::item_res(decl, _, _, _, _) {
|
||||
ast_map::node_ctor(nm, tps, ct, _) {
|
||||
alt ct {
|
||||
ast_map::res_ctor(decl,_, _) {
|
||||
set_inline_hint(lldecl);
|
||||
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
|
||||
}
|
||||
ast::item_class(tps, _, ctor) {
|
||||
set_inline_hint_if_appr(i.attrs, lldecl);
|
||||
ast_map::class_ctor(ctor, parent_id) {
|
||||
// ctors don't have attrs, at least not right now
|
||||
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);
|
||||
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);
|
||||
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)) {
|
||||
ccx.external.insert(fn_id, some(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,
|
||||
body: ast::blk, llctor_decl: ValueRef,
|
||||
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
|
||||
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);
|
||||
let rslt_ty = ty::mk_class(ccx.tcx, 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));
|
||||
|
@ -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
|
||||
// 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),
|
||||
let fields = ty::class_items_as_fields(bcx_top.tcx(), parent_id,
|
||||
psubsts.tys);
|
||||
let mut bcx = bcx_top;
|
||||
// Initialize fields to zero so init assignments can validly
|
||||
|
@ -4381,7 +4381,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
|
|||
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);
|
||||
ctor.node.id, local_def(item.id), ctor.span);
|
||||
}
|
||||
// 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 {
|
||||
#debug("get_item_val: %d", id);
|
||||
alt ccx.item_vals.find(id) {
|
||||
some(v) { v }
|
||||
none {
|
||||
|
@ -4593,16 +4594,16 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
|
|||
exprt = true;
|
||||
register_fn(ccx, ni.span, *pth + [path_name(ni.ident)], ni.id)
|
||||
}
|
||||
ast_map::node_ctor(i, _) {
|
||||
alt check i.node {
|
||||
ast::item_res(_, _, _, _, _) {
|
||||
let my_path = item_path(ccx, i);
|
||||
let llctor = register_fn(ccx, i.span, my_path, id);
|
||||
ast_map::node_ctor(nm, tps, ct, pt) {
|
||||
let my_path = *pt + [path_name(nm)];
|
||||
alt ct {
|
||||
ast_map::res_ctor(_,_,sp) {
|
||||
let llctor = register_fn(ccx, sp, my_path, id);
|
||||
set_inline_hint(llctor);
|
||||
llctor
|
||||
}
|
||||
ast::item_class(_, _, ctor) {
|
||||
register_fn(ccx, i.span, item_path(ccx, i), id)
|
||||
ast_map::class_ctor(ctor, _) {
|
||||
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),
|
||||
crate_map: crate_map,
|
||||
dbg_cx: dbg_cx,
|
||||
class_ctors: int_hash::<int>(),
|
||||
class_ctors: int_hash::<ast::def_id>(),
|
||||
mut do_not_commit_warning_issued: false};
|
||||
|
||||
|
||||
|
|
|
@ -121,7 +121,9 @@ type crate_ctxt = {
|
|||
dbg_cx: option<debuginfo::debug_ctxt>,
|
||||
// Mapping from class constructors to parent class --
|
||||
// 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};
|
||||
|
||||
// Types used for llself.
|
||||
|
|
|
@ -757,13 +757,14 @@ fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
|
|||
ast_map::node_method(method, _, _) {
|
||||
(method.ident, method.decl.output, method.id)
|
||||
}
|
||||
ast_map::node_ctor(item, _) {
|
||||
alt item.node {
|
||||
ast::item_res(decl, _, _, _, ctor_id) {
|
||||
(item.ident, decl.output, ctor_id)
|
||||
}
|
||||
_ { fcx.ccx.sess.span_bug(item.span, "create_function: \
|
||||
expected an item_res here"); }
|
||||
ast_map::node_ctor(nm, _, ct, _) {
|
||||
alt ct {
|
||||
ast_map::res_ctor(decl, ctor_id, _) {
|
||||
(nm, decl.output, ctor_id)
|
||||
}
|
||||
ast_map::class_ctor(ctor,_) {
|
||||
fcx.ccx.sess.span_bug(ctor.span, "create_function: \
|
||||
expected a resource ctor here"); }
|
||||
}
|
||||
}
|
||||
ast_map::node_expr(expr) {
|
||||
|
|
|
@ -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);
|
||||
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_res(_, _, body, _, _), _}, _) |
|
||||
ast_map::node_method(@{body, _}, _, _) {
|
||||
handle_body(cx, body);
|
||||
}
|
||||
ast_map::node_ctor(@{node: item_res(_, _, _, _, _), _},_) |
|
||||
ast_map::node_ctor(_, _, ast_map::res_ctor(_, _, _), _) |
|
||||
ast_map::node_variant(_, _, _) {
|
||||
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;}
|
||||
}
|
||||
}
|
||||
ast_map::node_ctor(@{node: item_class(_, _, ctor), _}, _) {
|
||||
ast_map::node_ctor(_, _, ast_map::class_ctor(ctor, _), _){
|
||||
handle_body(cx, ctor.node.body);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ fn check_states_against_conditions(fcx: fn_ctxt,
|
|||
|
||||
/* Check that the return value is initialized */
|
||||
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) &&
|
||||
!ty::type_is_nil(ty::ty_fn_ret(ty::node_id_to_type(
|
||||
fcx.ccx.tcx, id))) &&
|
||||
|
|
|
@ -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)]
|
||||
}
|
||||
|
||||
ast_map::node_ctor(i, path) {
|
||||
*path + [ast_map::path_name(i.ident)]
|
||||
ast_map::node_ctor(nm, _, _, path) {
|
||||
*path + [ast_map::path_name(nm)]
|
||||
}
|
||||
|
||||
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) {
|
||||
some(tpt) { ret tpt; }
|
||||
none {
|
||||
#debug("lookup_item_type: looking up %?", did);
|
||||
// The item is in this crate. The caller should have added it to the
|
||||
// type cache already
|
||||
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 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 {
|
||||
|
|
|
@ -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,
|
||||
name: ast::ident, ty: ty::t, tps: [ty::t],
|
||||
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 n_tps = vec::len(substs), n_tys = vec::len(tps);
|
||||
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 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 {
|
||||
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");
|
||||
|
||||
}
|
||||
/* If not enough types were given, make some ty vars */
|
||||
substs += vec::from_fn(method_n_tps, {|_i|
|
||||
ty::mk_var(tcx, next_ty_var_id(fcx))
|
||||
});
|
||||
} else {
|
||||
/* If the right number of types were given, just add them on */
|
||||
substs += tps;
|
||||
}
|
||||
/*
|
||||
For a class method, "substs" here begins with the class ty
|
||||
params
|
||||
*/
|
||||
fcx.write_ty_substs(node_id, fty, substs);
|
||||
} else {
|
||||
if n_tys > 0u {
|
||||
|
@ -2209,7 +2234,6 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
|
|||
include_private: bool)
|
||||
-> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
|
||||
origin: method_origin, self_sub: option<self_subst>}> {
|
||||
#debug("lookup_method_inner_: %? %? %s", ms, parent, name);
|
||||
let mut i = 0u;
|
||||
for ms.each {|m|
|
||||
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 \
|
||||
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,
|
||||
n_tps: vec::len(*m.tps),
|
||||
substs: tps,
|
||||
|
|
21
src/test/auxiliary/cci_class_6.rs
Normal file
21
src/test/auxiliary/cci_class_6.rs
Normal 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 }
|
||||
}
|
||||
|
||||
}
|
15
src/test/run-pass/class-poly-methods-cross-crate.rs
Normal file
15
src/test/run-pass/class-poly-methods-cross-crate.rs
Normal 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);
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
// xfail-test
|
||||
// needs metadata encoding on Windows
|
||||
class cat<U> {
|
||||
priv {
|
||||
let mut info : [U];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue