diff --git a/src/types/closure.md b/src/types/closure.md
index bcb82e98f..e4264a522 100644
--- a/src/types/closure.md
+++ b/src/types/closure.md
@@ -98,7 +98,9 @@ Async closures always capture all input arguments, regardless of whether or not
 ## Capture Precision
 
 r[type.closure.capture.precision.capture-path]
-A *capture path* is a sequence starting with a variable from the environment followed by zero or more place projections that were applied to that variable.
+A *capture path* is a sequence starting with a variable from the environment followed by zero or more place projections that were applied to that variable, as well as any [further projections performed by matching against patterns][pattern-wildcards].
+
+[pattern-wildcards]: type.closure.capture.precision.wildcard
 
 r[type.closure.capture.precision.place-projection]
 A *place projection* is a [field access], [tuple index], [dereference] (and automatic dereferences), or [array or slice index] expression applied to a variable.
@@ -202,7 +204,7 @@ let c = || match x {  // x is not captured
 c();
 ```
 
-This also includes destructuring of tuples, structs, and enums.
+This also includes destructuring of tuples, structs, and single-variant enums.
 Fields matched with the [RestPattern] or [StructPatternEtCetera] are also not considered as read, and thus those fields will not be captured.
 The following illustrates some of these:
 
@@ -264,6 +266,114 @@ let c = || {
 
 [wildcard pattern]: ../patterns.md#wildcard-pattern
 
+r[type.closure.capture.precision.discriminants]
+### Capturing for discriminant reads
+
+If pattern matching requires inspecting a discriminant, the relevant place will get captured by `ImmBorrow`.
+
+```rust
+enum Example {
+    A(i32),
+    B(i32),
+}
+
+let mut x = (Example::A(21), 37);
+
+let c = || match x { // captures `x.0` by ImmBorrow
+    (Example::A(_), _) => println!("variant A"),
+    (Example::B(_), _) => println!("variant B"),
+};
+x.1 += 1; // x.1 can still be modified
+c();
+```
+
+r[type.closure.capture.precision.discriminants.single-variant]
+Matching against the only variant of an enum does not constitute a discriminant read.
+
+```rust
+enum Example {
+    A(i32),
+}
+
+let mut x = Example::A(42);
+let c = || {
+    let Example::A(_) = x; // does not capture `x`
+};
+x = Example::A(57); // `x` can be modified while the closure is live
+c();
+```
+
+r[type.closure.capture.precision.discriminants.non-exhaustive]
+If [the `#[non_exhaustive]` attribute][non_exhaustive] is applied to an enum defined in an external crate, it is considered to have multiple variants, even if only one variant is actually present.
+
+[non_exhaustive]: attributes.type-system.non_exhaustive
+
+r[type.closure.capture.precision.discriminants.uninhabited-variant]
+Even if all other variants are uninhabited, the discriminant read still occurs.
+
+```rust,compile_fail,E0506
+enum Void {}
+
+enum Example {
+    A(i32),
+    B(Void),
+}
+
+let mut x = Example::A(42);
+let c = || {
+    let Example::A(_) = x; // captures `x` by ImmBorrow
+};
+x = Example::A(57); // ERROR: cannot assign to `x` because it is borrowed
+c();
+```
+
+r[type.closure.capture.precision.discriminants.range-patterns]
+Matching against a [range pattern][patterns.range] performs a read of the place being matched, causing the closure to borrow it by `ImmBorrow`. This is the case even if the range matches all possible values.
+
+```rust,compile_fail,E0506
+let mut x = 7_u8;
+let c = || {
+    let 0..=u8::MAX = x; // captures `x` by ImmBorrow
+};
+x += 1; // ERROR: cannot assign to `x` because it is borrowed
+c();
+```
+
+r[type.closure.capture.precision.discriminants.slice-patterns]
+Matching against a [slice pattern][patterns.slice] that needs to inspect the length of the scrutinee performs a read of the pointer value in order to fetch the length. The read will cause the closure to borrow the relevant place by `ImmBorrow`.
+
+```rust,compile_fail,E0506
+let x: &mut [i32] = &mut [1, 2, 3];
+let c = || match x { // captures `*x` by ImmBorrow
+    [_, _, _] => println!("three elements"),
+    _ => println!("something else"),
+};
+x[0] += 1; // ERROR: cannot assign to `x[_]` because it is borrowed
+c();
+```
+
+As such, matching against an array doesn't itself cause any borrows, as the lengthh is fixed and the pattern doesn't need to inspect it.
+
+```rust
+let mut x: [i32; 3] = [1, 2, 3];
+let c = || match x { // does not capture `x`
+    [_, _, _] => println!("three elements, obviously"),
+};
+x[0] += 1; // `x` can be modified while the closure is live
+c();
+```
+
+Likewise, a slice pattern that matches slices of all possible lengths does not constitute a read.
+
+```rust
+let x: &mut [i32] = &mut [1, 2, 3];
+let c = || match x { // does not capture `x`
+    [..] => println!("always matches"),
+};
+x[0] += 1; // `x` can be modified while the closure is live
+c();
+```
+
 r[type.closure.capture.precision.move-dereference]
 ### Capturing references in move contexts