about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-05-25 08:42:39 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-05-25 17:04:05 -0700
commit98740a59da4f73617351098c118d707134e561a8 (patch)
tree76c8556b15f12d4f6cd0e801f0433b857cf58535 /src/rustc
parent93633ea7343d74c6447ed814c7435e9b1a3ff67a (diff)
downloadrust-98740a59da4f73617351098c118d707134e561a8.tar.gz
rust-98740a59da4f73617351098c118d707134e561a8.zip
detect ambig. calls to iface bounds, use transactions
cc #2433
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/typeck/check.rs4
-rw-r--r--src/rustc/middle/typeck/check/method.rs49
-rw-r--r--src/rustc/middle/typeck/infer.rs37
3 files changed, 70 insertions, 20 deletions
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 07eeada10f8..7da1f27d3da 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -527,6 +527,10 @@ impl methods for @fn_ctxt {
         infer::mk_subty(self.infcx, sub, sup)
     }
 
+    fn can_mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
+        infer::can_mk_subty(self.infcx, sub, sup)
+    }
+
     fn mk_eqty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
         infer::mk_eqty(self.infcx, sub, sup)
     }
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index b6f01aed1fe..af27d8d8da1 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -45,6 +45,7 @@ impl methods for lookup {
         let tcx = self.tcx();
         let mut iface_bnd_idx = 0u; // count only iface bounds
         let bounds = tcx.ty_param_bounds.get(did.node);
+        let mut candidates = [];
         for vec::each(*bounds) {|bound|
             let (iid, bound_substs) = alt bound {
               ty::bound_copy | ty::bound_send | ty::bound_const {
@@ -74,14 +75,33 @@ impl methods for lookup {
                 // permitted).
                 let substs = {self_ty: some(self.self_ty)
                               with bound_substs};
-
-                ret some(self.write_mty_from_m(
-                    substs, ifce_methods[pos],
-                    method_param(iid, pos, n, iface_bnd_idx)));
+                candidates += [(substs, ifce_methods[pos],
+                                iid, pos, n, iface_bnd_idx)];
               }
             }
         }
-        ret none;
+
+        if candidates.len() == 0u {
+            ret none;
+        }
+
+        if candidates.len() > 1u {
+            self.tcx().sess.span_err(
+                self.expr.span,
+                "multiple applicable methods in scope");
+
+            for candidates.eachi { |i, candidate|
+                let (_, _, iid, _, _, _) = candidate;
+                self.tcx().sess.span_note(
+                    self.expr.span,
+                    #fmt["candidate #%u derives from the bound `%s`",
+                         (i+1u), ty::item_path_str(self.tcx(), iid)]);
+            }
+        }
+
+        let (substs, mty, iid, pos, n, iface_bnd_idx) = candidates[0u];
+        ret some(self.write_mty_from_m(
+            substs, mty, method_param(iid, pos, n, iface_bnd_idx)));
     }
 
     fn method_from_iface(
@@ -197,10 +217,11 @@ impl methods for lookup {
 
                     // if we can assign the caller to the callee, that's a
                     // potential match.  Collect those in the vector.
-                    alt self.fcx.mk_subty(ty, self_ty) {
+                    alt self.fcx.can_mk_subty(ty, self_ty) {
                       result::err(_) { /* keep looking */ }
                       result::ok(_) {
-                        results += [(self_substs, m.n_tps, m.did)];
+                        results += [(ty, self_ty, self_substs,
+                                     m.n_tps, m.did)];
                       }
                     }
                 }
@@ -216,7 +237,7 @@ impl methods for lookup {
                     // but I cannot for the life of me figure out how to
                     // annotate resolve to preserve this information.
                     for results.eachi { |i, result|
-                        let (_, _, did) = result;
+                        let (_, _, _, _, did) = result;
                         let span = if did.crate == ast::local_crate {
                             alt check self.tcx().items.get(did.node) {
                               ast_map::node_method(m, _, _) { m.span }
@@ -226,13 +247,21 @@ impl methods for lookup {
                         };
                         self.tcx().sess.span_note(
                             span,
-                            #fmt["candidate #%u is %s",
+                            #fmt["candidate #%u is `%s`",
                                  (i+1u),
                                  ty::item_path_str(self.tcx(), did)]);
                     }
                 }
 
-                let (self_substs, n_tps, did) = results[0];
+                let (ty, self_ty, self_substs, n_tps, did) = results[0];
+                alt self.fcx.mk_subty(ty, self_ty) {
+                  result::ok(_) {}
+                  result::err(_) {
+                    self.tcx().sess.span_bug(
+                        self.expr.span,
+                        "what was a subtype now is not?");
+                  }
+                }
                 let fty = self.ty_from_did(did);
                 ret some(self.write_mty_from_fty(
                     self_substs, n_tps, fty,
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index f94d1656c0b..d13123496b1 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -160,7 +160,7 @@ import util::common::{indent, indenter};
 
 export infer_ctxt;
 export new_infer_ctxt;
-export mk_subty;
+export mk_subty, can_mk_subty;
 export mk_subr;
 export mk_eqty;
 export mk_assignty;
@@ -235,6 +235,11 @@ fn mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
     indent {|| cx.commit {|| sub(cx).tys(a, b) } }.to_ures()
 }
 
+fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
+    #debug["can_mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx)];
+    indent {|| cx.probe {|| sub(cx).tys(a, b) } }.to_ures()
+}
+
 fn mk_subr(cx: infer_ctxt, a: ty::region, b: ty::region) -> ures {
     #debug["mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx)];
     indent {|| cx.commit {|| sub(cx).regions(a, b) } }.to_ures()
@@ -388,7 +393,17 @@ fn uok() -> ures {
     ok(())
 }
 
+fn rollback_to<V:copy vid, T:copy>(
+    vb: vals_and_bindings<V, T>, len: uint) {
+
+    while vb.bindings.len() != len {
+        let (vid, old_v) = vec::pop(vb.bindings);
+        vb.vals.insert(vid.to_uint(), old_v);
+    }
+}
+
 impl transaction_methods for infer_ctxt {
+    #[doc = "Execute `f` and commit the bindings if successful"]
     fn commit<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
 
         assert self.vb.bindings.len() == 0u;
@@ -404,17 +419,9 @@ impl transaction_methods for infer_ctxt {
         ret r;
     }
 
+    #[doc = "Execute `f`, unroll bindings on failure"]
     fn try<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
 
-        fn rollback_to<V:copy vid, T:copy>(
-            vb: vals_and_bindings<V, T>, len: uint) {
-
-            while vb.bindings.len() != len {
-                let (vid, old_v) = vec::pop(vb.bindings);
-                vb.vals.insert(vid.to_uint(), old_v);
-            }
-        }
-
         let vbl = self.vb.bindings.len();
         let rbl = self.rb.bindings.len();
         #debug["try(vbl=%u, rbl=%u)", vbl, rbl];
@@ -429,6 +436,16 @@ impl transaction_methods for infer_ctxt {
         }
         ret r;
     }
+
+    #[doc = "Execute `f` then unroll any bindings it creates"]
+    fn probe<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
+        assert self.vb.bindings.len() == 0u;
+        assert self.rb.bindings.len() == 0u;
+        let r <- f();
+        rollback_to(self.vb, 0u);
+        rollback_to(self.rb, 0u);
+        ret r;
+    }
 }
 
 impl methods for infer_ctxt {