rustc: Eliminate the necessity of having an expr in order to call lookup_vtables(). rs=#rust

Automatically-generated derived methods don't have exprs and need to call this function.
This commit is contained in:
Patrick Walton 2012-11-02 17:03:35 -07:00
parent e2f33e6883
commit 9e0c596141
3 changed files with 80 additions and 44 deletions

View file

@ -78,6 +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 std::map::HashMap;
@ -865,7 +866,8 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
fn impl_self_ty(fcx: @fn_ctxt,
expr: @ast::expr, // (potential) receiver for this impl
location_info: &LocationInfo, // (potential) receiver for
// this impl
did: ast::def_id) -> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
@ -902,7 +904,8 @@ fn impl_self_ty(fcx: @fn_ctxt,
};
let self_r = if region_param.is_some() {
Some(fcx.infcx().next_region_var(expr.span, expr.id))
Some(fcx.infcx().next_region_var(location_info.span,
location_info.id))
} else {
None
};

View file

@ -491,8 +491,9 @@ 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 {substs: impl_substs, ty: impl_ty} =
impl_self_ty(self.fcx, self.self_expr, impl_info.did);
impl_self_ty(self.fcx, location_info, impl_info.did);
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(

View file

@ -1,6 +1,7 @@
use check::{fn_ctxt, impl_self_ty};
use infer::{resolve_type, resolve_and_force_all_but_regions,
fixup_err_to_str};
use syntax::codemap::span;
use syntax::print::pprust;
use result::{Result, Ok, Err};
use util::common::indenter;
@ -21,6 +22,14 @@ use util::common::indenter;
// would require much more care, and this seems to work decently in
// practice.)
/// Location info records the span and ID of the expression or item that is
/// responsible for this vtable instantiation. (This may not be an expression
/// if the vtable instantiation is being performed as part of "deriving".)
struct LocationInfo {
span: span,
id: ast::node_id
}
fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
vec::any(tps, |bs| {
bs.any(|b| {
@ -30,16 +39,16 @@ fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
}
fn lookup_vtables(fcx: @fn_ctxt,
expr: @ast::expr,
location_info: &LocationInfo,
bounds: @~[ty::param_bounds],
substs: &ty::substs,
allow_unsafe: bool,
is_early: bool) -> vtable_res
{
debug!("lookup_vtables(expr=%?/%s, \
debug!("lookup_vtables(location_info=%?,
# bounds=%?, \
substs=%s",
expr.id, fcx.expr_to_str(expr),
location_info,
bounds.len(),
ty::substs_to_str(fcx.tcx(), substs));
let _i = indenter();
@ -51,12 +60,12 @@ fn lookup_vtables(fcx: @fn_ctxt,
match *bound {
ty::bound_trait(i_ty) => {
let i_ty = ty::subst(tcx, substs, i_ty);
match lookup_vtable_covariant(fcx, expr, *ty, i_ty,
match lookup_vtable_covariant(fcx, location_info, *ty, i_ty,
allow_unsafe, is_early) {
Some(vtable) => result.push(vtable),
None => {
fcx.tcx().sess.span_fatal(
expr.span,
location_info.span,
fmt!("failed to find an implementation of trait \
%s for %s",
ty_to_str(fcx.tcx(), i_ty),
@ -72,13 +81,13 @@ fn lookup_vtables(fcx: @fn_ctxt,
@result
}
fn fixup_substs(fcx: @fn_ctxt, expr: @ast::expr,
fn fixup_substs(fcx: @fn_ctxt, location_info: &LocationInfo,
id: ast::def_id, substs: ty::substs,
is_early: bool) -> Option<ty::substs> {
let tcx = fcx.ccx.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, expr, t, is_early).map |t_f| {
do fixup_ty(fcx, 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"
@ -86,15 +95,15 @@ fn fixup_substs(fcx: @fn_ctxt, expr: @ast::expr,
}
}
fn relate_trait_tys(fcx: @fn_ctxt, expr: @ast::expr,
fn relate_trait_tys(fcx: @fn_ctxt, location_info: &LocationInfo,
exp_trait_ty: ty::t, act_trait_ty: ty::t) {
demand::suptype(fcx, expr.span, exp_trait_ty, act_trait_ty)
demand::suptype(fcx, 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,
expr: @ast::expr,
location_info: &LocationInfo,
ty: ty::t,
trait_ty: ty::t,
allow_unsafe: bool,
@ -108,7 +117,7 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
worklist.push(trait_ty);
while worklist.len() > 0 {
let trait_ty = worklist.pop();
let result = lookup_vtable_invariant(fcx, expr, ty, trait_ty,
let result = lookup_vtable_invariant(fcx, location_info, ty, trait_ty,
allow_unsafe, is_early);
if result.is_some() {
return result;
@ -136,7 +145,7 @@ fn lookup_vtable_covariant(fcx: @fn_ctxt,
}
}
_ => {
fcx.ccx.tcx.sess.impossible_case(expr.span,
fcx.ccx.tcx.sess.impossible_case(location_info.span,
"lookup_vtable_covariant: \
non-trait in worklist");
}
@ -149,7 +158,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,
expr: @ast::expr,
location_info: &LocationInfo,
ty: ty::t,
trait_ty: ty::t,
allow_unsafe: bool,
@ -162,11 +171,11 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
let tcx = fcx.ccx.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(expr.span,
_ => 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, expr, ty, is_early) {
let ty = match fixup_ty(fcx, location_info, ty, is_early) {
Some(ty) => ty,
None => {
// fixup_ty can only fail if this is early resolution
@ -194,13 +203,13 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
debug!("(checking vtable) @0 relating \
ty to trait ty with did %?",
idid);
relate_trait_tys(fcx, expr,
relate_trait_tys(fcx, location_info,
trait_ty, ity);
return Some(vtable_param(n, n_bound));
}
}
_ => tcx.sess.impossible_case(
expr.span,
location_info.span,
"lookup_vtable_invariant: in loop, \
don't know how to handle a non-trait ity")
}
@ -214,17 +223,17 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
debug!("(checking vtable) @1 relating ty to trait ty with did %?",
did);
relate_trait_tys(fcx, expr, trait_ty, ty);
relate_trait_tys(fcx, 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)) {
tcx.sess.span_err(
expr.span,
location_info.span,
~"a boxed trait with self types may not be \
passed as a bounded type");
} else if (*m.tps).len() > 0u {
tcx.sess.span_err(
expr.span,
location_info.span,
~"a boxed trait with generic methods may not \
be passed as a bounded type");
@ -300,10 +309,11 @@ 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, expr, im.did);
impl_self_ty(fcx, location_info, im.did);
let im_bs = ty::lookup_item_type(tcx,
im.did).bounds;
match fcx.mk_subty(false, expr.span, ty, for_ty) {
match fcx.mk_subty(false, location_info.span, ty,
for_ty) {
result::Err(_) => loop,
result::Ok(()) => ()
}
@ -334,7 +344,8 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
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, expr, trait_ty, of_ty);
relate_trait_tys(fcx, location_info, trait_ty,
of_ty);
// Recall that trait_ty -- the trait type
// we're casting to -- is the trait with
@ -357,7 +368,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
// resolve them.
let substs_f = match fixup_substs(fcx,
expr,
location_info,
trait_id,
substs,
is_early) {
@ -382,11 +393,14 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
// to. connect_trait_tps requires these
// lists of types to unify pairwise.
connect_trait_tps(fcx, expr, substs_f.tps,
trait_tps, im.did,
connect_trait_tps(fcx,
location_info,
substs_f.tps,
trait_tps,
im.did,
trait_vstore);
let subres = lookup_vtables(
fcx, expr, im_bs, &substs_f,
fcx, location_info, im_bs, &substs_f,
false, is_early);
// Finally, we register that we found a
@ -408,7 +422,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
_ => {
if !is_early {
fcx.ccx.tcx.sess.span_err(
expr.span,
location_info.span,
~"multiple applicable methods in scope");
}
return Some(found[0]);
@ -421,7 +435,7 @@ fn lookup_vtable_invariant(fcx: @fn_ctxt,
}
fn fixup_ty(fcx: @fn_ctxt,
expr: @ast::expr,
location_info: &LocationInfo,
ty: ty::t,
is_early: bool) -> Option<ty::t>
{
@ -430,7 +444,7 @@ fn fixup_ty(fcx: @fn_ctxt,
Ok(new_type) => Some(new_type),
Err(e) if !is_early => {
tcx.sess.span_fatal(
expr.span,
location_info.span,
fmt!("cannot determine a type \
for this bounded type parameter: %s",
fixup_err_to_str(e)))
@ -441,8 +455,11 @@ fn fixup_ty(fcx: @fn_ctxt,
}
}
fn connect_trait_tps(fcx: @fn_ctxt, expr: @ast::expr, impl_tys: ~[ty::t],
trait_tys: ~[ty::t], impl_did: ast::def_id,
fn connect_trait_tps(fcx: @fn_ctxt,
location_info: &LocationInfo,
impl_tys: ~[ty::t],
trait_tys: ~[ty::t],
impl_did: ast::def_id,
vstore: ty::vstore) {
let tcx = fcx.ccx.tcx;
@ -454,10 +471,10 @@ fn connect_trait_tps(fcx: @fn_ctxt, expr: @ast::expr, impl_tys: ~[ty::t],
match ty::get(trait_ty).sty {
ty::ty_trait(_, substs, _) => {
for vec::each2(substs.tps, trait_tys) |a, b| {
demand::suptype(fcx, expr.span, *a, *b)
demand::suptype(fcx, location_info.span, *a, *b)
}
}
_ => tcx.sess.impossible_case(expr.span, "connect_trait_tps: \
_ => tcx.sess.impossible_case(location_info.span, "connect_trait_tps: \
don't know how to handle a non-trait ty")
}
}
@ -469,6 +486,13 @@ fn insert_vtables(ccx: @crate_ctxt, callee_id: ast::node_id,
ccx.vtable_map.insert(callee_id, vtables);
}
fn location_info_for_expr(expr: @ast::expr) -> LocationInfo {
LocationInfo {
span: expr.span,
id: expr.id
}
}
fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
debug!("vtable: early_resolve_expr() ex with id %? (early: %b): %s",
ex.id, is_early, expr_to_str(ex, fcx.tcx().sess.intr()));
@ -489,8 +513,9 @@ 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, ex, item_ty.bounds,
substs, false, is_early);
let vtbls = lookup_vtables(fcx, &location_info_for_expr(ex),
item_ty.bounds, substs, false,
is_early);
if !is_early { cx.vtable_map.insert(ex.id, vtbls); }
}
}
@ -514,8 +539,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, ex, bounds,
&substs, false, is_early);
let vtbls = lookup_vtables(fcx, &location_info_for_expr(ex),
bounds, &substs, false, is_early);
if !is_early {
insert_vtables(cx, callee_id, vtbls);
}
@ -534,8 +559,13 @@ 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 vtable_opt = lookup_vtable_invariant(fcx, ex, ty, target_ty,
true, is_early);
let vtable_opt =
lookup_vtable_invariant(fcx,
&location_info_for_expr(ex),
ty,
target_ty,
true,
is_early);
match vtable_opt {
None => {
// Try the new-style boxed trait; "@int as @Trait".
@ -553,9 +583,11 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
(ty::ty_box(_), ty::vstore_box) |
(ty::ty_uniq(_), ty::vstore_uniq) |
(ty::ty_rptr(*), ty::vstore_slice(*)) => {
let location_info =
&location_info_for_expr(ex);
let vtable_opt =
lookup_vtable_invariant(fcx,
ex,
location_info,
mt.ty,
target_ty,
true,