diff options
| author | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-03-28 18:50:33 -0700 |
|---|---|---|
| committer | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-03-28 20:30:07 -0700 |
| commit | f7bbe537c11b83c529d755622bc7fdb831d751cd (patch) | |
| tree | 6a822e808ac48046ab8932dbacf802036bb31150 /src/rustc/middle | |
| parent | fe610f04d89ae30e7ad68b9b519aa8461cd8d0fb (diff) | |
Allow explicit self-calls within classes
Allow writing self.f() within a class that has a method f. In a future commit, this syntax will be required. For now, you can write either self.f() or f(). I added a "privacy" field to all methods (whether class methods or not), which allowed me to refactor the AST somewhat (getting rid of the class_item type; now there's just class_member).
Diffstat (limited to 'src/rustc/middle')
| -rw-r--r-- | src/rustc/middle/ast_map.rs | 6 | ||||
| -rw-r--r-- | src/rustc/middle/mutbl.rs | 5 | ||||
| -rw-r--r-- | src/rustc/middle/resolve.rs | 16 | ||||
| -rw-r--r-- | src/rustc/middle/trans/base.rs | 3 | ||||
| -rw-r--r-- | src/rustc/middle/trans/reachable.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/ty.rs | 24 | ||||
| -rw-r--r-- | src/rustc/middle/typeck.rs | 96 |
7 files changed, 86 insertions, 66 deletions
diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs index 3b9a868776b..ee91b573daa 100644 --- a/src/rustc/middle/ast_map.rs +++ b/src/rustc/middle/ast_map.rs @@ -182,10 +182,8 @@ fn map_item(i: @item, cx: ctx, v: vt) { let p = extend(cx, i.ident); for ci in items { // only need to handle methods - alt ci.node.decl { - class_method(m) { - map_method(d_id, p, m, cx); - } + alt ci.node { + class_method(m) { map_method(d_id, p, m, cx); } _ {} } } diff --git a/src/rustc/middle/mutbl.rs b/src/rustc/middle/mutbl.rs index be06a16a0dc..45751bd4cfb 100644 --- a/src/rustc/middle/mutbl.rs +++ b/src/rustc/middle/mutbl.rs @@ -216,9 +216,8 @@ fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) { alt item.node { item_class(tps, items, ctor) { v.visit_ty_params(tps, cx, v); - vec::map::<@class_item, ()>(items, - {|i| v.visit_class_item(i.span, - i.node.privacy, i.node.decl, cx, v); }); + vec::map::<@class_member, ()>(items, + {|i| v.visit_class_item(i, cx, v); }); v.visit_fn(visit::fk_ctor(item.ident, tps), ctor.node.dec, ctor.node.body, ctor.span, ctor.node.id, @{in_ctor: some(ctor.node.self_id) with *cx}, v); diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index 91aac1c7d6a..7f38205b384 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -89,7 +89,7 @@ enum mod_index_entry { mie_import_ident(node_id, span), mie_item(@ast::item), mie_class_item(node_id, /* parent class name */ - @ast::class_item), /* class member */ + @ast::class_member), /* class member */ mie_native_item(@ast::native_item), mie_enum_variant(/* variant index */uint, /*parts of enum item*/ [variant], @@ -533,14 +533,14 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) { ctor_scope, v); /* visit the items */ for cm in members { - alt cm.node.decl { + alt cm.node { class_method(m) { let msc = cons(scope_method(m.self_id, tps + m.tps), @class_scope); visit_fn_with_scope(e, visit::fk_item_fn(m.ident, tps), m.decl, m.body, m.span, m.id, msc, v); } - instance_var(_,t,_,_) { v.visit_ty(t, class_scope, v); } + instance_var(_,t,_,_,_) { v.visit_ty(t, class_scope, v); } } } } @@ -1161,11 +1161,11 @@ fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl, using the mod_index stuff */ fn lookup_in_class(parent_id: def_id, - members: [@class_item], name: ident) + members: [@class_member], name: ident) -> option<def> { for m in members { - alt m.node.decl { - instance_var(v_name,_,_,id) { + alt m.node { + instance_var(v_name,_,_,id,_) { if v_name == name { ret some(def_class_field(parent_id, local_def(id))); } @@ -1560,8 +1560,8 @@ fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) -> } } mie_class_item(parent_id, class_item) { - alt class_item.node.decl { - instance_var(_,_,_,id) { + alt class_item.node { + instance_var(_,_,_,id,_) { ret some(ast::def_class_field(local_def(parent_id), local_def(id))); } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 82eec9b8bd6..f213519dac3 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -4368,8 +4368,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { // Translate methods let (_, ms) = ast_util::split_class_items(items); - impl::trans_impl(ccx, *path, item.ident, - vec::map(ms, {|m| m.meth}), tps); + impl::trans_impl(ccx, *path, item.ident, ms, tps); } _ {/* fall through */ } } diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs index db0b6f923b0..ca4ff733716 100644 --- a/src/rustc/middle/trans/reachable.rs +++ b/src/rustc/middle/trans/reachable.rs @@ -101,7 +101,7 @@ fn traverse_public_item(cx: ctx, item: @item) { item_class(tps, items, ctor) { cx.rmap.insert(ctor.node.id, ()); for vec::each(items) {|item| - alt item.node.decl { + alt item.node { class_method(m) { cx.rmap.insert(m.id, ()); if tps.len() > 0u || diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index bfaf356a3e5..7396e54cf77 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -156,7 +156,8 @@ type param_bounds = @[param_bound]; type method = {ident: ast::ident, tps: @[param_bounds], fty: fn_ty, - purity: ast::purity}; + purity: ast::purity, + privacy: ast::privacy}; type constr_table = hashmap<ast::node_id, [constr]>; @@ -2165,7 +2166,7 @@ fn lookup_class_method_ids(cx: ctxt, did: ast::def_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.meth.ident, id: m.meth.id, + vec::map(ms, {|m| {name: m.ident, id: m.id, privacy: m.privacy}}) } _ { @@ -2176,17 +2177,19 @@ fn lookup_class_method_ids(cx: ctxt, did: ast::def_id) /* Given a class def_id and a method name, return the method's def_id. Needed so we can do static dispatch for methods - Fails if the requested method is private */ + Doesn't care about the method's privacy. (It's assumed that + the caller already checked that.) +*/ 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 && m.privacy == ast::pub { + if m.name == name { ret ast_util::local_def(m.id); } } - cx.sess.span_fatal(sp, #fmt("Class doesn't have a public method \ + cx.sess.span_fatal(sp, #fmt("Class doesn't have a method \ named %s", name)); } else { @@ -2194,16 +2197,15 @@ fn lookup_class_method_by_name(cx:ctxt, did: ast::def_id, name: ident, } } -fn class_field_tys(items: [@class_item]) -> [field_ty] { +fn class_field_tys(items: [@class_member]) -> [field_ty] { let mut rslt = []; for it in items { - alt it.node.decl { - instance_var(nm, _, cm, id) { + alt it.node { + instance_var(nm, _, cm, id, privacy) { rslt += [{ident: nm, id: ast_util::local_def(id), - privacy: it.node.privacy, mutability: cm}]; - } - class_method(_) { + privacy: privacy, mutability: cm}]; } + class_method(_) { } } } rslt diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 75add819e39..1cf89045a70 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -83,6 +83,22 @@ type fn_ctxt = next_region_var_id: @mut int, ccx: @crate_ctxt}; +// Determines whether the given node ID is a use of the def of +// the self ID for the current method, if there is one +fn self_ref(fcx: @fn_ctxt, id: ast::node_id) -> bool { + let node_def = alt fcx.ccx.tcx.def_map.find(id) { + none { ret false; } + some(d) { d } }; + alt get_self_info(fcx.ccx) { + some(self_impl(_, slf_def)) { + alt node_def { + ast::def_self(slf_actual) { slf_def == slf_actual } + _ { false } + } + } + none { false } + } +} fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> int { alt fcx.locals.find(id) { @@ -709,13 +725,14 @@ fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param]) fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method { {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), - purity: m.decl.purity} + purity: m.decl.purity, privacy: m.privacy} } fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method) -> ty::method { {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), - purity: m.decl.purity} + // assume public, because this is only invoked on iface methods + purity: m.decl.purity, privacy: ast::pub} } // A convenience function to use a crate_ctxt to resolve names for @@ -939,9 +956,9 @@ mod collect { } ast_map::node_item(@{node: ast::item_class(_,its,_), _}, _) { let (_,ms) = split_class_items(its); - // Only public methods need to be stored - let ps = ast_util::public_methods(ms); - store_methods::<@ast::method>(tcx, id, ps, {|m| + // All methods need to be stored, since lookup_method + // relies on the same method cache for self-calls + store_methods::<@ast::method>(tcx, id, ms, {|m| ty_of_method(tcx, m_collect, m)}); } } @@ -1101,8 +1118,7 @@ mod collect { mk_ty_params(tcx, tps).params); // Need to convert all methods so we can check internal // references to private methods - convert_methods(tcx, ast_util::ignore_privacy(methods), @[], - some(selfty)); + convert_methods(tcx, methods, @[], some(selfty)); } _ { // This call populates the type cache with the converted type @@ -2011,9 +2027,10 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} { } fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, - name: ast::ident, ty: ty::t, tps: [ty::t]) + name: ast::ident, ty: ty::t, tps: [ty::t], + include_private: bool) -> option<method_origin> { - alt lookup_method_inner(fcx, expr, name, ty) { + alt lookup_method_inner(fcx, expr, name, ty, include_private) { some({method_ty: fty, n_tps: method_n_tps, substs, origin, self_sub}) { let tcx = fcx.ccx.tcx; let mut substs = substs; @@ -2064,7 +2081,8 @@ enum method_kind { } fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method], - tps: [ty::t], parent: method_kind, name: ast::ident, sp: span) + tps: [ty::t], parent: method_kind, name: ast::ident, sp: span, + include_private: bool) -> 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); @@ -2080,6 +2098,10 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method], tcx.sess.span_fatal( sp, "can not call a generic method through a \ boxed iface"); + } else if m.privacy == ast::priv && !include_private { + tcx.sess.span_fatal( + sp, "Call to private method not allowed outside \ + its defining class"); } ret some({method_ty: fty, n_tps: vec::len(*m.tps), @@ -2089,7 +2111,7 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method], // look up method named <name> // its id is did let m_declared = ty::lookup_class_method_by_name(tcx, - parent_id, name, sp); + parent_id, name, sp); method_static(m_declared) } an_iface(did) { method_iface(did, i) } @@ -2102,7 +2124,8 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method], } fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, - name: ast::ident, ty: ty::t) + name: ast::ident, ty: ty::t, + include_private: bool) -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t], origin: method_origin, self_sub: option<self_subst>}> { @@ -2145,14 +2168,14 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, } ty::ty_iface(did, tps) { alt lookup_method_inner_(tcx, *ty::iface_methods(tcx, did), tps, - an_iface(did), name, expr.span) { + an_iface(did), name, expr.span, include_private) { some(r) { ret some(r); } none { } } } ty::ty_class(did, tps) { alt lookup_method_inner_(tcx, *ty::iface_methods(tcx, did), tps, - cls(did), name, expr.span) { + cls(did), name, expr.span, include_private) { some(r) { ret some(r); } none { } } @@ -2499,7 +2522,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, opname: str, args: [option<@ast::expr>]) -> option<(ty::t, bool)> { let callee_id = ast_util::op_expr_callee_id(op_ex); - alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) { + alt lookup_method(fcx, op_ex, callee_id, opname, self_t, [], false) { some(origin) { let mut method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id); method_ty = universally_quantify_regions(fcx, region_env(), @@ -3108,6 +3131,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } } ty::ty_class(base_id, _params) { + // This is just for fields -- the same code handles + // methods in both classes and ifaces + // (1) verify that the class id actually has a field called // field #debug("class named %s", ty_to_str(tcx, base_t)); @@ -3116,17 +3142,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, determines whether we look at all fields or only public ones */ - let node_def = lookup_def(fcx, base.span, base.id); - let cls_items = alt get_self_info(fcx.ccx) { - some(self_impl(_, n_id)) if alt node_def { - ast::def_self(base_id) { base_id == n_id } - _ { false }} { - // base expr is "self" -- consider all fields - ty::lookup_class_fields(tcx, base_id) - } - _ { lookup_public_fields(tcx, base_id) } + let cls_items = if self_ref(fcx, base.id) { + // base expr is "self" -- consider all fields + ty::lookup_class_fields(tcx, base_id) + } + else { + lookup_public_fields(tcx, base_id) }; - alt lookup_field_ty(tcx, base_id, cls_items, field) { + alt lookup_field_ty(tcx, base_id, cls_items, field) { some(field_ty) { // (2) look up what field's type is, and return it // FIXME: actually instantiate any type params @@ -3140,7 +3163,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } if !handled { let tps = vec::map(tys, {|ty| ast_ty_to_ty_crate(fcx.ccx, ty)}); - alt lookup_method(fcx, expr, expr.id, field, expr_t, tps) { + alt lookup_method(fcx, expr, expr.id, field, expr_t, tps, + self_ref(fcx, base.id)) { some(origin) { fcx.ccx.method_map.insert(id, origin); } @@ -3193,7 +3217,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let p_ty = expr_ty(tcx, p); - alt lookup_method(fcx, p, alloc_id, "alloc", p_ty, []) { + alt lookup_method(fcx, p, alloc_id, "alloc", p_ty, [], false) { some(origin) { fcx.ccx.method_map.insert(alloc_id, origin); @@ -3665,16 +3689,16 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method) { false, none); } -fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map { +fn class_types(ccx: @crate_ctxt, members: [@ast::class_member]) -> class_map { let rslt = int_hash::<ty::t>(); for m in members { - alt m.node.decl { - ast::instance_var(_,t,_,id) { + alt m.node { + ast::instance_var(_,t,_,id,_) { rslt.insert(id, ast_ty_to_ty(ccx.tcx, m_collect, t)); } ast::class_method(mth) { rslt.insert(mth.id, ty::mk_fn(ccx.tcx, - ty_of_method(ccx.tcx, m_collect, mth).fty)); + ty_of_method(ccx.tcx, m_collect, mth).fty)); } } } @@ -3682,10 +3706,9 @@ fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map { } fn check_class_member(ccx: @crate_ctxt, class_t: ty::t, - cm: ast::class_member) { - alt cm { - ast::instance_var(_,t,_,_) { - } + cm: @ast::class_member) { + alt cm.node { + ast::instance_var(_,t,_,_,_) { } ast::class_method(m) { ccx.self_infos += [self_impl(class_t, m.self_id)]; check_method(ccx, m); @@ -3729,8 +3752,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { ctor.node.body, ctor.node.id, false, none); vec::pop(class_ccx.self_infos); // typecheck the members - for m in members { check_class_member(class_ccx, class_t, - m.node.decl); } + for m in members { check_class_member(class_ccx, class_t, m); } } _ {/* nothing to do */ } } |
