Do vtable resolution for *all* method calls, not just statically resolved ones... Closes #3221.
This commit is contained in:
@@ -226,25 +226,8 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||||||
_ => {
|
_ => {
|
||||||
// Type substitions should only occur on paths and
|
// Type substitions should only occur on paths and
|
||||||
// method calls, so this needs to be a method call.
|
// method calls, so this needs to be a method call.
|
||||||
match cx.method_map.get(e.id).origin {
|
ty::method_call_bounds(cx.tcx, cx.method_map, e.id).expect(
|
||||||
typeck::method_static(did) => {
|
~"non path/method call expr has type substs??")
|
||||||
// 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if vec::len(ts) != vec::len(*bounds) {
|
if vec::len(ts) != vec::len(*bounds) {
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ export eval_repeat_count;
|
|||||||
export fn_proto, proto_bare, proto_vstore;
|
export fn_proto, proto_bare, proto_vstore;
|
||||||
export ast_proto_to_proto;
|
export ast_proto_to_proto;
|
||||||
export is_blockish;
|
export is_blockish;
|
||||||
|
export method_call_bounds;
|
||||||
|
|
||||||
// Data types
|
// 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);
|
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 {
|
fn expr_is_lval(method_map: typeck::method_map, e: @ast::expr) -> bool {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::expr_path(_) | ast::expr_unary(ast::deref, _) => true,
|
ast::expr_path(_) | ast::expr_unary(ast::deref, _) => true,
|
||||||
|
|||||||
@@ -252,9 +252,8 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
|
|||||||
ast::expr_index(*) => {
|
ast::expr_index(*) => {
|
||||||
debug!("(vtable - resolving expr) resolving field/binary/unary/\
|
debug!("(vtable - resolving expr) resolving field/binary/unary/\
|
||||||
assign/index expr");
|
assign/index expr");
|
||||||
match cx.method_map.find(ex.id) {
|
match ty::method_call_bounds(cx.tcx, cx.method_map, ex.id) {
|
||||||
some({origin: method_static(did), _}) => {
|
some(bounds) => {
|
||||||
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
|
||||||
if has_trait_bounds(*bounds) {
|
if has_trait_bounds(*bounds) {
|
||||||
let callee_id = match ex.node {
|
let callee_id = match ex.node {
|
||||||
ast::expr_field(_, _, _) => ex.id,
|
ast::expr_field(_, _, _) => ex.id,
|
||||||
|
|||||||
23
src/test/compile-fail/vtable-res-trait-param.rs
Normal file
23
src/test/compile-fail/vtable-res-trait-param.rs
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user