Repository: rust
Issue: Diagnostic forgets about transitive trait bounds when there are multiple candidate impls.
Labels: A-diagnostics,A-trait-system,T-compiler,A-specialization,requires-nightly,F-specialization,F-rustc_attrs,D-confusing,D-terse

**EDIT this was originally reported as a problem specific to auto-traits, but I don't think it actually is. See the [comment below](https://github.com/rust-lang/rust/issues/90665#issuecomment-1243096941)**.

**EDIT 2: It's actually not specific to specialization either. See [this comment](https://github.com/rust-lang/rust/issues/90665#issuecomment-1246260554)**

This is spun off from https://github.com/rust-lang/rust/issues/90601.

Given the following code ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=4283307336cd352d7ff2dc7b876de71d)):

```rust
#![feature(min_specialization)]
#![feature(rustc_attrs)]

#[rustc_specialization_trait]
trait Special {}

trait Foo {
    fn foo();
}

impl<T: Send> Foo for T {
    default fn foo() {
        println!("foo");
    }
}

fn main() {
    <std::rc::Rc<()> as Foo>::foo();
}
```

The current (good) output is:

```
error[E0277]: `Rc<()>` cannot be sent between threads safely
  --> src/main.rs:18:5
   |
18 |     <std::rc::Rc<()> as Foo>::foo();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
   |
   = help: the trait `Send` is not implemented for `Rc<()>`
note: required because of the requirements on the impl of `Foo` for `Rc<()>`
  --> src/main.rs:11:15
   |
11 | impl<T: Send> Foo for T {
   |               ^^^     ^
note: required by `Foo::foo`
  --> src/main.rs:8:5
   |
8  |     fn foo();
   |     ^^^^^^^^^
```



But if you add a specialized impl of `Foo` ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6113f5db020bc7be414b75a8ef079bd3)):

```rust
#![feature(min_specialization)]
#![feature(rustc_attrs)]

#[rustc_specialization_trait]
trait Special {}

trait Foo {
    fn foo();
}

impl<T: Send> Foo for T {
    default fn foo() {
        println!("foo");
    }
}

impl<T: Send + Special> Foo for T {
    fn foo() {
        println!("special foo");
    }
}

fn main() {
    <std::rc::Rc<()> as Foo>::foo();
}
```

Then the error message loses all of the information regarding the unimplemented auto trait:

```
error[E0277]: the trait bound `Rc<()>: Foo` is not satisfied
  --> src/main.rs:24:5
   |
24 |     <std::rc::Rc<()> as Foo>::foo();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Rc<()>`
   |
note: required by `Foo::foo`
  --> src/main.rs:8:5
   |
8  |     fn foo();
   |     ^^^^^^^^^
```

So there is something about the presence of a specialized impl that causes trait selection to not know that there's an unimplemented auto trait obligation. I have confirmed this by exploring the debug logging of rustc a little bit:

```
Without specialized impl:
rustc_trait_selection::traits::error_reporting::report_fulfillment_error error=FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<std::rc::Rc<()> as std::marker::Send>, polarity:Positive), []), depth=1),Unimplemented), body_id=Some(BodyId { hir_id: HirId { owner: DefId(0:9 ~ issue_xxxxx_specialization[8170]::main), local_id: 12 } }), fallback_has_occurred=false

With specialized impl:
rustc_trait_selection::traits::error_reporting::report_fulfillment_error error=FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<std::rc::Rc<()> as Foo>, polarity:Positive), []), depth=0),Unimplemented), body_id=Some(BodyId { hir_id: HirId { owner: DefId(0:12 ~ issue_xxxxx_specialization[8170]::main), local_id: 12 } }), fallback_has_occurred=false
```

If you take a look at Example 4 in https://github.com/rust-lang/rust/issues/90601, you can see that this can result in detrimentally unhelpful error messages in more complex cases.

cc https://github.com/rust-lang/rust/issues/13231 https://github.com/rust-lang/rust/issues/31844 https://github.com/rust-lang/rust/pull/68970

@rustbot label +A-specialization +A-traits +D-confusing +D-terse +F-auto_traits +F-specialization