about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-12-14 15:23:11 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-12-16 11:46:57 +0100
commit7efef989011307bb9bb1679c9022c17bffecd2f6 (patch)
tree9d7138daf99bb6171809ccb1258fb770bac2edcc /src/comp
parent1dd2f1ec03f41e9ce15fdfe2c729b74f74df2e64 (diff)
Make uses of self in impls compile
Get rid of expr_self_call, introduces def_self. `self` is now,
syntactically, simply a variable. A method implicitly brings a `self`
binding into scope.

Issue #1227
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/alias.rs25
-rw-r--r--src/comp/middle/mut.rs3
-rw-r--r--src/comp/middle/resolve.rs47
-rw-r--r--src/comp/middle/trans.rs77
-rw-r--r--src/comp/middle/trans_closure.rs4
-rw-r--r--src/comp/middle/trans_objects.rs4
-rw-r--r--src/comp/middle/tstate/pre_post_conditions.rs1
-rw-r--r--src/comp/middle/tstate/states.rs1
-rw-r--r--src/comp/middle/ty.rs1
-rw-r--r--src/comp/middle/typeck.rs146
-rw-r--r--src/comp/syntax/ast.rs3
-rw-r--r--src/comp/syntax/fold.rs1
-rw-r--r--src/comp/syntax/parse/parser.rs18
-rw-r--r--src/comp/syntax/print/pprust.rs4
-rw-r--r--src/comp/syntax/visit.rs1
15 files changed, 135 insertions, 201 deletions
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index f5bebd344cc..8f15e10c3d0 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -240,7 +240,7 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
     }
     let f_may_close =
         alt f.node {
-          ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id), true) }
+          ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id)) }
           _ { true }
         };
     if f_may_close {
@@ -374,7 +374,7 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
 fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id,
              assign: bool, sc: scope) {
     let def = cx.tcx.def_map.get(id);
-    if !def_is_local(def, false) { ret; }
+    if !def_is_local(def) { ret; }
     let my_defnum = ast_util::def_id_of_def(def).node;
     let my_local_id = local_id_of_node(cx, my_defnum);
     let var_t = ty::expr_ty(cx.tcx, ex);
@@ -529,20 +529,19 @@ fn ty_can_unsafely_include(cx: ctx, needle: unsafe_ty, haystack: ty::t,
     ret helper(cx.tcx, needle, haystack, mut);
 }
 
-fn def_is_local(d: ast::def, objfields_count: bool) -> bool {
-    ret alt d {
-          ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
-          ast::def_upvar(_, _, _) | ast::def_self(_) {
-            true
-          }
-          ast::def_obj_field(_, _) { objfields_count }
-          _ { false }
-        };
+fn def_is_local(d: ast::def) -> bool {
+    alt d {
+      ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
+      ast::def_upvar(_, _, _) | ast::def_self(_) |
+      ast::def_obj_field(_, _) { true }
+      _ { false }
+    }
 }
 
 fn local_id_of_node(cx: ctx, id: node_id) -> uint {
-    alt cx.tcx.items.get(id) {
-      ast_map::node_arg(_, id) | ast_map::node_local(id) { id }
+    alt cx.tcx.items.find(id) {
+      some(ast_map::node_arg(_, id)) | some(ast_map::node_local(id)) { id }
+      _ { 0u }
     }
 }
 
diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs
index 8d952679678..d3856f4bd2d 100644
--- a/src/comp/middle/mut.rs
+++ b/src/comp/middle/mut.rs
@@ -203,6 +203,9 @@ fn check_move_rhs(cx: @ctx, src: @expr) {
           def_obj_field(_, _) {
             mk_err(cx, src.span, msg_move_out, "object field");
           }
+          def_self(_) {
+            mk_err(cx, src.span, msg_move_out, "method self");
+          }
           _ { }
         }
         check_lval(cx, src, msg_move_out);
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 22d5945a792..19d74e11cd8 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -37,6 +37,7 @@ tag scope {
     scope_loop(@ast::local); // there's only 1 decl per loop.
     scope_block(ast::blk, @mutable uint, @mutable uint);
     scope_arm(ast::arm);
+    scope_self(ast::node_id);
 }
 
 type scopes = list<scope>;
@@ -437,6 +438,9 @@ fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
         v.visit_local(decl, new_sc, v);
         v.visit_block(blk, new_sc, v);
       }
+      ast::expr_anon_obj(_) {
+        visit::visit_expr(x, cons(scope_self(x.id), @sc), v);
+      }
       _ { visit::visit_expr(x, sc, v); }
     }
 }
@@ -723,7 +727,10 @@ fn def_is_local(d: def) -> bool {
 }
 
 fn def_is_obj_field(d: def) -> bool {
-    ret alt d { ast::def_obj_field(_, _) { true } _ { false } };
+    alt d {
+      ast::def_obj_field(_, _) | ast::def_self(_) { true }
+      _ { false }
+    }
 }
 
 fn def_is_ty_arg(d: def) -> bool {
@@ -741,7 +748,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
           scope_item(it) {
             alt it.node {
               ast::item_obj(ob, ty_params, _) {
-                ret lookup_in_obj(name, ob, ty_params, ns);
+                ret lookup_in_obj(name, ob, ty_params, ns, it.id);
               }
               ast::item_impl(_, _, _) {
                 if (name == "self" && ns == ns_value) {
@@ -763,6 +770,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
               _ { }
             }
           }
+          scope_self(id) {
+            if (name == "self" && ns == ns_value) {
+                ret some(ast::def_self(local_def(id)));
+            }
+          }
           scope_native_item(it) {
             alt it.node {
               ast::native_item_fn(decl, ty_params) {
@@ -881,9 +893,10 @@ fn lookup_in_fn(name: ident, decl: ast::fn_decl, ty_params: [ast::ty_param],
 }
 
 fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param],
-                 ns: namespace) -> option::t<def> {
+                 ns: namespace, id: node_id) -> option::t<def> {
     alt ns {
       ns_value. {
+        if name == "self" { ret some(ast::def_self(local_def(id))); }
         for f: ast::obj_field in ob.fields {
             if str::eq(f.ident, name) {
                 ret some(ast::def_obj_field(local_def(f.id), f.mut));
@@ -1295,23 +1308,17 @@ fn index_nmod(md: ast::native_mod) -> mod_index {
 
 // External lookups
 fn ns_for_def(d: def) -> namespace {
-    ret alt d {
-          ast::def_fn(_, _) { ns_value }
-          ast::def_obj_field(_, _) { ns_value }
-          ast::def_mod(_) { ns_module }
-          ast::def_native_mod(_) { ns_module }
-          ast::def_const(_) { ns_value }
-          ast::def_arg(_, _) { ns_value }
-          ast::def_local(_, _) { ns_value }
-          ast::def_upvar(_, _, _) { ns_value }
-          ast::def_variant(_, _) { ns_value }
-          ast::def_ty(_) { ns_type }
-          ast::def_binding(_) { ns_type }
-          ast::def_use(_) { ns_module }
-          ast::def_native_ty(_) { ns_type }
-          ast::def_native_fn(_, _) { ns_value }
-          ast::def_self(_) { ns_value }
-        };
+    alt d {
+      ast::def_fn(_, _) | ast::def_obj_field(_, _) | ast::def_self(_) |
+      ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) |
+      ast::def_upvar(_, _, _) | ast::def_variant(_, _) |
+      ast::def_native_fn(_, _) | ast::def_self(_) { ns_value }
+
+      ast::def_mod(_) | ast::def_native_mod(_) { ns_module }
+
+      ast::def_ty(_) | ast::def_binding(_) | ast::def_use(_) |
+      ast::def_native_ty(_) { ns_type }
+    }
 }
 
 fn lookup_external(e: env, cnum: int, ids: [ident], ns: namespace) ->
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 886a8da2048..2c724ba8fca 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -2678,7 +2678,9 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result {
         ret { val: cx.fcx.llobjfields.get(did.node), kind: owned };
       }
       ast::def_self(did) {
-        ret lval_owned(cx, cx.fcx.llenv);
+        let slf = option::get(cx.fcx.llself);
+        let ptr = PointerCast(cx, slf.v, T_ptr(type_of_or_i8(cx, slf.t)));
+        ret {val: ptr, kind: owned};
       }
       _ {
         bcx_ccx(cx).sess.span_unimpl
@@ -2832,21 +2834,29 @@ fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
     ret lval_owned(next_cx, elt);
 }
 
+fn expr_is_lval(bcx: @block_ctxt, e: @ast::expr) -> bool {
+    let ccx = bcx_ccx(bcx);
+    ty::expr_is_lval(ccx.method_map, ccx.tcx, e)
+}
+
 // This is for impl methods, not obj methods.
 fn trans_method_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
                        did: ast::def_id) -> lval_maybe_callee {
-    let bcx = trans_expr(bcx, base, ignore); // FIXME pass self
-    lval_static_fn(bcx, did, e.id)
+    let tz = [], tr = [];
+    let basety = ty::expr_ty(bcx_tcx(bcx), base);
+    let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
+                                    type_of_or_i8(bcx, basety), tz, tr, base);
+    let val = PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx)));
+    {env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
 }
 
 fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
     alt e.node {
       ast::expr_path(p) { ret trans_path(bcx, p, e.id); }
       ast::expr_field(base, ident) {
-        let method_map = bcx_ccx(bcx).method_map;
         // Lval means this is a record field, so not a method
-        if !ty::expr_is_lval(method_map, bcx_tcx(bcx), e) {
-            alt method_map.find(e.id) {
+        if !expr_is_lval(bcx, e) {
+            alt bcx_ccx(bcx).method_map.find(e.id) {
               some(did) { // An impl method
                 ret trans_method_callee(bcx, e, base, did);
               }
@@ -2858,15 +2868,6 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
             }
         }
       }
-      ast::expr_self_method(ident) {
-        alt bcx.fcx.llself {
-          some(pair) {
-            let fld = trans_object_field_inner(bcx, pair.v, ident, pair.t);
-            ret {bcx: fld.bcx, val: fld.mthptr, kind: owned,
-                 env: obj_env(fld.objptr), generic: none};
-          }
-        }
-      }
       _ {}
     }
     let lv = trans_temp_lval(bcx, e);
@@ -3475,7 +3476,7 @@ fn trans_expr_save_in(bcx: @block_ctxt, e: @ast::expr, dest: ValueRef)
 // use trans_temp_expr.
 fn trans_temp_lval(bcx: @block_ctxt, e: @ast::expr) -> lval_result {
     let bcx = bcx;
-    if ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(bcx), e) {
+    if expr_is_lval(bcx, e) {
         ret trans_lval(bcx, e);
     } else {
         let tcx = bcx_tcx(bcx);
@@ -3513,7 +3514,7 @@ fn trans_temp_expr(bcx: @block_ctxt, e: @ast::expr) -> result {
 // - exprs with non-immediate type never get dest=by_val
 fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
     let tcx = bcx_tcx(bcx);
-    if ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, e) {
+    if expr_is_lval(bcx, e) {
         ret lval_to_dps(bcx, e, dest);
     }
 
@@ -3555,7 +3556,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
         ret trans_closure::trans_bind(bcx, f, args, e.id, dest);
       }
       ast::expr_copy(a) {
-        if !ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, a) {
+        if !expr_is_lval(bcx, a) {
             ret trans_expr(bcx, a, dest);
         }
         else { ret lval_to_dps(bcx, a, dest); }
@@ -3957,9 +3958,7 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
     let bcx = bcx;
     alt local.node.init {
       some(init) {
-        if init.op == ast::init_assign ||
-           !ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(bcx),
-                             init.expr) {
+        if init.op == ast::init_assign || !expr_is_lval(bcx, init.expr) {
             bcx = trans_expr_save_in(bcx, init.expr, llptr);
         } else { // This is a move from an lval, must perform an actual move
             let sub = trans_lval(bcx, init.expr);
@@ -4347,15 +4346,15 @@ fn new_fn_ctxt(cx: @local_ctxt, sp: span, llfndecl: ValueRef) -> @fn_ctxt {
 // spaces that have been created for them (by code in the llallocas field of
 // the function's fn_ctxt).  create_llargs_for_fn_args populates the llargs
 // field of the fn_ctxt with
-fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: option::t<ty::t>,
+fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
                              args: [ast::arg], ty_params: [ast::ty_param]) {
     // Skip the implicit arguments 0, and 1.  TODO: Pull out 2u and define
     // it as a constant, since we're using it in several places in trans this
     // way.
     let arg_n = 2u;
     alt ty_self {
-      some(tt) { cx.llself = some::<val_self_pair>({v: cx.llenv, t: tt}); }
-      none. {
+      obj_self(tt) | impl_self(tt) { cx.llself = some({v: cx.llenv, t: tt}); }
+      no_self. {
         let i = 0u;
         for tp: ast::ty_param in ty_params {
             let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
@@ -4473,19 +4472,23 @@ fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
     RetVoid(ret_cx);
 }
 
+tag self_arg { obj_self(ty::t); impl_self(ty::t); no_self; }
+
 // trans_closure: Builds an LLVM function out of a source function.
 // If the function closes over its environment a closure will be
 // returned.
 fn trans_closure(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
-                 ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
+                 ty_self: self_arg, ty_params: [ast::ty_param],
                  id: ast::node_id, maybe_load_env: block(@fn_ctxt)) {
     set_uwtable(llfndecl);
 
     // Set up arguments to the function.
     let fcx = new_fn_ctxt_w_id(cx, sp, llfndecl, id, f.decl.cf);
     create_llargs_for_fn_args(fcx, ty_self, f.decl.inputs, ty_params);
-    alt fcx.llself {
-      some(llself) { populate_fn_ctxt_from_llself(fcx, llself); }
+    alt ty_self {
+      obj_self(_) {
+          populate_fn_ctxt_from_llself(fcx, option::get(fcx.llself));
+      }
       _ { }
     }
 
@@ -4526,7 +4529,7 @@ fn trans_closure(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
 // trans_fn: creates an LLVM function corresponding to a source language
 // function.
 fn trans_fn(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
-            ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
+            ty_self: self_arg, ty_params: [ast::ty_param],
             id: ast::node_id) {
     let do_time = cx.ccx.sess.get_opts().stats;
     let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
@@ -4549,7 +4552,7 @@ fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::_fn,
     }
     let fcx = new_fn_ctxt(cx, sp, llctor_decl);
     let ret_t = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
-    create_llargs_for_fn_args(fcx, none, dtor.decl.inputs, ty_params);
+    create_llargs_for_fn_args(fcx, no_self, dtor.decl.inputs, ty_params);
     let bcx = new_top_block_ctxt(fcx);
     let lltop = bcx.llbb;
     let arg_t = arg_tys_of_fn(ccx, ctor_id)[0].ty;
@@ -4608,7 +4611,7 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
       }
     }
     let fcx = new_fn_ctxt(cx, variant.span, llfndecl);
-    create_llargs_for_fn_args(fcx, none, fn_args, ty_params);
+    create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
     let ty_param_substs: [ty::t] = [];
     i = 0u;
     for tp: ast::ty_param in ty_params {
@@ -4655,13 +4658,15 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
     finish_fn(fcx, lltop);
 }
 
-fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method]) {
+fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
+              id: ast::node_id) {
     let sub_cx = extend_path(cx, name);
     for m in methods {
         alt cx.ccx.item_ids.find(m.node.id) {
-          some(llfndecl) {
+          some(llfn) {
             trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth,
-                     llfndecl, none, [], m.node.id);
+                     llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
+                     [], m.node.id);
           }
         }
     }
@@ -4961,7 +4966,7 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
         let sub_cx = extend_path(cx, item.ident);
         alt cx.ccx.item_ids.find(item.id) {
           some(llfndecl) {
-            trans_fn(sub_cx, item.span, f, llfndecl, none, tps, item.id);
+            trans_fn(sub_cx, item.span, f, llfndecl, no_self, tps, item.id);
           }
           _ {
             cx.ccx.sess.span_fatal(item.span,
@@ -4975,14 +4980,14 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
                  with *extend_path(cx, item.ident)};
         trans_obj(sub_cx, item.span, ob, ctor_id, tps);
       }
-      ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms); }
+      ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms, item.id); }
       ast::item_res(dtor, dtor_id, tps, ctor_id) {
         trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
 
         // Create a function for the destructor
         alt cx.ccx.item_ids.find(item.id) {
           some(lldtor_decl) {
-            trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id);
+            trans_fn(cx, item.span, dtor, lldtor_decl, no_self, tps, dtor_id);
           }
           _ {
             cx.ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
diff --git a/src/comp/middle/trans_closure.rs b/src/comp/middle/trans_closure.rs
index 039709db8d6..d3a905d70df 100644
--- a/src/comp/middle/trans_closure.rs
+++ b/src/comp/middle/trans_closure.rs
@@ -339,7 +339,7 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
     let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
         let upvars = get_freevars(ccx.tcx, id);
         let {llbox, box_ty, bcx} = build_closure(bcx, upvars, ck);
-        trans_closure(sub_cx, sp, f, llfn, none, [], id, {|fcx|
+        trans_closure(sub_cx, sp, f, llfn, no_self, [], id, {|fcx|
             load_environment(bcx, fcx, box_ty, upvars, ck);
         });
         llbox
@@ -351,7 +351,7 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
       ast::proto_send. { trans_closure_env(ty::closure_send) }
       ast::proto_bare. {
         let closure = C_null(T_opaque_boxed_closure_ptr(ccx));
-        trans_closure(sub_cx, sp, f, llfn, none, [], id, {|_fcx|});
+        trans_closure(sub_cx, sp, f, llfn, no_self, [], id, {|_fcx|});
         closure
       }
     };
diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs
index 4b8795deea8..d6ede4eba31 100644
--- a/src/comp/middle/trans_objects.rs
+++ b/src/comp/middle/trans_objects.rs
@@ -52,7 +52,7 @@ fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
     let lltop = bcx.llbb;
 
     // Both regular arguments and type parameters are handled here.
-    create_llargs_for_fn_args(fcx, none::<ty::t>, fn_args, ty_params);
+    create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
     let arg_tys: [ty::arg] = arg_tys_of_fn(ccx, ctor_id);
     bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
 
@@ -893,7 +893,7 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
     // method's definition will be in the executable.
     ccx.item_ids.insert(m.node.id, llfn);
     ccx.item_symbols.insert(m.node.id, s);
-    trans_fn(mcx, m.span, m.node.meth, llfn, some(self_ty), ty_params,
+    trans_fn(mcx, m.span, m.node.meth, llfn, obj_self(self_ty), ty_params,
              m.node.id);
 
     ret llfn;
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index f622acb7040..384353c2800 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -335,7 +335,6 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
         clear_pp(rslt);
         handle_var(fcx, rslt, e.id, path_to_ident(fcx.ccx.tcx, p));
       }
-      expr_self_method(v) { clear_pp(expr_pp(fcx.ccx, e)); }
       expr_log(_, arg) {
         find_pre_post_expr(fcx, arg);
         copy_pre_post(fcx.ccx, e.id, arg);
diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs
index 414668f3c40..db020ec1bb0 100644
--- a/src/comp/middle/tstate/states.rs
+++ b/src/comp/middle/tstate/states.rs
@@ -592,7 +592,6 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
       }
       expr_break. { ret pure_exp(fcx.ccx, e.id, pres); }
       expr_cont. { ret pure_exp(fcx.ccx, e.id, pres); }
-      expr_self_method(_) { ret pure_exp(fcx.ccx, e.id, pres); }
       expr_anon_obj(anon_obj) {
         alt anon_obj.inner_obj {
           some(wt) { ret find_pre_post_state_sub(fcx, pres, wt, e.id, none); }
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 4265044c296..8c413376f14 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -90,6 +90,7 @@ export mk_uint;
 export mk_uniq;
 export mk_var;
 export mk_opaque_closure;
+export gen_ty;
 export mode;
 export mt;
 export node_type_table;
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 03b7f40470d..d697421bde4 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -8,7 +8,7 @@ import util::common::*;
 import syntax::codemap::span;
 import middle::ty;
 import middle::ty::{node_id_to_type, arg, bind_params_in_type, block_ty,
-                    expr_ty, field, node_type_table,
+                    expr_ty, field, node_type_table, mk_nil,
                     ty_param_substs_opt_and_ty, ty_param_kinds_and_ty};
 import util::ppaux::ty_to_str;
 import middle::ty::unify::{ures_ok, ures_err, fix_ok, fix_err};
@@ -25,17 +25,12 @@ type method_map = hashmap<ast::node_id, ast::def_id>;
 type ty_table = hashmap<ast::def_id, ty::t>;
 
 // Used for typechecking the methods of an object.
-tag obj_info {
-
-    // Regular objects have a node_id at compile time.
-    regular_obj([ast::obj_field], ast::node_id);
-
-    // Anonymous objects only have a type at compile time.  It's optional
-    // because not all anonymous objects have a inner_obj to attach to.
-    anon_obj([ast::obj_field], option::t<ty::sty>);
+tag self_info {
+    self_obj([ast::obj_field], ty::t);
+    self_impl(ty::t);
 }
 
-type crate_ctxt = {mutable obj_infos: [obj_info],
+type crate_ctxt = {mutable self_infos: [self_info],
                    impl_map: resolve::impl_map,
                    method_map: method_map,
                    tcx: ty::ctxt};
@@ -93,7 +88,13 @@ fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
         ret {kinds: [], ty: typ};
       }
-      ast::def_self(id) { fail "FIXME[impl]"; }
+      ast::def_self(id) {
+        alt get_self_info(fcx.ccx) {
+          some(self_obj(_, obj_t)) | some(self_impl(obj_t)) {
+            ret {kinds: [], ty: obj_t};
+          }
+        }
+      }
       ast::def_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
       ast::def_native_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
       ast::def_const(id) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
@@ -696,7 +697,7 @@ mod collect {
             write::ty_only(cx.tcx, it.id, tpt.ty);
             get_tag_variant_types(cx, local_def(it.id), variants, ty_params);
           }
-          ast::item_impl(_, _, ms) {
+          ast::item_impl(_, selfty, ms) {
             for m in ms {
                 let ty = ty::method_ty_to_fn_ty(
                     cx.tcx, ty_of_method(cx.tcx, m_collect, m));
@@ -704,6 +705,8 @@ mod collect {
                                      {kinds: [], ty: ty});
                 write::ty_only(cx.tcx, m.node.id, ty);
             }
+            write::ty_only(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
+                                                       selfty));
           }
           ast::item_obj(object, ty_params, ctor_id) {
             // Now we need to call ty_of_obj_ctor(); this is the type that
@@ -1115,19 +1118,13 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
         };
 
     // Add object fields, if any.
-    let obj_fields = [];
-    alt get_obj_info(ccx) {
-      some(oinfo) {
-        alt oinfo {
-          regular_obj(ofs, _) { obj_fields = ofs; }
-          anon_obj(ofs, _) { obj_fields = ofs; }
+    alt get_self_info(ccx) {
+      some(self_obj(ofs, _)) {
+        for f in ofs {
+            assign(f.id, some(ty::node_id_to_type(ccx.tcx, f.id)));
         }
       }
-      none. {/* no fields */ }
-    }
-    for f: ast::obj_field in obj_fields {
-        let field_ty = ty::node_id_to_type(ccx.tcx, f.id);
-        assign(f.id, some(field_ty));
+      _ {}
     }
 
     // Add formal parameters.
@@ -1992,60 +1989,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       ast::expr_call(f, args, _) {
         bot = check_call_full(fcx, expr.span, f, args, expr.id);
       }
-      ast::expr_self_method(ident) {
-        let t = ty::mk_nil(tcx);
-        let this_obj_sty: option::t<ty::sty> =
-            some(structure_of(fcx, expr.span, ty::mk_nil(tcx)));
-        let this_obj_info: option::t<obj_info> = get_obj_info(fcx.ccx);
-        alt this_obj_info {
-          some(oinfo) {
-            alt oinfo {
-              regular_obj(_, obj_id) {
-                let did = local_def(obj_id);
-
-                // Try looking up the current object in the type
-                // cache.
-                alt tcx.tcache.find(did) {
-                  some(tpt) {
-                    // If we're typechecking a self-method on
-                    // a regular object, this lookup should
-                    // succeed.
-                    this_obj_sty = some(structure_of(fcx, expr.span, tpt.ty));
-                  }
-                  none. {
-                    tcx.sess.bug("didn't find " + int::str(did.node) +
-                                     " in type cache");
-                  }
-                }
-              }
-              anon_obj(_, obj_sty) { this_obj_sty = obj_sty; }
-            }
-          }
-          none. {
-            // Shouldn't happen.
-            tcx.sess.span_err(expr.span, "self-call in non-object context");
-          }
-        }
-
-        // Grab this method's type out of the current object type.
-        alt this_obj_sty {
-          some(sty) {
-            alt sty {
-              ty::ty_obj(methods) {
-                for method: ty::method in methods {
-                    if method.ident == ident {
-                        t = ty::method_ty_to_fn_ty(tcx, method);
-                    }
-                }
-              }
-              _ { fail; }
-            }
-          }
-          none. { }
-        }
-        write::ty_only_fixup(fcx, id, t);
-        require_impure(tcx.sess, fcx.purity, expr.span);
-      }
       ast::expr_cast(e, t) {
         bot = check_expr(fcx, e);
         let t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
@@ -2172,15 +2115,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
             }
             result
         }
+
         bot |= check_expr(fcx, base);
         let base_t = expr_ty(tcx, base);
         let iscope = fcx.ccx.impl_map.get(expr.id);
         alt lookup_method(fcx, iscope, field, base_t) {
           some(method) {
             let mt = ty_of_method(fcx.ccx.tcx, m_check, method);
-            let f_ty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
-                                 mt.output, mt.cf, mt.constrs);
-            write::ty_only_fixup(fcx, id, f_ty);
+            let fty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
+                                mt.output, mt.cf, mt.constrs);
+            write::ty_only_fixup(fcx, id, fty);
             fcx.ccx.method_map.insert(id, local_def(method.node.id));
           }
           _ {
@@ -2255,15 +2199,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
             // Typecheck 'inner_obj'.  If it exists, it had better have object
             // type.
             let inner_obj_methods: [ty::method] = [];
-            let inner_obj_ty: ty::t = ty::mk_nil(tcx);
             let inner_obj_sty: option::t<ty::sty> = none;
             alt ao.inner_obj {
               none. { }
               some(e) {
-                // If there's a inner_obj, we push it onto the obj_infos stack
-                // so that self-calls can be checked within its context later.
+                // If there's a inner_obj, we push it onto the self_infos
+                // stack so that self-calls can be checked within its context
+                // later.
                 bot |= check_expr(fcx, e);
-                inner_obj_ty = expr_ty(tcx, e);
+                let inner_obj_ty = expr_ty(tcx, e);
                 inner_obj_sty = some(structure_of(fcx, e.span, inner_obj_ty));
 
                 alt inner_obj_sty {
@@ -2283,10 +2227,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
               }
             }
 
-            fcx.ccx.obj_infos +=
-                [anon_obj(vec::map(ast_util::obj_field_from_anon_obj_field,
-                                   fields), inner_obj_sty)];
-
             // Whenever an outer method overrides an inner, we need to remove
             // that inner from the type.  Filter inner_obj_methods to remove
             // any methods that share a name with an outer method.
@@ -2311,9 +2251,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
             }
 
             let f = bind filtering_fn(fcx.ccx, _, ao.methods);
-            inner_obj_methods =
-                vec::filter_map::<ty::method,
-                                       ty::method>(f, inner_obj_methods);
+            inner_obj_methods = vec::filter_map(f, inner_obj_methods);
 
             method_types += inner_obj_methods;
         }
@@ -2325,19 +2263,22 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         // Write the methods into the node type table.  (This happens in
         // collect::convert for regular objects.)
         let i = 0u;
-        while i < vec::len::<@ast::method>(ao.methods) {
+        while i < vec::len(ao.methods) {
             write::ty_only(tcx, ao.methods[i].node.id,
                            ty::method_ty_to_fn_ty(tcx, method_types[i]));
             i += 1u;
         }
 
+        fcx.ccx.self_infos +=
+            [self_obj(vec::map(ast_util::obj_field_from_anon_obj_field,
+                               fields), ot)];
         // Typecheck the methods.
         for method: @ast::method in ao.methods {
             check_method(fcx.ccx, method);
         }
 
         // Now remove the info from the stack.
-        vec::pop::<obj_info>(fcx.ccx.obj_infos);
+        vec::pop(fcx.ccx.self_infos);
       }
       _ { tcx.sess.unimpl("expr type in typeck::check_expr"); }
     }
@@ -2357,8 +2298,8 @@ fn next_ty_var(fcx: @fn_ctxt) -> ty::t {
     ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx));
 }
 
-fn get_obj_info(ccx: @crate_ctxt) -> option::t<obj_info> {
-    ret vec::last::<obj_info>(ccx.obj_infos);
+fn get_self_info(ccx: @crate_ctxt) -> option::t<self_info> {
+    ret vec::last(ccx.self_infos);
 }
 
 fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id,
@@ -2639,13 +2580,18 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
       ast::item_res(f, dtor_id, _, _) { check_fn(ccx, f, dtor_id, none); }
       ast::item_obj(ob, _, _) {
         // We're entering an object, so gather up the info we need.
-        ccx.obj_infos += [regular_obj(ob.fields, it.id)];
+        ccx.self_infos += [self_obj(ob.fields,
+                                    ccx.tcx.tcache.get(local_def(it.id)).ty)];
         // Typecheck the methods.
         for method: @ast::method in ob.methods { check_method(ccx, method); }
         // Now remove the info from the stack.
-        vec::pop::<obj_info>(ccx.obj_infos);
+        vec::pop(ccx.self_infos);
+      }
+      ast::item_impl(_, ty, ms) {
+        ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
+        for m in ms { check_method(ccx, m); }
+        vec::pop(ccx.self_infos);
       }
-      ast::item_impl(_, _, ms) { for m in ms { check_method(ccx, m); } }
       _ {/* nothing to do */ }
     }
 }
@@ -2701,9 +2647,7 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
                crate: @ast::crate) -> method_map {
     collect::collect_item_types(tcx, crate);
 
-    let obj_infos: [obj_info] = [];
-
-    let ccx = @{mutable obj_infos: obj_infos,
+    let ccx = @{mutable self_infos: [],
                 impl_map: impl_map,
                 method_map: std::map::new_int_hash(),
                 tcx: tcx};
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 0672e9de5c7..8fb6d41c0a8 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -28,13 +28,13 @@ type ty_param = {ident: ident, kind: kind};
 tag def {
     def_fn(def_id, purity);
     def_obj_field(def_id, mutability);
+    def_self(def_id);
     def_mod(def_id);
     def_native_mod(def_id);
     def_const(def_id);
     def_arg(def_id, mode);
     def_local(def_id, let_style);
     def_variant(def_id /* tag */, def_id /* variant */);
-    def_self(def_id);
     def_ty(def_id);
     def_ty_param(uint, kind);
     def_binding(def_id);
@@ -214,7 +214,6 @@ tag expr_ {
     expr_rec([field], option::t<@expr>);
     expr_call(@expr, [@expr], bool);
     expr_tup([@expr]);
-    expr_self_method(ident);
     expr_bind(@expr, [option::t<@expr>]);
     expr_binary(binop, @expr, @expr);
     expr_unary(unop, @expr);
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 05a4893ccd0..6bb95f0cfc0 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -353,7 +353,6 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
             expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args),
                       blk)
           }
-          expr_self_method(id) { expr_self_method(fld.fold_ident(id)) }
           expr_bind(f, args) {
             let opt_map_se = bind option::map(fld.fold_expr, _);
             expr_bind(fld.fold_expr(f), vec::map(opt_map_se, args))
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index d1e11bf8700..94a7c3e01b2 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -155,8 +155,7 @@ fn bad_expr_word_table() -> hashmap<str, ()> {
                  "cont", "ret", "be", "fail", "type", "resource", "check",
                  "assert", "claim", "native", "fn", "lambda", "pure",
                  "unsafe", "block", "import", "export", "let", "const",
-                 "log", "log_err", "tag", "obj", "self", "copy", "sendfn",
-                 "impl"] {
+                 "log", "log_err", "tag", "obj", "copy", "sendfn", "impl"] {
         words.insert(word, ());
     }
     words
@@ -942,15 +941,6 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
         let e = parse_expr(p);
         ex = ast::expr_copy(e);
         hi = e.span.hi;
-    } else if is_word(p, "self") && p.look_ahead(1u) == token::DOT {
-        p.bump(); p.bump();
-        // The rest is a call expression.
-        let f: @ast::expr = parse_self_method(p);
-        let es =
-            parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
-                      parse_expr, p);
-        hi = es.span.hi;
-        ex = ast::expr_call(f, es.node, false);
     } else if p.peek() == token::MOD_SEP ||
                   is_ident(p.peek()) && !is_word(p, "true") &&
                       !is_word(p, "false") {
@@ -998,12 +988,6 @@ fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr {
     ret mk_mac_expr(p, lo, hi, ast::mac_invoc(pth, e, none));
 }
 
-fn parse_self_method(p: parser) -> @ast::expr {
-    let sp = p.get_span();
-    let f_name: ast::ident = parse_ident(p);
-    ret mk_expr(p, sp.lo, sp.hi, ast::expr_self_method(f_name));
-}
-
 fn parse_dot_or_call_expr(p: parser) -> @ast::expr {
     let b = parse_bottom_expr(p);
     if expr_has_value(b) { parse_dot_or_call_expr_with(p, b) }
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index 57720d8dc14..25ba7e082f3 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -736,10 +736,6 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
             print_expr(s, option::get(blk));
         }
       }
-      ast::expr_self_method(ident) {
-        word(s.s, "self.");
-        print_ident(s, ident);
-      }
       ast::expr_bind(func, args) {
         fn print_opt(s: ps, expr: option::t<@ast::expr>) {
             alt expr {
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index 35f81fe187a..c3e8c65b15a 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -251,7 +251,6 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
         visit_exprs(args, e, v);
         v.visit_expr(callee, e, v);
       }
-      expr_self_method(_) { }
       expr_bind(callee, args) {
         v.visit_expr(callee, e, v);
         for eo: option::t<@expr> in args { visit_expr_opt(eo, e, v); }