1
Fork 0

Do vtable resolution for *all* method calls, not just statically resolved ones... Closes #3221.

This commit is contained in:
Michael Sullivan 2012-08-20 13:36:15 -07:00
parent 1300be58d7
commit a14485b7fd
4 changed files with 54 additions and 22 deletions

View file

@ -226,25 +226,8 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
_ => {
// Type substitions should only occur on paths and
// method calls, so this needs to be a method call.
match cx.method_map.get(e.id).origin {
typeck::method_static(did) => {
// n.b.: When we encode class/impl methods, the bounds
// that we encode include both the class/impl bounds
// and then the method bounds themselves...
ty::lookup_item_type(cx.tcx, did).bounds
}
typeck::method_param({trait_id:trt_id,
method_num:n_mth, _}) |
typeck::method_trait(trt_id, n_mth) => {
// ...trait methods bounds, in contrast, include only the
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
let trt_bounds =
ty::lookup_item_type(cx.tcx, trt_id).bounds;
let mth = ty::trait_methods(cx.tcx, trt_id)[n_mth];
@(vec::append(*trt_bounds, *mth.tps))
}
}
ty::method_call_bounds(cx.tcx, cx.method_map, e.id).expect(
~"non path/method call expr has type substs??")
}
};
if vec::len(ts) != vec::len(*bounds) {

View file

@ -178,6 +178,7 @@ export eval_repeat_count;
export fn_proto, proto_bare, proto_vstore;
export ast_proto_to_proto;
export is_blockish;
export method_call_bounds;
// Data types
@ -2414,6 +2415,32 @@ fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool {
return node_id_has_type_params(cx, expr.id);
}
fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map,
id: ast::node_id)
-> option<@~[param_bounds]> {
do method_map.find(id).map |method| {
match method.origin {
typeck::method_static(did) => {
// n.b.: When we encode class/impl methods, the bounds
// that we encode include both the class/impl bounds
// and then the method bounds themselves...
ty::lookup_item_type(tcx, did).bounds
}
typeck::method_param({trait_id:trt_id,
method_num:n_mth, _}) |
typeck::method_trait(trt_id, n_mth) => {
// ...trait methods bounds, in contrast, include only the
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
let trt_bounds =
ty::lookup_item_type(tcx, trt_id).bounds;
let mth = ty::trait_methods(tcx, trt_id)[n_mth];
@(vec::append(*trt_bounds, *mth.tps))
}
}
}
}
fn expr_is_lval(method_map: typeck::method_map, e: @ast::expr) -> bool {
match e.node {
ast::expr_path(_) | ast::expr_unary(ast::deref, _) => true,

View file

@ -252,9 +252,8 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
ast::expr_index(*) => {
debug!("(vtable - resolving expr) resolving field/binary/unary/\
assign/index expr");
match cx.method_map.find(ex.id) {
some({origin: method_static(did), _}) => {
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
match ty::method_call_bounds(cx.tcx, cx.method_map, ex.id) {
some(bounds) => {
if has_trait_bounds(*bounds) {
let callee_id = match ex.node {
ast::expr_field(_, _, _) => ex.id,

View file

@ -0,0 +1,23 @@
trait TraitA {
fn method_a() -> int;
}
trait TraitB {
fn gimme_an_a<A: TraitA>(a: A) -> int;
}
impl int: TraitB {
fn gimme_an_a<A: TraitA>(a: A) -> int {
a.method_a() + self
}
}
fn call_it<B: TraitB>(b: B) -> int {
let y = 4u;
b.gimme_an_a(y) //~ ERROR failed to find an implementation of trait @TraitA for uint
}
fn main() {
let x = 3i;
assert call_it(x) == 22;
}