---
# System prepended metadata

title: PR 123962

---

# PR 123962

https://github.com/rust-lang/rust/pull/123962

## Structurally resolution

niko's mental model (probably broken)

* auto-deref chain (when invoked on an opaque whose def-id which is in the defining scope)
    * structurally resolve
        * invokes the trait checker to normalize
            * OLD: no-op, returns opaque as is
            * NEW: returns an inference variable
        * match on the result
            * if it is an inference variable, we error
            * or if it is an opaque def-id that is in the defining scope, we error?
                * niko would like to see links to the kind of code that breaks
                * https://github.com/rust-lang/rust/pull/123962#issuecomment-2067883092
                * https://github.com/rust-lang/rust/pull/120798#issuecomment-1938414794
                    * https://github.com/kurnevsky/esxtool/blob/88538ca7c8e068b5e38d4b386eb1bf3d5cede3d0/src/mwscript/parser.rs#L186-L191
                * https://rust-lang.zulipchat.com/#narrow/stream/144729-t-types/topic/opaque.20type.20method.20resolution.20special.20casing
        * else, we continue assembling candidates for the opaque
            * check methods without autoref, then try to add reference `&self` and `&mut self` ty `whatever`, then &whatever`, `&mut whatever` etc
            * if we allow defining the opaque there, it unifies with all self types
    * ...



## Examples

```rust
//! The recursive method call yields the opaque type. The
//! `next` method call then constrains the hidden type to `&mut _`
//! because `next` takes `&mut self`. We never resolve the inference
//! variable, but get a type mismatch when comparing `&mut _` with
//! `std::iter::Empty`.

//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass

fn foo(b: bool) -> impl Iterator<Item = ()> {
    if b {
        foo(false).next().unwrap();
        //[next]~^ type annotations needed
    }
    std::iter::empty()
    //[next]~^ mismatched types
}

fn main() {}
```

```rust
trait Trait {
    fn foo(self: &mut &Self) {}
}


fn foo<T: Trait>(x: T) {
    x.foo(); // nope
    
    let mut y = &x;
    y.foo(); // ok
}
```
`autorefd_self_ty: &mut impl Trait`
```rust
trait Trait {
    fn foo(self: &mut &Self) -> Self;
}

fn use_trait<T: Trait>() -> impl Trait {
    use_trait::<T>().foo()
}
```

### `-> impl Trait` in return position without import

D'oh.

```rust
use std::fmt::Debug as _; // uncomment this and it stops compiling

fn foo(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug {
    if false {
        let x = foo(f);
        x.fmt(f);
    }
    ()
}


fn foo1(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug {
    if false {
        let x = &mut foo(f);
        x.fmt(f);
    }
    ()
}

// inconsistent with this
fn bar<T>(t: impl std::fmt::Debug, f:&mut std::fmt::Formatter<'_>) {
    t.fmt(f);
}

// and the desugared version, of course
fn baz<T: std::fmt::Debug>(t: T, f:&mut std::fmt::Formatter<'_>) {
    t.fmt(f);
}
```


### interesting example

this is interesting because it requires an extension trait

```rust
trait MyDebug { 
    fn my_debug(&self);
}

impl<T> MyDebug for T
where
    T: std::fmt::Debug,
{
    fn my_debug(&self) { }
}

fn my_foo() -> impl std::fmt::Debug {
    if false {
        let x = my_foo();
        x.my_debug();
    }
    ()
}
```

### fun and weird example

This works today but we think it will fail with ambiguity with the PR

The `&opaque` will be unified with `&&_` from the impl, constraining `opaque = &_`, and hence ambiguity.

```rust
trait MyDebug { 
    fn my_debug(&self);
}

impl<T> MyDebug for &T
where
    T: std::fmt::Debug,
{
    fn my_debug(&self) { }
}

fn my_foo() -> impl std::fmt::Debug {
    if false {
        let x = &my_foo();
        x.my_debug();
    }
    ()
}
```

### constraining opaques via method dispatch

The `&opaque` will be unified with `&&()` from the impl.

This did not compile before but it will now.

```rust
trait MyDebug { 
    fn my_debug(&self);
}

impl MyDebug for &() {
    fn my_debug(&self) { }
}

fn my_foo() -> impl std::fmt::Debug {
    if false {
        let x = &my_foo();
        x.my_debug();
    }
    ()
}
```

### example that changes behavior

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=0543258c04f67d66453f92aeb0f1ef13

```rust
#![feature(precise_capturing)]

trait Get {
    fn get(&mut self) -> u32;
}

impl Get for () {
    fn get(&mut self) -> u32 {
        0
    }
}

impl<T> Get for &mut T
where
    T: Get,
{
    fn get(&mut self) -> u32 {
        T::get(self) + 1
    }
}

fn foo(n: usize, m: &mut ()) -> impl use<'_> Get {
    if n > 0 {
        let mut iter = foo(n - 1, m);
        println!("{}", iter.get());
    }
    m
}

fn main() {
    let g = foo(1, &mut ()).get();
    println!("{}", g);
}

```