Skip to content

Conversion between the same type with different const generic values #86978

@Progdrasil

Description

@Progdrasil

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:

1.53.0

For the nightly example (from playground)
rustc --version --verbose:

1.55.0-nightly (2021-07-07 d2b04f075c0ce010758c)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-genericsArea: const generics (parameters and arguments)C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-langRelevant to the language team

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions