300300//!
301301//!
302302//!
303+ //! # `Missing` and relevant constructors
304+ //!
305+ //! Take the following example:
306+ //!
307+ //! ```compile_fail,E0004
308+ //! enum Direction { North, South, East, West }
309+ //! # let wind = (Direction::North, 0u8);
310+ //! match wind {
311+ //! (Direction::North, _) => {} // arm 1
312+ //! (_, 50..) => {} // arm 2
313+ //! }
314+ //! ```
315+ //!
316+ //! Remember that we represent the "everything else" cases with [`Constructor::Missing`]. When we
317+ //! specialize with `Missing` in the first column, we have one arm left:
318+ //!
319+ //! ```ignore(partial code)
320+ //! (50..) => {} // arm 2
321+ //! ```
322+ //!
323+ //! We then conclude that arm 2 is useful, and that the match is non-exhaustive with witness
324+ //! `(Missing, 0..50)` (which we would display to the user as `(_, 0..50)`).
325+ //!
326+ //! When we then specialize with `North`, we have two arms left:
327+ //!
328+ //! ```ignore(partial code)
329+ //! (_) => {} // arm 1
330+ //! (50..) => {} // arm 2
331+ //! ```
332+ //!
333+ //! Because `Missing` only matches wildcard rows, specializing with `Missing` is guaranteed to
334+ //! result in a subset of the rows obtained from specializing with anything else. This means that
335+ //! any row with a wildcard found useful when specializing with anything else would also be found
336+ //! useful in the `Missing` case. In our example, after specializing with `North` here we will not
337+ //! gain new information regarding the usefulness of arm 2 or of the fake wildcard row used for
338+ //! exhaustiveness. This allows us to skip cases.
339+ //!
340+ //! When specializing, if there is a `Missing` case we call the other constructors "irrelevant".
341+ //! When there is no `Missing` case there are no irrelevant constructors.
342+ //!
343+ //! What happens then is: when we specialize a wildcard with an irrelevant constructor, we know we
344+ //! won't get new info for this row; we consider that row "irrelevant". Whenever all the rows are
345+ //! found irrelevant, we can safely skip the case entirely.
346+ //!
347+ //! In the example above, we will entirely skip the `(North, 50..)` case. This skipping was
348+ //! developped as a solution to #118437. It doesn't look like much but it can save us from
349+ //! exponential blowup.
350+ //!
351+ //! There's a subtlety regarding exhaustiveness: while this shortcutting doesn't affect correctness,
352+ //! it can affect which witnesses are reported. For example, in the following:
353+ //!
354+ //! ```compile_fail,E0004
355+ //! # let foo = (true, true, true);
356+ //! match foo {
357+ //! (true, _, true) => {}
358+ //! (_, true, _) => {}
359+ //! }
360+ //! ```
361+ //!
362+ //! In this example we will skip the `(true, true, _)` case entirely. Thus `(true, true, false)`
363+ //! will not be reported as missing. In fact we go further than this: we deliberately do not report
364+ //! any cases that are irrelevant for the fake wildcard row. For example, in `match ... { (true,
365+ //! true) => {} }` we will not report `(true, false)` as missing. This was a deliberate choice made
366+ //! early in the development of rust; it so happens that it is beneficial for performance reasons
367+ //! too.
368+ //!
369+ //!
370+ //!
303371//! # Or-patterns
304372//!
305373//! What we have described so far works well if there are no or-patterns. To handle them, if the
@@ -658,11 +726,15 @@ impl fmt::Display for ValidityConstraint {
658726struct PatStack < ' p , ' tcx > {
659727 // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
660728 pats : SmallVec < [ & ' p DeconstructedPat < ' p , ' tcx > ; 2 ] > ,
729+ /// Sometimes we know that as far as this row is concerned, the current case is already handled
730+ /// by a different, more general, case. When all rows are irrelevant this allows us to skip many
731+ /// branches. This is purely an optimization. See at the top for details.
732+ relevant : bool ,
661733}
662734
663735impl < ' p , ' tcx > PatStack < ' p , ' tcx > {
664736 fn from_pattern ( pat : & ' p DeconstructedPat < ' p , ' tcx > ) -> Self {
665- PatStack { pats : smallvec ! [ pat] }
737+ PatStack { pats : smallvec ! [ pat] , relevant : true }
666738 }
667739
668740 fn is_empty ( & self ) -> bool {
@@ -697,12 +769,17 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
697769 & self ,
698770 pcx : & PatCtxt < ' _ , ' p , ' tcx > ,
699771 ctor : & Constructor < ' tcx > ,
772+ ctor_is_relevant : bool ,
700773 ) -> PatStack < ' p , ' tcx > {
701774 // We pop the head pattern and push the new fields extracted from the arguments of
702775 // `self.head()`.
703776 let mut new_pats = self . head ( ) . specialize ( pcx, ctor) ;
704777 new_pats. extend_from_slice ( & self . pats [ 1 ..] ) ;
705- PatStack { pats : new_pats }
778+ // `ctor` is relevant for this row if it is the actual constructor of this row, or if the
779+ // row has a wildcard and `ctor` is relevant for wildcards.
780+ let ctor_is_relevant =
781+ !matches ! ( self . head( ) . ctor( ) , Constructor :: Wildcard ) || ctor_is_relevant;
782+ PatStack { pats : new_pats, relevant : self . relevant && ctor_is_relevant }
706783 }
707784}
708785
@@ -768,10 +845,11 @@ impl<'p, 'tcx> MatrixRow<'p, 'tcx> {
768845 & self ,
769846 pcx : & PatCtxt < ' _ , ' p , ' tcx > ,
770847 ctor : & Constructor < ' tcx > ,
848+ ctor_is_relevant : bool ,
771849 parent_row : usize ,
772850 ) -> MatrixRow < ' p , ' tcx > {
773851 MatrixRow {
774- pats : self . pats . pop_head_constructor ( pcx, ctor) ,
852+ pats : self . pats . pop_head_constructor ( pcx, ctor, ctor_is_relevant ) ,
775853 parent_row,
776854 is_under_guard : self . is_under_guard ,
777855 useful : false ,
@@ -900,8 +978,9 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
900978 & self ,
901979 pcx : & PatCtxt < ' _ , ' p , ' tcx > ,
902980 ctor : & Constructor < ' tcx > ,
981+ ctor_is_relevant : bool ,
903982 ) -> Matrix < ' p , ' tcx > {
904- let wildcard_row = self . wildcard_row . pop_head_constructor ( pcx, ctor) ;
983+ let wildcard_row = self . wildcard_row . pop_head_constructor ( pcx, ctor, ctor_is_relevant ) ;
905984 let new_validity = self . place_validity [ 0 ] . specialize ( pcx, ctor) ;
906985 let new_place_validity = std:: iter:: repeat ( new_validity)
907986 . take ( ctor. arity ( pcx) )
@@ -911,7 +990,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
911990 Matrix { rows : Vec :: new ( ) , wildcard_row, place_validity : new_place_validity } ;
912991 for ( i, row) in self . rows ( ) . enumerate ( ) {
913992 if ctor. is_covered_by ( pcx, row. head ( ) . ctor ( ) ) {
914- let new_row = row. pop_head_constructor ( pcx, ctor, i) ;
993+ let new_row = row. pop_head_constructor ( pcx, ctor, ctor_is_relevant , i) ;
915994 matrix. expand_and_push ( new_row) ;
916995 }
917996 }
@@ -1109,7 +1188,10 @@ impl<'tcx> WitnessMatrix<'tcx> {
11091188 if matches ! ( ctor, Constructor :: Missing ) {
11101189 // We got the special `Missing` constructor that stands for the constructors not present
11111190 // in the match.
1112- if !report_individual_missing_ctors {
1191+ if missing_ctors. is_empty ( ) {
1192+ // Nothing to report.
1193+ * self = Self :: empty ( ) ;
1194+ } else if !report_individual_missing_ctors {
11131195 // Report `_` as missing.
11141196 let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: Wildcard ) ;
11151197 self . push_pattern ( pat) ;
@@ -1168,6 +1250,15 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
11681250) -> WitnessMatrix < ' tcx > {
11691251 debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
11701252
1253+ if !matrix. wildcard_row . relevant && matrix. rows ( ) . all ( |r| !r. pats . relevant ) {
1254+ // Here we know that nothing will contribute further to exhaustiveness or usefulness. This
1255+ // is purely an optimization: skipping this check doesn't affect correctness. This check
1256+ // does change runtime behavior from exponential to quadratic on some matches found in the
1257+ // wild, so it's pretty important. It also affects which missing patterns will be reported.
1258+ // See the top of the file for details.
1259+ return WitnessMatrix :: empty ( ) ;
1260+ }
1261+
11711262 let Some ( ty) = matrix. head_ty ( ) else {
11721263 // The base case: there are no columns in the matrix. We are morally pattern-matching on ().
11731264 // A row is useful iff it has no (unguarded) rows above it.
@@ -1180,8 +1271,14 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
11801271 return WitnessMatrix :: empty ( ) ;
11811272 }
11821273 }
1183- // No (unguarded) rows, so the match is not exhaustive. We return a new witness.
1184- return WitnessMatrix :: unit_witness ( ) ;
1274+ // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
1275+ // irrelevant.
1276+ return if matrix. wildcard_row . relevant {
1277+ WitnessMatrix :: unit_witness ( )
1278+ } else {
1279+ // We can omit the witness without affecting correctness, so we do.
1280+ WitnessMatrix :: empty ( )
1281+ } ;
11851282 } ;
11861283
11871284 debug ! ( "ty: {ty:?}" ) ;
@@ -1224,32 +1321,21 @@ fn compute_exhaustiveness_and_usefulness<'p, 'tcx>(
12241321
12251322 let mut ret = WitnessMatrix :: empty ( ) ;
12261323 for ctor in split_ctors {
1227- debug ! ( "specialize({:?})" , ctor) ;
12281324 // Dig into rows that match `ctor`.
1229- let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor) ;
1325+ debug ! ( "specialize({:?})" , ctor) ;
1326+ // `ctor` is *irrelevant* if there's another constructor in `split_ctors` that matches
1327+ // strictly fewer rows. In that case we can sometimes skip it. See the top of the file for
1328+ // details.
1329+ let ctor_is_relevant = matches ! ( ctor, Constructor :: Missing ) || missing_ctors. is_empty ( ) ;
1330+ let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor, ctor_is_relevant) ;
12301331 let mut witnesses = ensure_sufficient_stack ( || {
12311332 compute_exhaustiveness_and_usefulness ( cx, & mut spec_matrix, false )
12321333 } ) ;
12331334
1234- let counts_for_exhaustiveness = match ctor {
1235- Constructor :: Missing => !missing_ctors. is_empty ( ) ,
1236- // If there are missing constructors we'll report those instead. Since `Missing` matches
1237- // only the wildcard rows, it matches fewer rows than this constructor, and is therefore
1238- // guaranteed to result in the same or more witnesses. So skipping this does not
1239- // jeopardize correctness.
1240- _ => missing_ctors. is_empty ( ) ,
1241- } ;
1242- if counts_for_exhaustiveness {
1243- // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1244- witnesses. apply_constructor (
1245- pcx,
1246- & missing_ctors,
1247- & ctor,
1248- report_individual_missing_ctors,
1249- ) ;
1250- // Accumulate the found witnesses.
1251- ret. extend ( witnesses) ;
1252- }
1335+ // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1336+ witnesses. apply_constructor ( pcx, & missing_ctors, & ctor, report_individual_missing_ctors) ;
1337+ // Accumulate the found witnesses.
1338+ ret. extend ( witnesses) ;
12531339
12541340 // A parent row is useful if any of its children is.
12551341 for child_row in spec_matrix. rows ( ) {
0 commit comments