Skip to content

Invalid collision with TryFrom implementation? #50133

Open
@npmccallum

Description

@npmccallum

Sorry for the code dump. This is the smallest code I could make to reproduce the problem.

use std::marker::PhantomData;
use std::convert::TryFrom;

trait Integer {}
impl Integer for u8 {}

trait Adapter<I: Integer>: TryFrom<I> + Into<I> {}

enum Choice {
    Foo,
    Bar,
    Baz
}

impl From<Choice> for u8 {
    fn from(c: Choice) -> u8 {
        match c {
            Choice::Foo => 1,
            Choice::Bar => 2,
            Choice::Baz => 3,
        }
    }
}

impl TryFrom<u8> for Choice {
    type Error = ();
    fn try_from(i: u8) -> Result<Choice, ()> {
        match i {
            1 => Ok(Choice::Foo),
            2 => Ok(Choice::Bar),
            3 => Ok(Choice::Baz),
            _ => Err(()),
        }
    }
}

impl Adapter<u8> for Choice {}

struct Pick<I: Integer, A: Adapter<I>> {
    phantom: PhantomData<A>,
    value: I,
}

impl<I: Integer, A: Adapter<I>> From<A> for Pick<I, A> {
    fn from(a: A) -> Pick<I, A> {
        Pick {
            phantom: PhantomData,
            value: a.into(),
        }
    }
}

impl<I: Integer, A: Adapter<I>> TryFrom<Pick<I, A>> for A {
    type Error = A::Error;

    fn try_from(p: Pick<I, A>) -> Result<A, Self::Error> {
        A::try_from(p.value)
    }
}

Attempting to compile this produces:

error[E0119]: conflicting implementations of trait `std::convert::TryFrom<Pick<_, _>>`:
  --> src/main.rs:53:1
   |
53 | impl<I: Integer, A: Adapter<I>> TryFrom<Pick<I, A>> for A {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T, U> std::convert::TryFrom<U> for T
             where T: std::convert::From<U>;

error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g. `MyStruct<A>`)
  --> src/main.rs:53:1
   |
53 | impl<I: Integer, A: Adapter<I>> TryFrom<Pick<I, A>> for A {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `A` must be used as the type parameter for some local type
   |
   = note: only traits defined in the current crate can be implemented for a type parameter

I've spent several hours looking at this and I can't figure out why I'm getting these errors. The type parameter A is being used as the type parameter for a local type. Maybe the compiler can't tell because it is nested inside TryFrom<>?

But I'm also not sure why the first error occurs at all. The rule it conflicts with can basically be described as "types with infallible conversions implicitly implement fallible conversions." But in my case there is no infallible conversion. So I don't see where the conflict is arising from.

If there is really a bug and I'm not just overtired, this may impact #49305.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-langRelevant to the language team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions