300
300
//!
301
301
//!
302
302
//!
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
+ //!
303
371
//! # Or-patterns
304
372
//!
305
373
//! What we have described so far works well if there are no or-patterns. To handle them, if the
@@ -669,11 +737,15 @@ impl fmt::Display for ValidityConstraint {
669
737
struct PatStack < ' a , ' p , Cx : TypeCx > {
670
738
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
671
739
pats : SmallVec < [ & ' a DeconstructedPat < ' p , Cx > ; 2 ] > ,
740
+ /// Sometimes we know that as far as this row is concerned, the current case is already handled
741
+ /// by a different, more general, case. When all rows are irrelevant this allows us to skip many
742
+ /// branches. This is purely an optimization. See at the top for details.
743
+ relevant : bool ,
672
744
}
673
745
674
746
impl < ' a , ' p , Cx : TypeCx > PatStack < ' a , ' p , Cx > {
675
747
fn from_pattern ( pat : & ' a DeconstructedPat < ' p , Cx > ) -> Self {
676
- PatStack { pats : smallvec ! [ pat] }
748
+ PatStack { pats : smallvec ! [ pat] , relevant : true }
677
749
}
678
750
679
751
fn is_empty ( & self ) -> bool {
@@ -708,12 +780,17 @@ impl<'a, 'p, Cx: TypeCx> PatStack<'a, 'p, Cx> {
708
780
& self ,
709
781
pcx : & PlaceCtxt < ' a , ' p , Cx > ,
710
782
ctor : & Constructor < Cx > ,
783
+ ctor_is_relevant : bool ,
711
784
) -> PatStack < ' a , ' p , Cx > {
712
785
// We pop the head pattern and push the new fields extracted from the arguments of
713
786
// `self.head()`.
714
787
let mut new_pats = self . head ( ) . specialize ( pcx, ctor) ;
715
788
new_pats. extend_from_slice ( & self . pats [ 1 ..] ) ;
716
- PatStack { pats : new_pats }
789
+ // `ctor` is relevant for this row if it is the actual constructor of this row, or if the
790
+ // row has a wildcard and `ctor` is relevant for wildcards.
791
+ let ctor_is_relevant =
792
+ !matches ! ( self . head( ) . ctor( ) , Constructor :: Wildcard ) || ctor_is_relevant;
793
+ PatStack { pats : new_pats, relevant : self . relevant && ctor_is_relevant }
717
794
}
718
795
}
719
796
@@ -779,10 +856,11 @@ impl<'a, 'p, Cx: TypeCx> MatrixRow<'a, 'p, Cx> {
779
856
& self ,
780
857
pcx : & PlaceCtxt < ' a , ' p , Cx > ,
781
858
ctor : & Constructor < Cx > ,
859
+ ctor_is_relevant : bool ,
782
860
parent_row : usize ,
783
861
) -> MatrixRow < ' a , ' p , Cx > {
784
862
MatrixRow {
785
- pats : self . pats . pop_head_constructor ( pcx, ctor) ,
863
+ pats : self . pats . pop_head_constructor ( pcx, ctor, ctor_is_relevant ) ,
786
864
parent_row,
787
865
is_under_guard : self . is_under_guard ,
788
866
useful : false ,
@@ -897,8 +975,9 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> {
897
975
& self ,
898
976
pcx : & PlaceCtxt < ' a , ' p , Cx > ,
899
977
ctor : & Constructor < Cx > ,
978
+ ctor_is_relevant : bool ,
900
979
) -> Matrix < ' a , ' p , Cx > {
901
- let wildcard_row = self . wildcard_row . pop_head_constructor ( pcx, ctor) ;
980
+ let wildcard_row = self . wildcard_row . pop_head_constructor ( pcx, ctor, ctor_is_relevant ) ;
902
981
let new_validity = self . place_validity [ 0 ] . specialize ( ctor) ;
903
982
let new_place_validity = std:: iter:: repeat ( new_validity)
904
983
. take ( ctor. arity ( pcx) )
@@ -908,7 +987,7 @@ impl<'a, 'p, Cx: TypeCx> Matrix<'a, 'p, Cx> {
908
987
Matrix { rows : Vec :: new ( ) , wildcard_row, place_validity : new_place_validity } ;
909
988
for ( i, row) in self . rows ( ) . enumerate ( ) {
910
989
if ctor. is_covered_by ( pcx, row. head ( ) . ctor ( ) ) {
911
- let new_row = row. pop_head_constructor ( pcx, ctor, i) ;
990
+ let new_row = row. pop_head_constructor ( pcx, ctor, ctor_is_relevant , i) ;
912
991
matrix. expand_and_push ( new_row) ;
913
992
}
914
993
}
@@ -1108,7 +1187,10 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
1108
1187
if matches ! ( ctor, Constructor :: Missing ) {
1109
1188
// We got the special `Missing` constructor that stands for the constructors not present
1110
1189
// in the match.
1111
- if !report_individual_missing_ctors {
1190
+ if missing_ctors. is_empty ( ) {
1191
+ // Nothing to report.
1192
+ * self = Self :: empty ( ) ;
1193
+ } else if !report_individual_missing_ctors {
1112
1194
// Report `_` as missing.
1113
1195
let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: Wildcard ) ;
1114
1196
self . push_pattern ( pat) ;
@@ -1167,6 +1249,15 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1167
1249
) -> WitnessMatrix < Cx > {
1168
1250
debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
1169
1251
1252
+ if !matrix. wildcard_row . relevant && matrix. rows ( ) . all ( |r| !r. pats . relevant ) {
1253
+ // Here we know that nothing will contribute further to exhaustiveness or usefulness. This
1254
+ // is purely an optimization: skipping this check doesn't affect correctness. This check
1255
+ // does change runtime behavior from exponential to quadratic on some matches found in the
1256
+ // wild, so it's pretty important. It also affects which missing patterns will be reported.
1257
+ // See the top of the file for details.
1258
+ return WitnessMatrix :: empty ( ) ;
1259
+ }
1260
+
1170
1261
let Some ( ty) = matrix. head_ty ( mcx) else {
1171
1262
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
1172
1263
// A row is useful iff it has no (unguarded) rows above it.
@@ -1179,8 +1270,14 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1179
1270
return WitnessMatrix :: empty ( ) ;
1180
1271
}
1181
1272
}
1182
- // No (unguarded) rows, so the match is not exhaustive. We return a new witness.
1183
- return WitnessMatrix :: unit_witness ( ) ;
1273
+ // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
1274
+ // irrelevant.
1275
+ return if matrix. wildcard_row . relevant {
1276
+ WitnessMatrix :: unit_witness ( )
1277
+ } else {
1278
+ // We can omit the witness without affecting correctness, so we do.
1279
+ WitnessMatrix :: empty ( )
1280
+ } ;
1184
1281
} ;
1185
1282
1186
1283
debug ! ( "ty: {ty:?}" ) ;
@@ -1223,32 +1320,21 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1223
1320
1224
1321
let mut ret = WitnessMatrix :: empty ( ) ;
1225
1322
for ctor in split_ctors {
1226
- debug ! ( "specialize({:?})" , ctor) ;
1227
1323
// Dig into rows that match `ctor`.
1228
- let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor) ;
1324
+ debug ! ( "specialize({:?})" , ctor) ;
1325
+ // `ctor` is *irrelevant* if there's another constructor in `split_ctors` that matches
1326
+ // strictly fewer rows. In that case we can sometimes skip it. See the top of the file for
1327
+ // details.
1328
+ let ctor_is_relevant = matches ! ( ctor, Constructor :: Missing ) || missing_ctors. is_empty ( ) ;
1329
+ let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor, ctor_is_relevant) ;
1229
1330
let mut witnesses = ensure_sufficient_stack ( || {
1230
1331
compute_exhaustiveness_and_usefulness ( mcx, & mut spec_matrix, false )
1231
1332
} ) ;
1232
1333
1233
- let counts_for_exhaustiveness = match ctor {
1234
- Constructor :: Missing => !missing_ctors. is_empty ( ) ,
1235
- // If there are missing constructors we'll report those instead. Since `Missing` matches
1236
- // only the wildcard rows, it matches fewer rows than this constructor, and is therefore
1237
- // guaranteed to result in the same or more witnesses. So skipping this does not
1238
- // jeopardize correctness.
1239
- _ => missing_ctors. is_empty ( ) ,
1240
- } ;
1241
- if counts_for_exhaustiveness {
1242
- // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1243
- witnesses. apply_constructor (
1244
- pcx,
1245
- & missing_ctors,
1246
- & ctor,
1247
- report_individual_missing_ctors,
1248
- ) ;
1249
- // Accumulate the found witnesses.
1250
- ret. extend ( witnesses) ;
1251
- }
1334
+ // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1335
+ witnesses. apply_constructor ( pcx, & missing_ctors, & ctor, report_individual_missing_ctors) ;
1336
+ // Accumulate the found witnesses.
1337
+ ret. extend ( witnesses) ;
1252
1338
1253
1339
// A parent row is useful if any of its children is.
1254
1340
for child_row in spec_matrix. rows ( ) {
0 commit comments