Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eddyb opened this issue Mar 11, 2014 · 12 comments · Fixed by #17501 or #17934
Closed

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

eddyb opened this issue Mar 11, 2014 · 12 comments · Fixed by #17501 or #17934
Assignees
Milestone

Comments

@eddyb
Copy link
Member

eddyb commented Mar 11, 2014

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

@pnkfelix
Copy link
Member

cc me

@alexcrichton
Copy link
Member

Another test case:

use std::cell::RefCell;

fn main() {
    let a = RefCell::new((1i, 2i));
    match *a.borrow_mut() {
        (ref mut a, ref mut b) => { *a += *b; *b += *a; }
    }
}

This fail to compile, but if it's changed to *a.borrow_mut().deref_mut() it compiles just fine.

@nikomatsakis
Copy link
Contributor

I've been working, by the way, on a prototype of a new trait / method resolution algorithm that resolves issue (among many others). I hope to include it in a general RFC for #5527 very shortly.

@nrc
Copy link
Member

nrc commented Jul 14, 2014

Same issue with Index/IndexMut, ftr.

@alexcrichton
Copy link
Member

Nominating, if this is going to block vec switching to []-syntax I believe this is a 1.0 blocker.

@pnkfelix
Copy link
Member

Assigning 1.0 milestone, P-backcompat-lang.

@pcwalton
Copy link
Contributor

I'm going to go ahead and assign this to @nikomatsakis.

@pcwalton
Copy link
Contributor

We need to change precedence so that inherent and trait impls are on equal footing instead of having inherent impls be first.

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 30, 2014
prefer `Deref` over `DerefMut` in all other circumstances.

Closes rust-lang#12825.
bors added a commit that referenced this issue Oct 1, 2014
… r=nikomatsakis

prefer `Deref` over `DerefMut` in all other circumstances.

Because the compiler now prefers `Deref`, this can break code that
looked like:

    let mut foo = bar.borrow_mut();
    (*foo).call_something_that_requires_mutable_self();

Replace this code with:

    let mut foo = bar.baz();
    (&mut *foo).call_something_that_requires_mutable_self();

Closes #12825.

[breaking-change]

r? @nikomatsakis
@ftxqxd
Copy link
Contributor

ftxqxd commented Oct 1, 2014

Is this really fixed? @alexcrichton’s example from above still fails to compile, and is incidentally very similar to the example in #15609, which also does not compile.

@gifnksm
Copy link
Contributor

gifnksm commented Oct 6, 2014

impl<T> IndexMut<uint, T> for Vec<T> is commented out with refereeing this issue.
Should this issue be reopend or un-comment the impl?

@aturon
Copy link
Member

aturon commented Oct 7, 2014

I've confirmed that IndexMut is still not working properly, so we still can't provide full indexing notation on vectors. Note that this is why this issue was nominated and approved as a 1.0 blocker.

@pcwalton, would you prefer me to re-open this issue or create a new one?

@aturon
Copy link
Member

aturon commented Oct 7, 2014

Reopening.

@aturon aturon reopened this Oct 7, 2014
pcwalton added a commit to pcwalton/rust that referenced this issue Oct 14, 2014
`IndexMut` on mutable vectors.

This fixes a bug whereby the mutability fixups for method behavior were
not kicking in after autoderef failed to happen at any level. It also
adds support for `Index` to the fixer-upper.

Closes rust-lang#12825.
bors added a commit that referenced this issue Oct 15, 2014
librustc: Improve method autoderef/deref/index behavior more, and enable IndexMut on mutable vectors.

This fixes a bug whereby the mutability fixups for method behavior were
not kicking in after autoderef failed to happen at any level. It also
adds support for `Index` to the fixer-upper.

Closes #12825.

r? @pnkfelix
gifnksm added a commit to gifnksm/ProjectEulerRust that referenced this issue Oct 20, 2014
fasterthanlime pushed a commit to fasterthanlime/rust that referenced this issue Jul 22, 2022
fix: Fix search for associated trait items being inconsistent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment