Do vtable resolution for *all* method calls, not just statically resolved ones... Closes #3221.
This commit is contained in:
parent
1300be58d7
commit
a14485b7fd
4 changed files with 54 additions and 22 deletions
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue