# 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);
}
```