Try operator over TryInto picks up irrelevent type parameter

struct DummyError;
struct AnotherError;
impl From<AnotherError> for DummyError {
    fn from(_: AnotherError) -> Self {
        Self
    }
}

struct DummyStruct;
impl TryFrom<()> for DummyStruct {
    type Error = DummyError;
    fn try_from(_: ()) -> Result<Self, Self::Error> {
        Ok(Self)
    }
}


fn test<Dummy>(
) -> Result<(), DummyError>
where DummyError: From<Dummy> {
    let dummy: Result<DummyStruct, _> = ().try_into();
    let _ = dummy?;
    // The above is to demostrate that if we split the one line code below into 2 lines, there is no errors.
    let _ = ().try_into()?;
    Ok(())
}

The above code gives the following error message:

error[E0271]: type mismatch resolving `<() as TryFrom<()>>::Error == Dummy`
  --> src/lib.rs:23:16
   |
18 | fn test<Dummy>(
   |         ----- this type parameter
...
23 |     let _ = ().try_into()?;
   |                ^^^^^^^^ expected enum `Infallible`, found type parameter `Dummy`
   |
   = note:        expected enum `Infallible`
           found type parameter `Dummy`

For more information about this error, try `rustc --explain E0271`.

That code is of cause has errors, but it is not relevant to the one reported I think, because the generic type Dummy was not even referenced in the body.

Is this a bug? Shall I raise an issue?

Further Information

If we type annotate the line with error, like

let _:DummyStruct = ().try_into()?;

The error message is

error[E0271]: type mismatch resolving `<DummyStruct as TryFrom<()>>::Error == Dummy`
  --> src/lib.rs:23:28
   |
18 | fn test<Dummy>(
   |         ----- this type parameter
...
23 |     let _:DummyStruct = ().try_into()?;
   |                            ^^^^^^^^ expected struct `DummyError`, found type parameter `Dummy`
   |
   = note:      expected struct `DummyError`
           found type parameter `Dummy`

For more information about this error, try `rustc --explain E0271`.

Still trying to match the unused type parameter.

Further more information

Here is a more realistic example that does not have unused generic parameters. However I think unused generic parameters should be legal. Still, even without that we run into the same problem.

Playground

struct DummyError;
struct AnotherError;
impl From<AnotherError> for DummyError {
    fn from(_: AnotherError) -> Self {
        Self
    }
}

struct DummyStruct;
impl TryFrom<()> for DummyStruct {
    type Error = DummyError;
    fn try_from(_: ()) -> Result<Self, Self::Error> {
        Ok(Self)
    }
}

fn err<E>(e: E) -> Result<(), E> {
    Err(e)
}


fn test<Dummy>(
    r: Result<(),Dummy>
) -> Result<(), DummyError>
where DummyError: From<Dummy> {
    r?;
    let dummy: Result<DummyStruct, _> = ().try_into();
    let _ = dummy?;
    let _:DummyStruct = ().try_into()?;
    Ok(())
}

fn main() {
    let _ = test(Err(AnotherError));
}

The error disappears when one fully qualifies the function:

struct DummyError;
struct AnotherError;
impl From<AnotherError> for DummyError {
    fn from(_: AnotherError) -> Self {
        Self
    }
}

struct DummyStruct;
impl TryFrom<()> for DummyStruct {
    type Error = DummyError;
    fn try_from(_: ()) -> Result<Self, Self::Error> {
        Ok(Self)
    }
}


fn test<Dummy>(
) -> Result<(), DummyError>
where DummyError: From<Dummy> {
    let dummy: Result<DummyStruct, _> = <() as TryInto<DummyStruct>>::try_into(());
    let _: DummyStruct = dummy?;
    let _: DummyStruct = <() as TryInto<DummyStruct>>::try_into(())?;
    Ok(())
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.