about summary refs log tree commit diff
path: root/src/rustc/middle
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-03-28 18:50:33 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-03-28 20:30:07 -0700
commitf7bbe537c11b83c529d755622bc7fdb831d751cd (patch)
tree6a822e808ac48046ab8932dbacf802036bb31150 /src/rustc/middle
parentfe610f04d89ae30e7ad68b9b519aa8461cd8d0fb (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.rs6
-rw-r--r--src/rustc/middle/mutbl.rs5
-rw-r--r--src/rustc/middle/resolve.rs16
-rw-r--r--src/rustc/middle/trans/base.rs3
-rw-r--r--src/rustc/middle/trans/reachable.rs2
-rw-r--r--src/rustc/middle/ty.rs24
-rw-r--r--src/rustc/middle/typeck.rs96
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 */ }
     }