@@ -16,7 +16,7 @@ use smallvec::SmallVec;
16
16
use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
17
17
use crate :: ty:: {
18
18
self , ClosureArgs , CoroutineArgs , CoroutineClosureArgs , FallibleTypeFolder , InlineConstArgs ,
19
- Lift , List , Ty , TyCtxt , TypeFoldable , TypeVisitable , TypeVisitor , VisitorResult ,
19
+ Lift , List , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeVisitable , TypeVisitor , VisitorResult ,
20
20
walk_visitable_list,
21
21
} ;
22
22
@@ -322,6 +322,14 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
322
322
GenericArgKind :: Const ( ct) => ct. try_fold_with ( folder) . map ( Into :: into) ,
323
323
}
324
324
}
325
+
326
+ fn fold_with < F : TypeFolder < TyCtxt < ' tcx > > > ( self , folder : & mut F ) -> Self {
327
+ match self . unpack ( ) {
328
+ GenericArgKind :: Lifetime ( lt) => lt. fold_with ( folder) . into ( ) ,
329
+ GenericArgKind :: Type ( ty) => ty. fold_with ( folder) . into ( ) ,
330
+ GenericArgKind :: Const ( ct) => ct. fold_with ( folder) . into ( ) ,
331
+ }
332
+ }
325
333
}
326
334
327
335
impl < ' tcx > TypeVisitable < TyCtxt < ' tcx > > for GenericArg < ' tcx > {
@@ -591,6 +599,32 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
591
599
}
592
600
}
593
601
0 => Ok ( self ) ,
602
+ _ => ty:: util:: try_fold_list ( self , folder, |tcx, v| tcx. mk_args ( v) ) ,
603
+ }
604
+ }
605
+
606
+ fn fold_with < F : TypeFolder < TyCtxt < ' tcx > > > ( self , folder : & mut F ) -> Self {
607
+ // This code is hot enough that it's worth specializing for the most
608
+ // common length lists, to avoid the overhead of `SmallVec` creation.
609
+ // The match arms are in order of frequency. The 1, 2, and 0 cases are
610
+ // typically hit in 90--99.99% of cases. When folding doesn't change
611
+ // the args, it's faster to reuse the existing args rather than
612
+ // calling `mk_args`.
613
+ match self . len ( ) {
614
+ 1 => {
615
+ let param0 = self [ 0 ] . fold_with ( folder) ;
616
+ if param0 == self [ 0 ] { self } else { folder. cx ( ) . mk_args ( & [ param0] ) }
617
+ }
618
+ 2 => {
619
+ let param0 = self [ 0 ] . fold_with ( folder) ;
620
+ let param1 = self [ 1 ] . fold_with ( folder) ;
621
+ if param0 == self [ 0 ] && param1 == self [ 1 ] {
622
+ self
623
+ } else {
624
+ folder. cx ( ) . mk_args ( & [ param0, param1] )
625
+ }
626
+ }
627
+ 0 => self ,
594
628
_ => ty:: util:: fold_list ( self , folder, |tcx, v| tcx. mk_args ( v) ) ,
595
629
}
596
630
}
@@ -626,6 +660,36 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
626
660
Ok ( folder. cx ( ) . mk_type_list ( & [ param0, param1] ) )
627
661
}
628
662
}
663
+ _ => ty:: util:: try_fold_list ( self , folder, |tcx, v| tcx. mk_type_list ( v) ) ,
664
+ }
665
+ }
666
+
667
+ fn fold_with < F : TypeFolder < TyCtxt < ' tcx > > > ( self , folder : & mut F ) -> Self {
668
+ // This code is fairly hot, though not as hot as `GenericArgsRef`.
669
+ //
670
+ // When compiling stage 2, I get the following results:
671
+ //
672
+ // len | total | %
673
+ // --- | --------- | -----
674
+ // 2 | 15083590 | 48.1
675
+ // 3 | 7540067 | 24.0
676
+ // 1 | 5300377 | 16.9
677
+ // 4 | 1351897 | 4.3
678
+ // 0 | 1256849 | 4.0
679
+ //
680
+ // I've tried it with some private repositories and got
681
+ // close to the same result, with 4 and 0 swapping places
682
+ // sometimes.
683
+ match self . len ( ) {
684
+ 2 => {
685
+ let param0 = self [ 0 ] . fold_with ( folder) ;
686
+ let param1 = self [ 1 ] . fold_with ( folder) ;
687
+ if param0 == self [ 0 ] && param1 == self [ 1 ] {
688
+ self
689
+ } else {
690
+ folder. cx ( ) . mk_type_list ( & [ param0, param1] )
691
+ }
692
+ }
629
693
_ => ty:: util:: fold_list ( self , folder, |tcx, v| tcx. mk_type_list ( v) ) ,
630
694
}
631
695
}
0 commit comments