@@ -295,6 +295,7 @@ use self::WitnessPreference::*;
295
295
296
296
use rustc_data_structures:: captures:: Captures ;
297
297
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
298
+ use rustc_data_structures:: sync:: OnceCell ;
298
299
use rustc_index:: vec:: Idx ;
299
300
300
301
use super :: { compare_const_vals, PatternFoldable , PatternFolder } ;
@@ -346,32 +347,40 @@ impl<'tcx> Pat<'tcx> {
346
347
347
348
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
348
349
/// works well.
349
- #[ derive( Debug , Clone , PartialEq ) ]
350
- crate struct PatStack < ' p , ' tcx > ( SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) ;
350
+ #[ derive( Debug , Clone ) ]
351
+ crate struct PatStack < ' p , ' tcx > {
352
+ pats : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ,
353
+ /// Cache for the constructor of the head
354
+ head_ctor : OnceCell < Constructor < ' tcx > > ,
355
+ }
351
356
352
357
impl < ' p , ' tcx > PatStack < ' p , ' tcx > {
353
358
crate fn from_pattern ( pat : & ' p Pat < ' tcx > ) -> Self {
354
- PatStack ( smallvec ! [ pat] )
359
+ Self :: from_vec ( smallvec ! [ pat] )
355
360
}
356
361
357
362
fn from_vec ( vec : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) -> Self {
358
- PatStack ( vec)
363
+ PatStack { pats : vec, head_ctor : OnceCell :: new ( ) }
359
364
}
360
365
361
366
fn is_empty ( & self ) -> bool {
362
- self . 0 . is_empty ( )
367
+ self . pats . is_empty ( )
363
368
}
364
369
365
370
fn len ( & self ) -> usize {
366
- self . 0 . len ( )
371
+ self . pats . len ( )
367
372
}
368
373
369
374
fn head ( & self ) -> & ' p Pat < ' tcx > {
370
- self . 0 [ 0 ]
375
+ self . pats [ 0 ]
376
+ }
377
+
378
+ fn head_ctor < ' a > ( & ' a self , cx : & MatchCheckCtxt < ' p , ' tcx > ) -> & ' a Constructor < ' tcx > {
379
+ self . head_ctor . get_or_init ( || pat_constructor ( cx, self . head ( ) ) )
371
380
}
372
381
373
382
fn iter ( & self ) -> impl Iterator < Item = & Pat < ' tcx > > {
374
- self . 0 . iter ( ) . copied ( )
383
+ self . pats . iter ( ) . copied ( )
375
384
}
376
385
377
386
// If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
@@ -383,7 +392,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
383
392
pats. iter ( )
384
393
. map ( |pat| {
385
394
let mut new_patstack = PatStack :: from_pattern ( pat) ;
386
- new_patstack. 0 . extend_from_slice ( & self . 0 [ 1 ..] ) ;
395
+ new_patstack. pats . extend_from_slice ( & self . pats [ 1 ..] ) ;
387
396
new_patstack
388
397
} )
389
398
. collect ( ) ,
@@ -414,16 +423,13 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
414
423
is_my_head_ctor : bool ,
415
424
) -> Option < PatStack < ' p , ' tcx > > {
416
425
// We return `None` if `ctor` is not covered by `self.head()`. If `ctor` is known to be
417
- // derived from `self.head()`, then we don't need to check; otherwise, we compute the
418
- // constructor of `self.head()` and check for constructor inclusion.
426
+ // derived from `self.head()`, then we don't need to check; otherwise, we check for
427
+ // constructor inclusion.
419
428
// Note that this shortcut is also necessary for correctness: a pattern should always be
420
429
// specializable with its own constructor, even in cases where we refuse to inspect values like
421
430
// opaque constants.
422
- if !is_my_head_ctor {
423
- let head_ctor = pat_constructor ( cx. tcx , cx. param_env , self . head ( ) ) ;
424
- if !ctor. is_covered_by ( cx, & head_ctor, self . head ( ) . ty ) {
425
- return None ;
426
- }
431
+ if !is_my_head_ctor && !ctor. is_covered_by ( cx, self . head_ctor ( cx) , self . head ( ) . ty ) {
432
+ return None ;
427
433
}
428
434
let new_fields = ctor_wild_subpatterns. replace_with_pattern_arguments ( self . head ( ) ) ;
429
435
@@ -437,13 +443,19 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
437
443
438
444
// We pop the head pattern and push the new fields extracted from the arguments of
439
445
// `self.head()`.
440
- Some ( new_fields. push_on_patstack ( & self . 0 [ 1 ..] ) )
446
+ Some ( new_fields. push_on_patstack ( & self . pats [ 1 ..] ) )
441
447
}
442
448
}
443
449
444
450
impl < ' p , ' tcx > Default for PatStack < ' p , ' tcx > {
445
451
fn default ( ) -> Self {
446
- PatStack ( smallvec ! [ ] )
452
+ Self :: from_vec ( smallvec ! [ ] )
453
+ }
454
+ }
455
+
456
+ impl < ' p , ' tcx > PartialEq for PatStack < ' p , ' tcx > {
457
+ fn eq ( & self , other : & Self ) -> bool {
458
+ self . pats == other. pats
447
459
}
448
460
}
449
461
@@ -452,7 +464,7 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
452
464
where
453
465
T : IntoIterator < Item = & ' p Pat < ' tcx > > ,
454
466
{
455
- PatStack ( iter. into_iter ( ) . collect ( ) )
467
+ Self :: from_vec ( iter. into_iter ( ) . collect ( ) )
456
468
}
457
469
}
458
470
@@ -570,6 +582,14 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
570
582
self . patterns . iter ( ) . map ( |r| r. head ( ) )
571
583
}
572
584
585
+ /// Iterate over the first constructor of each row
586
+ fn head_ctors < ' a > (
587
+ & ' a self ,
588
+ cx : & ' a MatchCheckCtxt < ' p , ' tcx > ,
589
+ ) -> impl Iterator < Item = & ' a Constructor < ' tcx > > + Captures < ' a > + Captures < ' p > {
590
+ self . patterns . iter ( ) . map ( move |r| r. head_ctor ( cx) )
591
+ }
592
+
573
593
/// This computes `S(constructor, self)`. See top of the file for explanations.
574
594
fn specialize_constructor (
575
595
& self ,
@@ -906,10 +926,7 @@ impl Slice {
906
926
_ => return smallvec ! [ Slice ( self ) ] ,
907
927
} ;
908
928
909
- let head_ctors = matrix
910
- . heads ( )
911
- . map ( |p| pat_constructor ( cx. tcx , cx. param_env , p) )
912
- . filter ( |c| !c. is_wildcard ( ) ) ;
929
+ let head_ctors = matrix. head_ctors ( cx) . filter ( |c| !c. is_wildcard ( ) ) ;
913
930
914
931
let mut max_prefix_len = self_prefix;
915
932
let mut max_suffix_len = self_suffix;
@@ -1120,7 +1137,7 @@ impl<'tcx> Constructor<'tcx> {
1120
1137
/// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want
1121
1138
/// to lint for overlapping ranges.
1122
1139
fn split < ' p > (
1123
- self ,
1140
+ & self ,
1124
1141
cx : & MatchCheckCtxt < ' p , ' tcx > ,
1125
1142
pcx : PatCtxt < ' tcx > ,
1126
1143
matrix : & Matrix < ' p , ' tcx > ,
@@ -1138,7 +1155,7 @@ impl<'tcx> Constructor<'tcx> {
1138
1155
}
1139
1156
Slice ( slice @ Slice { kind : VarLen ( ..) , .. } ) => slice. split ( cx, matrix) ,
1140
1157
// Any other constructor can be used unchanged.
1141
- _ => smallvec ! [ self ] ,
1158
+ _ => smallvec ! [ self . clone ( ) ] ,
1142
1159
}
1143
1160
}
1144
1161
@@ -1991,25 +2008,9 @@ impl<'tcx> IntRange<'tcx> {
1991
2008
}
1992
2009
}
1993
2010
1994
- fn from_pat (
1995
- tcx : TyCtxt < ' tcx > ,
1996
- param_env : ty:: ParamEnv < ' tcx > ,
1997
- pat : & Pat < ' tcx > ,
1998
- ) -> Option < IntRange < ' tcx > > {
1999
- // This MUST be kept in sync with `pat_constructor`.
2000
- match * pat. kind {
2001
- PatKind :: Constant { value } => Self :: from_const ( tcx, param_env, value, pat. span ) ,
2002
- PatKind :: Range ( PatRange { lo, hi, end } ) => {
2003
- let ty = lo. ty ;
2004
- Self :: from_range (
2005
- tcx,
2006
- lo. eval_bits ( tcx, param_env, lo. ty ) ,
2007
- hi. eval_bits ( tcx, param_env, hi. ty ) ,
2008
- ty,
2009
- & end,
2010
- pat. span ,
2011
- )
2012
- }
2011
+ fn from_ctor < ' a > ( ctor : & ' a Constructor < ' tcx > ) -> Option < & ' a IntRange < ' tcx > > {
2012
+ match ctor {
2013
+ IntRange ( range) => Some ( range) ,
2013
2014
_ => None ,
2014
2015
}
2015
2016
}
@@ -2145,7 +2146,7 @@ impl<'tcx> IntRange<'tcx> {
2145
2146
/// between every pair of boundary points. (This essentially sums up to performing the intuitive
2146
2147
/// merging operation depicted above.)
2147
2148
fn split < ' p > (
2148
- self ,
2149
+ & self ,
2149
2150
cx : & MatchCheckCtxt < ' p , ' tcx > ,
2150
2151
pcx : PatCtxt < ' tcx > ,
2151
2152
matrix : & Matrix < ' p , ' tcx > ,
@@ -2176,15 +2177,13 @@ impl<'tcx> IntRange<'tcx> {
2176
2177
// Collect the span and range of all the intersecting ranges to lint on likely
2177
2178
// incorrect range patterns. (#63987)
2178
2179
let mut overlaps = vec ! [ ] ;
2180
+ let row_len = matrix. patterns . get ( 0 ) . map ( |r| r. len ( ) ) . unwrap_or ( 0 ) ;
2179
2181
// `borders` is the set of borders between equivalence classes: each equivalence
2180
2182
// class lies between 2 borders.
2181
2183
let row_borders = matrix
2182
- . patterns
2183
- . iter ( )
2184
- . flat_map ( |row| {
2185
- IntRange :: from_pat ( cx. tcx , cx. param_env , row. head ( ) ) . map ( |r| ( r, row. len ( ) ) )
2186
- } )
2187
- . flat_map ( |( range, row_len) | {
2184
+ . head_ctors ( cx)
2185
+ . filter_map ( |ctor| IntRange :: from_ctor ( ctor) )
2186
+ . filter_map ( |range| {
2188
2187
let intersection = self . intersection ( cx. tcx , & range) ;
2189
2188
let should_lint = self . suspicious_intersection ( & range) ;
2190
2189
if let ( Some ( range) , 1 , true ) = ( & intersection, row_len, should_lint) {
@@ -2229,7 +2228,7 @@ impl<'tcx> IntRange<'tcx> {
2229
2228
}
2230
2229
2231
2230
fn lint_overlapping_patterns (
2232
- self ,
2231
+ & self ,
2233
2232
tcx : TyCtxt < ' tcx > ,
2234
2233
hir_id : Option < HirId > ,
2235
2234
ty : Ty < ' tcx > ,
@@ -2412,7 +2411,7 @@ crate fn is_useful<'p, 'tcx>(
2412
2411
2413
2412
debug ! ( "is_useful_expand_first_col: pcx={:#?}, expanding {:#?}" , pcx, v. head( ) ) ;
2414
2413
2415
- let constructor = pat_constructor ( cx . tcx , cx . param_env , v . head ( ) ) ;
2414
+ let constructor = v . head_ctor ( cx ) ;
2416
2415
let ret = if !constructor. is_wildcard ( ) {
2417
2416
debug ! ( "is_useful - expanding constructor: {:#?}" , constructor) ;
2418
2417
constructor
@@ -2435,11 +2434,8 @@ crate fn is_useful<'p, 'tcx>(
2435
2434
} else {
2436
2435
debug ! ( "is_useful - expanding wildcard" ) ;
2437
2436
2438
- let used_ctors: Vec < Constructor < ' _ > > = matrix
2439
- . heads ( )
2440
- . map ( |p| pat_constructor ( cx. tcx , cx. param_env , p) )
2441
- . filter ( |c| !c. is_wildcard ( ) )
2442
- . collect ( ) ;
2437
+ let used_ctors: Vec < Constructor < ' _ > > =
2438
+ matrix. head_ctors ( cx) . cloned ( ) . filter ( |c| !c. is_wildcard ( ) ) . collect ( ) ;
2443
2439
debug ! ( "is_useful_used_ctors = {:#?}" , used_ctors) ;
2444
2440
// `all_ctors` are all the constructors for the given type, which
2445
2441
// should all be represented (or caught with the wild pattern `_`).
@@ -2563,12 +2559,10 @@ fn is_useful_specialized<'p, 'tcx>(
2563
2559
2564
2560
/// Determines the constructor that the given pattern can be specialized to.
2565
2561
/// Returns `None` in case of a catch-all, which can't be specialized.
2566
- fn pat_constructor < ' tcx > (
2567
- tcx : TyCtxt < ' tcx > ,
2568
- param_env : ty:: ParamEnv < ' tcx > ,
2569
- pat : & Pat < ' tcx > ,
2562
+ fn pat_constructor < ' p , ' tcx > (
2563
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
2564
+ pat : & ' p Pat < ' tcx > ,
2570
2565
) -> Constructor < ' tcx > {
2571
- // This MUST be kept in sync with `IntRange::from_pat`.
2572
2566
match * pat. kind {
2573
2567
PatKind :: AscribeUserType { .. } => bug ! ( ) , // Handled by `expand_pattern`
2574
2568
PatKind :: Binding { .. } | PatKind :: Wild => Wildcard ,
@@ -2577,7 +2571,7 @@ fn pat_constructor<'tcx>(
2577
2571
Variant ( adt_def. variants [ variant_index] . def_id )
2578
2572
}
2579
2573
PatKind :: Constant { value } => {
2580
- if let Some ( int_range) = IntRange :: from_const ( tcx, param_env, value, pat. span ) {
2574
+ if let Some ( int_range) = IntRange :: from_const ( cx . tcx , cx . param_env , value, pat. span ) {
2581
2575
IntRange ( int_range)
2582
2576
} else {
2583
2577
match value. ty . kind ( ) {
@@ -2593,9 +2587,9 @@ fn pat_constructor<'tcx>(
2593
2587
PatKind :: Range ( PatRange { lo, hi, end } ) => {
2594
2588
let ty = lo. ty ;
2595
2589
if let Some ( int_range) = IntRange :: from_range (
2596
- tcx,
2597
- lo. eval_bits ( tcx, param_env, lo. ty ) ,
2598
- hi. eval_bits ( tcx, param_env, hi. ty ) ,
2590
+ cx . tcx ,
2591
+ lo. eval_bits ( cx . tcx , cx . param_env , lo. ty ) ,
2592
+ hi. eval_bits ( cx . tcx , cx . param_env , hi. ty ) ,
2599
2593
ty,
2600
2594
& end,
2601
2595
pat. span ,
@@ -2608,7 +2602,7 @@ fn pat_constructor<'tcx>(
2608
2602
PatKind :: Array { ref prefix, ref slice, ref suffix }
2609
2603
| PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
2610
2604
let array_len = match pat. ty . kind ( ) {
2611
- ty:: Array ( _, length) => Some ( length. eval_usize ( tcx, param_env) ) ,
2605
+ ty:: Array ( _, length) => Some ( length. eval_usize ( cx . tcx , cx . param_env ) ) ,
2612
2606
ty:: Slice ( _) => None ,
2613
2607
_ => span_bug ! ( pat. span, "bad ty {:?} for slice pattern" , pat. ty) ,
2614
2608
} ;
0 commit comments