I'm currently working on a large rewrite on the crate simdeez which allows easy trait-based SIMD selection.
Each SIMD type implements a few traits that represents what operations it can perform. Everything works fine, except when I tried adding "where" constraints on operations associated with the underlying scalar.
Such as the constraint in this (stripped) example:
pub trait SimdBase: Copy
where
Self::Scalar: Sub<Self, Output = Self>,
{
type Scalar;
}
Which would allow the user to do 1.0 - simd_value instead of S::Vf32::set1(1.0) - simd_value (where S is the current SIMD instruction set generic).
The above example works fine, however when I add similar constraints onto other subtypes, I get errors that I can't seem to solve. The compiler recommends adding another where clause but it doesn't work at all.
Here's a minimal reproduction of my problem:
I can't add the Div constraint onto the SimdBase trait as only floating point values are able to perform division in the majority of SIMD. I've tried applying the compiler suggestion of course, but it doesn't appear to work.
Am I missing something, or is this a limitation of the compiler?
Huh, it appears that even the constraints that work correctly don't propagate around properly.
E.g. the trait that represents the current SIMD instruction set has associated types for each scalar type representation, however 1.0 - simd_value doesn't work unless I add the same "where" constraints onto those associated types as well, even though the trait itself already specifies them.
Not really, Float isn't needed because SimdBase::Scalar already specifies the type. And basically everything relies on Scalar, so duplicating multiple fields like that would probably cause more issues.
The main thing I want is to mark that this trait has operator overloading. So I already have things like SimdFloat: Div<Self, Output = Self> + Div<Self::Scalar, Output = Self>, there should also somehow be Self::Scalar: Div<Self, Output = Self>
Oh yeah, your playground link appears to be exactly what I need, I'll work upwards from there, thank you!
Also, weirdly enough, on my PC's installation of rust, the error's suggestion is different to playground and it suggests things like:
` where f32: std::ops::Div<<Self as base::SimdInt32>::SimdF32>`
Which contains base:: that doesn't appear to actually exist, and when I copy-paste it across it errors. What could it mean exactly, and is this something I should open an issue about?
Did you specify both the generic type parameter and the associated type, like f32: Div<Self::SimdF32, Output=Self::SimdF32>? The error only says the generic type parameter.
Ah yeah my bad, I do have a module called base, I got confused because I wouldn't be surprized if there was underlying nomenclature such as base to refer to an inherited trait, but yeah it makes sense now.
Anyway, I just noticed a bigger issue. My first playground link actually isn't the full picture, because the associated types actually reference each other. Here is a more complete playground link (implementing your solution as well):
There appears to be an issue with cyclical dependencies and it makes sense why, I'm just not sure if it's physically possible to solve this one.