diff options
| author | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-03-21 12:42:34 -0700 |
|---|---|---|
| committer | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-03-21 13:53:21 -0700 |
| commit | 30c272cb3a42cfd842736ddb90133362fe899290 (patch) | |
| tree | 5daa1ceb5c4570640b5d0a587b89cd350c985d6d | |
| parent | 3e474424714f8e24fd1237d77cf88a3b35a495e5 (diff) | |
| download | rust-30c272cb3a42cfd842736ddb90133362fe899290.tar.gz rust-30c272cb3a42cfd842736ddb90133362fe899290.zip | |
methods work
Cross-crate method calls don't work yet. Added run-pass/class-method-cross-crate to test that, but it's xfailed References to fields within methods don't work yet. Added run-pass/class-methods to test that, but it's also xfailed
| -rw-r--r-- | src/rustc/metadata/csearch.rs | 11 | ||||
| -rw-r--r-- | src/rustc/metadata/decoder.rs | 38 | ||||
| -rw-r--r-- | src/rustc/middle/trans/base.rs | 5 | ||||
| -rw-r--r-- | src/rustc/middle/ty.rs | 40 | ||||
| -rw-r--r-- | src/rustc/middle/typeck.rs | 47 | ||||
| -rw-r--r-- | src/rustc/syntax/ast_util.rs | 4 | ||||
| -rw-r--r-- | src/test/auxiliary/cci_class_2.rs | 15 | ||||
| -rw-r--r-- | src/test/run-pass/class-method-cross-crate.rs | 13 | ||||
| -rw-r--r-- | src/test/run-pass/class-methods.rs | 22 | ||||
| -rw-r--r-- | src/test/run-pass/classes-simple-method.rs | 6 |
10 files changed, 162 insertions, 39 deletions
diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs index 1d8965897ad..58192a8f163 100644 --- a/src/rustc/metadata/csearch.rs +++ b/src/rustc/metadata/csearch.rs @@ -13,6 +13,7 @@ import std::map::hashmap; export get_symbol; export get_class_fields; +// export get_class_method_ids; export get_field_type; export get_type_param_count; export lookup_defs; @@ -127,9 +128,17 @@ fn get_iface_methods(tcx: ty::ctxt, def: ast::def_id) -> @[ty::method] { fn get_class_fields(tcx: ty::ctxt, def: ast::def_id) -> [ty::field_ty] { let cstore = tcx.sess.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_class_fields(tcx, cdata, def.node) + decoder::get_class_fields(cdata, def.node) } +/* +fn get_class_method_ids(tcx: ty::ctxt, def: ast::def_id) -> [ty::field_ty] { + let cstore = tcx.sess.cstore; + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_class_method_ids(cdata, def.node) +} +*/ + 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/decoder.rs b/src/rustc/metadata/decoder.rs index 8916d32d393..f4e213e5157 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -17,6 +17,7 @@ import middle::trans::common::maps; import util::ppaux::ty_to_str; export get_class_fields; +// export get_class_method_ids; export get_symbol; export get_enum_variants; export get_type; @@ -113,7 +114,7 @@ fn item_parent_item(d: ebml::doc) -> option<ast::def_id> { found } -fn class_field_id(d: ebml::doc, cdata: cmd) -> ast::def_id { +fn class_member_id(d: ebml::doc, cdata: cmd) -> ast::def_id { let tagdoc = ebml::get_doc(d, tag_def_id); ret translate_def_id(cdata, parse_def_id(ebml::doc_data(tagdoc))); } @@ -408,27 +409,36 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) @result } -/* Take a node ID for a class, return a vector of the class's - field names/IDs */ -fn get_class_fields(tcx: ty::ctxt, - cdata: cmd, id: ast::node_id) -> [ty::field_ty] { +// Helper function that gets either fields or methods +fn get_class_members(cdata: cmd, id: ast::node_id, + family: char) -> [ty::field_ty] { let data = cdata.data; let item = lookup_item(id, data), result = []; ebml::tagged_docs(item, tag_items_data_item) {|an_item| - let fam = item_family(an_item); - alt fam { - 'g' { - let name = item_name(an_item); - let _ty = doc_type(an_item, tcx, cdata); - let did = class_field_id(an_item, cdata); - result += [{ident: name, id: did}]; - } - _ { /* this only handles fields */} + if item_family(an_item) == family { + let name = item_name(an_item); + let did = class_member_id(an_item, cdata); + result += [{ident: name, id: did}]; } } result } + +/* Take a node ID for a class, return a vector of the class's + field names/IDs */ +fn get_class_fields(cdata: cmd, id: ast::node_id) -> [ty::field_ty] { + get_class_members(cdata, id, 'g') +} + +/* +/* Take a node ID for a class, return a vector of the class's + method names/IDs */ +fn get_class_method_ids(cdata: cmd, id: ast::node_id) -> [ty::field_ty] { + get_class_members(cdata, id, 'h') +} +*/ + fn family_has_type_params(fam_ch: char) -> bool { alt check fam_ch { 'c' | 'T' | 'm' | 'n' | 'g' | 'h' { false } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index c0dbdc96210..648ac24208a 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -4194,7 +4194,10 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { trans_fn(ccx, *path + [path_name(item.ident)], ctor.node.dec, ctor_body__, llctor_decl, no_self, none, ctor.node.id, some(rslt_expr)); - // TODO: translate methods! + // Translate methods + let (_, ms) = ast_util::split_class_items(items); + // not sure how this is going to work what with "self" and fields + impl::trans_impl(ccx, *path, item.ident, ms, tps); } _ {/* fall through */ } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 4666487a238..47e60cc530b 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -6,6 +6,7 @@ import session::session; import syntax::ast; import syntax::ast::*; import syntax::ast_util; +import syntax::ast_util::{is_local, split_class_items}; import syntax::codemap::span; import metadata::csearch; import util::common::*; @@ -41,6 +42,7 @@ export get_element_type; export is_binopable; export is_pred_ty; export lookup_class_fields; +export lookup_class_method_by_name; export lookup_field_type; export lookup_item_type; export method; @@ -2523,7 +2525,7 @@ fn lookup_field_type(tcx: ctxt, class_id: def_id, id: def_id) -> ty::t { } } -// Look up the list of item types for a given class +// Look up the list of field names and IDs for a given class // Fails if the id is not bound to a class. fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] { if did.crate == ast::local_crate { @@ -2544,7 +2546,41 @@ fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] { } } -// must be called after typechecking? +// Look up the list of method names and IDs for a given class +// Fails if the id is not bound to a class. +fn lookup_class_method_ids(cx: ctxt, did: ast::def_id) + : is_local(did) -> [{name: ident, id: node_id}] { + alt cx.items.find(did.node) { + some(ast_map::node_item(@{node: item_class(_,items,_), _}, _)) { + let (_,ms) = split_class_items(items); + vec::map(ms, {|m| {name: m.ident, id: m.id}}) + } + _ { + cx.sess.bug("lookup_class_method_ids: id not bound to a class"); + } + } +} + +/* Given a class def_id and a method name, return the method's + def_id. Needed so we can do static dispatch for methods */ +fn lookup_class_method_by_name(cx:ctxt, did: ast::def_id, name: ident, + sp: span) -> + def_id { + if check is_local(did) { + let ms = lookup_class_method_ids(cx, did); + for m in ms { + if m.name == name { + ret ast_util::local_def(m.id); + } + } + cx.sess.span_fatal(sp, #fmt("Class doesn't have a method named %s", + name)); + } + else { + csearch::get_impl_method(cx.sess.cstore, did, name) + } +} + fn class_field_tys(items: [@class_item]) -> [field_ty] { let rslt = []; for it in items { diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index e55656d2b2f..eb4f87c824f 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -893,11 +893,20 @@ mod collect { } } fn ensure_iface_methods(tcx: ty::ctxt, id: ast::node_id) { + fn store_methods<T>(tcx: ty::ctxt, id: ast::node_id, + stuff: [T], f: fn@(T) -> ty::method) { + ty::store_iface_methods(tcx, id, @vec::map(stuff, f)); + } + alt check tcx.items.get(id) { ast_map::node_item(@{node: ast::item_iface(_, ms), _}, _) { - ty::store_iface_methods(tcx, id, @vec::map(ms, {|m| - ty_of_ty_method(tcx, m_collect, m) - })); + store_methods::<ast::ty_method>(tcx, id, ms, {|m| + ty_of_ty_method(tcx, m_collect, m)}); + } + ast_map::node_item(@{node: ast::item_class(_,its,_), _}, _) { + let (_,ms) = split_class_items(its); + store_methods::<@ast::method>(tcx, id, ms, {|m| + ty_of_method(tcx, m_collect, m)}); } } } @@ -1038,13 +1047,17 @@ mod collect { write_ty(tcx, ctor.node.id, t_ctor); tcx.tcache.insert(local_def(ctor.node.id), {bounds: tpt.bounds, ty: t_ctor}); + ensure_iface_methods(tcx, it.id); /* FIXME: check for proper public/privateness */ // Write the type of each of the members let (fields, methods) = split_class_items(members); for f in fields { convert_class_item(tcx, f); } - convert_methods(tcx, methods, @[], none); + let selfty = ty::mk_class(tcx, local_def(it.id), + mk_ty_params(tcx, tps).params); + // The selfty is just the class type + convert_methods(tcx, methods, @[], some(selfty)); } _ { // This call populates the type cache with the converted type @@ -1854,13 +1867,13 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, } } -enum method_parent { - cls(ast::def_id), +enum method_kind { + cls(ast::def_id), // *method* id (in both cases) an_iface(ast::def_id) } fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method], - tps: [ty::t], parent: method_parent, name: ast::ident, sp: span) + tps: [ty::t], parent: method_kind, name: ast::ident, sp: span) -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t], origin: method_origin, self_sub: option<self_subst>}> { #debug("lookup_method_inner_: %? %? %s", ms, parent, name); @@ -1878,13 +1891,19 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method], boxed iface"); } ret some({method_ty: fty, - n_tps: vec::len(*m.tps), - substs: tps, - origin: alt parent { - cls(did) { method_static(did) } - an_iface(did) { method_iface(did, i) } - }, - self_sub: none}); + n_tps: vec::len(*m.tps), + substs: tps, + origin: alt parent { + cls(parent_id) { + // look up method named <name> + // its id is did + let m_declared = ty::lookup_class_method_by_name(tcx, + parent_id, name, sp); + method_static(m_declared) + } + an_iface(did) { method_iface(did, i) } + }, + self_sub: none}); } i += 1u; } diff --git a/src/rustc/syntax/ast_util.rs b/src/rustc/syntax/ast_util.rs index 5625fecb953..7af080a2535 100644 --- a/src/rustc/syntax/ast_util.rs +++ b/src/rustc/syntax/ast_util.rs @@ -17,7 +17,9 @@ fn path_name(p: @path) -> str { path_name_i(p.node.idents) } fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") } -fn local_def(id: node_id) -> def_id { ret {crate: local_crate, node: id}; } +fn local_def(id: node_id) -> def_id { {crate: local_crate, node: id} } + +pure fn is_local(did: ast::def_id) -> bool { did.crate == local_crate } fn stmt_id(s: stmt) -> node_id { alt s.node { diff --git a/src/test/auxiliary/cci_class_2.rs b/src/test/auxiliary/cci_class_2.rs new file mode 100644 index 00000000000..50a5bf1e624 --- /dev/null +++ b/src/test/auxiliary/cci_class_2.rs @@ -0,0 +1,15 @@ +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; } + + fn speak() {} +} + +} diff --git a/src/test/run-pass/class-method-cross-crate.rs b/src/test/run-pass/class-method-cross-crate.rs new file mode 100644 index 00000000000..1d79fa3f56d --- /dev/null +++ b/src/test/run-pass/class-method-cross-crate.rs @@ -0,0 +1,13 @@ +// xfail-test +// xfail-fast +// aux-build:cci_class_2.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); + nyan.speak(); +} diff --git a/src/test/run-pass/class-methods.rs b/src/test/run-pass/class-methods.rs new file mode 100644 index 00000000000..e9587b752cb --- /dev/null +++ b/src/test/run-pass/class-methods.rs @@ -0,0 +1,22 @@ +// 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() { meows += 1u; } + fn meow_count() -> uint { meows } +} + +fn main() { + let nyan : cat = cat(52u, 99); + let kitty = cat(1000u, 2); + assert(nyan.how_hungry == 99); + assert(kitty.how_hungry == 2); + nyan.speak(); + assert(nyan.meow_count() == 53u); +} diff --git a/src/test/run-pass/classes-simple-method.rs b/src/test/run-pass/classes-simple-method.rs index 2c7c2c7c480..62084958d5a 100644 --- a/src/test/run-pass/classes-simple-method.rs +++ b/src/test/run-pass/classes-simple-method.rs @@ -1,4 +1,3 @@ -// xfail-test class cat { priv { let mutable meows : uint; @@ -9,10 +8,6 @@ class cat { new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; } fn speak() {} - /* - fn speak() { meows += 1u; } - fn meow_count() -> uint { meows } - */ } fn main() { @@ -21,5 +16,4 @@ fn main() { assert(nyan.how_hungry == 99); assert(kitty.how_hungry == 2); nyan.speak(); - // assert(nyan.meow_count() == 53u); } |
