rust-lang / trait-system-refactor-initiative

The Rustc Trait System Refactor Initiative
21 stars 0 forks source link

method resolution can use yet undefined opaques #131

Open lcnr opened 3 weeks ago

lcnr commented 3 weeks ago

to get methods from alias bounds

fn foo<T: Clone>(x: T, choose: bool) -> impl Clone {
    if choose {
        foo(x, false).clone()
    } else {
        x
    }
}

https://rust.godbolt.org/z/vecjoaYzK

People rely on this behavior, see https://github.com/rust-lang/rust/issues/117866, or more specifically, the crater run in https://github.com/rust-lang/rust/pull/120798#issuecomment-1938414794

lcnr commented 3 weeks ago

to get to nested receivers while computing auto deref steps

use std::ops::Deref;

fn foo(x: Box<u32>, choose: bool) -> impl Deref<Target = u32> {
    if choose {
        let value = foo(x, false).leading_zeros();
        Box::new(value)
    } else {
        x
    }
}

https://rust.godbolt.org/z/6Tf18YnPq

this can then be used ot define the opaque

use std::ops::Deref;
#[derive(Default)]
struct Foo;
impl Foo {
    fn method(self: Box<Foo>) {}
}

fn foo(choose: bool) -> impl Deref<Target = Foo> {
    if choose {
        foo(false).method();
    }

    Default::default()
}

https://rust.godbolt.org/z/1eoed4Tq7

and can very frequently be undesirable

use std::ops::Deref;
struct Foo;
impl Foo {
    fn method(&self) {}
}

struct Bar;
impl Deref for Bar {
    type Target = Foo;
    fn deref(&self) -> &Foo {
        &Foo
    }
}

fn deref_to_foo(choose: bool) -> impl Deref<Target = Foo> {
    if choose {
        deref_to_foo(false).method();
    }

    Bar
}

https://rust.godbolt.org/z/3hYs9TYhv

lcnr commented 3 weeks ago

to discard candidates for which an item bound does not hold

#[derive(Default)]
struct MyType<T>(T);
impl MyType<u32> {
    fn method(self) {}
}

impl MyType<String> {
    fn method(self) {}
}

fn foo(choose: bool) -> MyType<impl Copy> {
    if choose {
        foo(false).method();
    }

    Default::default()
}

https://rust.godbolt.org/z/MYEEzfvj9