diff --git a/src/rustc/metadata/common.rs b/src/rustc/metadata/common.rs index 88800e17aff..493166144f5 100644 --- a/src/rustc/metadata/common.rs +++ b/src/rustc/metadata/common.rs @@ -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 diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs index 08836703836..2451f9f37c7 100644 --- a/src/rustc/metadata/csearch.rs +++ b/src/rustc/metadata/csearch.rs @@ -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); diff --git a/src/rustc/metadata/cstore.rs b/src/rustc/metadata/cstore.rs index f8071538df4..1dc779232c9 100644 --- a/src/rustc/metadata/cstore.rs +++ b/src/rustc/metadata/cstore.rs @@ -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 diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 70c771b85c1..6effd8e2516 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -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 { 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 { 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"; } } } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index fee50a927e6..fe2f01624ca 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -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]) { + 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]) { // 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| diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs index eebbe51c665..9b2a87d9e18 100644 --- a/src/rustc/metadata/tydecode.rs +++ b/src/rustc/metadata/tydecode.rs @@ -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}; } diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index ebe9342f87a..7e16129846c 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -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(']'); } } diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs index 94a1e9a923a..1b2dbaf9d58 100644 --- a/src/rustc/middle/ast_map.rs +++ b/src/rustc/middle/ast_map.rs @@ -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)); } _ { } } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index 6b1296e5919..b6a58172819 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -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. diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index c2cb142b46e..bcae9a03b29 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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); diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs index 3f50be550df..38ca61230e3 100644 --- a/src/rustc/middle/trans/debuginfo.rs +++ b/src/rustc/middle/trans/debuginfo.rs @@ -746,7 +746,7 @@ fn create_function(fcx: fn_ctxt) -> @metadata { 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) diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs index 9d49c595fe5..77cf5e578d4 100644 --- a/src/rustc/middle/trans/type_of.rs +++ b/src/rustc/middle/trans/type_of.rs @@ -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]; } _ {} diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index b481371a8cb..99ccdeeb70e 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -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"); } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index cd1af0c5169..8cb2b0f50fc 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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; 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; diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 1dedf095506..1754625d5c9 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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 diff --git a/src/test/auxiliary/cci_class.rs b/src/test/auxiliary/cci_class.rs new file mode 100644 index 00000000000..a3984503fae --- /dev/null +++ b/src/test/auxiliary/cci_class.rs @@ -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; } +} + +} diff --git a/src/test/run-pass/classes-simple-cross-crate.rs b/src/test/run-pass/classes-simple-cross-crate.rs new file mode 100644 index 00000000000..6bfe96186d8 --- /dev/null +++ b/src/test/run-pass/classes-simple-cross-crate.rs @@ -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); +} diff --git a/src/test/run-pass/classes-simple-method.rs b/src/test/run-pass/classes-simple-method.rs new file mode 100644 index 00000000000..5d2eaf9d37e --- /dev/null +++ b/src/test/run-pass/classes-simple-method.rs @@ -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); +}