rustc: Refactor vtable lookup to use a vtable context, so that it can be called outside a function. rs=refactor

This commit is contained in:
Patrick Walton 2012-11-02 17:57:17 -07:00
parent 9e0c596141
commit b90d7d4c81
3 changed files with 101 additions and 62 deletions

View File

@ -78,7 +78,7 @@ use typeck::infer::{resolve_type, force_tvar};
use result::{Result, Ok, Err};
use syntax::print::pprust;
use syntax::parse::token::special_idents;
use vtable::LocationInfo;
use vtable::{LocationInfo, VtableContext};
use std::map::HashMap;
@ -865,20 +865,20 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
// declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
fn impl_self_ty(fcx: @fn_ctxt,
fn impl_self_ty(vcx: &VtableContext,
location_info: &LocationInfo, // (potential) receiver for
// this impl
did: ast::def_id) -> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
let tcx = vcx.tcx();
let {n_tps, region_param, raw_ty} = if did.crate == ast::local_crate {
let region_param = fcx.tcx().region_paramd_items.find(did.node);
let region_param = tcx.region_paramd_items.find(did.node);
match tcx.items.find(did.node) {
Some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
_}, _)) => {
{n_tps: ts.len(),
region_param: region_param,
raw_ty: fcx.ccx.to_ty(rscope::type_rscope(region_param), st)}
raw_ty: vcx.ccx.to_ty(rscope::type_rscope(region_param), st)}
}
Some(ast_map::node_item(@{node: ast::item_class(_, ts),
id: class_id, _},_)) => {
@ -904,12 +904,12 @@ fn impl_self_ty(fcx: @fn_ctxt,
};
let self_r = if region_param.is_some() {
Some(fcx.infcx().next_region_var(location_info.span,
Some(vcx.infcx.next_region_var(location_info.span,
location_info.id))
} else {
None
};
let tps = fcx.infcx().next_ty_vars(n_tps);
let tps = vcx.infcx.next_ty_vars(n_tps);
let substs = {self_r: self_r, self_ty: None, tps: tps};
let substd_ty = ty::subst(tcx, &substs, raw_ty);

View File

@ -492,8 +492,12 @@ impl LookupContext {
// determine the `self` of the impl with fresh
// variables for each parameter:
let location_info = &vtable::location_info_for_expr(self.self_expr);
let vcx = VtableContext {
ccx: self.fcx.ccx,
infcx: self.fcx.infcx()
};
let {substs: impl_substs, ty: impl_ty} =
impl_self_ty(self.fcx, location_info, impl_info.did);
impl_self_ty(&vcx, location_info, impl_info.did);
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(

View File

@ -1,5 +1,5 @@
use check::{fn_ctxt, impl_self_ty};
use infer::{resolve_type, resolve_and_force_all_but_regions,
use infer::{infer_ctxt, resolve_type, resolve_and_force_all_but_regions,
fixup_err_to_str};
use syntax::codemap::span;
use syntax::print::pprust;
@ -30,6 +30,17 @@ struct LocationInfo {
id: ast::node_id
}
/// A vtable context includes an inference context, a crate context, and a
/// callback function to call in case of type error.
struct VtableContext {
ccx: @crate_ctxt,
infcx: infer::infer_ctxt
}
impl VtableContext {
fn tcx(&const self) -> ty::ctxt { self.ccx.tcx }
}
fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
vec::any(tps, |bs| {
bs.any(|b| {
@ -38,7 +49,7 @@ fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
})
}
fn lookup_vtables(fcx: @fn_ctxt,
fn lookup_vtables(vcx: &VtableContext,
location_info: &LocationInfo,
bounds: @~[ty::param_bounds],
substs: &ty::substs,
@ -50,26 +61,26 @@ fn lookup_vtables(fcx: @fn_ctxt,
substs=%s",
location_info,
bounds.len(),
ty::substs_to_str(fcx.tcx(), substs));
ty::substs_to_str(vcx.tcx(), substs));
let _i = indenter();
let tcx = fcx.ccx.tcx;
let tcx = vcx.tcx();
let mut result = ~[], i = 0u;
for substs.tps.each |ty| {
for vec::each(*bounds[i]) |bound| {
match *bound {
ty::bound_trait(i_ty) => {
let i_ty = ty::subst(tcx, substs, i_ty);
match lookup_vtable_covariant(fcx, location_info, *ty, i_ty,
match lookup_vtable_covariant(vcx, location_info, *ty, i_ty,
allow_unsafe, is_early) {
Some(vtable) => result.push(vtable),
None => {
fcx.tcx().sess.span_fatal(
vcx.tcx().sess.span_fatal(
location_info.span,
fmt!("failed to find an implementation of trait \
%s for %s",
ty_to_str(fcx.tcx(), i_ty),
ty_to_str(fcx.tcx(), *ty)));
ty_to_str(vcx.tcx(), i_ty),
ty_to_str(vcx.tcx(), *ty)));
}
}
}
@ -81,13 +92,13 @@ fn lookup_vtables(fcx: @fn_ctxt,
@result
}
fn fixup_substs(fcx: @fn_ctxt, location_info: &LocationInfo,
fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
id: ast::def_id, substs: ty::substs,
is_early: bool) -> Option<ty::substs> {
let tcx = fcx.ccx.tcx;
let tcx = vcx.tcx();
// use a dummy type just to package up the substs that need fixing up
let t = ty::mk_trait(tcx, id, substs, ty::vstore_slice(ty::re_static));
do fixup_ty(fcx, location_info, t, is_early).map |t_f| {
do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
match ty::get(*t_f).sty {
ty::ty_trait(_, substs_f, _) => substs_f,
_ => fail ~"t_f should be a trait"
@ -95,14 +106,14 @@ fn fixup_substs(fcx: @fn_ctxt, location_info: &LocationInfo,
}
}
fn relate_trait_tys(fcx: @fn_ctxt, location_info: &LocationInfo,
fn relate_trait_tys(vcx: &VtableContext, location_info: &LocationInfo,
exp_trait_ty: ty::t, act_trait_ty: ty::t) {
demand::suptype(fcx, location_info.span, exp_trait_ty, act_trait_ty)
demand_suptype(vcx, location_info.span, exp_trait_ty, act_trait_ty)
}
// Look up the vtable to use when treating an item of type `t` as if it has
// type `trait_ty`. This does allow subtraits.
fn lookup_vtable_covariant(fcx: @fn_ctxt,
fn lookup_vtable_covariant(vcx: &VtableContext,
location_info: &LocationInfo,
ty: ty::t,
trait_ty: ty::t,
@ -110,14 +121,14 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
is_early: bool)
-> Option<vtable_origin> {
debug!("lookup_vtable_covariant(ty: %s, trait_ty=%s)",
fcx.infcx().ty_to_str(ty),
fcx.infcx().ty_to_str(trait_ty));
vcx.infcx.ty_to_str(ty),
vcx.infcx.ty_to_str(trait_ty));
let worklist = dvec::DVec();
worklist.push(trait_ty);
while worklist.len() > 0 {
let trait_ty = worklist.pop();
let result = lookup_vtable_invariant(fcx, location_info, ty, trait_ty,
let result = lookup_vtable_invariant(vcx, location_info, ty, trait_ty,
allow_unsafe, is_early);
if result.is_some() {
return result;
@ -126,7 +137,7 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
// Add subtraits to the worklist, if applicable.
match ty::get(trait_ty).sty {
ty::ty_trait(trait_id, _, _) => {
let table = fcx.ccx.coherence_info.supertrait_to_subtraits;
let table = vcx.ccx.coherence_info.supertrait_to_subtraits;
match table.find(trait_id) {
None => {}
Some(subtraits) => {
@ -135,7 +146,7 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
// have substs.
let substs =
{ self_r: None, self_ty: None, tps: ~[] };
let trait_ty = ty::mk_trait(fcx.ccx.tcx,
let trait_ty = ty::mk_trait(vcx.tcx(),
*subtrait_id,
substs,
ty::vstore_box);
@ -145,9 +156,9 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
}
}
_ => {
fcx.ccx.tcx.sess.impossible_case(location_info.span,
"lookup_vtable_covariant: \
non-trait in worklist");
vcx.tcx().sess.impossible_case(location_info.span,
"lookup_vtable_covariant: \
non-trait in worklist");
}
}
}
@ -157,7 +168,7 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
// Look up the vtable to use when treating an item of type `t` as if it has
// type `trait_ty`. This does not allow subtraits.
fn lookup_vtable_invariant(fcx: @fn_ctxt,
fn lookup_vtable_invariant(vcx: &VtableContext,
location_info: &LocationInfo,
ty: ty::t,
trait_ty: ty::t,
@ -165,17 +176,17 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
is_early: bool)
-> Option<vtable_origin> {
debug!("lookup_vtable_invariant(ty=%s, trait_ty=%s)",
fcx.infcx().ty_to_str(ty), fcx.inh.infcx.ty_to_str(trait_ty));
vcx.infcx.ty_to_str(ty), vcx.infcx.ty_to_str(trait_ty));
let _i = indenter();
let tcx = fcx.ccx.tcx;
let tcx = vcx.tcx();
let (trait_id, trait_substs, trait_vstore) = match ty::get(trait_ty).sty {
ty::ty_trait(did, substs, vstore) => (did, substs, vstore),
_ => tcx.sess.impossible_case(location_info.span,
"lookup_vtable_invariant: \
don't know how to handle a non-trait")
};
let ty = match fixup_ty(fcx, location_info, ty, is_early) {
let ty = match fixup_ty(vcx, location_info, ty, is_early) {
Some(ty) => ty,
None => {
// fixup_ty can only fail if this is early resolution
@ -203,7 +214,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
debug!("(checking vtable) @0 relating \
ty to trait ty with did %?",
idid);
relate_trait_tys(fcx, location_info,
relate_trait_tys(vcx, location_info,
trait_ty, ity);
return Some(vtable_param(n, n_bound));
}
@ -223,7 +234,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
debug!("(checking vtable) @1 relating ty to trait ty with did %?",
did);
relate_trait_tys(fcx, location_info, trait_ty, ty);
relate_trait_tys(vcx, location_info, trait_ty, ty);
if !allow_unsafe && !is_early {
for vec::each(*ty::trait_methods(tcx, did)) |m| {
if ty::type_has_self(ty::mk_fn(tcx, m.fty)) {
@ -248,7 +259,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
let mut impls_seen = HashMap();
match fcx.ccx.coherence_info.extension_methods.find(trait_id) {
match vcx.ccx.coherence_info.extension_methods.find(trait_id) {
None => {
// Nothing found. Continue.
}
@ -309,11 +320,14 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
// to some_trait. If not, then we try the next
// impl.
let {substs: substs, ty: for_ty} =
impl_self_ty(fcx, location_info, im.did);
impl_self_ty(vcx, location_info, im.did);
let im_bs = ty::lookup_item_type(tcx,
im.did).bounds;
match fcx.mk_subty(false, location_info.span, ty,
for_ty) {
match infer::mk_subty(vcx.infcx,
false,
location_info.span,
ty,
for_ty) {
result::Err(_) => loop,
result::Ok(()) => ()
}
@ -322,8 +336,8 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
// bound to the type self_ty, and substs
// is bound to [T].
debug!("The self ty is %s and its substs are %s",
fcx.infcx().ty_to_str(for_ty),
tys_to_str(fcx.ccx.tcx, substs.tps));
vcx.infcx.ty_to_str(for_ty),
tys_to_str(vcx.tcx(), substs.tps));
// Next, we unify trait_ty -- the type
// that we want to cast to -- with of_ty
@ -341,10 +355,10 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
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));
vcx.infcx.ty_to_str(trait_ty),
vcx.infcx.ty_to_str(*of_ty));
let of_ty = ty::subst(tcx, &substs, *of_ty);
relate_trait_tys(fcx, location_info, trait_ty,
relate_trait_tys(vcx, location_info, trait_ty,
of_ty);
// Recall that trait_ty -- the trait type
@ -357,7 +371,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
debug!("Casting to a trait ty whose substs \
(trait_tps) are %s",
tys_to_str(fcx.ccx.tcx, trait_tps));
tys_to_str(vcx.tcx(), trait_tps));
// Recall that substs is the impl self
// type's list of substitutions. That is,
@ -367,7 +381,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
// variables, so we call fixup_substs to
// resolve them.
let substs_f = match fixup_substs(fcx,
let substs_f = match fixup_substs(vcx,
location_info,
trait_id,
substs,
@ -383,8 +397,8 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
debug!("The fixed-up substs are %s - \
they will be unified with the bounds for \
the target ty, %s",
tys_to_str(fcx.ccx.tcx, substs_f.tps),
tys_to_str(fcx.ccx.tcx, trait_tps));
tys_to_str(vcx.tcx(), substs_f.tps),
tys_to_str(vcx.tcx(), trait_tps));
// Next, we unify the fixed-up
// substitutions for the impl self ty with
@ -393,14 +407,14 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
// to. connect_trait_tps requires these
// lists of types to unify pairwise.
connect_trait_tps(fcx,
connect_trait_tps(vcx,
location_info,
substs_f.tps,
trait_tps,
im.did,
trait_vstore);
let subres = lookup_vtables(
fcx, location_info, im_bs, &substs_f,
vcx, location_info, im_bs, &substs_f,
false, is_early);
// Finally, we register that we found a
@ -421,7 +435,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
1 => { return Some(found[0]); }
_ => {
if !is_early {
fcx.ccx.tcx.sess.span_err(
vcx.tcx().sess.span_err(
location_info.span,
~"multiple applicable methods in scope");
}
@ -434,13 +448,13 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
return None;
}
fn fixup_ty(fcx: @fn_ctxt,
fn fixup_ty(vcx: &VtableContext,
location_info: &LocationInfo,
ty: ty::t,
is_early: bool) -> Option<ty::t>
{
let tcx = fcx.ccx.tcx;
match resolve_type(fcx.infcx(), ty, resolve_and_force_all_but_regions) {
let tcx = vcx.tcx();
match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
Ok(new_type) => Some(new_type),
Err(e) if !is_early => {
tcx.sess.span_fatal(
@ -455,13 +469,31 @@ fn fixup_ty(fcx: @fn_ctxt,
}
}
fn connect_trait_tps(fcx: @fn_ctxt,
// Version of demand::suptype() that takes a vtable context instead of a
// function context.
fn demand_suptype(vcx: &VtableContext, sp: span, e: ty::t, a: ty::t) {
// NB: Order of actual, expected is reversed.
match infer::mk_subty(vcx.infcx, false, sp, a, e) {
result::Ok(()) => {} // Ok.
result::Err(ref err) => {
vcx.tcx().sess.span_err(
sp,
fmt!("mismatched types: expected `%s` but found `%s` (%s)",
vcx.infcx.ty_to_str(e),
vcx.infcx.ty_to_str(a),
ty::type_err_to_str(vcx.tcx(), err)));
ty::note_and_explain_type_err(vcx.tcx(), err);
}
}
}
fn connect_trait_tps(vcx: &VtableContext,
location_info: &LocationInfo,
impl_tys: ~[ty::t],
trait_tys: ~[ty::t],
impl_did: ast::def_id,
vstore: ty::vstore) {
let tcx = fcx.ccx.tcx;
let tcx = vcx.tcx();
// XXX: This should work for multiple traits.
let ity = ty::impl_traits(tcx, impl_did, vstore)[0];
@ -471,7 +503,7 @@ fn connect_trait_tps(fcx: @fn_ctxt,
match ty::get(trait_ty).sty {
ty::ty_trait(_, substs, _) => {
for vec::each2(substs.tps, trait_tys) |a, b| {
demand::suptype(fcx, location_info.span, *a, *b)
demand_suptype(vcx, location_info.span, *a, *b);
}
}
_ => tcx.sess.impossible_case(location_info.span, "connect_trait_tps: \
@ -513,7 +545,8 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
%s",
ty::param_bounds_to_str(fcx.tcx(), *bounds));
}
let vtbls = lookup_vtables(fcx, &location_info_for_expr(ex),
let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() };
let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
item_ty.bounds, substs, false,
is_early);
if !is_early { cx.vtable_map.insert(ex.id, vtbls); }
@ -539,7 +572,8 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
_ => ex.callee_id
};
let substs = fcx.node_ty_substs(callee_id);
let vtbls = lookup_vtables(fcx, &location_info_for_expr(ex),
let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() };
let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
bounds, &substs, false, is_early);
if !is_early {
insert_vtables(cx, callee_id, vtbls);
@ -559,8 +593,9 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
// XXX: This is invariant and shouldn't be. --pcw
let ty = fcx.expr_ty(src);
let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() };
let vtable_opt =
lookup_vtable_invariant(fcx,
lookup_vtable_invariant(&vcx,
&location_info_for_expr(ex),
ty,
target_ty,
@ -586,7 +621,7 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
let location_info =
&location_info_for_expr(ex);
let vtable_opt =
lookup_vtable_invariant(fcx,
lookup_vtable_invariant(&vcx,
location_info,
mt.ty,
target_ty,