181
181
//! we ignore all the patterns in the first column of `P` that involve other constructors.
182
182
//! This is where `S(c, P)` comes in:
183
183
//! `U(P, p) := U(S(c, P), S(c, p))`
184
- //! This special case is handled in `is_useful_specialized`.
185
184
//!
186
185
//! For example, if `P` is:
187
186
//!
@@ -1116,8 +1115,8 @@ impl<'tcx> Constructor<'tcx> {
1116
1115
}
1117
1116
}
1118
1117
1119
- /// Some constructors (namely IntRange and Slice) actually stand for a set of actual
1120
- /// constructors (integers and fixed-sized slices). When specializing for these
1118
+ /// Some constructors (namely Wildcard, IntRange and Slice) actually stand for a set of actual
1119
+ /// constructors (like variants, integers or fixed-sized slices). When specializing for these
1121
1120
/// constructors, we want to be specialising for the actual underlying constructors.
1122
1121
/// Naively, we would simply return the list of constructors they correspond to. We instead are
1123
1122
/// more clever: if there are constructors that we know will behave the same wrt the current
@@ -1136,6 +1135,7 @@ impl<'tcx> Constructor<'tcx> {
1136
1135
debug ! ( "Constructor::split({:#?}, {:#?})" , self , pcx. matrix) ;
1137
1136
1138
1137
match self {
1138
+ Wildcard => Constructor :: split_wildcard ( pcx) ,
1139
1139
// Fast-track if the range is trivial. In particular, we don't do the overlapping
1140
1140
// ranges check.
1141
1141
IntRange ( ctor_range)
@@ -1149,6 +1149,30 @@ impl<'tcx> Constructor<'tcx> {
1149
1149
}
1150
1150
}
1151
1151
1152
+ /// For wildcards, there are two groups of constructors: there are the constructors actually
1153
+ /// present in the matrix (`head_ctors`), and the constructors not present (`missing_ctors`).
1154
+ /// Two constructors that are not in the matrix will either both be catched (by a wildcard), or
1155
+ /// both not be catched. Therefore we can keep the missing constructors grouped together.
1156
+ fn split_wildcard < ' p > ( pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> SmallVec < [ Self ; 1 ] > {
1157
+ // Missing constructors are those that are not matched by any non-wildcard patterns in the
1158
+ // current column. We only fully construct them on-demand, because they're rarely used and
1159
+ // can be big.
1160
+ let missing_ctors = MissingConstructors :: new ( pcx) ;
1161
+
1162
+ if missing_ctors. is_empty ( ) {
1163
+ // All the constructors are present in the matrix, so we just go through them all.
1164
+ // We must also split them first.
1165
+ // Since `all_ctors` never contains wildcards, this won't recurse more than once.
1166
+ let ( all_ctors, _) = missing_ctors. into_inner ( ) ;
1167
+ all_ctors. into_iter ( ) . flat_map ( |ctor| ctor. split ( pcx, None ) ) . collect ( )
1168
+ } else {
1169
+ // Some constructors are missing, thus we can specialize with the wildcard constructor,
1170
+ // which will stand for those constructors that are missing, and behaves like any of
1171
+ // them.
1172
+ smallvec ! [ Wildcard ]
1173
+ }
1174
+ }
1175
+
1152
1176
/// Returns whether `self` is covered by `other`, ie whether `self` is a subset of `other`. For
1153
1177
/// the simple cases, this is simply checking for equality. For the "grouped" constructors,
1154
1178
/// this checks for inclusion.
@@ -1617,8 +1641,8 @@ impl<'tcx> Usefulness<'tcx> {
1617
1641
match self {
1618
1642
UsefulWithWitness ( witnesses) => {
1619
1643
let new_witnesses = if ctor. is_wildcard ( ) {
1620
- let missing_ctors = MissingConstructors :: new ( pcx, is_top_level ) ;
1621
- let new_patterns = missing_ctors. report_patterns ( pcx) ;
1644
+ let missing_ctors = MissingConstructors :: new ( pcx) ;
1645
+ let new_patterns = missing_ctors. report_patterns ( pcx, is_top_level ) ;
1622
1646
witnesses
1623
1647
. into_iter ( )
1624
1648
. flat_map ( |witness| {
@@ -2217,16 +2241,15 @@ impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
2217
2241
struct MissingConstructors < ' tcx > {
2218
2242
all_ctors : Vec < Constructor < ' tcx > > ,
2219
2243
used_ctors : Vec < Constructor < ' tcx > > ,
2220
- is_top_level : bool ,
2221
2244
}
2222
2245
2223
2246
impl < ' tcx > MissingConstructors < ' tcx > {
2224
- fn new < ' p > ( pcx : PatCtxt < ' _ , ' p , ' tcx > , is_top_level : bool ) -> Self {
2247
+ fn new < ' p > ( pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> Self {
2225
2248
let used_ctors: Vec < Constructor < ' _ > > =
2226
2249
pcx. matrix . head_ctors ( pcx. cx ) . cloned ( ) . filter ( |c| !c. is_wildcard ( ) ) . collect ( ) ;
2227
2250
let all_ctors = all_constructors ( pcx) ;
2228
2251
2229
- MissingConstructors { all_ctors, used_ctors, is_top_level }
2252
+ MissingConstructors { all_ctors, used_ctors }
2230
2253
}
2231
2254
2232
2255
fn into_inner ( self ) -> ( Vec < Constructor < ' tcx > > , Vec < Constructor < ' tcx > > ) {
@@ -2244,7 +2267,11 @@ impl<'tcx> MissingConstructors<'tcx> {
2244
2267
2245
2268
/// List the patterns corresponding to the missing constructors. In some cases, instead of
2246
2269
/// listing all constructors of a given type, we prefer to simply report a wildcard.
2247
- fn report_patterns < ' p > ( & self , pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
2270
+ fn report_patterns < ' p > (
2271
+ & self ,
2272
+ pcx : PatCtxt < ' _ , ' p , ' tcx > ,
2273
+ is_top_level : bool ,
2274
+ ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
2248
2275
// There are 2 ways we can report a witness here.
2249
2276
// Commonly, we can report all the "free"
2250
2277
// constructors as witnesses, e.g., if we have:
@@ -2272,7 +2299,7 @@ impl<'tcx> MissingConstructors<'tcx> {
2272
2299
// `used_ctors` is empty.
2273
2300
// The exception is: if we are at the top-level, for example in an empty match, we
2274
2301
// sometimes prefer reporting the list of constructors instead of just `_`.
2275
- let report_when_all_missing = self . is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
2302
+ let report_when_all_missing = is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
2276
2303
if self . used_ctors . is_empty ( ) && !report_when_all_missing {
2277
2304
// All constructors are unused. Report only a wildcard
2278
2305
// rather than each individual constructor.
@@ -2407,103 +2434,26 @@ crate fn is_useful<'p, 'tcx>(
2407
2434
2408
2435
debug ! ( "is_useful_expand_first_col: ty={:#?}, expanding {:#?}" , pcx. ty, v. head( ) ) ;
2409
2436
2410
- let constructor = v. head_ctor ( cx) ;
2411
- let ret = if !constructor. is_wildcard ( ) {
2412
- debug ! ( "is_useful - expanding constructor: {:#?}" , constructor) ;
2413
- constructor
2414
- . split ( pcx, Some ( hir_id) )
2415
- . into_iter ( )
2416
- . map ( |c| {
2417
- is_useful_specialized (
2418
- pcx,
2419
- v,
2420
- & c,
2421
- witness_preference,
2422
- hir_id,
2423
- is_under_guard,
2424
- is_top_level,
2425
- )
2426
- } )
2427
- . find ( |result| result. is_useful ( ) )
2428
- . unwrap_or ( NotUseful )
2429
- } else {
2430
- debug ! ( "is_useful - expanding wildcard" ) ;
2431
-
2432
- // `missing_ctors` is the set of constructors from the same type as the
2433
- // first column of `matrix` that are matched only by wildcard patterns
2434
- // from the first column.
2435
- //
2436
- // Therefore, if there is some pattern that is unmatched by `matrix`,
2437
- // it will still be unmatched if the first constructor is replaced by
2438
- // any of the constructors in `missing_ctors`
2439
-
2440
- // Missing constructors are those that are not matched by any non-wildcard patterns in the
2441
- // current column. We only fully construct them on-demand, because they're rarely used and
2442
- // can be big.
2443
- let missing_ctors = MissingConstructors :: new ( pcx, is_top_level) ;
2444
-
2445
- debug ! ( "is_useful_missing_ctors.empty()={:#?}" , missing_ctors. is_empty( ) , ) ;
2446
-
2447
- if missing_ctors. is_empty ( ) {
2448
- let ( all_ctors, _) = missing_ctors. into_inner ( ) ;
2449
- all_ctors
2450
- . into_iter ( )
2451
- . flat_map ( |ctor| ctor. split ( pcx, None ) )
2452
- . map ( |c| {
2453
- is_useful_specialized (
2454
- pcx,
2455
- v,
2456
- & c,
2457
- witness_preference,
2458
- hir_id,
2459
- is_under_guard,
2460
- is_top_level,
2461
- )
2462
- } )
2463
- . find ( |result| result. is_useful ( ) )
2464
- . unwrap_or ( NotUseful )
2465
- } else {
2466
- // Some constructors are missing, thus we can specialize with the wildcard constructor,
2467
- // which will stand for those constructors that are missing, and behaves like any of
2468
- // them.
2469
- is_useful_specialized (
2470
- pcx,
2471
- v,
2472
- constructor,
2473
- witness_preference,
2474
- hir_id,
2475
- is_under_guard,
2476
- is_top_level,
2477
- )
2478
- }
2479
- } ;
2437
+ let ret = v
2438
+ . head_ctor ( cx)
2439
+ . split ( pcx, Some ( hir_id) )
2440
+ . into_iter ( )
2441
+ . map ( |ctor| {
2442
+ // We cache the result of `Fields::wildcards` because it is used a lot.
2443
+ let ctor_wild_subpatterns = Fields :: wildcards ( pcx, & ctor) ;
2444
+ let matrix = pcx. matrix . specialize_constructor ( pcx, & ctor, & ctor_wild_subpatterns) ;
2445
+ // Unwrap is ok: v can always be specialized with its own constructor.
2446
+ let v = v. specialize_constructor ( pcx, & ctor, & ctor_wild_subpatterns, true ) . unwrap ( ) ;
2447
+ let usefulness =
2448
+ is_useful ( pcx. cx , & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
2449
+ usefulness. apply_constructor ( pcx, & ctor, & ctor_wild_subpatterns, is_top_level)
2450
+ } )
2451
+ . find ( |result| result. is_useful ( ) )
2452
+ . unwrap_or ( NotUseful ) ;
2480
2453
debug ! ( "is_useful::returns({:#?}, {:#?}) = {:?}" , matrix, v, ret) ;
2481
2454
ret
2482
2455
}
2483
2456
2484
- /// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
2485
- /// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
2486
- fn is_useful_specialized < ' p , ' tcx > (
2487
- pcx : PatCtxt < ' _ , ' p , ' tcx > ,
2488
- v : & PatStack < ' p , ' tcx > ,
2489
- ctor : & Constructor < ' tcx > ,
2490
- witness_preference : WitnessPreference ,
2491
- hir_id : HirId ,
2492
- is_under_guard : bool ,
2493
- is_top_level : bool ,
2494
- ) -> Usefulness < ' tcx > {
2495
- debug ! ( "is_useful_specialized({:#?}, {:#?}, {:?})" , v, ctor, pcx. ty) ;
2496
-
2497
- // We cache the result of `Fields::wildcards` because it is used a lot.
2498
- let ctor_wild_subpatterns = Fields :: wildcards ( pcx, ctor) ;
2499
- let matrix = pcx. matrix . specialize_constructor ( pcx, ctor, & ctor_wild_subpatterns) ;
2500
- // Unwrap is ok: v can always be specialized with its own constructor.
2501
- let v = v. specialize_constructor ( pcx, ctor, & ctor_wild_subpatterns, true ) . unwrap ( ) ;
2502
- let usefulness =
2503
- is_useful ( pcx. cx , & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
2504
- usefulness. apply_constructor ( pcx, ctor, & ctor_wild_subpatterns, is_top_level)
2505
- }
2506
-
2507
2457
/// Determines the constructor that the given pattern can be specialized to.
2508
2458
/// Returns `None` in case of a catch-all, which can't be specialized.
2509
2459
fn pat_constructor < ' p , ' tcx > (
0 commit comments