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:
Tim Chevalier 2012-03-06 08:02:13 -08:00
parent 47d468f08c
commit 1680ccce1e
18 changed files with 381 additions and 116 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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