2024-03-04 15:57:32 +00:00
|
|
|
//! Test exhaustiveness checking.
|
2024-06-19 19:04:30 +00:00
|
|
|
|
2024-03-04 15:57:32 +00:00
|
|
|
use common::*;
|
|
|
|
use rustc_pattern_analysis::MatchArm;
|
|
|
|
use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
|
|
|
|
use rustc_pattern_analysis::usefulness::PlaceValidity;
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
mod common;
|
|
|
|
|
|
|
|
/// Analyze a match made of these patterns.
|
|
|
|
fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
|
|
|
|
let ty = *patterns[0].ty();
|
|
|
|
let arms: Vec<_> =
|
|
|
|
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
|
|
|
|
let report =
|
|
|
|
compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
|
|
|
|
report.non_exhaustiveness_witnesses
|
|
|
|
}
|
|
|
|
|
|
|
|
#[track_caller]
|
|
|
|
fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
|
|
|
|
let witnesses = check(patterns);
|
|
|
|
if !witnesses.is_empty() {
|
2024-09-02 05:50:22 +00:00
|
|
|
panic!("non-exhaustive match: missing {witnesses:?}");
|
2024-03-04 15:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[track_caller]
|
|
|
|
fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
|
|
|
|
let witnesses = check(patterns);
|
|
|
|
assert!(!witnesses.is_empty())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_int_ranges() {
|
|
|
|
let ty = Ty::U8;
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
0..=255,
|
|
|
|
));
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
0..,
|
|
|
|
));
|
|
|
|
assert_non_exhaustive(pats!(ty;
|
|
|
|
0..255,
|
|
|
|
));
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
0..255,
|
|
|
|
255,
|
|
|
|
));
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
..10,
|
|
|
|
10..
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_nested() {
|
|
|
|
let ty = Ty::BigStruct { arity: 2, ty: &Ty::BigEnum { arity: 2, ty: &Ty::Bool } };
|
|
|
|
assert_non_exhaustive(pats!(ty;
|
|
|
|
Struct(Variant.0, _),
|
|
|
|
));
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
Struct(Variant.0, _),
|
|
|
|
Struct(Variant.1, _),
|
|
|
|
));
|
|
|
|
assert_non_exhaustive(pats!(ty;
|
|
|
|
Struct(Variant.0, _),
|
|
|
|
Struct(_, Variant.0),
|
|
|
|
));
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
Struct(Variant.0, _),
|
|
|
|
Struct(_, Variant.0),
|
|
|
|
Struct(Variant.1, Variant.1),
|
|
|
|
));
|
|
|
|
}
|
2024-07-21 12:37:10 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_empty() {
|
|
|
|
// `TY = Result<bool, !>`
|
|
|
|
const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]);
|
|
|
|
assert_exhaustive(pats!(TY;
|
|
|
|
Variant.0,
|
|
|
|
));
|
|
|
|
let ty = Ty::Tuple(&[Ty::Bool, TY]);
|
|
|
|
assert_exhaustive(pats!(ty;
|
|
|
|
(true, Variant.0),
|
|
|
|
(false, Variant.0),
|
|
|
|
));
|
|
|
|
}
|