about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-12-14 14:38:25 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-12-16 11:46:57 +0100
commit1dd2f1ec03f41e9ce15fdfe2c729b74f74df2e64 (patch)
tree7578d955b5478408dcf1b653032e6b02bb38f85b /src/comp
parent6a16f57c0a3f37d86b4c8e074f0796669fcd9528 (diff)
downloadrust-1dd2f1ec03f41e9ce15fdfe2c729b74f74df2e64.tar.gz
rust-1dd2f1ec03f41e9ce15fdfe2c729b74f74df2e64.zip
Get very simple impl method calls to compile
Resolution is still dumb, and no self support yet.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/driver/rustc.rs9
-rw-r--r--src/comp/middle/kind.rs10
-rw-r--r--src/comp/middle/trans.rs95
-rw-r--r--src/comp/middle/trans_common.rs1
-rw-r--r--src/comp/middle/ty.rs13
-rw-r--r--src/comp/middle/typeck.rs35
6 files changed, 103 insertions, 60 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index 2ba91d2ecbd..758f9bf85b6 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -171,8 +171,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
     time(time_passes, "const checking",
          bind middle::check_const::check_crate(sess, crate));
     let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
-    time(time_passes, "typechecking",
-         bind typeck::check_crate(ty_cx, impl_map, crate));
+    let method_map = time(time_passes, "typechecking",
+                          bind typeck::check_crate(ty_cx, impl_map, crate));
     time(time_passes, "block-use checking",
          bind middle::block_use::check_crate(ty_cx, crate));
     time(time_passes, "function usage",
@@ -190,7 +190,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
     let last_uses = time(time_passes, "last use finding",
         bind last_use::find_last_uses(crate, def_map, ref_map, ty_cx));
     time(time_passes, "kind checking",
-         bind kind::check_crate(ty_cx, last_uses, crate));
+         bind kind::check_crate(ty_cx, method_map, last_uses, crate));
     if sess.get_opts().no_trans { ret; }
 
     let outputs = build_output_filenames(input, outdir, output, sess);
@@ -199,7 +199,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
         time(time_passes, "translation",
              bind trans::trans_crate(sess, crate, ty_cx,
                                      outputs.obj_filename, exp_map, ast_map,
-                                     mut_map, copy_map, last_uses));
+                                     mut_map, copy_map, last_uses,
+                                     method_map));
     time(time_passes, "LLVM passes",
          bind link::write::run_passes(sess, llmod, outputs.obj_filename));
 
diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs
index 8e577484303..863d02d3d92 100644
--- a/src/comp/middle/kind.rs
+++ b/src/comp/middle/kind.rs
@@ -30,12 +30,15 @@ type rval_map = std::map::hashmap<node_id, ()>;
 
 type ctx = {tcx: ty::ctxt,
             rval_map: rval_map,
+            method_map: typeck::method_map,
             last_uses: last_use::last_uses};
 
-fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses,
-               crate: @crate) -> rval_map {
+fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map,
+               last_uses: last_use::last_uses, crate: @crate)
+    -> rval_map {
     let ctx = {tcx: tcx,
                rval_map: std::map::new_int_hash(),
+               method_map: method_map,
                last_uses: last_uses};
     let visit = visit::mk_vt(@{
         visit_expr: check_expr,
@@ -150,7 +153,8 @@ fn maybe_copy(cx: ctx, ex: @expr) {
 }
 
 fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) {
-    if ty::expr_is_lval(cx.tcx, ex) && !cx.last_uses.contains_key(ex.id) {
+    if ty::expr_is_lval(cx.method_map, cx.tcx, ex) &&
+       !cx.last_uses.contains_key(ex.id) {
         let ty = ty::expr_ty(cx.tcx, ex);
         check_copy(cx, ty, ex.span);
         // FIXME turn this on again once vector types are no longer unique.
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index a0493b8cbc8..886a8da2048 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -13,7 +13,7 @@
 //     but many TypeRefs correspond to one ty::t; for instance, tup(int, int,
 //     int) and rec(x=int, y=int, z=int) will have the same TypeRef.
 
-import core::{either, str, uint, option, vec};
+import core::{either, str, int, uint, option, vec};
 import std::{map, time};
 import std::map::hashmap;
 import std::map::{new_int_hash, new_str_hash};
@@ -948,8 +948,6 @@ fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
                       &static_ti: option::t<@tydesc_info>) -> result {
     alt cx.fcx.derived_tydescs.find(t) {
       some(info) {
-
-
         // If the tydesc escapes in this context, the cached derived
         // tydesc also has to be one that was marked as escaping.
         if !(escapes && !info.escapes) && storage == tps_normal {
@@ -2606,8 +2604,9 @@ fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
                          type_of_ty_param_kinds_and_ty(lcx, cx.sp, tpt));
 }
 
-fn lval_static_fn(bcx: @block_ctxt, tpt: ty::ty_param_kinds_and_ty,
-                  fn_id: ast::def_id, id: ast::node_id) -> lval_maybe_callee {
+fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
+    -> lval_maybe_callee {
+    let tpt = ty::lookup_item_type(bcx_tcx(bcx), fn_id);
     let val = if fn_id.crate == ast::local_crate {
         // Internal reference.
         assert (bcx_ccx(bcx).item_ids.contains_key(fn_id.node));
@@ -2698,17 +2697,13 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
     let ccx = bcx_ccx(cx);
     alt def {
       ast::def_fn(did, _) | ast::def_native_fn(did, _) {
-        let tyt = ty::lookup_item_type(ccx.tcx, did);
-        ret lval_static_fn(cx, tyt, did, id);
+        ret lval_static_fn(cx, did, id);
       }
       ast::def_variant(tid, vid) {
-        let v_tyt = ty::lookup_item_type(ccx.tcx, vid);
-        alt ty::struct(ccx.tcx, v_tyt.ty) {
-          ty::ty_fn(_, _, _, _, _) {
+        if vec::len(ty::tag_variant_with_id(ccx.tcx, tid, vid).args) > 0u {
             // N-ary variant.
-            ret lval_static_fn(cx, v_tyt, vid, id);
-          }
-          _ {
+            ret lval_static_fn(cx, vid, id);
+        } else {
             // Nullary variant.
             let tag_ty = node_id_type(ccx, id);
             let alloc_result = alloc_ty(cx, tag_ty);
@@ -2724,7 +2719,6 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
             } else { C_int(ccx, 0) };
             Store(bcx, d, lldiscrimptr);
             ret lval_no_env(bcx, lltagptr, temporary);
-          }
         }
       }
       ast::def_const(did) {
@@ -2838,15 +2832,30 @@ fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
     ret lval_owned(next_cx, elt);
 }
 
+// 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)
+}
+
 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(bcx_tcx(bcx), e) {
-            let of = trans_object_field(bcx, base, ident);
-            ret {bcx: of.bcx, val: of.mthptr, kind: owned,
-                 env: obj_env(of.objptr), generic: none};
+        if !ty::expr_is_lval(method_map, bcx_tcx(bcx), e) {
+            alt method_map.find(e.id) {
+              some(did) { // An impl method
+                ret trans_method_callee(bcx, e, base, did);
+              }
+              none. { // An object method
+                let of = trans_object_field(bcx, base, ident);
+                ret {bcx: of.bcx, val: of.mthptr, kind: owned,
+                     env: obj_env(of.objptr), generic: none};
+              }
+            }
         }
       }
       ast::expr_self_method(ident) {
@@ -3466,7 +3475,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_tcx(bcx), e) {
+    if ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(bcx), e) {
         ret trans_lval(bcx, e);
     } else {
         let tcx = bcx_tcx(bcx);
@@ -3504,7 +3513,9 @@ 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(tcx, e) { ret lval_to_dps(bcx, e, dest); }
+    if ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, e) {
+        ret lval_to_dps(bcx, e, dest);
+    }
 
     alt e.node {
       ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) {
@@ -3544,7 +3555,9 @@ 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(tcx, a) { ret trans_expr(bcx, a, dest); }
+        if !ty::expr_is_lval(bcx_ccx(bcx).method_map, tcx, a) {
+            ret trans_expr(bcx, a, dest);
+        }
         else { ret lval_to_dps(bcx, a, dest); }
       }
       ast::expr_cast(val, _) {
@@ -3945,7 +3958,8 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
     alt local.node.init {
       some(init) {
         if init.op == ast::init_assign ||
-           !ty::expr_is_lval(bcx_tcx(bcx), init.expr) {
+           !ty::expr_is_lval(bcx_ccx(bcx).method_map, bcx_tcx(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);
@@ -4641,6 +4655,18 @@ 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]) {
+    let sub_cx = extend_path(cx, name);
+    for m in methods {
+        alt cx.ccx.item_ids.find(m.node.id) {
+          some(llfndecl) {
+            trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth,
+                     llfndecl, none, [], m.node.id);
+          }
+        }
+    }
+}
+
 
 // FIXME: this should do some structural hash-consing to avoid
 // duplicate constants. I think. Maybe LLVM has a magical mode
@@ -4949,10 +4975,7 @@ 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(_, _, _) {
-        
-        fail "FIXME[impl]";
-      }
+      ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms); }
       ast::item_res(dtor, dtor_id, tps, ctor_id) {
         trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
 
@@ -5167,8 +5190,6 @@ fn raw_native_fn_type(ccx: @crate_ctxt, sp: span, args: [ty::arg],
     ret T_fn(type_of_explicit_args(ccx, sp, args), type_of(ccx, sp, ret_ty));
 }
 
-fn item_path(item: @ast::item) -> [str] { ret [item.ident]; }
-
 fn link_name(i: @ast::native_item) -> str {
     alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
       none. { ret i.ident; }
@@ -5259,12 +5280,12 @@ fn collect_item_1(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
       }
       _ { }
     }
-    visit::visit_item(i, pt + item_path(i), v);
+    visit::visit_item(i, pt + [i.ident], v);
 }
 
 fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
                   v: vt<[str]>) {
-    let new_pt = pt + item_path(i);
+    let new_pt = pt + [i.ident];
     visit::visit_item(i, new_pt, v);
     alt i.node {
       ast::item_fn(f, tps) {
@@ -5278,6 +5299,13 @@ fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
             ccx.obj_methods.insert(m.node.id, ());
         }
       }
+      ast::item_impl(_, _, methods) {
+        let name = ccx.names.next(i.ident);
+        for m in methods {
+            register_fn(ccx, i.span, pt + [name, m.node.ident],
+                        "impl_method", [], m.node.id);
+        }
+      }
       ast::item_res(_, dtor_id, tps, ctor_id) {
         register_fn(ccx, i.span, new_pt, "res_ctor", tps, ctor_id);
         // Note that the destructor is associated with the item's id, not
@@ -5307,7 +5335,7 @@ fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) {
 
 fn collect_tag_ctor(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
                     v: vt<[str]>) {
-    let new_pt = pt + item_path(i);
+    let new_pt = pt + [i.ident];
     visit::visit_item(i, new_pt, v);
     alt i.node {
       ast::item_tag(variants, tps) {
@@ -5333,7 +5361,7 @@ fn collect_tag_ctors(ccx: @crate_ctxt, crate: @ast::crate) {
 // The constant translation pass.
 fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
                   v: vt<[str]>) {
-    let new_pt = pt + item_path(it);
+    let new_pt = pt + [it.ident];
     visit::visit_item(it, new_pt, v);
     alt it.node {
       ast::item_tag(variants, _) {
@@ -5520,7 +5548,7 @@ fn write_abi_version(ccx: @crate_ctxt) {
 fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
                output: str, emap: resolve::exp_map, amap: ast_map::map,
                mut_map: mut::mut_map, copy_map: alias::copy_map,
-               last_uses: last_use::last_uses)
+               last_uses: last_use::last_uses, method_map: typeck::method_map)
     -> (ModuleRef, link::link_meta) {
     let sha = std::sha1::mk_sha1();
     let link_meta = link::build_link_meta(sess, *crate, output, sha);
@@ -5595,6 +5623,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           mut_map: mut_map,
           copy_map: copy_map,
           last_uses: last_uses,
+          method_map: method_map,
           stats:
               {mutable n_static_tydescs: 0u,
                mutable n_derived_tydescs: 0u,
diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs
index 7d9775a6c2a..19f439235e4 100644
--- a/src/comp/middle/trans_common.rs
+++ b/src/comp/middle/trans_common.rs
@@ -104,6 +104,7 @@ type crate_ctxt =
      mut_map: mut::mut_map,
      copy_map: alias::copy_map,
      last_uses: last_use::last_uses,
+     method_map: typeck::method_map,
      stats: stats,
      upcalls: @upcall::upcalls,
      rust_object_type: TypeRef,
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 1c5bdcb18f5..4265044c296 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -1672,15 +1672,18 @@ fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool {
     ret node_id_has_type_params(cx, expr.id);
 }
 
-fn expr_is_lval(tcx: ty::ctxt, e: @ast::expr) -> bool {
+fn expr_is_lval(method_map: typeck::method_map, tcx: ty::ctxt,
+                e: @ast::expr) -> bool {
     alt e.node {
       ast::expr_path(_) | ast::expr_index(_, _) |
       ast::expr_unary(ast::deref., _) { true }
       ast::expr_field(base, ident) {
-        let basety = type_autoderef(tcx, expr_ty(tcx, base));
-        alt struct(tcx, basety) {
-          ty_obj(_) { false }
-          ty_rec(_) { true }
+        method_map.contains_key(e.id) ? false : {
+            let basety = type_autoderef(tcx, expr_ty(tcx, base));
+            alt struct(tcx, basety) {
+              ty_obj(_) { false }
+              ty_rec(_) { true }
+            }
         }
       }
       _ { false }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 10814ed61ae..03b7f40470d 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -18,7 +18,9 @@ import std::map::{hashmap, new_int_hash};
 import option::{none, some};
 import syntax::print::pprust::*;
 
-export check_crate;
+export check_crate, method_map;
+
+type method_map = hashmap<ast::node_id, ast::def_id>;
 
 type ty_table = hashmap<ast::def_id, ty::t>;
 
@@ -35,6 +37,7 @@ tag obj_info {
 
 type crate_ctxt = {mutable obj_infos: [obj_info],
                    impl_map: resolve::impl_map,
+                   method_map: method_map,
                    tcx: ty::ctxt};
 
 type fn_ctxt =
@@ -74,22 +77,21 @@ fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def {
 // Returns the type parameter count and the type for the given definition.
 fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
    ty_param_kinds_and_ty {
-    let no_kinds: [ast::kind] = [];
     alt defn {
       ast::def_arg(id, _) {
         assert (fcx.locals.contains_key(id.node));
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
-        ret {kinds: no_kinds, ty: typ};
+        ret {kinds: [], ty: typ};
       }
       ast::def_local(id, _) {
         assert (fcx.locals.contains_key(id.node));
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
-        ret {kinds: no_kinds, ty: typ};
+        ret {kinds: [], ty: typ};
       }
       ast::def_obj_field(id, _) {
         assert (fcx.locals.contains_key(id.node));
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
-        ret {kinds: no_kinds, ty: typ};
+        ret {kinds: [], ty: typ};
       }
       ast::def_self(id) { fail "FIXME[impl]"; }
       ast::def_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
@@ -99,12 +101,12 @@ fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
       ast::def_binding(id) {
         assert (fcx.locals.contains_key(id.node));
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
-        ret {kinds: no_kinds, ty: typ};
+        ret {kinds: [], ty: typ};
       }
       ast::def_mod(_) {
         // Hopefully part of a path.
         // TODO: return a type that's more poisonous, perhaps?
-        ret {kinds: no_kinds, ty: ty::mk_nil(fcx.ccx.tcx)};
+        ret {kinds: [], ty: ty::mk_nil(fcx.ccx.tcx)};
       }
       ast::def_ty(_) {
         fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type");
@@ -410,11 +412,10 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
 
 fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
     -> ty::ty_param_kinds_and_ty {
-    let no_kinds: [ast::kind] = [];
     alt it.node {
       ast::item_const(t, _) {
         let typ = ast_ty_to_ty(tcx, mode, t);
-        let tpt = {kinds: no_kinds, ty: typ};
+        let tpt = {kinds: [], ty: typ};
         tcx.tcache.insert(local_def(it.id), tpt);
         ret tpt;
       }
@@ -463,7 +464,6 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
 }
 fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
     -> ty::ty_param_kinds_and_ty {
-    let no_kinds: [ast::kind] = [];
     alt it.node {
       ast::native_item_fn(fn_decl, params) {
         ret ty_of_native_fn_decl(tcx, mode, fn_decl, params,
@@ -475,7 +475,7 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
           none. { }
         }
         let t = ty::mk_native(tcx, ast_util::local_def(it.id));
-        let tpt = {kinds: no_kinds, ty: t};
+        let tpt = {kinds: [], ty: t};
         tcx.tcache.insert(local_def(it.id), tpt);
         ret tpt;
       }
@@ -698,9 +698,11 @@ mod collect {
           }
           ast::item_impl(_, _, ms) {
             for m in ms {
-                write::ty_only(cx.tcx, m.node.id, 
-                               ty::method_ty_to_fn_ty(cx.tcx, ty_of_method(
-                                   cx.tcx, m_collect, m)));
+                let ty = ty::method_ty_to_fn_ty(
+                    cx.tcx, ty_of_method(cx.tcx, m_collect, m));
+                cx.tcx.tcache.insert(local_def(m.node.id),
+                                     {kinds: [], ty: ty});
+                write::ty_only(cx.tcx, m.node.id, ty);
             }
           }
           ast::item_obj(object, ty_params, ctor_id) {
@@ -2179,6 +2181,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
             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);
+            fcx.ccx.method_map.insert(id, local_def(method.node.id));
           }
           _ {
             base_t = do_autoderef(fcx, expr.span, base_t);
@@ -2695,13 +2698,14 @@ fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) {
 }
 
 fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
-               crate: @ast::crate) {
+               crate: @ast::crate) -> method_map {
     collect::collect_item_types(tcx, crate);
 
     let obj_infos: [obj_info] = [];
 
     let ccx = @{mutable obj_infos: obj_infos,
                 impl_map: impl_map,
+                method_map: std::map::new_int_hash(),
                 tcx: tcx};
     let visit =
         visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _)
@@ -2709,6 +2713,7 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
     visit::visit_crate(*crate, (), visit);
     check_for_main_fn(tcx, crate);
     tcx.sess.abort_if_errors();
+    ccx.method_map
 }
 //
 // Local Variables: