Make cross-crate calls to class methods work

This commit is contained in:
Tim Chevalier 2012-03-22 18:03:12 -07:00
parent f7f1490d6e
commit 73a0c17d77
6 changed files with 99 additions and 24 deletions

View file

@ -78,7 +78,7 @@ const tag_path: uint = 0x40u;
const tag_path_len: uint = 0x41u;
const tag_path_elt_mod: uint = 0x42u;
const tag_path_elt_name: uint = 0x43u;
const tag_items_class_member: uint = 0x44u;
const tag_item_field: uint = 0x44u;
// used to encode crate_ctxt side tables
enum astencode_tag { // Reserves 0x50 -- 0x6f

View file

@ -13,6 +13,7 @@ import std::map::hashmap;
export get_symbol;
export get_class_fields;
export get_class_method;
// export get_class_method_ids;
export get_field_type;
export get_type_param_count;
@ -179,6 +180,16 @@ fn get_impl_method(cstore: cstore::cstore, def: ast::def_id, mname: str)
decoder::get_impl_method(cdata, def.node, mname)
}
/* Because classes use the iface format rather than the impl format
for their methods (so that get_iface_methods can be reused to get
class methods), classes require a slightly different version of
get_impl_method. Sigh. */
fn get_class_method(cstore: cstore::cstore, def: ast::def_id, mname: str)
-> ast::def_id {
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_class_method(cdata, def.node, mname)
}
fn item_is_intrinsic(cstore: cstore::cstore, def: ast::def_id) -> bool {
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::item_is_intrinsic(cdata, def.node)

View file

@ -23,6 +23,7 @@ export get_enum_variants;
export get_type;
export get_type_param_count;
export get_impl_iface;
export get_class_method;
export get_impl_method;
export lookup_def;
export lookup_item_name;
@ -289,6 +290,25 @@ fn get_impl_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
option::get(found)
}
fn get_class_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
let items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
let mut found = none;
let cls_items = alt maybe_find_item(id, items) {
some(it) { it }
none { fail (#fmt("get_class_method: class id not found \
when looking up method %s", name)) }};
ebml::tagged_docs(cls_items, tag_item_method) {|mid|
let m_did = class_member_id(mid, cdata);
if item_name(mid) == name {
found = some(m_did);
}
}
alt found {
some(found) { found }
none { fail (#fmt("get_class_method: no method named %s", name)) }
}
}
fn item_is_intrinsic(cdata: cmd, id: ast::node_id) -> bool {
let mut intrinsic = false;
ebml::tagged_docs(lookup_item(id, cdata.data), tag_item_is_intrinsic,
@ -306,6 +326,7 @@ fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path {
fn maybe_get_item_ast(cdata: cmd, tcx: ty::ctxt, maps: maps,
id: ast::node_id) -> csearch::found_ast {
#debug("Looking up item: %d", id);
let item_doc = lookup_item(id, cdata.data);
let path = vec::init(item_path(item_doc));
alt astencode::decode_inlined_item(cdata, tcx, maps, path, item_doc) {
@ -389,6 +410,7 @@ fn get_impls_for_mod(cdata: cmd, m_id: ast::node_id,
@result
}
/* Works for both classes and ifaces */
fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
-> @[ty::method] {
let data = cdata.data;
@ -417,7 +439,7 @@ fn get_class_members(cdata: cmd, id: ast::node_id,
let data = cdata.data;
let item = lookup_item(id, data);
let mut result = [];
ebml::tagged_docs(item, tag_items_data_item) {|an_item|
ebml::tagged_docs(item, tag_item_field) {|an_item|
if item_family(an_item) == family {
let name = item_name(an_item);
let did = class_member_id(an_item, cdata);

View file

@ -353,19 +353,12 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod,
/* 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, name: ident,
tps: [ty_param], items: [@class_item])
id: node_id, path: ast_map::path,
items: [@class_item],
global_index: @mutable[entry<int>])
-> [entry<int>] {
let index = @mutable [];
let tcx = ecx.ccx.tcx;
encode_def_id(ebml_w, local_def(id));
encode_family(ebml_w, 'C');
encode_type_param_bounds(ebml_w, ecx, tps);
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
encode_name(ebml_w, name);
encode_path(ebml_w, path, ast_map::path_name(name));
for ci in items {
/* We encode both private and public fields -- need to include
private fields to get the offsets right */
@ -380,22 +373,23 @@ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
/* TODO: mutability */
encode_def_id(ebml_w, local_def(id));
ebml_w.end_tag();
}
class_method(m) {
*index += [{val: m.id, pos: ebml_w.writer.tell()}];
ebml_w.start_tag(tag_items_data_item);
encode_family(ebml_w, 'h');
encode_name(ebml_w, m.ident);
/* Not sure whether we really need to have two indices,
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, []);
}
}
ebml_w.end_tag();
}
*index
}
@ -404,6 +398,7 @@ 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) {
ebml_w.start_tag(tag_items_data_item);
encode_name(ebml_w, ident);
encode_def_id(ebml_w, local_def(id));
encode_family(ebml_w, purity_fn_family(decl.purity));
encode_type_param_bounds(ebml_w, ecx, tps);
@ -469,10 +464,16 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
let tcx = ecx.ccx.tcx;
let must_write = alt item.node { item_enum(_, _) { true } _ { false } };
if !must_write && !ecx.ccx.reachable.contains_key(item.id) { ret; }
*index += [{val: item.id, pos: ebml_w.writer.tell()}];
fn add_to_index_(item: @item, ebml_w: ebml::writer,
index: @mutable [entry<int>]) {
*index += [{val: item.id, pos: ebml_w.writer.tell()}];
}
let add_to_index = bind add_to_index_(item, ebml_w, index);
alt item.node {
item_const(_, _) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'c');
@ -482,6 +483,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
ebml_w.end_tag();
}
item_fn(decl, tps, _) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, purity_fn_family(decl.purity));
@ -496,9 +498,11 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
ebml_w.end_tag();
}
item_mod(m) {
add_to_index();
encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident);
}
item_native_mod(_) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'n');
@ -507,6 +511,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
ebml_w.end_tag();
}
item_ty(_, tps) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'y');
@ -517,6 +522,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
ebml_w.end_tag();
}
item_enum(variants, tps) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 't');
@ -533,15 +539,50 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
path, index, tps);
}
item_class(tps,items,ctor) {
/* First, encode the fields and methods
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);
/* Index the class*/
add_to_index();
/* Now, make an item for the class itself */
ebml_w.start_tag(tag_items_data_item);
let idx = encode_info_for_class(ecx, ebml_w, item.id, path,
item.ident, tps, items);
/* each class must have its own index */
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'C');
encode_type_param_bounds(ebml_w, ecx, tps);
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
encode_path(ebml_w, path, ast_map::path_name(item.ident));
/* Encode def_ids for each field and method
for methods, write all the stuff get_iface_method
needs to know*/
let (fs,ms) = ast_util::split_class_items(items);
for f in fs {
ebml_w.start_tag(tag_item_field);
encode_family(ebml_w, 'g');
encode_name(ebml_w, f.ident);
encode_def_id(ebml_w, local_def(f.id));
ebml_w.end_tag();
}
for m in ms {
ebml_w.start_tag(tag_item_method);
#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(ecx, ebml_w, node_id_to_type(tcx, m.id));
encode_def_id(ebml_w, local_def(m.id));
ebml_w.end_tag();
}
/* Each class has its own index -- encode it */
let bkts = create_index(idx, hash_node_id);
encode_index(ebml_w, bkts, write_int);
ebml_w.end_tag();
}
item_res(_, tps, _, _, ctor_id) {
add_to_index();
let fn_ty = node_id_to_type(tcx, ctor_id);
ebml_w.start_tag(tag_items_data_item);
@ -565,6 +606,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
ebml_w.end_tag();
}
item_impl(tps, ifce, _, methods) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'i');
@ -598,6 +640,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
}
}
item_iface(tps, ms) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'I');

View file

@ -2606,7 +2606,7 @@ fn lookup_class_method_by_name(cx:ctxt, did: ast::def_id, name: ident,
name));
}
else {
csearch::get_impl_method(cx.sess.cstore, did, name)
csearch::get_class_method(cx.sess.cstore, did, name)
}
}

View file

@ -1,8 +1,7 @@
// xfail-test
// xfail-fast
// aux-build:cci_class_2.rs
use cci_class;
import cci_class::kitties::*;
use cci_class_2;
import cci_class_2::kitties::*;
fn main() {
let nyan : cat = cat(52u, 99);