Question about never type and closures

I was wondering why one of the following function compiles and one doesn't:

fn exit() -> ! {
    std::process::exit(0);
}

pub fn okay() {
    let _: u8 = Some(42).unwrap_or_else(|| exit());
}

// Error: type mismatch resolving `<fn() -> ! {exit} as std::ops::FnOnce<()>>::Output == {integer}`
pub fn not_okay() {
    let _: u8 = Some(42).unwrap_or_else(exit);
}

Shouldn't the second one be okay since the types of both closures is FnOnce() -> !?

Thanks in advance!

In the okay case, the type of closure is in fact impl FnOnce() -> {integer}, since this is dictated by the unwrap_or_else signature. But inside it, exit's return type of never can coerce to the required type of {integer}. When you're using exit directly, there's no "bare" never type, so there's nothing to coerce, hence the mismatch.

3 Likes

If you want to perform that eta reduction, you can write exit as follows (coercing within the body of the exit function itself, rather than coercing when calling it):

fn exit<T> () -> T
{
    ::std::process::exit(0)
}

Then,

.unwrap_or_else(exit)
//              exit::<_>
//              exit::<u8>

will work.

2 Likes