Skip to content

Improve method lookup auto-deref behavior (subissue of trait reform) #12825

@eddyb

Description

@eddyb

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();
}

cc @nikomatsakis

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions