Avoid hanging on complex matches

This commit is contained in:
Nadrieril 2024-03-17 16:38:01 +01:00
parent e67adf40c9
commit 040f37a99d
2 changed files with 26 additions and 2 deletions

View file

@ -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(())
}
}

View file

@ -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::*;