Skip to content
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

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

Closed
eddyb opened this Issue Mar 11, 2014 · 12 comments

Comments

Projects
None yet
9 participants
@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

This comment has been minimized.

Copy link
Member

pnkfelix commented Mar 11, 2014

cc me

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Mar 22, 2014

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

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 26, 2014

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

This comment has been minimized.

Copy link
Member

nrc commented Jul 14, 2014

Same issue with Index/IndexMut, ftr.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jul 14, 2014

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

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Jul 17, 2014

Assigning 1.0 milestone, P-backcompat-lang.

@pcwalton

This comment has been minimized.

Copy link
Contributor

pcwalton commented Jul 24, 2014

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

@pcwalton

This comment has been minimized.

Copy link
Contributor

pcwalton commented Sep 15, 2014

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 24, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
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 rust-lang#12825.

[breaking-change]

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 24, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
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 rust-lang#12825.

[breaking-change]

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 26, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
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 rust-lang#12825.

[breaking-change]

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 27, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
prefer `Deref` over `DerefMut` in all other circumstances.

Closes rust-lang#12825.

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 30, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
prefer `Deref` over `DerefMut` in all other circumstances.

Closes rust-lang#12825.

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 30, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
prefer `Deref` over `DerefMut` in all other circumstances.

Closes rust-lang#12825.

pcwalton added a commit to pcwalton/rust that referenced this issue Sep 30, 2014

librustc: Fix up mutability in method autoderefs if incorrect, and
prefer `Deref` over `DerefMut` in all other circumstances.

Closes rust-lang#12825.

bors added a commit that referenced this issue Oct 1, 2014

auto merge of #17501 : pcwalton/rust/improve-method-lookup-autoderef,…
… 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

bors added a commit that referenced this issue Oct 1, 2014

auto merge of #17501 : pcwalton/rust/improve-method-lookup-autoderef,…
… 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

@bors bors closed this in #17501 Oct 1, 2014

@P1start

This comment has been minimized.

Copy link
Contributor

P1start 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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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 10, 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 rust-lang#12825.

pcwalton added a commit to pcwalton/rust that referenced this issue Oct 13, 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 rust-lang#12825.

pcwalton added a commit to pcwalton/rust that referenced this issue Oct 14, 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 rust-lang#12825.

bors added a commit that referenced this issue Oct 15, 2014

auto merge of #17934 : pcwalton/rust/better-autoderef-fixup, r=pnkfelix
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

bors added a commit that referenced this issue Oct 15, 2014

auto merge of #17934 : pcwalton/rust/better-autoderef-fixup, r=pnkfelix
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

@bors bors closed this in #17934 Oct 16, 2014

gifnksm added a commit to gifnksm/ProjectEulerRust that referenced this issue Oct 20, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.