Why plan to make `Infallible` a type alias of never type?

The doc of [std::convert::Infallible] says

This enum has the same role as the ! “never” type, which is unstable in this version of Rust. When ! is stabilized, we plan to make Infallible a type alias to it:

It prevents the stabilization of never type, as it causes multiple issues listed in https://github.com/rust-lang/rust/issues/35121, otherwise, we could have never type stabilized in Rust v1.41

std::convert::Infallible is an empty enum, which has no value, so cannot be constructed anyway.

So a function returning never type and function returning Infallible can neither be compiled, unless they do not return.

#![feature(never_type)]
fn never_type() -> ! {
    panic!();
}

fn infallible() -> std::convert::Infallible {
   panic!();
}

So I did not see real difference between empty enum and never type. I think keeping Infallible being empty enum should be a valid choice. Why Rust developer considering changing it to never type in the future?

1 Like

! has access to a bit more functionality -- primarily that ! can coerce to any type (this is what allows you to use diverging functions where other types are expected), since I think other things (match exhaustiveness impacts) are planned to come to empty enums as well.

The only reason core::convert::Infallible exists is because we wanted to be able to stabilize the APIs which currently mention it before ! is ready to be stabilized, due to the aforementioned issues. Before stabilization they were phrased in terms of ! and the plan has always been to eventually alias Infallible back to !.

14 Likes

(NOT A CONTRIBUTION)

Would it possibly be a non-breaking change to switch the stable uses of Infallible now with !? ! should unify with Infallible so possibly it wouldn't cause any type errors? Given how long ! has sat unstable, if that is possible it would perhaps be a better solution to just do that, stabilize ! and deprecate Infallible rather than waiting indefinitely to be able to make it a type alias.

1 Like

Continuing from the docs of Infallible under the "Future compatibility" heading:

However there is one case where ! syntax can be used before ! is stabilized as a full-fledged type: in the position of a function’s return type. Specifically, it is possible to have implementations for two different function pointer types:

trait MyTrait {}
impl MyTrait for fn() -> ! {}
impl MyTrait for fn() -> std::convert::Infallible {}

With Infallible being an enum, this code is valid. However when Infallible becomes an alias for the never type, the two impls will start to overlap and therefore will be disallowed by the language’s trait coherence rules.

While ! will coerce to any type, that is different from unifying. The case where Infallible is used is as the error for infallible TryFrom, and it's AIUI not possible to coerce from Result<T, !> to Result<T, E>. In this case, it's theoretically possible, but coercing ! behind a generic isn't possible in the general case if an indirection is used.

If ! is stable enough that it can exist in stable code with some subset functionality but be unnameable, that same functionality subset would be equally stable with the type being nameable. Keeping the type unnameable doesn't help in any meaningful way.

I'm personally not fully confident that the plan to make Infallible an alias will happen, even if/when ! becomes stably usable. But IIRC, when Infallible was stabilized, part of the rationale was that it's still an acceptable result for conversions to use the named type, even if using the primitive would be preferable.

3 Likes

That said, you can actually name ! already if you're tricky enough, so I really don't know the full extent of the stability calculus.

9 Likes

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