@@ -364,14 +364,14 @@ impl<'tcx> Pat<'tcx> {
364
364
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
365
365
/// works well.
366
366
#[ derive( Debug , Clone ) ]
367
- crate struct PatStack < ' p , ' tcx > {
367
+ struct PatStack < ' p , ' tcx > {
368
368
pats : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ,
369
369
/// Cache for the constructor of the head
370
370
head_ctor : OnceCell < Constructor < ' tcx > > ,
371
371
}
372
372
373
373
impl < ' p , ' tcx > PatStack < ' p , ' tcx > {
374
- crate fn from_pattern ( pat : & ' p Pat < ' tcx > ) -> Self {
374
+ fn from_pattern ( pat : & ' p Pat < ' tcx > ) -> Self {
375
375
Self :: from_vec ( smallvec ! [ pat] )
376
376
}
377
377
@@ -455,17 +455,17 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
455
455
456
456
/// A 2D matrix.
457
457
#[ derive( Clone , PartialEq ) ]
458
- crate struct Matrix < ' p , ' tcx > {
458
+ struct Matrix < ' p , ' tcx > {
459
459
patterns : Vec < PatStack < ' p , ' tcx > > ,
460
460
}
461
461
462
462
impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
463
- crate fn empty ( ) -> Self {
463
+ fn empty ( ) -> Self {
464
464
Matrix { patterns : vec ! [ ] }
465
465
}
466
466
467
467
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
468
- crate fn push ( & mut self , row : PatStack < ' p , ' tcx > ) {
468
+ fn push ( & mut self , row : PatStack < ' p , ' tcx > ) {
469
469
if let Some ( rows) = row. expand_or_pat ( ) {
470
470
for row in rows {
471
471
// We recursively expand the or-patterns of the new rows.
@@ -588,7 +588,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
588
588
}
589
589
590
590
/// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
591
- crate fn is_foreign_non_exhaustive_enum ( & self , ty : Ty < ' tcx > ) -> bool {
591
+ fn is_foreign_non_exhaustive_enum ( & self , ty : Ty < ' tcx > ) -> bool {
592
592
match ty. kind ( ) {
593
593
ty:: Adt ( def, ..) => {
594
594
def. is_enum ( ) && def. is_variant_list_non_exhaustive ( ) && !def. did . is_local ( )
@@ -1392,13 +1392,12 @@ impl<'tcx> Usefulness<'tcx> {
1392
1392
pcx : PatCtxt < ' _ , ' p , ' tcx > ,
1393
1393
ctor : & Constructor < ' tcx > ,
1394
1394
ctor_wild_subpatterns : & Fields < ' p , ' tcx > ,
1395
- is_top_level : bool ,
1396
1395
) -> Self {
1397
1396
match self {
1398
1397
UsefulWithWitness ( witnesses) => {
1399
1398
let new_witnesses = if ctor. is_wildcard ( ) {
1400
1399
let missing_ctors = MissingConstructors :: new ( pcx) ;
1401
- let new_patterns = missing_ctors. report_patterns ( pcx, is_top_level ) ;
1400
+ let new_patterns = missing_ctors. report_patterns ( pcx) ;
1402
1401
witnesses
1403
1402
. into_iter ( )
1404
1403
. flat_map ( |witness| {
@@ -1440,7 +1439,7 @@ impl<'tcx> Usefulness<'tcx> {
1440
1439
}
1441
1440
1442
1441
#[ derive( Copy , Clone , Debug ) ]
1443
- crate enum WitnessPreference {
1442
+ enum WitnessPreference {
1444
1443
ConstructWitness ,
1445
1444
LeaveOutWitness ,
1446
1445
}
@@ -1454,6 +1453,9 @@ struct PatCtxt<'a, 'p, 'tcx> {
1454
1453
ty : Ty < ' tcx > ,
1455
1454
/// Span of the current pattern under investigation.
1456
1455
span : Span ,
1456
+ /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
1457
+ /// subpattern.
1458
+ is_top_level : bool ,
1457
1459
}
1458
1460
1459
1461
/// A witness of non-exhaustiveness for error reporting, represented
@@ -1493,7 +1495,8 @@ struct PatCtxt<'a, 'p, 'tcx> {
1493
1495
crate struct Witness < ' tcx > ( Vec < Pat < ' tcx > > ) ;
1494
1496
1495
1497
impl < ' tcx > Witness < ' tcx > {
1496
- crate fn single_pattern ( self ) -> Pat < ' tcx > {
1498
+ /// Asserts that the witness contains a single pattern, and returns it.
1499
+ fn single_pattern ( self ) -> Pat < ' tcx > {
1497
1500
assert_eq ! ( self . 0 . len( ) , 1 ) ;
1498
1501
self . 0 . into_iter ( ) . next ( ) . unwrap ( )
1499
1502
}
@@ -1585,11 +1588,12 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
1585
1588
let is_declared_nonexhaustive = cx. is_foreign_non_exhaustive_enum ( pcx. ty ) ;
1586
1589
1587
1590
// If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
1588
- // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
1589
- // an empty match will still be considered exhaustive because that case is handled
1590
- // separately in `check_match`.
1591
- let is_secretly_empty =
1592
- def. variants . is_empty ( ) && !cx. tcx . features ( ) . exhaustive_patterns ;
1591
+ // as though it had an "unknown" constructor to avoid exposing its emptiness. The
1592
+ // exception is if the pattern is at the top level, because we want empty matches to be
1593
+ // considered exhaustive.
1594
+ let is_secretly_empty = def. variants . is_empty ( )
1595
+ && !cx. tcx . features ( ) . exhaustive_patterns
1596
+ && !pcx. is_top_level ;
1593
1597
1594
1598
if is_secretly_empty || is_declared_nonexhaustive {
1595
1599
vec ! [ NonExhaustive ]
@@ -1635,6 +1639,13 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
1635
1639
let max = size. truncate ( u128:: MAX ) ;
1636
1640
vec ! [ make_range( 0 , max) ]
1637
1641
}
1642
+ // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
1643
+ // expose its emptiness. The exception is if the pattern is at the top level, because we
1644
+ // want empty matches to be considered exhaustive.
1645
+ ty:: Never if !cx. tcx . features ( ) . exhaustive_patterns && !pcx. is_top_level => {
1646
+ vec ! [ NonExhaustive ]
1647
+ }
1648
+ ty:: Never => vec ! [ ] ,
1638
1649
_ if cx. is_uninhabited ( pcx. ty ) => vec ! [ ] ,
1639
1650
ty:: Adt ( ..) | ty:: Tuple ( ..) | ty:: Ref ( ..) => vec ! [ Single ] ,
1640
1651
// This type is one for which we cannot list constructors, like `str` or `f64`.
@@ -2012,11 +2023,7 @@ impl<'tcx> MissingConstructors<'tcx> {
2012
2023
2013
2024
/// List the patterns corresponding to the missing constructors. In some cases, instead of
2014
2025
/// listing all constructors of a given type, we prefer to simply report a wildcard.
2015
- fn report_patterns < ' p > (
2016
- & self ,
2017
- pcx : PatCtxt < ' _ , ' p , ' tcx > ,
2018
- is_top_level : bool ,
2019
- ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
2026
+ fn report_patterns < ' p > ( & self , pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
2020
2027
// There are 2 ways we can report a witness here.
2021
2028
// Commonly, we can report all the "free"
2022
2029
// constructors as witnesses, e.g., if we have:
@@ -2044,7 +2051,7 @@ impl<'tcx> MissingConstructors<'tcx> {
2044
2051
// `used_ctors` is empty.
2045
2052
// The exception is: if we are at the top-level, for example in an empty match, we
2046
2053
// sometimes prefer reporting the list of constructors instead of just `_`.
2047
- let report_when_all_missing = is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
2054
+ let report_when_all_missing = pcx . is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
2048
2055
if self . used_ctors . is_empty ( ) && !report_when_all_missing {
2049
2056
// All constructors are unused. Report only a wildcard
2050
2057
// rather than each individual constructor.
@@ -2086,7 +2093,7 @@ impl<'tcx> MissingConstructors<'tcx> {
2086
2093
/// `is_under_guard` is used to inform if the pattern has a guard. If it
2087
2094
/// has one it must not be inserted into the matrix. This shouldn't be
2088
2095
/// relied on for soundness.
2089
- crate fn is_useful < ' p , ' tcx > (
2096
+ fn is_useful < ' p , ' tcx > (
2090
2097
cx : & MatchCheckCtxt < ' p , ' tcx > ,
2091
2098
matrix : & Matrix < ' p , ' tcx > ,
2092
2099
v : & PatStack < ' p , ' tcx > ,
@@ -2200,7 +2207,7 @@ crate fn is_useful<'p, 'tcx>(
2200
2207
2201
2208
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
2202
2209
let ty = matrix. heads ( ) . next ( ) . map ( |r| r. ty ) . unwrap_or ( v. head ( ) . ty ) ;
2203
- let pcx = PatCtxt { cx, matrix, ty, span : v. head ( ) . span } ;
2210
+ let pcx = PatCtxt { cx, matrix, ty, span : v. head ( ) . span , is_top_level } ;
2204
2211
2205
2212
debug ! ( "is_useful_expand_first_col: ty={:#?}, expanding {:#?}" , pcx. ty, v. head( ) ) ;
2206
2213
@@ -2215,7 +2222,7 @@ crate fn is_useful<'p, 'tcx>(
2215
2222
let v = v. pop_head_constructor ( & ctor_wild_subpatterns) ;
2216
2223
let usefulness =
2217
2224
is_useful ( pcx. cx , & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
2218
- usefulness. apply_constructor ( pcx, & ctor, & ctor_wild_subpatterns, is_top_level )
2225
+ usefulness. apply_constructor ( pcx, & ctor, & ctor_wild_subpatterns)
2219
2226
} )
2220
2227
. find ( |result| result. is_useful ( ) )
2221
2228
. unwrap_or ( NotUseful ) ;
@@ -2283,3 +2290,63 @@ fn pat_constructor<'p, 'tcx>(
2283
2290
PatKind :: Or { .. } => bug ! ( "Or-pattern should have been expanded earlier on." ) ,
2284
2291
}
2285
2292
}
2293
+
2294
+ /// The arm of a match expression.
2295
+ #[ derive( Clone , Copy ) ]
2296
+ crate struct MatchArm < ' p , ' tcx > {
2297
+ /// The pattern must have been lowered through `MatchVisitor::lower_pattern`.
2298
+ crate pat : & ' p super :: Pat < ' tcx > ,
2299
+ crate hir_id : HirId ,
2300
+ crate has_guard : bool ,
2301
+ }
2302
+
2303
+ /// The output of checking a match for exhaustiveness and arm reachability.
2304
+ crate struct UsefulnessReport < ' p , ' tcx > {
2305
+ /// For each arm of the input, whether that arm is reachable after the arms above it.
2306
+ crate arm_usefulness : Vec < ( MatchArm < ' p , ' tcx > , Usefulness < ' tcx > ) > ,
2307
+ /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
2308
+ /// exhaustiveness.
2309
+ crate non_exhaustiveness_witnesses : Vec < super :: Pat < ' tcx > > ,
2310
+ }
2311
+
2312
+ /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
2313
+ /// of its arms are reachable.
2314
+ ///
2315
+ /// Note: the input patterns must have been lowered through `MatchVisitor::lower_pattern`.
2316
+ crate fn compute_match_usefulness < ' p , ' tcx > (
2317
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
2318
+ arms : & [ MatchArm < ' p , ' tcx > ] ,
2319
+ scrut_hir_id : HirId ,
2320
+ scrut_ty : Ty < ' tcx > ,
2321
+ ) -> UsefulnessReport < ' p , ' tcx > {
2322
+ let mut matrix = Matrix :: empty ( ) ;
2323
+ let arm_usefulness: Vec < _ > = arms
2324
+ . iter ( )
2325
+ . copied ( )
2326
+ . map ( |arm| {
2327
+ let v = PatStack :: from_pattern ( arm. pat ) ;
2328
+ let usefulness =
2329
+ is_useful ( cx, & matrix, & v, LeaveOutWitness , arm. hir_id , arm. has_guard , true ) ;
2330
+ if !arm. has_guard {
2331
+ matrix. push ( v) ;
2332
+ }
2333
+ ( arm, usefulness)
2334
+ } )
2335
+ . collect ( ) ;
2336
+
2337
+ let wild_pattern = cx. pattern_arena . alloc ( super :: Pat :: wildcard_from_ty ( scrut_ty) ) ;
2338
+ let v = PatStack :: from_pattern ( wild_pattern) ;
2339
+ let usefulness = is_useful ( cx, & matrix, & v, ConstructWitness , scrut_hir_id, false , true ) ;
2340
+ let non_exhaustiveness_witnesses = match usefulness {
2341
+ NotUseful => vec ! [ ] , // Wildcard pattern isn't useful, so the match is exhaustive.
2342
+ UsefulWithWitness ( pats) => {
2343
+ if pats. is_empty ( ) {
2344
+ bug ! ( "Exhaustiveness check returned no witnesses" )
2345
+ } else {
2346
+ pats. into_iter ( ) . map ( |w| w. single_pattern ( ) ) . collect ( )
2347
+ }
2348
+ }
2349
+ Useful ( _) => bug ! ( ) ,
2350
+ } ;
2351
+ UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
2352
+ }
0 commit comments