summary refs log tree commit diff
path: root/compiler/rustc_pattern_analysis/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-05 21:36:25 +0000
committerbors <bors@rust-lang.org>2024-02-05 21:36:25 +0000
commitf067fd6084d750f3797f54b71771c5dbc149726f (patch)
tree4dd1eede2b078f8ee37e192ac5a107feb3770f33 /compiler/rustc_pattern_analysis/src
parentea37e8091fe87ae0a7e204c034e7d55061e56790 (diff)
parent400dc46a05f41ba1e1137f11073cec1951442668 (diff)
downloadrust-f067fd6084d750f3797f54b71771c5dbc149726f.tar.gz
rust-f067fd6084d750f3797f54b71771c5dbc149726f.zip
Auto merge of #120313 - Nadrieril:graceful-error, r=compiler-errors
pattern_analysis: Gracefully abort on type incompatibility

This leaves the option for a consumer of the crate to return `Err` instead of panicking on type error. rust-analyzer could use that (e.g. https://github.com/rust-lang/rust-analyzer/issues/15808).

Since the only use of `TypeCx::bug` is in `Constructor::is_covered_by`, it is tempting to return `false` instead of `Err()`, but that would cause "non-exhaustive match" false positives.

r? `@compiler-errors`
Diffstat (limited to 'compiler/rustc_pattern_analysis/src')
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs18
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/pat_column.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs8
5 files changed, 18 insertions, 14 deletions
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index d6c194fb9dc..24824682b74 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -758,10 +758,12 @@ impl<Cx: TypeCx> Constructor<Cx> {
     /// this checks for inclusion.
     // We inline because this has a single call site in `Matrix::specialize_constructor`.
     #[inline]
-    pub(crate) fn is_covered_by(&self, cx: &Cx, other: &Self) -> bool {
-        match (self, other) {
+    pub(crate) fn is_covered_by(&self, cx: &Cx, other: &Self) -> Result<bool, Cx::Error> {
+        Ok(match (self, other) {
             (Wildcard, _) => {
-                cx.bug(format_args!("Constructor splitting should not have returned `Wildcard`"))
+                return Err(cx.bug(format_args!(
+                    "Constructor splitting should not have returned `Wildcard`"
+                )));
             }
             // Wildcards cover anything
             (_, Wildcard) => true,
@@ -803,10 +805,12 @@ impl<Cx: TypeCx> Constructor<Cx> {
             (Opaque(self_id), Opaque(other_id)) => self_id == other_id,
             (Opaque(..), _) | (_, Opaque(..)) => false,
 
-            _ => cx.bug(format_args!(
-                "trying to compare incompatible constructors {self:?} and {other:?}"
-            )),
-        }
+            _ => {
+                return Err(cx.bug(format_args!(
+                    "trying to compare incompatible constructors {self:?} and {other:?}"
+                )));
+            }
+        })
     }
 }
 
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 3d0eb117d17..8e16d4d7bf4 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -123,7 +123,7 @@ pub trait TypeCx: Sized + fmt::Debug {
     ) -> fmt::Result;
 
     /// Raise a bug.
-    fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
+    fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error;
 
     /// Lint that the range `pat` overlapped with all the ranges in `overlaps_with`, where the range
     /// they overlapped over is `overlaps_on`. We only detect singleton overlaps.
diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs
index 3cacfc491b9..0339818d61d 100644
--- a/compiler/rustc_pattern_analysis/src/pat_column.rs
+++ b/compiler/rustc_pattern_analysis/src/pat_column.rs
@@ -78,7 +78,7 @@ impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
         let mut specialized_columns: Vec<_> =
             (0..arity).map(|_| Self { patterns: Vec::new() }).collect();
         let relevant_patterns =
-            self.patterns.iter().filter(|pat| ctor.is_covered_by(cx, pat.ctor()));
+            self.patterns.iter().filter(|pat| ctor.is_covered_by(cx, pat.ctor()).unwrap_or(false));
         for pat in relevant_patterns {
             let specialized = pat.specialize(ctor, arity);
             for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) {
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 15de3346a97..c02a24048f9 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -901,7 +901,7 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
         Ok(())
     }
 
-    fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
+    fn bug(&self, fmt: fmt::Arguments<'_>) -> Self::Error {
         span_bug!(self.scrut_span, "{}", fmt)
     }
 
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index f729f0aa41b..bbb68b353e4 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -1082,7 +1082,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
         pcx: &PlaceCtxt<'_, Cx>,
         ctor: &Constructor<Cx>,
         ctor_is_relevant: bool,
-    ) -> Matrix<'p, Cx> {
+    ) -> Result<Matrix<'p, Cx>, Cx::Error> {
         let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
         let arity = ctor_sub_tys.len();
         let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect();
@@ -1098,12 +1098,12 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
             wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant,
         };
         for (i, row) in self.rows().enumerate() {
-            if ctor.is_covered_by(pcx.cx, row.head().ctor()) {
+            if ctor.is_covered_by(pcx.cx, row.head().ctor())? {
                 let new_row = row.pop_head_constructor(ctor, arity, ctor_is_relevant, i);
                 matrix.expand_and_push(new_row);
             }
         }
-        matrix
+        Ok(matrix)
     }
 }
 
@@ -1523,7 +1523,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
         // strictly fewer rows. In that case we can sometimes skip it. See the top of the file for
         // details.
         let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
-        let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
+        let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?;
         let mut witnesses = ensure_sufficient_stack(|| {
             compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
         })?;