@@ -17,7 +17,7 @@ use smallvec::SmallVec;
1717use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
1818use crate :: ty:: {
1919 self , ClosureArgs , CoroutineArgs , CoroutineClosureArgs , FallibleTypeFolder , InlineConstArgs ,
20- Lift , List , Ty , TyCtxt , TypeFoldable , TypeVisitable , TypeVisitor , VisitorResult ,
20+ Lift , List , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeVisitable , TypeVisitor , VisitorResult ,
2121 walk_visitable_list,
2222} ;
2323
@@ -337,6 +337,14 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
337337 GenericArgKind :: Const ( ct) => ct. try_fold_with ( folder) . map ( Into :: into) ,
338338 }
339339 }
340+
341+ fn fold_with < F : TypeFolder < TyCtxt < ' tcx > > > ( self , folder : & mut F ) -> Self {
342+ match self . unpack ( ) {
343+ GenericArgKind :: Lifetime ( lt) => lt. fold_with ( folder) . into ( ) ,
344+ GenericArgKind :: Type ( ty) => ty. fold_with ( folder) . into ( ) ,
345+ GenericArgKind :: Const ( ct) => ct. fold_with ( folder) . into ( ) ,
346+ }
347+ }
340348}
341349
342350impl < ' tcx > TypeVisitable < TyCtxt < ' tcx > > for GenericArg < ' tcx > {
@@ -606,6 +614,32 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
606614 }
607615 }
608616 0 => Ok ( self ) ,
617+ _ => ty:: util:: try_fold_list ( self , folder, |tcx, v| tcx. mk_args ( v) ) ,
618+ }
619+ }
620+
621+ fn fold_with < F : TypeFolder < TyCtxt < ' tcx > > > ( self , folder : & mut F ) -> Self {
622+ // This code is hot enough that it's worth specializing for the most
623+ // common length lists, to avoid the overhead of `SmallVec` creation.
624+ // The match arms are in order of frequency. The 1, 2, and 0 cases are
625+ // typically hit in 90--99.99% of cases. When folding doesn't change
626+ // the args, it's faster to reuse the existing args rather than
627+ // calling `mk_args`.
628+ match self . len ( ) {
629+ 1 => {
630+ let param0 = self [ 0 ] . fold_with ( folder) ;
631+ if param0 == self [ 0 ] { self } else { folder. cx ( ) . mk_args ( & [ param0] ) }
632+ }
633+ 2 => {
634+ let param0 = self [ 0 ] . fold_with ( folder) ;
635+ let param1 = self [ 1 ] . fold_with ( folder) ;
636+ if param0 == self [ 0 ] && param1 == self [ 1 ] {
637+ self
638+ } else {
639+ folder. cx ( ) . mk_args ( & [ param0, param1] )
640+ }
641+ }
642+ 0 => self ,
609643 _ => ty:: util:: fold_list ( self , folder, |tcx, v| tcx. mk_args ( v) ) ,
610644 }
611645 }
@@ -641,6 +675,36 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
641675 Ok ( folder. cx ( ) . mk_type_list ( & [ param0, param1] ) )
642676 }
643677 }
678+ _ => ty:: util:: try_fold_list ( self , folder, |tcx, v| tcx. mk_type_list ( v) ) ,
679+ }
680+ }
681+
682+ fn fold_with < F : TypeFolder < TyCtxt < ' tcx > > > ( self , folder : & mut F ) -> Self {
683+ // This code is fairly hot, though not as hot as `GenericArgsRef`.
684+ //
685+ // When compiling stage 2, I get the following results:
686+ //
687+ // len | total | %
688+ // --- | --------- | -----
689+ // 2 | 15083590 | 48.1
690+ // 3 | 7540067 | 24.0
691+ // 1 | 5300377 | 16.9
692+ // 4 | 1351897 | 4.3
693+ // 0 | 1256849 | 4.0
694+ //
695+ // I've tried it with some private repositories and got
696+ // close to the same result, with 4 and 0 swapping places
697+ // sometimes.
698+ match self . len ( ) {
699+ 2 => {
700+ let param0 = self [ 0 ] . fold_with ( folder) ;
701+ let param1 = self [ 1 ] . fold_with ( folder) ;
702+ if param0 == self [ 0 ] && param1 == self [ 1 ] {
703+ self
704+ } else {
705+ folder. cx ( ) . mk_type_list ( & [ param0, param1] )
706+ }
707+ }
644708 _ => ty:: util:: fold_list ( self , folder, |tcx, v| tcx. mk_type_list ( v) ) ,
645709 }
646710 }
0 commit comments