Shouldn't the implementations of TryFrom for integer types be infallible for unbounded conversions?

While writing a small embedded program I came across the fact that the implementation of TryFrom<u32> for usize in platforms where the pointer size is 32 bits has an Error type of TryFromIntError. In fact, all unbounded integer conversions in core are defined through the use of this macro, present in num.rs:

// no possible bounds violation
macro_rules! try_from_unbounded {
    ($source:ty, $($target:ty),*) => {$(
        #[stable(feature = "try_from", since = "1.34.0")]
        #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
        impl const TryFrom<$source> for $target {
            type Error = TryFromIntError;

            /// Try to create the target number type from a source
            /// number type. This returns an error if the source value
            /// is outside of the range of the target type.
            #[inline]
            fn try_from(value: $source) -> Result<Self, Self::Error> {
                Ok(value as Self)
            }
        }
    )*}
}

Is there any reason for the error type here to be a "real" error type, rather than Infallible or !? I haven't been able to come up with anything on my own, so I'm wondering if anyone knows what the reason for it is.

I especially don't understand why that's the case as having it be infallible would also open up the possibility of, for instance, using Result::into_ok to check a for a lossless conversion at compile time, rather than at runtime. A feature which would come in handy for embedded applications, where the usefulness of a panic is limited.

It started out as you suggest, but that conditional-infallibility was seen as a portability footgun. See the tracking issue for the discussion:

https://github.com/rust-lang/rust/issues/49415

4 Likes

Well, I guess that makes sense then. Thank you!