mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-30 20:44:34 +00:00 
			
		
		
		
	 6bf3cbe39e
			
		
	
	
		6bf3cbe39e
		
	
	
	
	
		
			
			In rustc it doesn't really matter what the order of the witnesses is, but I'm planning to use the witnesses for implementing the "add missing match arms" assist in rust-analyzer, and there `true` before `false` is the natural order (like `Some` before `None`), and also what the current assist does. The current order doesn't seem to be intentional; the code was created when bool ctors became their own thing, not just int ctors, but for integer, 0 before 1 is indeed the natural order.
		
			
				
	
	
		
			197 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Test exhaustiveness checking.
 | |
| 
 | |
| #![allow(unused_crate_dependencies)]
 | |
| 
 | |
| 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 run(
 | |
|     ty: Ty,
 | |
|     patterns: Vec<DeconstructedPat<Cx>>,
 | |
|     exhaustive_witnesses: bool,
 | |
| ) -> Vec<WitnessPat<Cx>> {
 | |
|     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,
 | |
|         usize::MAX,
 | |
|         exhaustive_witnesses,
 | |
|     )
 | |
|     .unwrap();
 | |
|     report.non_exhaustiveness_witnesses
 | |
| }
 | |
| 
 | |
| /// Analyze a match made of these patterns. Panics if there are no patterns
 | |
| fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
 | |
|     let ty = *patterns[0].ty();
 | |
|     run(ty, patterns, true)
 | |
| }
 | |
| 
 | |
| #[track_caller]
 | |
| fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
 | |
|     let witnesses = check(patterns);
 | |
|     if !witnesses.is_empty() {
 | |
|         panic!("non-exhaustive match: missing {witnesses:?}");
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[track_caller]
 | |
| fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
 | |
|     let witnesses = check(patterns);
 | |
|     assert!(!witnesses.is_empty())
 | |
| }
 | |
| 
 | |
| use WhichWitnesses::*;
 | |
| enum WhichWitnesses {
 | |
|     AllOfThem,
 | |
|     OnlySome,
 | |
| }
 | |
| 
 | |
| #[track_caller]
 | |
| /// We take the type as input to support empty matches.
 | |
| fn assert_witnesses(
 | |
|     which: WhichWitnesses,
 | |
|     ty: Ty,
 | |
|     patterns: Vec<DeconstructedPat<Cx>>,
 | |
|     expected: Vec<&str>,
 | |
| ) {
 | |
|     let exhaustive_wit = matches!(which, AllOfThem);
 | |
|     let witnesses = run(ty, patterns, exhaustive_wit);
 | |
|     let witnesses: Vec<_> = witnesses.iter().map(|w| format!("{w:?}")).collect();
 | |
|     assert_eq!(witnesses, expected)
 | |
| }
 | |
| 
 | |
| #[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() {
 | |
|     // enum E { A(bool), B(bool) }
 | |
|     // ty = (E, E)
 | |
|     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),
 | |
|     ));
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn test_witnesses() {
 | |
|     // TY = Option<bool>
 | |
|     const TY: Ty = Ty::Enum(&[Ty::Bool, UNIT]);
 | |
|     // ty = (Option<bool>, Option<bool>)
 | |
|     let ty = Ty::Tuple(&[TY, TY]);
 | |
|     assert_witnesses(AllOfThem, ty, vec![], vec!["(_, _)"]);
 | |
|     assert_witnesses(
 | |
|         OnlySome,
 | |
|         ty,
 | |
|         pats!(ty;
 | |
|             (Variant.0(false), Variant.0(false)),
 | |
|         ),
 | |
|         vec!["(Enum::Variant1(_), _)"],
 | |
|     );
 | |
|     assert_witnesses(
 | |
|         AllOfThem,
 | |
|         ty,
 | |
|         pats!(ty;
 | |
|             (Variant.0(false), Variant.0(false)),
 | |
|         ),
 | |
|         vec![
 | |
|             "(Enum::Variant0(false), Enum::Variant0(true))",
 | |
|             "(Enum::Variant0(false), Enum::Variant1(_))",
 | |
|             "(Enum::Variant0(true), _)",
 | |
|             "(Enum::Variant1(_), _)",
 | |
|         ],
 | |
|     );
 | |
|     assert_witnesses(
 | |
|         OnlySome,
 | |
|         ty,
 | |
|         pats!(ty;
 | |
|             (_, Variant.0(false)),
 | |
|         ),
 | |
|         vec!["(_, Enum::Variant1(_))"],
 | |
|     );
 | |
|     assert_witnesses(
 | |
|         AllOfThem,
 | |
|         ty,
 | |
|         pats!(ty;
 | |
|             (_, Variant.0(false)),
 | |
|         ),
 | |
|         vec!["(_, Enum::Variant0(true))", "(_, Enum::Variant1(_))"],
 | |
|     );
 | |
| 
 | |
|     let ty = Ty::NonExhaustiveEnum(&[UNIT, UNIT, UNIT]);
 | |
|     assert_witnesses(
 | |
|         OnlySome,
 | |
|         ty,
 | |
|         pats!(ty;
 | |
|             Variant.0,
 | |
|         ),
 | |
|         vec!["_"],
 | |
|     );
 | |
|     assert_witnesses(
 | |
|         AllOfThem,
 | |
|         ty,
 | |
|         pats!(ty;
 | |
|             Variant.0,
 | |
|         ),
 | |
|         vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"],
 | |
|     );
 | |
| 
 | |
|     // Assert we put `true` before `false`.
 | |
|     assert_witnesses(AllOfThem, Ty::Bool, Vec::new(), vec!["true", "false"]);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn test_empty() {
 | |
|     // `TY = Result<bool, !>`
 | |
|     const TY: Ty = Ty::Enum(&[Ty::Bool, NEVER]);
 | |
|     assert_exhaustive(pats!(TY;
 | |
|         Variant.0,
 | |
|     ));
 | |
|     let ty = Ty::Tuple(&[Ty::Bool, TY]);
 | |
|     assert_exhaustive(pats!(ty;
 | |
|         (true, Variant.0),
 | |
|         (false, Variant.0),
 | |
|     ));
 | |
| }
 |