Description
Previously to #12491, there were no real issues with the current method lookup implementation, which collects candidates and picks the first one in the auto-deref chain, without caring too much about mutability.
The problematic case #12491 introduces was (*x).foo()
where *x
is an overloaded dereference, calling either Deref::deref
or DerefMut::deref_mut
.
However, the method could take &mut self
- which we can't know until we've picked one of deref
or deref_mut
and continued to the lookup of .foo
.
The choice I've made was to always try deref_mut
(if not obviously immutable, e.g. x having a type of &T
instead of &mut T
or T
) first, and that will work for RefCell
's RefMut
, which only had a mutable .get()
method previously.
In #12610 it gets worse as the issue can happen at any auto-deref level, and here's a test case that fails to compile:
// Generic unique/owned smaht pointer.
struct Own<T> {
value: *mut T
}
impl<T> Deref<T> for Own<T> {
fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self.value }
}
}
impl<T> DerefMut<T> for Own<T> {
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self.value }
}
}
struct Point {
x: int,
y: int
}
impl Point {
fn get(&self) -> (int, int) {
(self.x, self.y)
}
}
fn test(x: Own<Point>) {
// This method call will attempt a deref_mut call, which succeeds
// (because type checking doesn't have the mem_categorization
// information borrow checking uses to confirm the sanity of such
// borrows), but causes a borrow error later.
// Ideally, auto-deref should recognize x as immutable and call
// deref instead of deref_mut` Also, method lookup could use
// the self type of the method to pick deref instead of deref_mut.
let _ = x.get();
}