Classes WIP
Cross-crate metadata for classes works well enough that programs with classes in other crates compile successfully, but output wrong results. Checking in work so far to avoid merge hassles. (Tests are xfailed.)
This commit is contained in:
parent
47d468f08c
commit
1680ccce1e
@ -78,6 +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;
|
||||
|
||||
// used to encode crate_ctxt side tables
|
||||
enum astencode_tag { // Reserves 0x50 -- 0x6f
|
||||
|
@ -9,6 +9,7 @@ import middle::trans::common::maps;
|
||||
import std::map::hashmap;
|
||||
|
||||
export get_symbol;
|
||||
export get_class_items;
|
||||
export get_type_param_count;
|
||||
export lookup_defs;
|
||||
export lookup_method_purity;
|
||||
@ -35,6 +36,7 @@ fn get_type_param_count(cstore: cstore::cstore, def: ast::def_id) -> uint {
|
||||
fn lookup_defs(cstore: cstore::cstore, cnum: ast::crate_num,
|
||||
path: [ast::ident]) -> [ast::def] {
|
||||
let result = [];
|
||||
#debug("lookup_defs: path = %? cnum = %?", path, cnum);
|
||||
for (c, data, def) in resolve_path(cstore, cnum, path) {
|
||||
result += [decoder::lookup_def(c, data, def)];
|
||||
}
|
||||
@ -116,6 +118,12 @@ fn get_iface_methods(tcx: ty::ctxt, def: ast::def_id) -> @[ty::method] {
|
||||
decoder::get_iface_methods(cdata, def.node, tcx)
|
||||
}
|
||||
|
||||
fn get_class_items(tcx: ty::ctxt, def: ast::def_id) -> [@ty::class_item_ty] {
|
||||
let cstore = tcx.sess.cstore;
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
decoder::get_class_items(cdata, def.node, tcx)
|
||||
}
|
||||
|
||||
fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_bounds_and_ty {
|
||||
let cstore = tcx.sess.cstore;
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
|
@ -162,10 +162,9 @@ fn get_dep_hashes(cstore: cstore) -> [str] {
|
||||
}
|
||||
|
||||
fn get_path(cstore: cstore, d: ast::def_id) -> [str] {
|
||||
alt p(cstore).mod_path_map.find(d) {
|
||||
option::some(ds) { str::split_str(ds, "::") }
|
||||
option::none { [] }
|
||||
}
|
||||
// let f = bind str::split_str(_, "::");
|
||||
option::maybe([], p(cstore).mod_path_map.find(d),
|
||||
{|ds| str::split_str(ds, "::")})
|
||||
}
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
@ -9,11 +9,13 @@ import front::attr;
|
||||
import middle::ty;
|
||||
import middle::ast_map;
|
||||
import common::*;
|
||||
import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data};
|
||||
import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data,
|
||||
parse_ident};
|
||||
import syntax::print::pprust;
|
||||
import cmd=cstore::crate_metadata;
|
||||
import middle::trans::common::maps;
|
||||
|
||||
export get_class_items;
|
||||
export get_symbol;
|
||||
export get_enum_variants;
|
||||
export get_type;
|
||||
@ -84,7 +86,10 @@ fn find_item(item_id: int, items: ebml::doc) -> ebml::doc {
|
||||
// to the item data.
|
||||
fn lookup_item(item_id: int, data: @[u8]) -> ebml::doc {
|
||||
let items = ebml::get_doc(ebml::doc(data), tag_items);
|
||||
ret find_item(item_id, items);
|
||||
alt maybe_find_item(item_id, items) {
|
||||
none { fail(#fmt("lookup_item: id not found: %d", item_id)); }
|
||||
some(d) { d }
|
||||
}
|
||||
}
|
||||
|
||||
fn item_family(item: ebml::doc) -> char {
|
||||
@ -105,6 +110,11 @@ fn item_parent_item(d: ebml::doc) -> option<ast::def_id> {
|
||||
found
|
||||
}
|
||||
|
||||
fn class_field_id(d: ebml::doc) -> ast::def_id {
|
||||
let tagdoc = ebml::get_doc(d, tag_def_id);
|
||||
ret parse_def_id(ebml::doc_data(tagdoc));
|
||||
}
|
||||
|
||||
fn variant_disr_val(d: ebml::doc) -> option<int> {
|
||||
option::chain(ebml::maybe_get_doc(d, tag_disr_val)) {|val_doc|
|
||||
int::parse_buf(ebml::doc_data(val_doc), 10u)
|
||||
@ -178,6 +188,7 @@ fn resolve_path(path: [ast::ident], data: @[u8]) -> [ast::def_id] {
|
||||
let paths = ebml::get_doc(md, tag_paths);
|
||||
let eqer = bind eq_item(_, s);
|
||||
let result: [ast::def_id] = [];
|
||||
#debug("resolve_path: looking up %s", s);
|
||||
for doc: ebml::doc in lookup_hash(paths, eqer, hash_path(s)) {
|
||||
let did_doc = ebml::get_doc(doc, tag_def_id);
|
||||
result += [parse_def_id(ebml::doc_data(did_doc))];
|
||||
@ -226,6 +237,7 @@ fn lookup_def(cnum: ast::crate_num, data: @[u8], did_: ast::def_id) ->
|
||||
// We treat references to enums as references to types.
|
||||
alt check fam_ch {
|
||||
'c' { ast::def_const(did) }
|
||||
'C' { ast::def_class(did) }
|
||||
'u' { ast::def_fn(did, ast::unsafe_fn) }
|
||||
'f' { ast::def_fn(did, ast::impure_fn) }
|
||||
'p' { ast::def_fn(did, ast::pure_fn) }
|
||||
@ -393,10 +405,48 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
||||
@result
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME
|
||||
This is not working. metadata is broken -- fields get encoded correctly,
|
||||
but not decoded. look at this code, see what it's actually writing out
|
||||
also see what "data" is
|
||||
*/
|
||||
fn get_class_items(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
||||
-> [@ty::class_item_ty] {
|
||||
let data = cdata.data;
|
||||
let item = lookup_item(id, data), result = [];
|
||||
#debug("get_class_items: %s", item_name(item));
|
||||
#debug("item: %?", item);
|
||||
// right tag?
|
||||
ebml::tagged_docs(item, tag_items_class_member) {|an_item|
|
||||
let fam = item_family(an_item);
|
||||
let decl = alt check fam {
|
||||
'g' {
|
||||
let name = item_name(an_item);
|
||||
#debug("why hello there! %s", name);
|
||||
let ty = doc_type(an_item, tcx, cdata);
|
||||
let did = class_field_id(an_item);
|
||||
{ident: name,
|
||||
id: did.node,
|
||||
contents: ty::var_ty(ty)}
|
||||
}
|
||||
_ {
|
||||
fail; // FIXME
|
||||
}
|
||||
};
|
||||
result += [@decl];
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn family_has_type_params(fam_ch: char) -> bool {
|
||||
alt check fam_ch {
|
||||
'c' | 'T' | 'm' | 'n' { false }
|
||||
'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' { true }
|
||||
'c' | 'T' | 'm' | 'n' | 'g' | 'h' { false }
|
||||
'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' | 'C'
|
||||
| 'a'
|
||||
{ true }
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,6 +484,7 @@ fn item_family_to_str(fam: char) -> str {
|
||||
'v' { ret "enum"; }
|
||||
'i' { ret "impl"; }
|
||||
'I' { ret "iface"; }
|
||||
'C' { ret "class"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,23 @@ fn encode_native_module_item_paths(ebml_w: ebml::writer, nmod: native_mod,
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_class_item_paths(ebml_w: ebml::writer,
|
||||
items: [@class_item], path: [str], &index: [entry<str>]) {
|
||||
for it in items {
|
||||
alt it.node.privacy {
|
||||
priv { cont; }
|
||||
pub {
|
||||
let (id, ident) = alt it.node.decl {
|
||||
instance_var(v, _, _, vid) { (vid, v) }
|
||||
class_method(it) { (it.id, it.ident) }
|
||||
};
|
||||
add_to_index(ebml_w, path, index, ident);
|
||||
encode_named_def_id(ebml_w, ident, local_def(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
|
||||
module: _mod, path: [str], &index: [entry<str>]) {
|
||||
// FIXME factor out add_to_index/start/encode_name/encode_def_id/end ops
|
||||
@ -128,8 +145,20 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
|
||||
encode_def_id(ebml_w, local_def(it.id));
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
item_class(_,_,_) {
|
||||
fail "encode: implement item_class";
|
||||
item_class(tps,items,ctor) {
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
ebml_w.start_tag(tag_paths_data_item);
|
||||
encode_name(ebml_w, it.ident);
|
||||
encode_def_id(ebml_w, local_def(it.id));
|
||||
ebml_w.end_tag();
|
||||
ebml_w.start_tag(tag_paths);
|
||||
/* a bit confused -- adding the same ident twice
|
||||
(once for class, once for ctor) */
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
encode_named_def_id(ebml_w, it.ident, local_def(ctor.node.id));
|
||||
encode_class_item_paths(ebml_w, items, path + [it.ident],
|
||||
index);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
item_enum(variants, tps) {
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
@ -312,13 +341,80 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod,
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { ecx.ccx.tcx.sess.bug("encode_info_for_mod: \
|
||||
undocumented invariant"); }
|
||||
_ { ecx.ccx.tcx.sess.bug(#fmt("encode_info_for_mod: empty impl_map \
|
||||
entry for %?", path)); }
|
||||
}
|
||||
encode_path(ebml_w, path, ast_map::path_mod(name));
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
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]) {
|
||||
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);
|
||||
|
||||
for ci in items {
|
||||
alt ci.node.privacy {
|
||||
pub {
|
||||
ebml_w.start_tag(tag_items_class_member); // ???
|
||||
alt ci.node.decl {
|
||||
instance_var(nm, _, _, id) {
|
||||
#debug("encode_info_for_class: doing %s", nm);
|
||||
encode_family(ebml_w, 'g');
|
||||
encode_name(ebml_w, nm);
|
||||
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
|
||||
/* TODO: mutability */
|
||||
encode_def_id(ebml_w, local_def(id));
|
||||
}
|
||||
class_method(it) {
|
||||
encode_family(ebml_w, 'h');
|
||||
encode_name(ebml_w, it.ident);
|
||||
alt it.node {
|
||||
item_fn(fdecl, tps, _) {
|
||||
encode_info_for_fn(ecx, ebml_w, it.id, it.ident,
|
||||
path, none, tps, fdecl);
|
||||
}
|
||||
_ { fail; /* TODO */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
priv {
|
||||
/* don't export it, then! */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_def_id(ebml_w, local_def(id));
|
||||
encode_family(ebml_w, purity_fn_family(decl.purity));
|
||||
encode_type_param_bounds(ebml_w, ecx, tps);
|
||||
let its_ty = node_id_to_type(ecx.ccx.tcx, id);
|
||||
#debug("fn name = %s ty = %s", ident,
|
||||
util::ppaux::ty_to_str(ecx.ccx.tcx, its_ty));
|
||||
encode_type(ecx, ebml_w, its_ty);
|
||||
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));
|
||||
}
|
||||
none {
|
||||
encode_symbol(ecx, ebml_w, id);
|
||||
}
|
||||
}
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
fn purity_fn_family(p: purity) -> char {
|
||||
alt p {
|
||||
unsafe_fn { 'u' }
|
||||
@ -404,8 +500,13 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
|
||||
encode_enum_variant_info(ecx, ebml_w, item.id, variants,
|
||||
path, index, tps);
|
||||
}
|
||||
item_class(_,_,_) {
|
||||
fail "encode: implement item_class";
|
||||
item_class(tps,items,_) {
|
||||
/* We're not forgetting about the ctor here! It gets
|
||||
encoded elsewhere */
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_info_for_class(ecx, ebml_w, item.id, path, item.ident,
|
||||
tps, items);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
item_res(_, tps, _, _, ctor_id) {
|
||||
let fn_ty = node_id_to_type(tcx, ctor_id);
|
||||
@ -539,6 +640,21 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
||||
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 */
|
||||
ast_map::node_ctor(i, path) {
|
||||
alt i.node {
|
||||
item_class(tps, _, ctor) {
|
||||
#debug("class, encoding a fn: %d", ctor.node.id);
|
||||
/* this is assuming that ctors aren't inlined...
|
||||
probably shouldn't assume that */
|
||||
encode_info_for_fn(ecx, ebml_w, ctor.node.id, i.ident,
|
||||
*path, none, tps, ctor.node.dec)
|
||||
}
|
||||
_ { /* TODO: should handle item_res, probably */ }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
visit_native_item: {|ni, cx, v|
|
||||
|
@ -7,7 +7,7 @@ import syntax::ast_util::respan;
|
||||
import middle::ty;
|
||||
import std::map::hashmap;
|
||||
|
||||
export parse_ty_data, parse_def_id;
|
||||
export parse_ty_data, parse_def_id, parse_ident;
|
||||
export parse_bounds_data;
|
||||
|
||||
// Compact string representation for ty::t values. API ty_str &
|
||||
@ -303,6 +303,17 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
||||
ty::mk_with_id(st.tcx, inner, def)
|
||||
}
|
||||
'B' { ty::mk_opaque_box(st.tcx) }
|
||||
'a' {
|
||||
#debug("saw a class");
|
||||
assert (next(st) == '[');
|
||||
#debug("saw a [");
|
||||
let did = parse_def(st, conv);
|
||||
#debug("parsed a def_id %?", did);
|
||||
let params: [ty::t] = [];
|
||||
while peek(st) != ']' { params += [parse_ty(st, conv)]; }
|
||||
assert (next(st) == ']');
|
||||
ret ty::mk_class(st.tcx, did, params);
|
||||
}
|
||||
c { #error("unexpected char in type string: %c", c); fail;}
|
||||
}
|
||||
}
|
||||
@ -387,8 +398,18 @@ fn parse_def_id(buf: [u8]) -> ast::def_id {
|
||||
for b: u8 in crate_part { crate_part_vec += [b]; }
|
||||
for b: u8 in def_part { def_part_vec += [b]; }
|
||||
|
||||
let crate_num = option::get(uint::parse_buf(crate_part_vec, 10u)) as int;
|
||||
let def_num = option::get(uint::parse_buf(def_part_vec, 10u)) as int;
|
||||
let crate_num = alt uint::parse_buf(crate_part_vec, 10u) {
|
||||
some(cn) { cn as int }
|
||||
none { fail (#fmt("internal error: parse_def_id: error parsing %? \
|
||||
as crate",
|
||||
crate_part_vec)); }
|
||||
};
|
||||
let def_num = alt uint::parse_buf(def_part_vec, 10u) {
|
||||
some(dn) { dn as int }
|
||||
none { fail (#fmt("internal error: parse_def_id: error parsing %? \
|
||||
as id",
|
||||
def_part_vec)); }
|
||||
};
|
||||
ret {crate: crate_num, node: def_num};
|
||||
}
|
||||
|
||||
|
@ -214,10 +214,15 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
||||
}
|
||||
ty::ty_opaque_box { w.write_char('B'); }
|
||||
ty::ty_class(def, tys) {
|
||||
w.write_str("c[");
|
||||
w.write_str(cx.ds(def));
|
||||
w.write_char('|');
|
||||
#debug("~~~~ %s", "a[");
|
||||
w.write_str("a[");
|
||||
let s = cx.ds(def);
|
||||
#debug("~~~~ %s", s);
|
||||
w.write_str(s);
|
||||
#debug("~~~~ %s", "|");
|
||||
w.write_str("|");
|
||||
for t: ty::t in tys { enc_ty(w, cx, t); }
|
||||
#debug("~~~~ %s", "]");
|
||||
w.write_char(']');
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ enum ast_node {
|
||||
// order they are introduced.
|
||||
node_arg(arg, uint),
|
||||
node_local(uint),
|
||||
node_ctor(@item),
|
||||
node_ctor(@item, @path),
|
||||
node_block(blk),
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ fn map_item(i: @item, cx: ctx, v: vt) {
|
||||
}
|
||||
}
|
||||
item_res(_, _, _, dtor_id, ctor_id) {
|
||||
cx.map.insert(ctor_id, node_ctor(i));
|
||||
cx.map.insert(ctor_id, node_ctor(i, item_path));
|
||||
cx.map.insert(dtor_id, node_item(i, item_path));
|
||||
}
|
||||
item_enum(vs, _) {
|
||||
@ -173,7 +173,7 @@ fn map_item(i: @item, cx: ctx, v: vt) {
|
||||
}
|
||||
}
|
||||
item_class(_, _, ctor) {
|
||||
cx.map.insert(ctor.node.id, node_ctor(i));
|
||||
cx.map.insert(ctor.node.id, node_ctor(i, item_path));
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ fn map_crate(e: @env, c: @ast::crate) {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: a glob export works as an implict import, along with a
|
||||
// Note: a glob export works as an implicit import, along with a
|
||||
// re-export of anything that was exported at the glob-target location.
|
||||
// So we wind up reusing the glob-import machinery when looking at
|
||||
// glob exports. They just do re-exporting in a later step.
|
||||
|
@ -1886,7 +1886,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
|
||||
must_cast: true,
|
||||
intrinsic: abi == ast::native_abi_rust_intrinsic};
|
||||
}
|
||||
ast_map::node_ctor(i) {
|
||||
ast_map::node_ctor(i, _) {
|
||||
alt check ccx.tcx.items.get(i.id) {
|
||||
ast_map::node_item(i, pt) { (pt, i.ident) }
|
||||
}
|
||||
@ -1926,7 +1926,7 @@ 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, none);
|
||||
}
|
||||
ast_map::node_ctor(i) {
|
||||
ast_map::node_ctor(i, _) {
|
||||
alt check i.node {
|
||||
ast::item_res(decl, _, _, _, _) {
|
||||
set_inline_hint(lldecl);
|
||||
@ -4378,7 +4378,7 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
|
||||
ast_map::node_native_item(ni, _, pth) {
|
||||
native::decl_native_fn(ccx, ni, *pth + [path_name(ni.ident)])
|
||||
}
|
||||
ast_map::node_ctor(i) {
|
||||
ast_map::node_ctor(i, _) {
|
||||
alt check i.node {
|
||||
ast::item_res(_, _, _, _, _) {
|
||||
let my_path = item_path(ccx, i);
|
||||
|
@ -746,7 +746,7 @@ 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) {
|
||||
ast_map::node_ctor(item, _) {
|
||||
alt item.node {
|
||||
ast::item_res(decl, _, _, _, ctor_id) {
|
||||
(item.ident, decl.output, ctor_id)
|
||||
|
@ -83,13 +83,12 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
ty::ty_constr(subt,_) { type_of(cx, subt) }
|
||||
ty::ty_class(did, _) {
|
||||
let tys: [TypeRef] = [];
|
||||
// TODO: only handles local classes
|
||||
let cls_items = lookup_class_items(cx.tcx, did);
|
||||
let cls_items = lookup_class_item_tys(cx.tcx, did);
|
||||
for ci in cls_items {
|
||||
// only instance vars are record fields at runtime
|
||||
alt ci.node.decl {
|
||||
ast::instance_var(_,_,_,_) {
|
||||
let fty = type_of(cx, class_item_type(cx.tcx, ci));
|
||||
alt ci.contents {
|
||||
var_ty(t) {
|
||||
let fty = type_of(cx, t);
|
||||
tys += [fty];
|
||||
}
|
||||
_ {}
|
||||
|
@ -67,7 +67,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
|
||||
ast_map::node_method(@{body, _}, _, _) {
|
||||
handle_body(cx, body);
|
||||
}
|
||||
ast_map::node_ctor(@{node: item_res(_, _, _, _, _), _}) |
|
||||
ast_map::node_ctor(@{node: item_res(_, _, _, _, _), _},_) |
|
||||
ast_map::node_variant(_, _, _) {
|
||||
uint::range(0u, n_tps) {|n| cx.uses[n] |= use_repr;}
|
||||
}
|
||||
@ -76,7 +76,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
|
||||
uint::range(0u, n_tps) {|n| cx.uses[n] |= use_tydesc;}
|
||||
}
|
||||
}
|
||||
ast_map::node_ctor(@{node: item_class(_, _, ctor), _}) {
|
||||
ast_map::node_ctor(@{node: item_class(_, _, ctor), _}, _) {
|
||||
ccx.sess.unimpl("type uses in class constructor");
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ export arg;
|
||||
export args_eq;
|
||||
export ast_constr_to_constr;
|
||||
export block_ty;
|
||||
export class_item_type;
|
||||
export class_contents_ty;
|
||||
export class_item_ty;
|
||||
export class_items_as_fields;
|
||||
export constr;
|
||||
export constr_general;
|
||||
@ -40,7 +41,7 @@ export fm_general, fm_rptr;
|
||||
export get_element_type;
|
||||
export is_binopable;
|
||||
export is_pred_ty;
|
||||
export lookup_class_items;
|
||||
export lookup_class_item_tys;
|
||||
export lookup_item_type;
|
||||
export method;
|
||||
export method_idx;
|
||||
@ -157,6 +158,16 @@ type constr_table = hashmap<ast::node_id, [constr]>;
|
||||
|
||||
type mt = {ty: t, mutbl: ast::mutability};
|
||||
|
||||
type class_item_ty = {
|
||||
ident: ident,
|
||||
id: node_id,
|
||||
contents: class_contents_ty
|
||||
};
|
||||
|
||||
enum class_contents_ty {
|
||||
var_ty(t), // FIXME: need mutability, too
|
||||
method_ty(fn_decl)
|
||||
}
|
||||
|
||||
// Contains information needed to resolve types and (in the future) look up
|
||||
// the types of AST nodes.
|
||||
@ -2331,8 +2342,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) {
|
||||
item_path(cx, ast_util::local_def(i.id))
|
||||
ast_map::node_ctor(i, path) {
|
||||
*path + [ast_map::path_name(i.ident)]
|
||||
}
|
||||
|
||||
ast_map::node_expr(_) | ast_map::node_arg(_, _) |
|
||||
@ -2406,9 +2417,13 @@ fn enum_variant_with_id(cx: ctxt, enum_id: ast::def_id,
|
||||
// If the given item is in an external crate, looks up its type and adds it to
|
||||
// the type cache. Returns the type parameters and type.
|
||||
fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
|
||||
/*
|
||||
Are we putting class ids in the tcache (where does that happen?)
|
||||
*/
|
||||
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;
|
||||
@ -2419,54 +2434,75 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the list of items for a given class (in the item map).
|
||||
// Look up the list of item types for a given class
|
||||
// Fails if the id is not bound to a class.
|
||||
fn lookup_class_items(cx: ctxt, did: ast::def_id) -> [@class_item] {
|
||||
fn lookup_class_item_tys(cx: ctxt, did: ast::def_id) -> [@class_item_ty] {
|
||||
/*
|
||||
TODO: Check whether this is a local id or not; use csearch / tcache
|
||||
if it's external
|
||||
*/
|
||||
if did.crate == ast::local_crate {
|
||||
alt cx.items.find(did.node) {
|
||||
some(ast_map::node_item(i,_)) {
|
||||
alt i.node {
|
||||
ast::item_class(_, items, _) {
|
||||
items
|
||||
}
|
||||
_ { cx.sess.bug("class ID bound to non-class"); }
|
||||
alt i.node {
|
||||
ast::item_class(_, items, _) {
|
||||
class_item_tys(cx, items)
|
||||
}
|
||||
_ { cx.sess.bug("class ID bound to non-class"); }
|
||||
}
|
||||
}
|
||||
_ { cx.sess.bug("class ID not bound to an item"); }
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret csearch::get_class_items(cx, did);
|
||||
}
|
||||
}
|
||||
|
||||
// must be called after typechecking?
|
||||
fn class_item_tys(cx: ctxt, items: [@class_item]) -> [@class_item_ty] {
|
||||
let rslt = [];
|
||||
for it in items {
|
||||
alt it.node.decl {
|
||||
instance_var(nm, _, _, id) {
|
||||
rslt += [@{ident: nm, id: id,
|
||||
contents: var_ty(node_id_to_type(cx, id)) }];
|
||||
}
|
||||
class_method(it) {
|
||||
alt it.node {
|
||||
item_fn(dec, _, _) {
|
||||
rslt += [@{ident: it.ident, id: it.id,
|
||||
contents: method_ty(dec)}];
|
||||
}
|
||||
_ { fail; /* TODO */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rslt
|
||||
}
|
||||
|
||||
// Return a list of fields corresponding to the class's items
|
||||
// (as if the class was a record). trans uses this
|
||||
fn class_items_as_fields(cx:ctxt, did: ast::def_id) -> [field] {
|
||||
let rslt = [];
|
||||
for ci in lookup_class_items(cx, did) {
|
||||
rslt += [alt ci.node.decl {
|
||||
instance_var(i, _, _, id) {
|
||||
for ci in lookup_class_item_tys(cx, did) {
|
||||
alt ci.contents {
|
||||
var_ty(t) {
|
||||
// consider all instance vars mutable, because the
|
||||
// constructor may mutate all vars
|
||||
{ident: i, mt: {ty: node_id_to_type(cx, id),
|
||||
mutbl: m_mutbl}}
|
||||
}
|
||||
class_method(it) {
|
||||
{ident:it.ident, mt: {ty: node_id_to_type(cx, it.id),
|
||||
mutbl: m_const}}
|
||||
}
|
||||
}];
|
||||
rslt += [{ident: ci.ident, mt: {ty: t,
|
||||
mutbl: m_mutbl}}];
|
||||
}
|
||||
/* do nothing, since methods don't have a runtime
|
||||
representation? */
|
||||
method_ty(_) {
|
||||
}
|
||||
}
|
||||
}
|
||||
rslt
|
||||
}
|
||||
|
||||
// Looks up the type for a given class item. Must be called
|
||||
// post-typechecking.
|
||||
fn class_item_type(cx: ctxt, ci: @ast::class_item) -> t {
|
||||
alt ci.node.decl {
|
||||
ast::instance_var(_,_,_,id) { node_id_to_type(cx, id) }
|
||||
// TODO: only works for local classes
|
||||
ast::class_method(it) { lookup_item_type(cx,
|
||||
ast_util::local_def(it.id)).ty }
|
||||
}
|
||||
}
|
||||
|
||||
fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool {
|
||||
const tycat_other: int = 0;
|
||||
const tycat_bool: int = 1;
|
||||
|
@ -11,7 +11,7 @@ import pat_util::*;
|
||||
import middle::ty;
|
||||
import middle::ty::{node_id_to_type, arg, block_ty,
|
||||
expr_ty, field, node_type_table, mk_nil,
|
||||
ty_param_bounds_and_ty, lookup_class_items};
|
||||
ty_param_bounds_and_ty, lookup_class_item_tys};
|
||||
import util::ppaux::ty_to_str;
|
||||
import std::smallintmap;
|
||||
import std::map::{hashmap, int_hash};
|
||||
@ -419,29 +419,29 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::def_class(class_id) {
|
||||
alt tcx.items.find(class_id.node) {
|
||||
some(ast_map::node_item(
|
||||
@{node: ast::item_class(tps, _, _), _}, _)) {
|
||||
if vec::len(tps) != vec::len(path.node.types) {
|
||||
tcx.sess.span_err(ast_ty.span, "incorrect number \
|
||||
of type parameters to object type");
|
||||
}
|
||||
ty::mk_class(tcx, class_id,
|
||||
vec::map(path.node.types, {|ast_ty|
|
||||
do_ast_ty_to_ty(tcx,
|
||||
use_site,
|
||||
mode,
|
||||
ast_ty)
|
||||
}))
|
||||
ast::def_class(class_id) {
|
||||
if class_id.crate == ast::local_crate {
|
||||
alt tcx.items.find(class_id.node) {
|
||||
some(ast_map::node_item(
|
||||
@{node: ast::item_class(tps, _, _), _}, _)) {
|
||||
if vec::len(tps) != vec::len(path.node.types) {
|
||||
tcx.sess.span_err(ast_ty.span, "incorrect number \
|
||||
of type parameters to object type");
|
||||
}
|
||||
ty::mk_class(tcx, class_id, vec::map(path.node.types,
|
||||
{|ast_ty| ast_ty_to_ty(tcx, mode, ast_ty)}))
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_bug(ast_ty.span, "class id is unbound \
|
||||
in items");
|
||||
}
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_bug(ast_ty.span, #fmt("class id is \
|
||||
unbound in items"));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {
|
||||
else {
|
||||
getter(tcx, use_site, mode, class_id).ty
|
||||
}
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
"found type name used as a variable");
|
||||
}
|
||||
@ -1003,18 +1003,15 @@ mod collect {
|
||||
}
|
||||
ast::item_class(tps, members, ctor) {
|
||||
// Write the class type
|
||||
let {bounds,params} = mk_ty_params(tcx, tps);
|
||||
let class_ty = ty::mk_class(tcx, local_def(it.id), params);
|
||||
let tpt = {bounds: bounds, ty: class_ty};
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
write_ty(tcx, it.id, class_ty);
|
||||
let tpt = ty_of_item(tcx, m_collect, it);
|
||||
write_ty(tcx, it.id, tpt.ty);
|
||||
// Write the ctor type
|
||||
let t_ctor = ty::mk_fn(tcx,
|
||||
ty_of_fn_decl(tcx, m_collect,
|
||||
ast::proto_any, ctor.node.dec));
|
||||
write_ty(tcx, ctor.node.id, t_ctor);
|
||||
tcx.tcache.insert(local_def(ctor.node.id),
|
||||
{bounds: bounds, ty: t_ctor});
|
||||
{bounds: tpt.bounds, ty: t_ctor});
|
||||
/* FIXME: check for proper public/privateness */
|
||||
// Write the type of each of the members
|
||||
for m in members {
|
||||
@ -1941,25 +1938,16 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
|
||||
result
|
||||
}
|
||||
|
||||
fn lookup_field_ty(cx: ty::ctxt, items:[@ast::class_item],
|
||||
// problem -- class_item_ty should really be only used for internal stuff.
|
||||
// or should have a privacy field.
|
||||
fn lookup_field_ty(cx: ty::ctxt, items:[@ty::class_item_ty],
|
||||
fieldname: ast::ident, sp: span)
|
||||
-> ty::t {
|
||||
for item in items {
|
||||
// this is an access outside the class, so accessing a private
|
||||
// field is an error
|
||||
alt item.node.decl {
|
||||
ast::instance_var(declname, t, _, _) if declname == fieldname {
|
||||
alt item.node.privacy {
|
||||
ast::priv {
|
||||
cx.sess.span_fatal(sp, "accessed private field outside \
|
||||
its enclosing class");
|
||||
}
|
||||
ast::pub {
|
||||
ret ast_ty_to_ty(cx, m_check, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { /* do nothing */ }
|
||||
#debug("%s $$$ %s", fieldname, item.ident);
|
||||
alt item.contents {
|
||||
ty::var_ty(t) if item.ident == fieldname { ret t; }
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
cx.sess.span_fatal(sp, #fmt("unbound field %s", fieldname));
|
||||
@ -2763,10 +2751,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||
ty::ty_class(base_id, _params) {
|
||||
// (1) verify that the class id actually has a field called
|
||||
// field
|
||||
// For now, this code assumes the class is defined in the local
|
||||
// crate
|
||||
// FIXME: handle field references to classes in external crate
|
||||
let cls_items = lookup_class_items(tcx, base_id);
|
||||
let cls_items = lookup_class_item_tys(tcx, base_id);
|
||||
let field_ty = lookup_field_ty(fcx.ccx.tcx, cls_items, field,
|
||||
expr.span);
|
||||
// (2) look up what field's type is, and return it
|
||||
|
13
src/test/auxiliary/cci_class.rs
Normal file
13
src/test/auxiliary/cci_class.rs
Normal file
@ -0,0 +1,13 @@
|
||||
mod kitties {
|
||||
|
||||
class cat {
|
||||
priv {
|
||||
let mutable meows : uint;
|
||||
}
|
||||
|
||||
let how_hungry : int;
|
||||
|
||||
new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; }
|
||||
}
|
||||
|
||||
}
|
12
src/test/run-pass/classes-simple-cross-crate.rs
Normal file
12
src/test/run-pass/classes-simple-cross-crate.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// xfail-test
|
||||
// xfail-fast
|
||||
// aux-build:cci_class.rs
|
||||
use cci_class;
|
||||
import cci_class::kitties::*;
|
||||
|
||||
fn main() {
|
||||
let nyan : cat = cat(52u, 99);
|
||||
let kitty = cat(1000u, 2);
|
||||
assert(nyan.how_hungry == 99);
|
||||
assert(kitty.how_hungry == 2);
|
||||
}
|
19
src/test/run-pass/classes-simple-method.rs
Normal file
19
src/test/run-pass/classes-simple-method.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// xfail-test
|
||||
class cat {
|
||||
priv {
|
||||
let mutable meows : uint;
|
||||
}
|
||||
|
||||
let how_hungry : int;
|
||||
|
||||
new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; }
|
||||
|
||||
fn speak() { fail; }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let nyan : cat = cat(52u, 99);
|
||||
let kitty = cat(1000u, 2);
|
||||
assert(nyan.how_hungry == 99);
|
||||
assert(kitty.how_hungry == 2);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user