@@ -364,14 +364,14 @@ impl<'tcx> Pat<'tcx> {
364364/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
365365/// works well.
366366#[ derive( Debug , Clone ) ]
367- crate struct PatStack < ' p , ' tcx > {
367+ struct PatStack < ' p , ' tcx > {
368368 pats : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ,
369369 /// Cache for the constructor of the head
370370 head_ctor : OnceCell < Constructor < ' tcx > > ,
371371}
372372
373373impl < ' p , ' tcx > PatStack < ' p , ' tcx > {
374- crate fn from_pattern ( pat : & ' p Pat < ' tcx > ) -> Self {
374+ fn from_pattern ( pat : & ' p Pat < ' tcx > ) -> Self {
375375 Self :: from_vec ( smallvec ! [ pat] )
376376 }
377377
@@ -455,17 +455,17 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
455455
456456/// A 2D matrix.
457457#[ derive( Clone , PartialEq ) ]
458- crate struct Matrix < ' p , ' tcx > {
458+ struct Matrix < ' p , ' tcx > {
459459 patterns : Vec < PatStack < ' p , ' tcx > > ,
460460}
461461
462462impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
463- crate fn empty ( ) -> Self {
463+ fn empty ( ) -> Self {
464464 Matrix { patterns : vec ! [ ] }
465465 }
466466
467467 /// 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 > ) {
469469 if let Some ( rows) = row. expand_or_pat ( ) {
470470 for row in rows {
471471 // We recursively expand the or-patterns of the new rows.
@@ -588,7 +588,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
588588 }
589589
590590 /// 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 {
592592 match ty. kind ( ) {
593593 ty:: Adt ( def, ..) => {
594594 def. is_enum ( ) && def. is_variant_list_non_exhaustive ( ) && !def. did . is_local ( )
@@ -1392,13 +1392,12 @@ impl<'tcx> Usefulness<'tcx> {
13921392 pcx : PatCtxt < ' _ , ' p , ' tcx > ,
13931393 ctor : & Constructor < ' tcx > ,
13941394 ctor_wild_subpatterns : & Fields < ' p , ' tcx > ,
1395- is_top_level : bool ,
13961395 ) -> Self {
13971396 match self {
13981397 UsefulWithWitness ( witnesses) => {
13991398 let new_witnesses = if ctor. is_wildcard ( ) {
14001399 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) ;
14021401 witnesses
14031402 . into_iter ( )
14041403 . flat_map ( |witness| {
@@ -1440,7 +1439,7 @@ impl<'tcx> Usefulness<'tcx> {
14401439}
14411440
14421441#[ derive( Copy , Clone , Debug ) ]
1443- crate enum WitnessPreference {
1442+ enum WitnessPreference {
14441443 ConstructWitness ,
14451444 LeaveOutWitness ,
14461445}
@@ -1454,6 +1453,9 @@ struct PatCtxt<'a, 'p, 'tcx> {
14541453 ty : Ty < ' tcx > ,
14551454 /// Span of the current pattern under investigation.
14561455 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 ,
14571459}
14581460
14591461/// A witness of non-exhaustiveness for error reporting, represented
@@ -1493,7 +1495,8 @@ struct PatCtxt<'a, 'p, 'tcx> {
14931495crate struct Witness < ' tcx > ( Vec < Pat < ' tcx > > ) ;
14941496
14951497impl < ' 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 > {
14971500 assert_eq ! ( self . 0 . len( ) , 1 ) ;
14981501 self . 0 . into_iter ( ) . next ( ) . unwrap ( )
14991502 }
@@ -1585,11 +1588,12 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
15851588 let is_declared_nonexhaustive = cx. is_foreign_non_exhaustive_enum ( pcx. ty ) ;
15861589
15871590 // 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 ;
15931597
15941598 if is_secretly_empty || is_declared_nonexhaustive {
15951599 vec ! [ NonExhaustive ]
@@ -1635,6 +1639,13 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
16351639 let max = size. truncate ( u128:: MAX ) ;
16361640 vec ! [ make_range( 0 , max) ]
16371641 }
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 ! [ ] ,
16381649 _ if cx. is_uninhabited ( pcx. ty ) => vec ! [ ] ,
16391650 ty:: Adt ( ..) | ty:: Tuple ( ..) | ty:: Ref ( ..) => vec ! [ Single ] ,
16401651 // This type is one for which we cannot list constructors, like `str` or `f64`.
@@ -2012,11 +2023,7 @@ impl<'tcx> MissingConstructors<'tcx> {
20122023
20132024 /// List the patterns corresponding to the missing constructors. In some cases, instead of
20142025 /// 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 ] > {
20202027 // There are 2 ways we can report a witness here.
20212028 // Commonly, we can report all the "free"
20222029 // constructors as witnesses, e.g., if we have:
@@ -2044,7 +2051,7 @@ impl<'tcx> MissingConstructors<'tcx> {
20442051 // `used_ctors` is empty.
20452052 // The exception is: if we are at the top-level, for example in an empty match, we
20462053 // 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 ) ;
20482055 if self . used_ctors . is_empty ( ) && !report_when_all_missing {
20492056 // All constructors are unused. Report only a wildcard
20502057 // rather than each individual constructor.
@@ -2086,7 +2093,7 @@ impl<'tcx> MissingConstructors<'tcx> {
20862093/// `is_under_guard` is used to inform if the pattern has a guard. If it
20872094/// has one it must not be inserted into the matrix. This shouldn't be
20882095/// relied on for soundness.
2089- crate fn is_useful < ' p , ' tcx > (
2096+ fn is_useful < ' p , ' tcx > (
20902097 cx : & MatchCheckCtxt < ' p , ' tcx > ,
20912098 matrix : & Matrix < ' p , ' tcx > ,
20922099 v : & PatStack < ' p , ' tcx > ,
@@ -2200,7 +2207,7 @@ crate fn is_useful<'p, 'tcx>(
22002207
22012208 // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
22022209 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 } ;
22042211
22052212 debug ! ( "is_useful_expand_first_col: ty={:#?}, expanding {:#?}" , pcx. ty, v. head( ) ) ;
22062213
@@ -2215,7 +2222,7 @@ crate fn is_useful<'p, 'tcx>(
22152222 let v = v. pop_head_constructor ( & ctor_wild_subpatterns) ;
22162223 let usefulness =
22172224 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)
22192226 } )
22202227 . find ( |result| result. is_useful ( ) )
22212228 . unwrap_or ( NotUseful ) ;
@@ -2283,3 +2290,63 @@ fn pat_constructor<'p, 'tcx>(
22832290 PatKind :: Or { .. } => bug ! ( "Or-pattern should have been expanded earlier on." ) ,
22842291 }
22852292}
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