Finish resolving and calling of crate-external impls

Issue #1227
This commit is contained in:
Marijn Haverbeke 2011-12-16 14:41:12 +01:00
parent dd9693f211
commit 58a81a68ed
7 changed files with 196 additions and 76 deletions

View 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);
}

View 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};

View File

@ -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 }
};
}

View 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);

View File

@ -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)); }
}
_ { }
}
}

View File

@ -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 = [];

View 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 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);