diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-16 14:41:12 +0100 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-16 22:18:38 +0100 |
| commit | 58a81a68edb605dabe5f1aa04a087e412ad73936 (patch) | |
| tree | 66ea1ecac1c2f5c156654f16b43ddfef0d25237a | |
| parent | dd9693f211f65d4c69a2e65c3e33ccc337d7f695 (diff) | |
| download | rust-58a81a68edb605dabe5f1aa04a087e412ad73936.tar.gz rust-58a81a68edb605dabe5f1aa04a087e412ad73936.zip | |
Finish resolving and calling of crate-external impls
Issue #1227
| -rw-r--r-- | src/comp/driver/rustc.rs | 2 | ||||
| -rw-r--r-- | src/comp/metadata/csearch.rs | 36 | ||||
| -rw-r--r-- | src/comp/metadata/decoder.rs | 50 | ||||
| -rw-r--r-- | src/comp/metadata/encoder.rs | 50 | ||||
| -rw-r--r-- | src/comp/middle/ast_map.rs | 4 | ||||
| -rw-r--r-- | src/comp/middle/resolve.rs | 63 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 67 |
7 files changed, 196 insertions, 76 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index a97afa7cb83..c87fff86bb9 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -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); } diff --git a/src/comp/metadata/csearch.rs b/src/comp/metadata/csearch.rs index 222d6ac7f0e..81bd90a0a41 100644 --- a/src/comp/metadata/csearch.rs +++ b/src/comp/metadata/csearch.rs @@ -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}; diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index 2451a567ea7..9428d420270 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -16,6 +16,7 @@ export get_type; 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 crate_dep; 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 resolve_path(path: [ast::ident], data: @[u8]) -> [ast::def_id] { 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 } }; } diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs index 340328f666a..92ab6db903f 100644 --- a/src/comp/metadata/encoder.rs +++ b/src/comp/metadata/encoder.rs @@ -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); diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs index a86208dd8c6..78e3da6b030 100644 --- a/src/comp/middle/ast_map.rs +++ b/src/comp/middle/ast_map.rs @@ -8,6 +8,7 @@ tag ast_node { 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)); } + } _ { } } } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 75bd5de7c68..484e36be184 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -19,7 +19,8 @@ import option::{some, none, is_none, is_some}; 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 @@ tag import_state { 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 @@ type def_map = hashmap<node_id, def>; 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 @@ type env = 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_exports(e: @env) { // 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 = []; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 580930e561b..2a8673a265a 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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 check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, 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); |
