I have a piece of code that does not compile and that can be reduced to this snippet:
use std::error::Error;
use std
I'm still not sure why, but it seems just removing the 'static bound on the error worked?
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d4f46a0ad9a5dd7dc538fe4e197d823d
This appears to be a gap in the compiler's ability to reason about lifetimes and associated types.
Sometimes, in order to help the compiler, you can add a generic parameter to alias an associated type. This parameter doesn't "count" in that it doesn't make the item "more generic", but because generics are resolved at use instead of declaration, it defers the hard part of type checking until the exact types are known. In other words: the compiler might be able to prove that any particular T::Error
works, but it can't quite prove that every T::Error
must work, so we introduce a new parameter E
which is bound to be T::Error
and tell the compiler to figure out what E
is only when we try to use it.
The following works (playground):
impl<'a, T, E> Deserializable<T> for MyBuffer<'a>
where
T: TryFrom<&'a [u8], Error = E>,
E: Error + Sync + Send + 'static,
{
// ...
}
Instead of bounding T::Error
, we introduce a new type parameter E
with the bounds we want and constrain T
such that its TryFrom::Error
is E
. This is logically (as far as I can tell) the same thing as what you wrote, but it compiles without complaint.
I can't find official documentation that refers to this; it may be an inherent limitation of the solver, or merely a bug.