Description
EDIT this was originally reported as a problem specific to auto-traits, but I don't think it actually is. See the comment below.
EDIT 2: It's actually not specific to specialization either. See this comment
This is spun off from #90601.
Given the following code (playground):
#![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):
#![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 #90601, you can see that this can result in detrimentally unhelpful error messages in more complex cases.
@rustbot label +A-specialization +A-traits +D-confusing +D-terse +F-auto_traits +F-specialization