I have a struct which uses const generics for defining some of its properties.
I'd like to use the standard From and Into traits for converting from one struct to another with different const values.
There exists a non-fallible equation for the conversion.
However the default impl<T> From<T> for T is clashing with my implementation.
I tried this code:
struct Decimal<const X: u32>(/* fields unimportant */);
impl<const X: u32, const Y: u32> From<Decimal<X>> for Decimal<Y> {
fn from(previous: Decimal<X>) -> Self {
/*
mathematical conversions
*/
Self(/*ommited*/)
}
}
The compiler outputs
error[E0119]: conflicting implementations of trait `std::convert::From<Decimal<{_: u32}>>` for type `Decimal<{_: u32}>`
--> src/lib.rs:3:1
|
3 | impl<const S1: u32, const S2: u32> From<Decimal<S1>> for Decimal<S2> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> From<T> for T;
I understand this might fall into specialization territory but I expected this to compile since T<const X> and T<const Y> should not be the same type. And indeed the seems to agree since the default implementation does not allow the following:
struct Decimal<const S: u32>(/* fields unimportant */);
fn main() {
let x = Decimal::<7>();
let y: Decimal<8> = x.into();
}
This fails to compile with:
error[E0277]: the trait bound `Decimal<8_u32>: From<Decimal<7_u32>>` is not satisfied
--> src/main.rs:5:27
|
5 | let y: Decimal<8> = x.into();
| ^^^^ the trait `From<Decimal<7_u32>>` is not implemented for `Decimal<8_u32>`
|
= note: required because of the requirements on the impl of `Into<Decimal<8_u32>>` for `Decimal<7_u32>`
error: aborting due to previous error
quinedot tried some nightly for the case where X==Y but it also does not work.
#![feature(const_generics)]
#![feature(const_evaluatable_checked)]
struct Decimal<const S: u32>(/* fields unimportant */);
// Const generics hackery: `NotEqual` is implemented only for pairs of
// `Decimal`s with non-equal `const` parameters
struct NoDefault;
trait NotEqual {}
impl<const S1: u32, const S2: u32> NotEqual for (Decimal<S1>, Decimal<S2>)
where
[NoDefault; (S1 == S2) as usize]: Default
{}
// Illustration
fn test_ne () {
#![allow(unused)]
fn test<NE: NotEqual>(_: NE) {}
// okay
test((Decimal::<1>(), Decimal::<2>()));
// fails
// test((Decimal::<1>(), Decimal::<1>()));
}
// Still fails though
impl<const S1: u32, const S2: u32> From<Decimal<S1>> for Decimal<S2>
where
(Decimal<S1>, Decimal<S2>): NotEqual
{
fn from(previous: Decimal<S1>) -> Self {
// Mathematical conversions from S1 to S2
Decimal::<S2>(/*fields*/)
}
}
with output:
error[E0119]: conflicting implementations of trait `std::convert::From<Decimal<{_: u32}>>` for type `Decimal<{_: u32}>`
--> src/lib.rs:26:1
|
26 | / impl<const S1: u32, const S2: u32> From<Decimal<S1>> for Decimal<S2>
27 | | where
28 | | (Decimal<S1>, Decimal<S2>): NotEqual
29 | | {
... |
33 | | }
34 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T> From<T> for T;
Meta
For stable examples
rustc --version --verbose:
For the nightly example (from playground)
rustc --version --verbose:
1.55.0-nightly (2021-07-07 d2b04f075c0ce010758c)
I have a struct which uses const generics for defining some of its properties.
I'd like to use the standard
FromandIntotraits for converting from one struct to another with different const values.There exists a non-fallible equation for the conversion.
However the default
impl<T> From<T> for Tis clashing with my implementation.I tried this code:
The compiler outputs
I understand this might fall into specialization territory but I expected this to compile since
T<const X>andT<const Y>should not be the same type. And indeed the seems to agree since the default implementation does not allow the following:This fails to compile with:
quinedot tried some nightly for the case where
X==Ybut it also does not work.with output:
Meta
For stable examples
rustc --version --verbose:For the nightly example (from playground)
rustc --version --verbose: