Skip to content

Commit 038f925

Browse files
committed
Be less eager about implicit borrowing when doing method resolution. Closes #2796.
1 parent ceac155 commit 038f925

File tree

2 files changed

+67
-15
lines changed

2 files changed

+67
-15
lines changed

src/rustc/middle/typeck/check/method.rs

+24-15
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,20 @@ class lookup {
7777
// loop for impls in scope. Note: I don't love these
7878
// semantics, but that's what we had so I am preserving
7979
// it.
80-
if self.candidates.len() > 0u {
81-
break;
82-
}
80+
if self.candidates.len() > 0u { break; }
81+
82+
// now look for impls in scope, but don't look for impls that
83+
// would require doing an implicit borrow of the lhs.
84+
self.add_candidates_from_scope(false);
8385

84-
self.add_candidates_from_scope();
86+
// if we found anything, stop before trying borrows
87+
if self.candidates.len() > 0u { break; }
88+
89+
// now look for impls in scope that might require a borrow
90+
self.add_candidates_from_scope(true);
8591

8692
// if we found anything, stop before attempting auto-deref.
87-
if self.candidates.len() > 0u {
88-
break;
89-
}
93+
if self.candidates.len() > 0u { break; }
9094

9195
// check whether we can autoderef and if so loop around again.
9296
alt ty::deref(self.tcx(), self.self_ty, false) {
@@ -290,7 +294,7 @@ class lookup {
290294
*/
291295
}
292296

293-
fn add_candidates_from_scope() {
297+
fn add_candidates_from_scope(use_assignability: bool) {
294298
let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);
295299
let mut added_any = false;
296300

@@ -306,13 +310,18 @@ class lookup {
306310
let {substs: impl_substs, ty: impl_ty} =
307311
impl_self_ty(self.fcx, im.did);
308312

309-
// if we can assign the caller to the callee, that's a
310-
// potential match. Collect those in the vector.
311-
let can_assign = self.fcx.can_mk_assignty(
312-
self.self_expr, self.borrow_scope,
313-
self.self_ty, impl_ty);
314-
#debug["can_assign = %?", can_assign];
315-
alt can_assign {
313+
// Depending on our argument, we find potential
314+
// matches either by checking subtypability or
315+
// type assignability. Collect the matches.
316+
let matches = if use_assignability {
317+
self.fcx.can_mk_assignty(
318+
self.self_expr, self.borrow_scope,
319+
self.self_ty, impl_ty)
320+
} else {
321+
self.fcx.can_mk_subty(self.self_ty, impl_ty)
322+
};
323+
#debug["matches = %?", matches];
324+
alt matches {
316325
result::err(_) { /* keep looking */ }
317326
result::ok(_) {
318327
if !self.candidate_impls.contains_key(im.did) {
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Tests that type assignability is used to search for instances when
2+
// making method calls, but only if there aren't any matches without
3+
// it.
4+
5+
iface iterable<A> {
6+
fn iterate(blk: fn(A) -> bool);
7+
}
8+
9+
impl vec/&<A> of iterable<A> for &[const A] {
10+
fn iterate(f: fn(A) -> bool) {
11+
vec::each(self, f);
12+
}
13+
}
14+
15+
impl vec<A> of iterable<A> for ~[const A] {
16+
fn iterate(f: fn(A) -> bool) {
17+
vec::each(self, f);
18+
}
19+
}
20+
21+
fn length<A, T: iterable<A>>(x: T) -> uint {
22+
let mut len = 0;
23+
for x.iterate() |_y| { len += 1 }
24+
ret len;
25+
}
26+
27+
fn main() {
28+
let x = ~[0,1,2,3];
29+
// Call a method
30+
for x.iterate() |y| { assert x[y] == y; }
31+
// Call a parameterized function
32+
assert length(x) == vec::len(x);
33+
// Call a parameterized function, with type arguments that require
34+
// a borrow
35+
assert length::<int, &[int]>(x) == vec::len(x);
36+
37+
// Now try it with a type that *needs* to be borrowed
38+
let z = [0,1,2,3]/_;
39+
// Call a method
40+
for z.iterate() |y| { assert z[y] == y; }
41+
// Call a parameterized function
42+
assert length::<int, &[int]>(z) == vec::len(z);
43+
}

0 commit comments

Comments
 (0)