@@ -295,6 +295,7 @@ use self::WitnessPreference::*;
295295
296296use rustc_data_structures:: captures:: Captures ;
297297use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
298+ use rustc_data_structures:: sync:: OnceCell ;
298299use rustc_index:: vec:: Idx ;
299300
300301use super :: { compare_const_vals, PatternFoldable , PatternFolder } ;
@@ -346,32 +347,40 @@ impl<'tcx> Pat<'tcx> {
346347
347348/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
348349/// 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+ }
351356
352357impl < ' p , ' tcx > PatStack < ' p , ' tcx > {
353358 crate fn from_pattern ( pat : & ' p Pat < ' tcx > ) -> Self {
354- PatStack ( smallvec ! [ pat] )
359+ Self :: from_vec ( smallvec ! [ pat] )
355360 }
356361
357362 fn from_vec ( vec : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) -> Self {
358- PatStack ( vec)
363+ PatStack { pats : vec, head_ctor : OnceCell :: new ( ) }
359364 }
360365
361366 fn is_empty ( & self ) -> bool {
362- self . 0 . is_empty ( )
367+ self . pats . is_empty ( )
363368 }
364369
365370 fn len ( & self ) -> usize {
366- self . 0 . len ( )
371+ self . pats . len ( )
367372 }
368373
369374 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 ( ) ) )
371380 }
372381
373382 fn iter ( & self ) -> impl Iterator < Item = & Pat < ' tcx > > {
374- self . 0 . iter ( ) . copied ( )
383+ self . pats . iter ( ) . copied ( )
375384 }
376385
377386 // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
@@ -383,7 +392,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
383392 pats. iter ( )
384393 . map ( |pat| {
385394 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 ..] ) ;
387396 new_patstack
388397 } )
389398 . collect ( ) ,
@@ -414,16 +423,13 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
414423 is_my_head_ctor : bool ,
415424 ) -> Option < PatStack < ' p , ' tcx > > {
416425 // 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.
419428 // Note that this shortcut is also necessary for correctness: a pattern should always be
420429 // specializable with its own constructor, even in cases where we refuse to inspect values like
421430 // 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 ;
427433 }
428434 let new_fields = ctor_wild_subpatterns. replace_with_pattern_arguments ( self . head ( ) ) ;
429435
@@ -437,13 +443,19 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
437443
438444 // We pop the head pattern and push the new fields extracted from the arguments of
439445 // `self.head()`.
440- Some ( new_fields. push_on_patstack ( & self . 0 [ 1 ..] ) )
446+ Some ( new_fields. push_on_patstack ( & self . pats [ 1 ..] ) )
441447 }
442448}
443449
444450impl < ' p , ' tcx > Default for PatStack < ' p , ' tcx > {
445451 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
447459 }
448460}
449461
@@ -452,7 +464,7 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
452464 where
453465 T : IntoIterator < Item = & ' p Pat < ' tcx > > ,
454466 {
455- PatStack ( iter. into_iter ( ) . collect ( ) )
467+ Self :: from_vec ( iter. into_iter ( ) . collect ( ) )
456468 }
457469}
458470
@@ -570,6 +582,14 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
570582 self . patterns . iter ( ) . map ( |r| r. head ( ) )
571583 }
572584
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+
573593 /// This computes `S(constructor, self)`. See top of the file for explanations.
574594 fn specialize_constructor (
575595 & self ,
@@ -906,10 +926,7 @@ impl Slice {
906926 _ => return smallvec ! [ Slice ( self ) ] ,
907927 } ;
908928
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 ( ) ) ;
913930
914931 let mut max_prefix_len = self_prefix;
915932 let mut max_suffix_len = self_suffix;
@@ -1120,7 +1137,7 @@ impl<'tcx> Constructor<'tcx> {
11201137 /// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want
11211138 /// to lint for overlapping ranges.
11221139 fn split < ' p > (
1123- self ,
1140+ & self ,
11241141 cx : & MatchCheckCtxt < ' p , ' tcx > ,
11251142 pcx : PatCtxt < ' tcx > ,
11261143 matrix : & Matrix < ' p , ' tcx > ,
@@ -1138,7 +1155,7 @@ impl<'tcx> Constructor<'tcx> {
11381155 }
11391156 Slice ( slice @ Slice { kind : VarLen ( ..) , .. } ) => slice. split ( cx, matrix) ,
11401157 // Any other constructor can be used unchanged.
1141- _ => smallvec ! [ self ] ,
1158+ _ => smallvec ! [ self . clone ( ) ] ,
11421159 }
11431160 }
11441161
@@ -1991,25 +2008,9 @@ impl<'tcx> IntRange<'tcx> {
19912008 }
19922009 }
19932010
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) ,
20132014 _ => None ,
20142015 }
20152016 }
@@ -2145,7 +2146,7 @@ impl<'tcx> IntRange<'tcx> {
21452146 /// between every pair of boundary points. (This essentially sums up to performing the intuitive
21462147 /// merging operation depicted above.)
21472148 fn split < ' p > (
2148- self ,
2149+ & self ,
21492150 cx : & MatchCheckCtxt < ' p , ' tcx > ,
21502151 pcx : PatCtxt < ' tcx > ,
21512152 matrix : & Matrix < ' p , ' tcx > ,
@@ -2176,15 +2177,13 @@ impl<'tcx> IntRange<'tcx> {
21762177 // Collect the span and range of all the intersecting ranges to lint on likely
21772178 // incorrect range patterns. (#63987)
21782179 let mut overlaps = vec ! [ ] ;
2180+ let row_len = matrix. patterns . get ( 0 ) . map ( |r| r. len ( ) ) . unwrap_or ( 0 ) ;
21792181 // `borders` is the set of borders between equivalence classes: each equivalence
21802182 // class lies between 2 borders.
21812183 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| {
21882187 let intersection = self . intersection ( cx. tcx , & range) ;
21892188 let should_lint = self . suspicious_intersection ( & range) ;
21902189 if let ( Some ( range) , 1 , true ) = ( & intersection, row_len, should_lint) {
@@ -2229,7 +2228,7 @@ impl<'tcx> IntRange<'tcx> {
22292228 }
22302229
22312230 fn lint_overlapping_patterns (
2232- self ,
2231+ & self ,
22332232 tcx : TyCtxt < ' tcx > ,
22342233 hir_id : Option < HirId > ,
22352234 ty : Ty < ' tcx > ,
@@ -2412,7 +2411,7 @@ crate fn is_useful<'p, 'tcx>(
24122411
24132412 debug ! ( "is_useful_expand_first_col: pcx={:#?}, expanding {:#?}" , pcx, v. head( ) ) ;
24142413
2415- let constructor = pat_constructor ( cx . tcx , cx . param_env , v . head ( ) ) ;
2414+ let constructor = v . head_ctor ( cx ) ;
24162415 let ret = if !constructor. is_wildcard ( ) {
24172416 debug ! ( "is_useful - expanding constructor: {:#?}" , constructor) ;
24182417 constructor
@@ -2435,11 +2434,8 @@ crate fn is_useful<'p, 'tcx>(
24352434 } else {
24362435 debug ! ( "is_useful - expanding wildcard" ) ;
24372436
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 ( ) ;
24432439 debug ! ( "is_useful_used_ctors = {:#?}" , used_ctors) ;
24442440 // `all_ctors` are all the constructors for the given type, which
24452441 // should all be represented (or caught with the wild pattern `_`).
@@ -2563,12 +2559,10 @@ fn is_useful_specialized<'p, 'tcx>(
25632559
25642560/// Determines the constructor that the given pattern can be specialized to.
25652561/// 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 > ,
25702565) -> Constructor < ' tcx > {
2571- // This MUST be kept in sync with `IntRange::from_pat`.
25722566 match * pat. kind {
25732567 PatKind :: AscribeUserType { .. } => bug ! ( ) , // Handled by `expand_pattern`
25742568 PatKind :: Binding { .. } | PatKind :: Wild => Wildcard ,
@@ -2577,7 +2571,7 @@ fn pat_constructor<'tcx>(
25772571 Variant ( adt_def. variants [ variant_index] . def_id )
25782572 }
25792573 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 ) {
25812575 IntRange ( int_range)
25822576 } else {
25832577 match value. ty . kind ( ) {
@@ -2593,9 +2587,9 @@ fn pat_constructor<'tcx>(
25932587 PatKind :: Range ( PatRange { lo, hi, end } ) => {
25942588 let ty = lo. ty ;
25952589 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 ) ,
25992593 ty,
26002594 & end,
26012595 pat. span ,
@@ -2608,7 +2602,7 @@ fn pat_constructor<'tcx>(
26082602 PatKind :: Array { ref prefix, ref slice, ref suffix }
26092603 | PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
26102604 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 ) ) ,
26122606 ty:: Slice ( _) => None ,
26132607 _ => span_bug ! ( pat. span, "bad ty {:?} for slice pattern" , pat. ty) ,
26142608 } ;
0 commit comments