Never type does not satisfy type check of unwrap_or_else closure

Hello,

I am trying to pass a function to unwrap_or_else to handle errors where I either exit or panic. The example in the playground here should elaborate.

I can't seem to be able to make the compiler happy, since it expects a function that returns a type other than !. I thought this is precisely where I would use the Never type. Why is this the case? Do you have any suggestion for an alternative way to achieve this (aside from simply passing in the same closure everytime)?

Thank you in advance.

This works, although it is not very satisfying.

    let _unwrapped = result.map_err(handle_cancellation).unwrap();

Cool trick! thanks. I am going to use it if no one suggests a better solution.

1 Like

Here's a different version of the workaround, using the fact that the Result type only has one possible variant left:

let Ok(_unwrapped) = result.map_err(handle_cancellation);
3 Likes

Perfect! That's the better solution, since it takes advantage of the never type.

I like this. But I don't get how this is possible, and not the one I tried. So, in this, the compiler can infer that we have only one variant left (from the return type of handle_cancellation), but in the case with the unwrap_or_else it cannot infer that the function never returns and we don't need a string.

I don't know the internals, but it seems like it's not able to ignore the never type in a generic context. unwrap_or_else requires the return type to be the same as otherwise. Thinking about it like that, I realized that this also works:

fn handle_cancellation<T>(e: Error) -> T {

Here, we pretend that it's going to return whatever we ask it to.

2 Likes

The problem is that the closure passed to unwrap_or_else returns T, and your closure doesn't do that. We can fix that and return T but then we're not using the never type.
playground

2 Likes

It's not about inference, it's about type signatures and bounds. ! is a concrete type,[1] and your OP function returned !. But unwrap_or_else requires a function that returns String.

You get the same sort of error here, for example, even though &[(); 0] can coerce to &[()].

fn handle_cancellation(e: Error) -> &'static [(); 0] {
    &[]
}

fn main() {
    let result: Result<&[()], Error> = Err(Error::Canceled);
    let _unwrapped = result.unwrap_or_else(handle_cancellation);
}

  1. albeit with special abilities like being able to coerce to any type ↩ī¸Ž

4 Likes

There's no coercions for function types.

If you instead pass

.unwrap_or_else(|x|handle_cancellation(x))

it works because it coerces from ! to Error inside the closure.

5 Likes