Explain how to fix “no field on type” on a TAIT / ATPIT typed value #113581
Description
Code
#![feature(impl_trait_in_assoc_type)]
pub trait Transaction {
type Check: 'static;
fn check(&self) -> Self::Check;
fn commit(&self, check: Self::Check);
}
pub mod foo {
pub struct Foo;
struct FooC {
field: (),
}
impl super::Transaction for Foo {
type Check = impl Sized;
fn check(&self) -> Self::Check {
FooC { field: () }
}
fn commit(&self, check: Self::Check) {
assert_eq!(check.field, ());
}
}
}
Current output
error[E0609]: no field `field` on type `<Foo as Transaction>::Check`
--> src/lib.rs:24:30
|
24 | assert_eq!(check.field, ());
| ^^^^^
For more information about this error, try `rustc --explain E0609`.
error: could not compile `playground` (lib) due to previous error
Desired output
help: to access fields of the underlying type `FooC`, coerce the value to it:
`(check as FooC).field`
Rationale and extra context
If users are not given this advice, it will not be obvious how to proceed; they may think that it is not even possible. For me at least, it is obvious only in hindsight that
- the incoming
check
argument is of a different type than the outgoing return value, and - a type coercion would solve the problem here.
The alternate mental model I was working with before I understood the problem was something like:
Self::Check
is an alias for a particularimpl Sized
- which, only this
impl
or module knows (being in the defining scope of theimpl Trait
), is an alias forFooC
so check
should be of type FooC
already. Now that I understand what's actually going on, it makes much more sense that the compiler would work this way (scope-dependent type equality would be a nightmare), but it wasn't obvious when I started.
Other cases
No response
Anything else?
This exact same problem happens with TAIT; I just think it's just a little less clear and more important for associated types in traits.
Another detail to consider is what the output should be when the underlying type does not have such a field (or method). I think there should still be a similar hint, but phrased differently — in general, this hint should show up whenever
- an opaque type is used,
- in a place where the coercion would be allowed,
- at a use site which does not itself cause a coercion already (e.g. a generic rather than concrete function parameter).
@rustbot label +A-impl-trait +F-type_alias_impl_trait
Activity