The following code compiles fine:
struct StructA<F>(F);
impl<F, T> StructA<F> where F: Fn() -> T {}
Although T doesn't show up in StructA's type parameters, it is still constrained due to the where clause. This trick is used, for example, in std::iter::Map so Map<I, F> only needs two type parameters while the impl<B, I, F> Iterator for Map<I, F> takes three.
However the following code does not compile:
struct StructB<F>(F);
impl<F, T> StructB<F> where F: Fn(T) -> T {}
error[E0207]: the type parameter `B` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:5:9
|
5 | impl<F, T> StructB<F> where F: Fn(T) -> T {}
| ^ unconstrained type parameter
For more information about this error, try `rustc --explain E0207`.
error: could not compile `playground` due to previous error
This is unintuitive, why would using T in more places make it less constrained? Is this intended or is it a limitation in Rust?
Note this also happens with regular traits, i.e. the desugared version of Fn:
trait FnTrait<Args> {
type Output;
}
// Works
struct StructA<F>(F);
impl<F, T> StructA<F> where F: FnTrait<(), Output = T> {}
// Fails
struct StructB<F>(F);
impl<F, T> StructB<F> where F: FnTrait<(T,), Output = T> {}