# Pattern binding modes +!

**URL:** <https://internals.rust-lang.org/t/pattern-binding-modes/16829>\
**Category:** Uncategorized\
**Created:** [June 16, 2022, 1:31pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829 "2022-06-16T13:31:24Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [June 16, 2022, 1:31pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/1 "2022-06-16T13:31:24Z")

</div>

`&!` is an inhabited type. As such,

```rust
fn test(it: &!) {
    match it {}
}

```

fails to compile, as the patterns provided are nonexhaustive.

Even with ~~match ergonomics~~ default binding modes, a literal `x` pattern matches at type `&!` and is still inhabited.

But... a pattern `&x` dereferences the reference and observes the `!`. As such, you can make a case that we should consider the inhabitedness behind references when checking if a match scrutinee is covered by zero patterns.

This would allow replacing the

```rust
  = note: the matched value is of type `&!`
  = note: references are always considered inhabited

```

diagnostic with the code "just working."

But the question is: do we want to make this argument? This would paper a bit over the "`&!` is still inhabited" point but also make it accidentally write code that assumes that it isn't. (Is there a soundness problem with assuming it's not inhabited when it just unconstructable? There is in the other direction.) I'm not sure either way.

---

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [June 16, 2022, 1:48pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/2 "2022-06-16T13:48:55Z")

</div>

The question:

how could you call test?

Never type could not be created, thus I have no knowledge to create a `&!` type.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [June 16, 2022, 1:55pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/3 "2022-06-16T13:55:27Z")

</div>

You can't safely construct `&!`. However, the type `&!` itself is useful in a generic context for the same reason `!` is.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [June 16, 2022, 2:09pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/4 "2022-06-16T14:09:32Z")

</div>

```rust
let v: String = match it {};

```

If `&!` is inhabited, this is UB.

---

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [June 16, 2022, 2:15pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/5 "2022-06-16T14:15:41Z")

</div>

IMHO, since &! could be created, they must be matched with something

```rust
#![feature(strict_provenance)]
#![feature(never_type)]
fn test(it: &!) ->usize {
    println!("before test");
    let ans=match it{
        ans=>{
            let ans=( ans as *const ! ).addr();
            println!("in match");
            ans
        }
    };
    println!("fine");
    drop(it);
    println!("after test");
    ans
}
fn wtf(){
    let a=1usize;
    let b=(&a as *const usize).cast::<!>();
    unsafe{dbg!(test(&*b));return};
}
fn main(){
    wtf();
    println!("wtf done")
}

```

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [June 16, 2022, 2:18pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/6 "2022-06-16T14:18:16Z")

</div>

Note that creating `&!` is considered UB: it is considerd inhabited to keep the possibility of allowing that, but currently it is both inhabited and unconstructable.

---

<div class="post-metadata">

**Author:** ![sfackler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sfackler/32/9_2.png) [@sfackler](https://internals.rust-lang.org/u/sfackler)\
**Post date:** [June 16, 2022, 2:30pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/7 "2022-06-16T14:30:09Z")

</div>

> <https://github.com/rust-lang/rust/issues/24885>
>
> This compiles:
> 
> \`\`\` rust
> enum Void {}
> 
> fn foo(v: &Void) -\> ! {
> match \*v {
> … }
> }
> 
> fn main() {}
> \`\`\`
> 
> But this doesn't:
> 
> \`\`\` rust
> 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)\`.

---

<div class="post-metadata">

**Author:** ![simonbuchan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonbuchan/32/9390_2.png) [@simonbuchan](https://internals.rust-lang.org/u/simonbuchan)\
**Post date:** [June 17, 2022, 8:02am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/8 "2022-06-17T08:02:09Z")

</div>

My reading: being inhabited means you can write code that creates a value with said type, in this case, `todo!()` or `&todo!()`. That doesn't mean that code will run (to completion).

For example, you can't write code that constructs a value of `enum Empty {}`, even only at the type level. You need to resort to an extern function: [Rust Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=f767777a6418457f372dfc4f5afab65a)

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [June 17, 2022, 8:13am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/9 "2022-06-17T08:13:55Z")

</div>

`let e: Empty = todo!();` works just fine.

I still like the idea of being (able to be) explicit about not matching (`match e { ! }`) combining a `!` pattern that matches a `!` value, and being able to elide the code block for an unreachable match. Though that doesn’t help with something like `let Ok(v): Result<usize, &!> = e;` if the implicit `Err(&!)` branch isn’t considered unreachable.

---

<div class="post-metadata">

**Author:** ![simonbuchan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonbuchan/32/9390_2.png) [@simonbuchan](https://internals.rust-lang.org/u/simonbuchan)\
**Post date:** [June 17, 2022, 8:18am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/10 "2022-06-17T08:18:19Z")

</div>

Interesting, that does, and `let e: &Empty = todo!()`, but `let e: &Empty = &todo!()` doesn't! I wonder what the logic is there.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [June 17, 2022, 8:59am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/11 "2022-06-17T08:59:17Z")

</div>

Simple: the type of `todo!()` is `!`. `!` can coerce to any type, but coercion is not recursive (because this is impossible in the general case), and thus `&!` cannot coerce to `&Never`. You can do `let _: &Never = &(todo!() as _);`.

---

<div class="post-metadata">

**Author:** ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)\
**Post date:** [June 17, 2022, 2:01pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/12 "2022-06-17T14:01:31Z")

</div>

Code:

```rust
enum E{
   Safe(u8),
   Unsafe(u8,&!),
}

fn foo() {
   let data = E::Safe(10);
   //use unsafe to mutate discriminant, and co.
   //have an `E::Unsafe` variant of the enum
}

```

We can handle this by adding smth like unsafe `match`. This way we can both provide access for data in unsafe code and have nice exhaustive matching in safe code:

```rust
fn safe(data: E) {
   let E::Safe(byte) = data; // if data is `E::Unsafe` - panic
}

unsafe fn usafe(data: E) {
   match data {
      Safe(byte)=>{},
      Unsafe(r)=>{}, // note this variant
   }
}

```

Yes, I know that panicking out is not good at all... but it's the only easy solution.

---

<div class="post-metadata">

**Author:** ![felix.s](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/felix.s/32/8073_2.png) [@felix.s](https://internals.rust-lang.org/u/felix.s)\
**Post date:** [June 17, 2022, 8:06pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/13 "2022-06-17T20:06:11Z")

</div>

> [@chrefr](#):
>
> inhabited and unconstructable

That’s a contradiction in terms. The definition of an inhabited type is that it not only has an element, but you have the constructor to prove it. Put another way: if `&!` is inhabited, what is it inhabited by?

I can accept `&!` being called _nonempty_…

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [June 17, 2022, 8:15pm UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/14 "2022-06-17T20:15:16Z")

</div>

I can construct an instance of `Never` or `!` just as easily:

```rust
let never: Never = unsafe { std::mem::transmute(()) };
println!("{:p}", &never);
println!("This is obvious UB, don't do this");

```

[[playground]](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3f68a71b98066acecda9c86a7e405b14)

`&!` is a type which has _valid_ values but no _safe_ values. This is the difference between [safety and validity invariants](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html).

The validity invariant of references is still an open question, but it's _generally_ accepted that the validity should be shallow, and not require the validity of the pointee. If you don't require the validity of `!` as a pointee, you're left with a reference which must be dereferencable for `size_of::<!>() == 0` bytes and aligned to `align_of::<!>() == 1` bytes. If you satisfy that, you have a _valid_ value, and thus the type is inhabited.

So if you want to be specific, you could say that `&!` is _inhabited_ but not _safely inhabited_, as there is no value which satisfies the safety invariant (which for references, is that the referee satisfies its safety invariant plus something to guarantee the borrow model is inviolable).

---

<div class="post-metadata">

**Author:** ![ratmice](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ratmice/32/4917_2.png) [@ratmice](https://internals.rust-lang.org/u/ratmice)\
**Post date:** [June 18, 2022, 12:41am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/15 "2022-06-18T00:41:40Z")

</div>

> [@CAD97](#):
>
> So if you want to be specific, you could say that `&!` is _inhabited_ but not _safely inhabited_

I think there _is_ a safe thing you could do with an inhabited value of `&!`, which would be `std::ptr::eq`.

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [June 18, 2022, 1:30am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/16 "2022-06-18T01:30:05Z")

</div>

That doesn't really make any sense. Having a value of type `T` means that you can perform all operations which are defined on `T`. For references, it means that I can dereference it and get a value of the pointee, which is impossible with `&!`. This means that you can't construct an element of `&!`, which means it isn't inhabited.

Making an "unsafe" element of `&!` via unsafe code has about as much sense as finding a magical "unsafe" third value of `bool`.

What _is_ inhabited is `*mut !`, since raw pointers don't guarantee any safe operations which could expose a pointee. Any non-null pointer is a valid element of `*mut !`, but dereferencing it is always UB.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [June 18, 2022, 2:32am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/17 "2022-06-18T02:32:31Z")

</div>

> [@afetisov](#):
>
> Having a value of type `T` means that you can perform all operations which are defined on `T`.

This is true of the safety invariant, yes. If I have a `str` which is valid UTF-8, I can do anything that the API offers. If I have a `str` which is invalid UTF-8, though, which does not satisfy the safety invariant but does the validity invariant, I can't do many otherwise safe operations; for example, `s.chars().last()` could index out of bounds, causing UB.

It is the _safety_ invariant that you can dereference `&T` and get a valid `T`. It is a _validity_ invariant that you can dereference `&T` and get `size_of::<T>()` bytes, and that the reference is aligned to `align_of::<T>()` bytes.

Of course, this is non normative, but this is the [general consensus of the unsafe code working group](https://github.com/rust-lang/unsafe-code-guidelines/issues/77), and making validity recursive is really hard to check for basically no optimization benefit.

Making a `bool` which is not `0x00` or `0x01` is a different class of invalid, because that's a _validity_ invariant of the type. Moreover, it's the "bitstring validity," which is used for layout optimizations.

`&!` could still potentially have not (unsafe but) valid values still, if we make it part of the validity invariant that the pointee type is inhabited. But as currently informally defined, transmuting `&()` to `&!` gives you a _valid but unsafe_ instance of `&!` where not fulfilling the safety invariant of a reference means that the only sound operations are

- a typed copy,
- turn it into a pointer, or
- dereference to `size_of::<T>()` bytes (but to not do a typed copy of said bytes, or otherwise use them at type `T`).

This ignores any retagging operations done by Stacked Borrows or any other memory model enforcing the borrow quality of references, as this does care about the type of the pointee (though similarly doesn't necessarily recurse into retagging the pointee's contained references).

We _might_ end up renaming safety/validity invariants in the future, because informally "validity" can refer to an instance which satisfies the safety invariants. But those are the terms we currently have.

> [@afetisov](#):
>
> Any non-null pointer is a valid element of `*mut !`, but dereferencing it is always UB.

(And so is the null pointer.)

Note that it's only to dereference _at type `!`_. `MaybeUninit<!>` is fine, as is `[u8: 0]` or any other inhabited ZST. The UB from dereferencing a pointer to `!` comes to that doing a typed copy of an uninhabited type with the validity invariant of _false_.

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [June 18, 2022, 2:53am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/18 "2022-06-18T02:53:42Z")

</div>

I don't see why matching on a reference should be treated as a special case compared to any other operation that dereferences the reference. What is unique about this case?

Also, we allow

```rust
fn test(it: &bool) {
    match &it {
        &true => (),
        &false => (),
    }
}

```

even though it's possible to construct an `&bool` in unsafe code that doesn't uphold `bool`s validity invariants. Again, why should we have a special case?

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [June 18, 2022, 3:21am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/19 "2022-06-18T03:21:28Z")

</div>

> [@Jules-Bertholet](#):
>
> We allow [`match bool { true | false => () }`] even though it's possible to construct an `&bool` in unsafe code that doesn't uphold `bool`s validity invariants. Again, why should we have a special case?

`&T` pointing to a valid `T` is not currently part of the validity invariant, just the safety invariant. (This is not a guaranteed decided truth.) So this is a false equivalence here.

And if `&T` it _is_ part of the validity invariant of `&T`, then this is in support of `match (x: &!) {}` being valid, because there are no valid values of `&!`.

> [@Jules-Bertholet](#):
>
> I don't see why matching on a reference should be treated as a special case compared to any other operation that dereferences the reference.

Well, matching doesn't dereference until it hits a pattern. `match (x: &!) { ! => () }` _would_ dereference the reference, as would `match x { &_ => () }`, but `match x { _ => () }` doesn't dereference the reference.

The position of my OP is that we could if we wanted say that a `match` with no patterns does dereference the scrutinee, like a pattern could with default binding modes, and the result of that would be a zero-arm match on reference-to-uninhabited behaving the same as a zero-arm match on uninhabited.

Effectively, applying default binding modes to the "uninhabited pattern" to pattern match through references in the scrutinee.

(To anyone: it's probably best to clarify explicitly whether a post is for or against `&!` being inhabited, and for or against a zero-arm match over `&!` being valid if `&!` is inhabited.)

To be explicit: my position is that

- `&T` has a validity invariant that does not refer to the validity of `T`
- Thus `&!` is inhabited
- However, holding a `&!` is basically instant UB anyway, because
  - doing basically anything to `&T` asserts the validity of `T`
  - this includes minimally a retag of `&T` (which a typed copy does), as well as of course anything that actually uses `T`
  - the only thing that _might_ be exempted is `as` casts
  - notably functions such as `ptr::addr` or `ptr::eq` retag and thus assert `T` validity

- It would be a nice bit of ergonomics if ~~match ergonomics~~ default binding modes applied to the "uninhabited pattern" seeing through references
  - but since this only applies when the concrete type is known anyway, `&!` can just do `*it` instead of `match it {}`
  - so this basically only applies to custom uninhabited enums

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [June 18, 2022, 5:20am UTC](https://internals.rust-lang.org/t/pattern-binding-modes/16829/20 "2022-06-18T05:20:32Z")

</div>

To be clear, I understand that "T breaks validity invariants =\> &T breaks validity invariants" is likely too strong, and that "T breaks validity invariants =\> &T breaks safety invariants" is the current consensus. I see no reason to change that. But even given that latter standard, dissalowing empty matches on references to uninhabited types seems strange to me, because in the `&bool` match example I gave, Rust makes no special allowances for the possibility of an `&bool` that breaks safety invariants, but in the case of `&!` it does. Or at least that's the impression I get.

> [@CAD97](#):
>
> Well, matching doesn't dereference until it hits a pattern.

I think this is the point where my intuition diverges from your rationale. I generally think of pattern matching in purely "declarative" terms, not in terms of performing operations like dereferencing. The idea that a specific pattern within a pattern match could have a side effect (in this case, a dereference invoking UB) just never occurred to me. I haven't written much complex `unsafe` code before, so maybe there are subtleties I'm missing. But I don't see why safe code should be encumbered just to remove 1 footgun for `unsafe` code that uses references to invalid values, even though such code would still have 9,999,999 other footguns to contend with (and should probably be using raw pointers anyway).

[Next page](https://internals.rust-lang.org/t/pattern-binding-modes/16829.md?page=2)
