about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2024-03-17 16:38:01 +0100
committerNadrieril <nadrieril+git@gmail.com>2024-03-18 21:21:52 +0100
commit040f37a99d430395b0d9ace6ea468f895f50fc16 (patch)
treeac3f04aecf530153be352cf1f5874dd14cd5935d
parente67adf40c98c95bb25a27a66c5b3f20a8094b296 (diff)
downloadrust-040f37a99d430395b0d9ace6ea468f895f50fc16.tar.gz
rust-040f37a99d430395b0d9ace6ea468f895f50fc16.zip
Avoid hanging on complex matches
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs5
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_match_arms.rs23
2 files changed, 26 insertions, 2 deletions
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index dfe082cb560..f45beb4c92b 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -67,7 +67,9 @@ impl<'p> MatchCheckCtx<'p> {
     ) -> Result<UsefulnessReport<'p, Self>, ()> {
         // FIXME: Determine place validity correctly. For now, err on the safe side.
         let place_validity = PlaceValidity::MaybeInvalid;
-        compute_match_usefulness(self, arms, scrut_ty, place_validity, None)
+        // Measured to take ~100ms on modern hardware.
+        let complexity_limit = Some(500000);
+        compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
     }
 
     fn is_uninhabited(&self, ty: &Ty) -> bool {
@@ -476,7 +478,6 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
     }
 
     fn complexity_exceeded(&self) -> Result<(), Self::Error> {
-        // FIXME(Nadrieril): make use of the complexity counter.
         Err(())
     }
 }
diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 67daa172b27..c03bb3aeb53 100644
--- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -1004,6 +1004,29 @@ fn f() {
         );
     }
 
+    #[test]
+    fn exponential_match() {
+        // Constructs a match where match checking takes exponential time. Ensures we bail early.
+        use std::fmt::Write;
+        let struct_arity = 30;
+        let mut code = String::new();
+        write!(code, "struct BigStruct {{").unwrap();
+        for i in 0..struct_arity {
+            write!(code, "  field{i}: bool,").unwrap();
+        }
+        write!(code, "}}").unwrap();
+        write!(code, "fn big_match(s: BigStruct) {{").unwrap();
+        write!(code, "  match s {{").unwrap();
+        for i in 0..struct_arity {
+            write!(code, "    BigStruct {{ field{i}: true, ..}} => {{}},").unwrap();
+            write!(code, "    BigStruct {{ field{i}: false, ..}} => {{}},").unwrap();
+        }
+        write!(code, "    _ => {{}},").unwrap();
+        write!(code, "  }}").unwrap();
+        write!(code, "}}").unwrap();
+        check_diagnostics_no_bails(&code);
+    }
+
     mod rust_unstable {
         use super::*;