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_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 */)
}
//

View file

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

View file

@ -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) {

View file

@ -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);

View file

@ -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)
}
}
}
// ______________________________________________________________________

View file

@ -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)
}
_ {}
}

View file

@ -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(_)) {

View file

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

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); }
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, []) }

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),
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};

View file

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

View file

@ -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) {

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);
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);
}
}

View file

@ -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))) &&

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)]
}
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 {

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,
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,

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> {
priv {
let mut info : [U];