Repository navigation
Rust incorrectly concludes that trait is not implemented #82252
Description
Activity
- addedA-associated-itemsArea: Associated items (types, constants & functions)Area: Associated items (types, constants & functions)A-trait-systemArea: Trait systemArea: Trait system
on Feb 18, 2021 - addedT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
on Apr 5, 2023 Two year later I've came across this issue again, and I've got some more practical example where the type system breaks. I was trying to implement
serde_with::DeserializeAs<T>trait for allTsuch thatT: TryFrom<&[u8]>. Plus, I do need to know that<T as TryFrom<&[u8]>>::ErrorimplementsDisplayfor better error reporting. Trait implementation was supposed to look something like that:impl<'de, T> serde_with::DeserializeAs<'de, T> for MyType where T: TryFrom<&[u8]>, <T as TryFrom<&[u8]>>::Error: Display { /* ... */ }
However, here Rust forces me to use
for<'a>syntax. The final (simplified) code:impl<'de, T> serde_with::DeserializeAs<'de, T> for MyType where for<'a> T: TryFrom<&'a [u8]>, for<'a> <T as TryFrom<&'a [u8]>>::Error: std::fmt::Display, { /* ... */ }
The type system is capable of figuring out that
MyTypeimplementsserde_with::DeserializeAs<'de, [u8; 32]>, for instance.fn it_implements_trait<'de, M, T>() where M: serde_with::DeserializeAs<'de, T>, {} it_implements_trait::<MyType, [u8; 32]>(); // this compiles it_implements_trait::<Option<MyType>, Option<[u8; 32]>>(); // and that compiles
but it breaks when it's needed the most: inside
serde::Deserializemacro which produces the code similar to:struct Foo([u8; 32]); impl<'de> serde::Deserialize<'de> for Foo { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>, { let inner: [u8; 32] = serde_with::As::<MyType>::deserialize(deserializer)?; Ok(Self(inner)) } }
...that causes a compilation error:
error[E0277]: `<_ as TryFrom<&'a [u8]>>::Error` doesn't implement `std::fmt::Display` --> cggmp21/src/utils.rs:365:35 | 365 | let inner: [u8; 32] = serde_with::As::<MyType>::deserialize(deserializer)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<_ as TryFrom<&'a [u8]>>::Error` cannot be formatted with the default formatter | = help: the trait `for<'a> std::fmt::Display` is not implemented for `<_ as TryFrom<&'a [u8]>>::Error` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = help: the trait `DeserializeAs<'de, T>` is implemented for `MyType` note: required for `MyType` to implement `DeserializeAs<'_, _>` --> cggmp21/src/utils.rs:277:18 | 277 | impl<'de, T> serde_with::DeserializeAs<'de, T> for MyType | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ ... 280 | for<'a> <T as TryFrom<&'a [u8]>>::Error: std::fmt::Display, | ----------------- unsatisfied trait bound introduced here note: required by a bound in `serde_with::de::<impl As<T>>::deserialize` --> /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_with-2.3.3/src/de/mod.rs:153:12 | 151 | pub fn deserialize<'de, D, I>(deserializer: D) -> Result<I, D::Error> | ----------- required by a bound in this associated function 152 | where 153 | T: DeserializeAs<'de, I>, | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `serde_with::de::<impl As<T>>::deserialize`which is not true because
<[u8; 32] as TryFrom<&[u8]>::Erroris TryFromSliceError and it does implement Display.- addedE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
on Mar 26, 2024 The first example compiles on latest Rust, so I suppose it is indeed fixed!
Suppose I have a function:
Here, for some reason, Rust refuses to infer that
<T as TryFrom<&'a U64>>::Errorimplements Debug. Can be checked by adding more code:If we replace main function with:
then it will be compiled, so Rust is able to infer that TooLargeErr implements Debug, but it doesn't do the same in generic bounds.
Here's a link on playground
Meta
Reproduces at Rust 1.50.0 stable, beta, nightly