]> git.lizzy.rs Git - rust.git/commitdiff
Do vtable resolution for *all* method calls, not just statically resolved ones.....
authorMichael Sullivan <sully@msully.net>
Mon, 20 Aug 2012 20:36:15 +0000 (13:36 -0700)
committerMichael Sullivan <sully@msully.net>
Mon, 20 Aug 2012 20:36:15 +0000 (13:36 -0700)
src/rustc/middle/kind.rs
src/rustc/middle/ty.rs
src/rustc/middle/typeck/check/vtable.rs
src/test/compile-fail/vtable-res-trait-param.rs [new file with mode: 0644]

index 35675b9102b32c254cab2acb4ae396343d173967..15882d5e9fa6b2ff37068964fbe45c513cd838c1 100644 (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) {
index fa6ca057602da2eeaacc4862de69fe6b636b826b..bc74f654ca84d68b05c281358a62eddfa5af3fd0 100644 (file)
 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,
index a0218f3e9b5a0235dbea100630796e9c8c2bd01e..a3cd3c6c79e371f04224021c75b1ed0d1d634b4b 100644 (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,
diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs
new file mode 100644 (file)
index 0000000..550be31
--- /dev/null
@@ -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;
+}