about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2024-01-10 22:07:48 +0100
committerNadrieril <nadrieril+git@gmail.com>2024-01-10 22:10:08 +0100
commit68a13bf7fd0e456969ea591fc216bf44eea9890d (patch)
tree6f5e1ff11ea05d1e0fb58193c00adbcc40ffbb42 /compiler/rustc_resolve/src
parent223cda41071416c20d3d1db458ce7c6c789e2b08 (diff)
downloadrust-68a13bf7fd0e456969ea591fc216bf44eea9890d.tar.gz
rust-68a13bf7fd0e456969ea591fc216bf44eea9890d.zip
Explain never patterns in resolve
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/late.rs32
1 files changed, 31 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5c246893d87..e100c925478 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3196,6 +3196,21 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     /// consistent when encountering or-patterns and never patterns.
     /// This is done hygienically: this could arise for a macro that expands into an or-pattern
     /// where one 'x' was from the user and one 'x' came from the macro.
+    ///
+    /// A never pattern by definition indicates an unreachable case. For example, matching on
+    /// `Result<T, &!>` could look like:
+    /// ```rust
+    /// # #![feature(never_type)]
+    /// # #![feature(never_patterns)]
+    /// # fn bar(_x: u32) {}
+    /// let foo: Result<u32, &!> = Ok(0);
+    /// match foo {
+    ///     Ok(x) => bar(x),
+    ///     Err(&!),
+    /// }
+    /// ```
+    /// This extends to product types: `(x, !)` is likewise unreachable. So it doesn't make sense to
+    /// have a binding here, and we tell the user to use `_` instead.
     fn compute_and_check_binding_map(
         &mut self,
         pat: &Pat,
@@ -3247,6 +3262,21 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     /// have exactly the same set of bindings, with the same binding modes for each.
     /// Returns the computed binding map and a boolean indicating whether the pattern is a never
     /// pattern.
+    ///
+    /// A never pattern by definition indicates an unreachable case. For example, destructuring a
+    /// `Result<T, &!>` could look like:
+    /// ```rust
+    /// # #![feature(never_type)]
+    /// # #![feature(never_patterns)]
+    /// # fn foo() -> Result<bool, &'static !> { Ok(true) }
+    /// let (Ok(x) | Err(&!)) = foo();
+    /// # let _ = x;
+    /// ```
+    /// Because the `Err(&!)` branch is never reached, it does not need to have the same bindings as
+    /// the other branches of the or-pattern. So we must ignore never pattern when checking the
+    /// bindings of an or-pattern.
+    /// Moreover, if all the subpatterns are never patterns (e.g. `Ok(!) | Err(!)`), then the
+    /// pattern as a whole counts as a never pattern (since it's definitionallly unreachable).
     fn compute_and_check_or_pat_binding_map(
         &mut self,
         pats: &[P<Pat>],
@@ -3254,7 +3284,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         let mut missing_vars = FxIndexMap::default();
         let mut inconsistent_vars = FxIndexMap::default();
 
-        // 1) Compute the binding maps of all arms; never patterns don't participate in this.
+        // 1) Compute the binding maps of all arms; we must ignore never patterns here.
         let not_never_pats = pats
             .iter()
             .filter_map(|pat| {