rustc: Make vtables use the coherence tables

This commit is contained in:
Patrick Walton
2012-07-23 10:11:10 -07:00
parent 81f108154a
commit 674dd14eec
2 changed files with 108 additions and 77 deletions

View File

@@ -1,6 +1,7 @@
import check::{fn_ctxt, impl_self_ty, methods}; import check::{fn_ctxt, impl_self_ty, methods};
import infer::{resolve_type, resolve_all, force_all, fixup_err_to_str}; import infer::{resolve_type, resolve_all, force_all, fixup_err_to_str};
import ast_util::new_def_hash; import ast_util::new_def_hash;
import dvec::extensions;
fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool { fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
vec::any(tps, |bs| { vec::any(tps, |bs| {
@@ -10,7 +11,7 @@ fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
}) })
} }
fn lookup_vtables(fcx: @fn_ctxt, isc: resolve3::ImplScopes, sp: span, fn lookup_vtables(fcx: @fn_ctxt, sp: span,
bounds: @~[ty::param_bounds], substs: ty::substs, bounds: @~[ty::param_bounds], substs: ty::substs,
allow_unsafe: bool) -> vtable_res { allow_unsafe: bool) -> vtable_res {
let tcx = fcx.ccx.tcx; let tcx = fcx.ccx.tcx;
@@ -20,8 +21,8 @@ fn lookup_vtables(fcx: @fn_ctxt, isc: resolve3::ImplScopes, sp: span,
alt bound { alt bound {
ty::bound_trait(i_ty) { ty::bound_trait(i_ty) {
let i_ty = ty::subst(tcx, substs, i_ty); let i_ty = ty::subst(tcx, substs, i_ty);
vec::push(result, lookup_vtable(fcx, isc, sp, ty, i_ty, vec::push(result, lookup_vtable(fcx, sp, ty, i_ty,
allow_unsafe)); allow_unsafe));
} }
_ {} _ {}
} }
@@ -50,12 +51,10 @@ fn relate_trait_tys(fcx: @fn_ctxt, sp: span,
/* /*
Look up the vtable to use when treating an item of type <t> Look up the vtable to use when treating an item of type <t>
as if it has type <trait_ty> as if it has type <trait_ty>
XXX: This doesn't use the coherence tables yet.
*/ */
fn lookup_vtable(fcx: @fn_ctxt, isc: resolve3::ImplScopes, sp: span, fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
ty: ty::t, trait_ty: ty::t, allow_unsafe: bool) allow_unsafe: bool)
-> vtable_origin { -> vtable_origin {
#debug["lookup_vtable(ty=%s, trait_ty=%s)", #debug["lookup_vtable(ty=%s, trait_ty=%s)",
fcx.infcx.ty_to_str(ty), fcx.infcx.ty_to_str(trait_ty)]; fcx.infcx.ty_to_str(ty), fcx.infcx.ty_to_str(trait_ty)];
@@ -119,64 +118,72 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve3::ImplScopes, sp: span,
let mut impls_seen = new_def_hash(); let mut impls_seen = new_def_hash();
for list::each(isc) |impls| { alt fcx.ccx.coherence_info.extension_methods.find(trait_id) {
/* For each impl in scope... */ none {
for vec::each(*impls) |im| { // Nothing found. Continue.
// im = one specific impl }
some(implementations) {
for uint::range(0, implementations.len()) |i| {
let im = implementations[i];
// First, ensure that we haven't processed this impl yet. // im = one specific impl
if impls_seen.contains_key(im.did) {
again;
}
impls_seen.insert(im.did, ());
// find the trait that im implements (if any) // First, ensure that we haven't processed this impl yet.
for vec::each(ty::impl_traits(tcx, im.did)) |of_ty| { if impls_seen.contains_key(im.did) {
// it must have the same id as the expected one again;
alt ty::get(of_ty).struct {
ty::ty_trait(id, _) if id != trait_id { again; }
_ { /* ok */ }
} }
impls_seen.insert(im.did, ());
// check whether the type unifies with the type // find the trait that im implements (if any)
// that the impl is for, and continue if not for vec::each(ty::impl_traits(tcx, im.did)) |of_ty| {
let {substs: substs, ty: for_ty} = // it must have the same id as the expected one
impl_self_ty(fcx, im.did); alt ty::get(of_ty).struct {
let im_bs = ty::lookup_item_type(tcx, im.did).bounds; ty::ty_trait(id, _) if id != trait_id { again; }
alt fcx.mk_subty(ty, for_ty) { _ { /* ok */ }
result::err(_) { again; } }
result::ok(()) { }
// check whether the type unifies with the type
// that the impl is for, and continue if not
let {substs: substs, ty: for_ty} =
impl_self_ty(fcx, im.did);
let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
alt fcx.mk_subty(ty, for_ty) {
result::err(_) { again; }
result::ok(()) { }
}
// check that desired trait type unifies
#debug("(checking vtable) @2 relating trait ty %s to \
of_ty %s",
fcx.infcx.ty_to_str(trait_ty),
fcx.infcx.ty_to_str(of_ty));
let of_ty = ty::subst(tcx, substs, of_ty);
relate_trait_tys(fcx, sp, trait_ty, of_ty);
// recursively process the bounds
let trait_tps = trait_substs.tps;
let substs_f = fixup_substs(fcx, sp, trait_id,
substs);
connect_trait_tps(fcx, sp, substs_f.tps,
trait_tps, im.did);
let subres = lookup_vtables(fcx, sp, im_bs, substs_f,
false);
vec::push(found,
vtable_static(im.did, substs_f.tps,
subres));
} }
// check that desired trait type unifies
#debug("(checking vtable) @2 relating trait ty %s to \
of_ty %s",
fcx.infcx.ty_to_str(trait_ty),
fcx.infcx.ty_to_str(of_ty));
let of_ty = ty::subst(tcx, substs, of_ty);
relate_trait_tys(fcx, sp, trait_ty, of_ty);
// recursively process the bounds
let trait_tps = trait_substs.tps;
let substs_f = fixup_substs(fcx, sp, trait_id, substs);
connect_trait_tps(fcx, sp, substs_f.tps,
trait_tps, im.did);
let subres = lookup_vtables(fcx, isc, sp,
im_bs, substs_f, false);
vec::push(found,
vtable_static(im.did, substs_f.tps, subres));
} }
} }
}
alt found.len() { alt found.len() {
0u { /* fallthrough */ } 0u { /* fallthrough */ }
1u { ret found[0]; } 1u { ret found[0]; }
_ { _ {
fcx.ccx.tcx.sess.span_err( fcx.ccx.tcx.sess.span_err(
sp, ~"multiple applicable methods in scope"); sp, ~"multiple applicable methods in scope");
ret found[0]; ret found[0];
} }
}
} }
} }
} }
@@ -227,10 +234,11 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)); let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
let item_ty = ty::lookup_item_type(cx.tcx, did); let item_ty = ty::lookup_item_type(cx.tcx, did);
if has_trait_bounds(*item_ty.bounds) { if has_trait_bounds(*item_ty.bounds) {
let impls = cx.impl_map.get(ex.id); cx.vtable_map.insert(ex.id, lookup_vtables(fcx,
cx.vtable_map.insert(ex.id, lookup_vtables( ex.span,
fcx, impls, ex.span, item_ty.bounds,
item_ty.bounds, substs, false)); substs,
false));
} }
} }
_ {} _ {}
@@ -249,9 +257,11 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
_ { ex.callee_id } _ { ex.callee_id }
}; };
let substs = fcx.node_ty_substs(callee_id); let substs = fcx.node_ty_substs(callee_id);
let iscs = cx.impl_map.get(ex.id); cx.vtable_map.insert(callee_id, lookup_vtables(fcx,
cx.vtable_map.insert(callee_id, lookup_vtables( ex.span,
fcx, iscs, ex.span, bounds, substs, false)); bounds,
substs,
false));
} }
} }
_ {} _ {}
@@ -261,17 +271,12 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
let target_ty = fcx.expr_ty(ex); let target_ty = fcx.expr_ty(ex);
alt ty::get(target_ty).struct { alt ty::get(target_ty).struct {
ty::ty_trait(*) { ty::ty_trait(*) {
/* Casting to an interface type.
Look up all impls for the cast expr...
*/
let impls = cx.impl_map.get(ex.id);
/* /*
Look up vtables for the type we're casting to, Look up vtables for the type we're casting to,
passing in the source and target type passing in the source and target type
*/ */
let vtable = lookup_vtable(fcx, impls, ex.span, let vtable = lookup_vtable(fcx, ex.span, fcx.expr_ty(src),
fcx.expr_ty(src), target_ty, target_ty, true);
true);
/* /*
Map this expression to that vtable (that is: "ex has Map this expression to that vtable (that is: "ex has
vtable <vtable>") vtable <vtable>")

View File

@@ -17,10 +17,10 @@ import middle::ty::{ty_param, ty_self, ty_type, ty_opaque_box};
import middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_var}; import middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_var};
import middle::typeck::infer::{infer_ctxt, mk_subty}; import middle::typeck::infer::{infer_ctxt, mk_subty};
import middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; import middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
import syntax::ast::{crate, def_id, def_mod, item, item_class, item_const}; import syntax::ast::{class_method, crate, def_id, def_mod, instance_var};
import syntax::ast::{item_enum, item_fn, item_foreign_mod, item_impl}; import syntax::ast::{item, item_class, item_const, item_enum, item_fn};
import syntax::ast::{item_mac, item_mod, item_trait, item_ty, local_crate}; import syntax::ast::{item_foreign_mod, item_impl, item_mac, item_mod};
import syntax::ast::{method, node_id}; import syntax::ast::{item_trait, item_ty, local_crate, method, node_id};
import syntax::ast::{trait_ref}; import syntax::ast::{trait_ref};
import syntax::ast_map::node_item; import syntax::ast_map::node_item;
import syntax::ast_util::{def_id_of_def, dummy_sp, new_def_hash}; import syntax::ast_util::{def_id_of_def, dummy_sp, new_def_hash};
@@ -161,7 +161,10 @@ class CoherenceChecker {
#debug("(checking coherence) item '%s'", *item.ident); #debug("(checking coherence) item '%s'", *item.ident);
alt item.node { alt item.node {
item_impl(_, associated_traits, self_type, _) { item_impl(_, associated_traits, _, _) {
self.check_implementation(item, associated_traits);
}
item_class(_, associated_traits, _, _, _) {
self.check_implementation(item, associated_traits); self.check_implementation(item, associated_traits);
} }
_ { _ {
@@ -499,6 +502,29 @@ class CoherenceChecker {
methods: methods methods: methods
}; };
} }
item_class(ty_params, _, class_members, _, _) {
let mut methods = ~[];
for class_members.each |class_member| {
alt class_member.node {
instance_var(*) {
// Nothing to do.
}
class_method(ast_method) {
push(methods, @{
did: local_def(ast_method.id),
n_tps: ast_method.tps.len(),
ident: ast_method.ident
});
}
}
}
ret @{
did: local_def(item.id),
ident: item.ident,
methods: methods
};
}
_ { _ {
self.crate_context.tcx.sess.span_bug(item.span, self.crate_context.tcx.sess.span_bug(item.span,
~"can't convert a \ ~"can't convert a \