Uninhabited-ness isn't propagated through nesting

a4daf16
Opened by Steven Fackler at 2024-12-21 05:10:54

This compiles:

enum Void {}

fn foo(v: &Void) -> ! {
    match *v {
    }
}

fn main() {}

But this doesn't:

enum Void {}

fn foo(v: &Void) -> ! {
    match v {
    }
}

fn main() {}
<anon>:4:5: 5:6 error: non-exhaustive patterns: type &Void is non-empty [E0002]
<anon>:4     match v {
<anon>:5     }
<anon>:4:5: 5:6 help: pass `--explain E0002` to see a detailed explanation
error: aborting due to previous error
playpen: application terminated with error code 101

but an instance of &Void can't exist any more than Void can.

Same deal with e.g. struct Foo(Void).

  1. Without some OIBIT-like (or ?Sized-like) scheme, you can't handle this for generic type parameters - assuming you don't want to ban the use of uninhabited types in all generics.

    Also, if we consider &Void to be uninhabited, should *const Void get different treatment, for its uses in FFI? Or does it simply not matter, as long as nobody tries to match over such a raw pointer?

    Eduard-Mihai Burtescu at 2015-05-06 14:57:35

  2. Additionally, I assume "nesting" would include marking arms with variants containing uninhabited types as unreachable, such as:

    let x: Result<u8, Void> = Ok(1);
    match x {
        Ok(b) => (),
        Err(_) => () 
    }
    

    Currently, to do so, you must explicitly handle uninhabited variants:

    let x: Result<u8, Void> = Ok(1);
    match x {
        Ok(b) => (),
        Err(e) => match e {} 
    }
    

    Sean McArthur at 2015-06-03 18:34:31

  3. Triage: no change

    Steve Klabnik at 2016-11-29 21:00:15

  4. Triage: no change

    Steve Klabnik at 2018-10-31 14:03:12

  5. Would this allow layout optimizations like so?

    assert_eq!(core::mem::size_of::<Option<(core::convert::Infallible, u8)>>(), 0);
    

    It'd be incredibly useful for an AST I'm writing, where I want some variants to be considered impossible given certain generic parameters

    Plecra at 2020-07-30 14:05:29