]> git.lizzy.rs Git - rust.git/commitdiff
Finish resolving and calling of crate-external impls
authorMarijn Haverbeke <marijnh@gmail.com>
Fri, 16 Dec 2011 13:41:12 +0000 (14:41 +0100)
committerMarijn Haverbeke <marijnh@gmail.com>
Fri, 16 Dec 2011 21:18:38 +0000 (22:18 +0100)
Issue #1227

src/comp/driver/rustc.rs
src/comp/metadata/csearch.rs
src/comp/metadata/decoder.rs
src/comp/metadata/encoder.rs
src/comp/middle/ast_map.rs
src/comp/middle/resolve.rs
src/comp/middle/typeck.rs

index a97afa7cb83318f0cd23082d3fbdd790c2533a62..c87fff86bb905e038b8803bacb95cfb1528494b8 100644 (file)
@@ -497,7 +497,7 @@ fn build_session(sopts: @session::options) -> session::session {
         sopts.target_triple,
         sopts.addl_lib_search_paths);
     ret session::session(target_cfg, sopts, cstore,
-                         @{cm: codemap::new_codemap(), mutable next_id: 0},
+                         @{cm: codemap::new_codemap(), mutable next_id: 1},
                          none, 0u, filesearch, false);
 }
 
index 222d6ac7f0e0f6d0371cceabbe4171e271b4f0f9..81bd90a0a4199c8e68b2811b2fed429485f93947 100644 (file)
@@ -2,13 +2,15 @@
 
 import syntax::ast;
 import middle::ty;
-import option;
+import option::{some, none};
 import driver::session;
 
 export get_symbol;
 export get_type_param_count;
 export lookup_defs;
 export get_tag_variants;
+export get_impls_for_mod;
+export get_impl_methods;
 export get_type;
 
 fn get_symbol(cstore: cstore::cstore, def: ast::def_id) -> str {
@@ -56,15 +58,38 @@ fn get_tag_variants(tcx: ty::ctxt, def: ast::def_id) -> [ty::variant_info] {
     let cstore = tcx.sess.get_cstore();
     let cnum = def.crate;
     let cdata = cstore::get_crate_data(cstore, cnum).data;
-    let resolver = bind translate_def_id(tcx.sess, cnum, _);
+    let resolver = bind translate_def_id(cstore, cnum, _);
     ret decoder::get_tag_variants(cdata, def, tcx, resolver)
 }
 
+fn get_impls_for_mod(cstore: cstore::cstore, def: ast::def_id,
+                     name: option::t<ast::ident>)
+    -> [@middle::resolve::_impl] {
+    let cdata = cstore::get_crate_data(cstore, def.crate).data;
+    let result = [];
+    for did in decoder::get_impls_for_mod(cdata, def.node, def.crate) {
+        let nm = decoder::lookup_item_name(cdata, did.node);
+        if alt name { some(n) { n == nm } none. { true } } {
+            result += [@{did: did,
+                         ident: nm,
+                         methods: decoder::lookup_impl_methods(
+                             cdata, did.node, did.crate)}];
+        }
+    }
+    result
+}
+
+fn get_impl_methods(cstore: cstore::cstore, def: ast::def_id)
+    -> [@middle::resolve::method_info] {
+    let cdata = cstore::get_crate_data(cstore, def.crate).data;
+    decoder::lookup_impl_methods(cdata, def.node, def.crate)
+}
+
 fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_kinds_and_ty {
     let cstore = tcx.sess.get_cstore();
     let cnum = def.crate;
     let cdata = cstore::get_crate_data(cstore, cnum).data;
-    let resolver = bind translate_def_id(tcx.sess, cnum, _);
+    let resolver = bind translate_def_id(cstore, cnum, _);
     decoder::get_type(cdata, def, tcx, resolver)
 }
 
@@ -73,7 +98,7 @@ fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_kinds_and_ty {
 // external crates - if those types further refer to types in other crates
 // then we must translate the crate number from that encoded in the external
 // crate to the correct local crate number.
-fn translate_def_id(sess: session::session, searched_crate: ast::crate_num,
+fn translate_def_id(cstore: cstore::cstore, searched_crate: ast::crate_num,
                     def_id: ast::def_id) -> ast::def_id {
 
     let ext_cnum = def_id.crate;
@@ -82,13 +107,12 @@ fn translate_def_id(sess: session::session, searched_crate: ast::crate_num,
     assert (searched_crate != ast::local_crate);
     assert (ext_cnum != ast::local_crate);
 
-    let cstore = sess.get_cstore();
     let cmeta = cstore::get_crate_data(cstore, searched_crate);
 
     let local_cnum =
         alt cmeta.cnum_map.find(ext_cnum) {
           option::some(n) { n }
-          option::none. { sess.bug("didn't find a crate in the cnum_map") }
+          option::none. { fail "didn't find a crate in the cnum_map"; }
         };
 
     ret {crate: local_cnum, node: node_id};
index 2451a567ea71b8ef7c8558fe49b26deb03ed18e4..9428d420270a8c58733dd71e1f43d5f89cb3a92f 100644 (file)
@@ -16,6 +16,7 @@
 export get_type_param_count;
 export get_type_param_kinds;
 export lookup_def;
+export lookup_item_name;
 export resolve_path;
 export get_crate_attributes;
 export list_crate_metadata;
@@ -23,7 +24,8 @@
 export get_crate_deps;
 export get_crate_hash;
 export external_resolver;
-
+export get_impls_for_mod;
+export lookup_impl_methods;
 // A function that takes a def_id relative to the crate being searched and
 // returns a def_id relative to the compilation environment, i.e. if we hit a
 // def_id for an item defined in another crate, somebody needs to figure out
@@ -130,6 +132,15 @@ fn item_ty_param_kinds(item: ebml::doc) -> [ast::kind] {
     ret ks;
 }
 
+fn item_ty_param_count(item: ebml::doc) -> uint {
+    let n = 0u;
+    let tp = tag_items_data_item_ty_param_kinds;
+    ebml::tagged_docs(item, tp) {|p|
+        n += ebml::vint_at(ebml::doc_data(p), 0u).val;
+    }
+    n
+}
+
 fn tag_variant_ids(item: ebml::doc, this_cnum: ast::crate_num) ->
    [ast::def_id] {
     let ids: [ast::def_id] = [];
@@ -159,6 +170,15 @@ fn eq_item(data: [u8], s: str) -> bool {
     ret result;
 }
 
+fn item_name(item: ebml::doc) -> ast::ident {
+    let name = ebml::get_doc(item, tag_paths_data_name);
+    str::unsafe_from_bytes(ebml::doc_data(name))
+}
+
+fn lookup_item_name(data: @[u8], id: ast::node_id) -> ast::ident {
+    item_name(lookup_item(id, data))
+}
+
 // FIXME doesn't yet handle renamed re-exported externals
 fn lookup_def(cnum: ast::crate_num, data: @[u8], did_: ast::def_id) ->
    ast::def {
@@ -205,7 +225,7 @@ fn get_type(data: @[u8], def: ast::def_id, tcx: ty::ctxt,
 }
 
 fn get_type_param_count(data: @[u8], id: ast::node_id) -> uint {
-    ret vec::len(get_type_param_kinds(data, id));
+    item_ty_param_count(lookup_item(id, data))
 }
 
 fn get_type_param_kinds(data: @[u8], id: ast::node_id) -> [ast::kind] {
@@ -243,6 +263,31 @@ fn get_tag_variants(_data: @[u8], def: ast::def_id, tcx: ty::ctxt,
     ret infos;
 }
 
+fn get_impls_for_mod(data: @[u8], node: ast::node_id, cnum: ast::crate_num)
+    -> [ast::def_id] {
+    let mod_item = lookup_item(node, data), result = [];
+    ebml::tagged_docs(mod_item, tag_mod_impl) {|doc|
+        let did = parse_def_id(ebml::doc_data(doc));
+        result += [{crate: cnum with did}];
+    }
+    result
+}
+
+fn lookup_impl_methods(data: @[u8], node: ast::node_id, cnum: ast::crate_num)
+    -> [@middle::resolve::method_info] {
+    let impl_item = lookup_item(node, data), rslt = [];
+    let base_tps = item_ty_param_count(impl_item);
+    ebml::tagged_docs(impl_item, tag_impl_method) {|doc|
+        let m_did = parse_def_id(ebml::doc_data(doc));
+        let mth_item = lookup_item(m_did.node, data);
+        rslt += [@{did: {crate: cnum, node: m_did.node},
+                   n_tps: item_ty_param_count(mth_item) - base_tps,
+                   ident: item_name(mth_item)}];
+    }
+    rslt
+}
+
+
 fn family_has_type_params(fam_ch: u8) -> bool {
     ret alt fam_ch as char {
           'c' { false }
@@ -258,6 +303,7 @@ fn family_has_type_params(fam_ch: u8) -> bool {
           'm' { false }
           'n' { false }
           'v' { true }
+          'i' { true }
         };
 }
 
index 340328f666ada8ec492a97e90836078717ad75c3..92ab6db903f1677c1b3292218ea23e1f37bf1a5e 100644 (file)
@@ -249,6 +249,26 @@ fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
     }
 }
 
+fn encode_info_for_mod(ebml_w: ebml::writer, md: _mod,
+                       id: node_id) {
+    ebml::start_tag(ebml_w, tag_items_data_item);
+    encode_def_id(ebml_w, local_def(id));
+    encode_family(ebml_w, 'm' as u8);
+    for i in md.items {
+        alt i.node {
+          item_impl(_, _, _) {
+            if ast_util::is_exported(i.ident, md) {
+                ebml::start_tag(ebml_w, tag_mod_impl);
+                ebml_w.writer.write(str::bytes(def_to_str(local_def(i.id))));
+                ebml::end_tag(ebml_w);
+            }
+          }
+          _ {}
+        }
+    }
+    ebml::end_tag(ebml_w);
+}
+
 fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
                         &index: [entry<int>]) {
     alt item.node {
@@ -280,20 +300,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         ebml::end_tag(ebml_w);
       }
       item_mod(m) {
-        ebml::start_tag(ebml_w, tag_items_data_item);
-        encode_def_id(ebml_w, local_def(item.id));
-        encode_family(ebml_w, 'm' as u8);
-        for i in m.items {
-            alt i.node {
-              item_impl(_, _, _) {
-                ebml::start_tag(ebml_w, tag_mod_impl);
-                ebml_w.writer.write(str::bytes(def_to_str(local_def(i.id))));
-                ebml::end_tag(ebml_w);
-              }
-              _ {}
-            }
-        }
-        ebml::end_tag(ebml_w);
+        encode_info_for_mod(ebml_w, m, item.id);
       }
       item_native_mod(_) {
         ebml::start_tag(ebml_w, tag_items_data_item);
@@ -363,9 +370,10 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
       item_impl(tps, _, methods) {
         ebml::start_tag(ebml_w, tag_items_data_item);
         encode_def_id(ebml_w, local_def(item.id));
-        encode_family(ebml_w, 'I' as u8);
+        encode_family(ebml_w, 'i' as u8);
         encode_type_param_kinds(ebml_w, tps);
         encode_type(ecx, ebml_w, node_id_to_monotype(ecx.ccx.tcx, item.id));
+        encode_name(ebml_w, item.ident);
         for m in methods {
             ebml::start_tag(ebml_w, tag_impl_method);
             ebml_w.writer.write(str::bytes(def_to_str(local_def(m.node.id))));
@@ -377,10 +385,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
             index += [{val: m.node.id, pos: ebml_w.writer.tell()}];
             ebml::start_tag(ebml_w, tag_items_data_item);
             encode_def_id(ebml_w, local_def(m.node.id));
-            encode_family(ebml_w, 'i' as u8);
+            encode_family(ebml_w, 'f' as u8);
+            encode_inlineness(ebml_w, 'n' as u8);
             encode_type_param_kinds(ebml_w, tps + m.node.tps);
             encode_type(ecx, ebml_w,
                         node_id_to_monotype(ecx.ccx.tcx, m.node.id));
+            encode_name(ebml_w, m.node.ident);
             encode_symbol(ecx, ebml_w, m.node.id);
             ebml::end_tag(ebml_w);
         }
@@ -415,10 +425,12 @@ fn encode_info_for_native_item(ecx: @encode_ctxt, ebml_w: ebml::writer,
     ebml::end_tag(ebml_w);
 }
 
-fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer) ->
-   [entry<int>] {
+fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
+                         crate_mod: _mod) -> [entry<int>] {
     let index: [entry<int>] = [];
     ebml::start_tag(ebml_w, tag_items_data);
+    index += [{val: crate_node_id, pos: ebml_w.writer.tell()}];
+    encode_info_for_mod(ebml_w, crate_mod, crate_node_id);
     ecx.ccx.ast_map.items {|key, val|
         alt val {
           middle::ast_map::node_item(i) {
@@ -658,7 +670,7 @@ fn encode_metadata(cx: @crate_ctxt, crate: @crate) -> str {
     // Encode and index the items.
 
     ebml::start_tag(ebml_w, tag_items);
-    let items_index = encode_info_for_items(ecx, ebml_w);
+    let items_index = encode_info_for_items(ecx, ebml_w, crate.node.module);
     let items_buckets = create_index(items_index, hash_node_id);
     encode_index(ebml_w, items_buckets, write_int);
     ebml::end_tag(ebml_w);
index a86208dd8c6c9d594e5816d2b726c76b6dfe277e..78e3da6b03037a7efee3e67b1a04b2ea97c989c3 100644 (file)
@@ -8,6 +8,7 @@
     node_item(@item);
     node_obj_ctor(@item);
     node_native_item(@native_item);
+    node_method(@method);
     node_expr(@expr);
     // Locals are numbered, because the alias analysis needs to know in which
     // order they are introduced.
@@ -63,6 +64,9 @@ fn map_item(cx: ctx, i: @item) {
     cx.map.insert(i.id, node_item(i));
     alt i.node {
       item_obj(_, _, ctor_id) { cx.map.insert(ctor_id, node_obj_ctor(i)); }
+      item_impl(_, _, ms) {
+        for m in ms { cx.map.insert(m.node.id, node_method(m)); }
+      }
       _ { }
     }
 }
index 75bd5de7c6802bff65f77a3c0a76b6df80b59a81..484e36be18445a8ad88b40c1f29f3c2f5950dff5 100644 (file)
@@ -19,7 +19,8 @@
 import syntax::print::pprust::*;
 
 export resolve_crate;
-export def_map, ext_map, exp_map, impl_map, iscopes;
+export def_map, ext_map, exp_map, impl_map;
+export _impl, iscopes, method_info;
 
 // Resolving happens in two passes. The first pass collects defids of all
 // (internal) imports and modules, so that they can be looked up when needed,
@@ -47,7 +48,7 @@
     resolved(option::t<def>, /* value */
              option::t<def>, /* type */
              option::t<def>, /* module */
-             @[@ast::item],
+             @[@_impl], /* impls */
              /* used for reporting unused import warning */
              ast::ident, codemap::span);
 }
@@ -106,6 +107,7 @@ fn eq(v1: key, v2: key) -> bool {
 type ext_map = hashmap<def_id, [ident]>;
 type exp_map = hashmap<str, def>;
 type impl_map = hashmap<node_id, iscopes>;
+type impl_cache = hashmap<def_id, @[@_impl]>;
 
 type env =
     {cstore: cstore::cstore,
@@ -117,6 +119,7 @@ fn eq(v1: key, v2: key) -> bool {
      block_map: hashmap<ast::node_id, [glob_imp_def]>,
      ext_map: ext_map,
      impl_map: impl_map,
+     impl_cache: impl_cache,
      ext_cache: ext_hash,
      used_imports: {mutable track: bool,
                     mutable data: [ast::node_id]},
@@ -144,6 +147,7 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
           block_map: new_int_hash(),
           ext_map: new_def_hash(),
           impl_map: new_int_hash(),
+          impl_cache: new_def_hash(),
           ext_cache: new_ext_hash(),
           used_imports: {mutable track: false, mutable data:  []},
           mutable reported: [],
@@ -489,7 +493,7 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
                   ids: [ast::ident], sp: codemap::span, sc: scopes) {
     fn register(e: env, id: node_id, cx: ctxt, sp: codemap::span,
                 name: ast::ident, lookup: block(namespace) -> option::t<def>,
-                impls: [@ast::item]) {
+                impls: [@_impl]) {
         let val = lookup(ns_value), typ = lookup(ns_type),
             md = lookup(ns_module);
         if is_none(val) && is_none(typ) && is_none(md) &&
@@ -1058,7 +1062,7 @@ fn lookup_in_mod(e: env, m: def, sp: span, name: ident, ns: namespace,
         if !is_none(cached) { ret cached; }
         let path = [name];
         if defid.node != ast::crate_node_id {
-            path = e.ext_map.get(defid) + path; 
+            path = e.ext_map.get(defid) + path;
         }
         let fnd = lookup_external(e, defid.crate, path, ns);
         if !is_none(fnd) {
@@ -1631,6 +1635,10 @@ fn check_export(e: @env, ident: str, val: @indexed_mod, vi: @view_item) {
 
 // Impl resolution
 
+type method_info = {did: def_id, n_tps: uint, ident: ast::ident};
+type _impl = {did: def_id, ident: ast::ident, methods: [@method_info]};
+type iscopes = list<@[@_impl]>;
+
 fn resolve_impls(e: @env, c: @ast::crate) {
     visit::visit_crate(*c, nil, visit::mk_vt(@{
         visit_block: bind visit_block_with_impl_scope(e, _, _, _),
@@ -1641,21 +1649,25 @@ fn resolve_impls(e: @env, c: @ast::crate) {
 }
 
 fn find_impls_in_view_item(e: env, vi: @ast::view_item,
-                           &impls: [@ast::item], sc: iscopes) {
+                           &impls: [@_impl], sc: iscopes) {
     alt vi.node {
-      ast::view_item_import(_, pt, id) {
+      ast::view_item_import(name, pt, id) {
         let found = [];
         if vec::len(*pt) == 1u {
             list::iter(sc) {|level|
                 if vec::len(found) > 0u { ret; }
                 for imp in *level {
-                    if imp.ident == pt[0] { found += [imp]; }
+                    if imp.ident == pt[0] {
+                        found += [@{ident: name with *imp}];
+                    }
                 }
                 if vec::len(found) > 0u { impls += found; }
             }
         } else {
             alt e.imports.get(id) {
-              resolved(_, _, _, is, _, _) { impls += *is; }
+              resolved(_, _, _, is, _, _) {
+                for i in *is { impls += [@{ident: name with *i}]; }
+              }
             }
         }
       }
@@ -1680,38 +1692,51 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item,
     }
 }
 
-fn find_impls_in_item(i: @ast::item, &impls: [@ast::item],
+fn find_impls_in_item(i: @ast::item, &impls: [@_impl],
                       name: option::t<ident>,
                       ck_exports: option::t<ast::_mod>) {
     alt i.node {
-      ast::item_impl(_, _, _) {
+      ast::item_impl(_, _, mthds) {
         if alt name { some(n) { n == i.ident } _ { true } } &&
            alt ck_exports { some(m) { is_exported(i.ident, m) } _ { true } } {
-            impls += [i];
+            impls += [@{did: local_def(i.id),
+                        ident: i.ident,
+                        methods: vec::map({|m| @{did: local_def(m.node.id),
+                                                 n_tps: vec::len(m.node.tps),
+                                                 ident: m.node.ident}},
+                                          mthds)}];
         }
       }
       _ {}
     }
 }
 
-// FIXME[impl] external importing of impls
-fn find_impls_in_mod(e: env, m: def, &impls: [@ast::item],
+// FIXME[impl] we should probably cache this
+fn find_impls_in_mod(e: env, m: def, &impls: [@_impl],
                      name: option::t<ident>) {
     alt m {
       ast::def_mod(defid) {
-        if defid.crate == ast::local_crate {
-            let md = option::get(e.mod_map.get(defid.node).m);
-            for i in md.items {
-                find_impls_in_item(i, impls, name, some(md));
+        alt e.impl_cache.find(defid) {
+          some(v) { impls += *v; }
+          none. {
+            let found = [];
+            if defid.crate == ast::local_crate {
+                let md = option::get(e.mod_map.get(defid.node).m);
+                for i in md.items {
+                    find_impls_in_item(i, found, name, some(md));
+                }
+            } else {
+                found = csearch::get_impls_for_mod(e.cstore, defid, name);
             }
+            impls += found;
+            e.impl_cache.insert(defid, @found);
+          }
         }
       }
       _ {}
     }
 }
 
-type iscopes = list<@[@ast::item]>;
-
 fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes,
                                v: vt<iscopes>) {
     let impls = [];
index 580930e561ba29e60db0f6986390943129e4d6ae..2a8673a265a3b646a9ac157aa2afad04d0cfabd6 100644 (file)
@@ -1463,33 +1463,36 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
 // FIXME[impl] notice/resolve conflicts
 fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
                  name: ast::ident, ty: ty::t)
-    -> option::t<{method: @ast::method, ids: [int]}> {
+    -> option::t<{method: @resolve::method_info, ids: [int]}> {
     let result = none;
     std::list::iter(isc) {|impls|
-        for im in *impls {
-            alt im.node {
-              ast::item_impl(tps, slf, mthds) {
-                let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
-                let tp_count = vec::len(tps);
-                let {ids, ty: self_ty} = if tp_count > 0u {
-                    bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
-                                        bind next_ty_var_id(fcx), self_ty,
-                                        tp_count)
-                } else { {ids: [], ty: self_ty} };
-                // FIXME[impl] Don't unify in the current fcx, use
-                // scratch context
-                alt unify::unify(fcx, ty, self_ty) {
-                  ures_ok(_) {
-                    for m in mthds {
-                        if m.node.ident == name {
-                            result = some({method: m, ids: ids});
-                            ret;
-                        }
-                    }
+        for @{did, methods, _} in *impls {
+            let (n_tps, self_ty) = if did.crate == ast::local_crate {
+                alt fcx.ccx.tcx.items.get(did.node) {
+                  ast_map::node_item(@{node: ast::item_impl(tps, st, _), _}) {
+                    (vec::len(tps), ast_ty_to_ty_crate(fcx.ccx, st))
                   }
-                  _ {}
+                }
+            } else {
+                let tpt = csearch::get_type(fcx.ccx.tcx, did);
+                (vec::len(tpt.kinds), tpt.ty)
+            };
+            let {ids, ty: self_ty} = if n_tps > 0u {
+                bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
+                                    bind next_ty_var_id(fcx), self_ty, n_tps)
+            } else { {ids: [], ty: self_ty} };
+            // FIXME[impl] Don't unify in the current fcx, use
+            // scratch context
+            alt unify::unify(fcx, ty, self_ty) {
+              ures_ok(_) {
+                for m in methods {
+                    if m.ident == name {
+                        result = some({method: m, ids: ids});
+                        ret;
+                    }
                 }
               }
+              _ {}
             }
         }
     }
@@ -2129,20 +2132,26 @@ fn get_node(f: spanned<field>) -> field { f.node }
         let iscope = fcx.ccx.impl_map.get(expr.id);
         alt lookup_method(fcx, iscope, field, base_t) {
           some({method, ids}) {
-            let mt = ty_of_method(fcx.ccx.tcx, m_check, method), ids = ids;
-            let fty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
-                                mt.output, mt.cf, mt.constrs);
-            let tp_count = vec::len(method.node.tps);
-            if tp_count > 0u {
+            let fty = if method.did.crate == ast::local_crate {
+                alt tcx.items.get(method.did.node) {
+                  ast_map::node_method(m) {
+                    let mt = ty_of_method(tcx, m_check, m);
+                    ty::mk_fn(tcx, mt.proto, mt.inputs,
+                              mt.output, mt.cf, mt.constrs)
+                  }
+                }
+            } else { csearch::get_type(tcx, method.did).ty };
+            let ids = ids;
+            if method.n_tps > 0u {
                 let b = bind_params_in_type(expr.span, tcx,
                                             bind next_ty_var_id(fcx),
-                                            fty, tp_count);
+                                            fty, method.n_tps);
                 ids += b.ids;
                 fty = b.ty;
             }
             let substs = vec::map(ids, {|id| ty::mk_var(tcx, id)});
             write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
-            fcx.ccx.method_map.insert(id, local_def(method.node.id));
+            fcx.ccx.method_map.insert(id, method.did);
           }
           _ {
             base_t = do_autoderef(fcx, expr.span, base_t);