Make cross-crate calls to class methods work
This commit is contained in:
parent
f7f1490d6e
commit
73a0c17d77
6 changed files with 99 additions and 24 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue