Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using TryInto generics with anyhow::Error

The function is expected to accept a command which can be converted to a string, and also I am using anyhow to handle the error thing. Here is the code:

pub fn converter<T: TryInto<String>>(input: T) -> Result<String>
where
    T::Error: Into<anyhow::Error>,
{
    // error here
    // the trait bound `<T as TryInto<std::string::String>>::Error: StdError` is not satisfied
    // required because of the requirements on the impl of `From<<T as TryInto<std::string::String>>::Error>` for `anyhow::Error`
    // required because of the requirements on the impl of `FromResidual<Result<Infallible, <T as TryInto<std::string::String>>::Error>>` for `Result<std::string::String, anyhow::Error>
    let out_str = input.try_into()?;
    Ok(out_str)
}

I have added a type restriction for T::Error as T::Error: Into<anyhow::Error>, hope the compiler can do the error handling, but shows the T::Error can't be convert to a anyhow::Error.

The type restriction is referred from: https://github.com/dtolnay/anyhow/issues/172, but I still can't figure out how to use the TryInto generic with anyhow.

like image 990
sofx Avatar asked Jun 19 '26 23:06

sofx


1 Answers

TL;DR: Replace T::Error: Into<anyhow::Error> with anyhow::Error: From<T::Error>.


This one is quite subtle.

You might have expected the desugaring of ? to be like (ignoring extra facility like the Try trait):

let out_str = match input.try_into() {
    Ok(v) => v,
    Err(e) => return Err(Into::into(e)),
};

But it is not. Rather, it is more like:

let out_str = match input.try_into() {
    Ok(v) => v,
    Err(e) => return Err(From::from(e)),
};

Which produce the exact same error(s). This is because Result uses From to convert the error, not Into.

Now, having a From impl implies having an Into impl - because of the blanket implementation impl<T, U: From<T>> Into<U> for T - but the opposite is not true, and moreover, cannot be true with the current Rust trait system.

If Result would use Into in the desugaring, you'd have been fine, because the compiler can prove T::Error: Into<anyhow::Error> holds from your where clause, but given it uses From, the compiler cannot prove anyhow::Error: From<T::Error> holds, and thus raises an error.

There was an attempt to change the desugaring in the past (#60796), but unfortunately it caused too much inference breakage, so it is probably impossible by now. See:

  • https://github.com/rust-lang/rust/issues/84277#issuecomment-903944296
  • https://github.com/rust-lang/rust/issues/31436#issuecomment-299482914
  • https://github.com/rust-lang/rust/issues/31436#issuecomment-619427209
  • https://github.com/rust-lang/rust/issues/38751
like image 133
Chayim Friedman Avatar answered Jun 23 '26 07:06

Chayim Friedman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!