rustc: Make vtables use the coherence tables
This commit is contained in:
@@ -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>")
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
Reference in New Issue
Block a user