diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index 709db8733d58..b91f9778e1c8 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -77,16 +77,20 @@ class lookup {
// loop for impls in scope. Note: I don't love these
// semantics, but that's what we had so I am preserving
// it.
- if self.candidates.len() > 0u {
- break;
- }
+ if self.candidates.len() > 0u { break; }
- self.add_candidates_from_scope();
+ // now look for impls in scope, but don't look for impls that
+ // would require doing an implicit borrow of the lhs.
+ self.add_candidates_from_scope(false);
+
+ // if we found anything, stop before trying borrows
+ if self.candidates.len() > 0u { break; }
+
+ // now look for impls in scope that might require a borrow
+ self.add_candidates_from_scope(true);
// if we found anything, stop before attempting auto-deref.
- if self.candidates.len() > 0u {
- break;
- }
+ if self.candidates.len() > 0u { break; }
// check whether we can autoderef and if so loop around again.
alt ty::deref(self.tcx(), self.self_ty, false) {
@@ -290,7 +294,7 @@ class lookup {
*/
}
- fn add_candidates_from_scope() {
+ fn add_candidates_from_scope(use_assignability: bool) {
let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);
let mut added_any = false;
@@ -306,13 +310,18 @@ class lookup {
let {substs: impl_substs, ty: impl_ty} =
impl_self_ty(self.fcx, im.did);
- // if we can assign the caller to the callee, that's a
- // potential match. Collect those in the vector.
- let can_assign = self.fcx.can_mk_assignty(
- self.self_expr, self.borrow_scope,
- self.self_ty, impl_ty);
- #debug["can_assign = %?", can_assign];
- alt can_assign {
+ // Depending on our argument, we find potential
+ // matches either by checking subtypability or
+ // type assignability. Collect the matches.
+ let matches = if use_assignability {
+ self.fcx.can_mk_assignty(
+ self.self_expr, self.borrow_scope,
+ self.self_ty, impl_ty)
+ } else {
+ self.fcx.can_mk_subty(self.self_ty, impl_ty)
+ };
+ #debug["matches = %?", matches];
+ alt matches {
result::err(_) { /* keep looking */ }
result::ok(_) {
if !self.candidate_impls.contains_key(im.did) {
diff --git a/src/test/run-pass/assignability-iface.rs b/src/test/run-pass/assignability-iface.rs
new file mode 100644
index 000000000000..47cf7535a6e0
--- /dev/null
+++ b/src/test/run-pass/assignability-iface.rs
@@ -0,0 +1,43 @@
+// Tests that type assignability is used to search for instances when
+// making method calls, but only if there aren't any matches without
+// it.
+
+iface iterable {
+ fn iterate(blk: fn(A) -> bool);
+}
+
+impl vec/& of iterable for &[const A] {
+ fn iterate(f: fn(A) -> bool) {
+ vec::each(self, f);
+ }
+}
+
+impl vec of iterable for ~[const A] {
+ fn iterate(f: fn(A) -> bool) {
+ vec::each(self, f);
+ }
+}
+
+fn length>(x: T) -> uint {
+ let mut len = 0;
+ for x.iterate() |_y| { len += 1 }
+ ret len;
+}
+
+fn main() {
+ let x = ~[0,1,2,3];
+ // Call a method
+ for x.iterate() |y| { assert x[y] == y; }
+ // Call a parameterized function
+ assert length(x) == vec::len(x);
+ // Call a parameterized function, with type arguments that require
+ // a borrow
+ assert length::(x) == vec::len(x);
+
+ // Now try it with a type that *needs* to be borrowed
+ let z = [0,1,2,3]/_;
+ // Call a method
+ for z.iterate() |y| { assert z[y] == y; }
+ // Call a parameterized function
+ assert length::(z) == vec::len(z);
+}