@@ -16,7 +16,7 @@ use smallvec::SmallVec;
1616use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
1717use crate :: ty:: {
1818 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 ,
2020 walk_visitable_list,
2121} ;
2222
@@ -322,6 +322,14 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
322322 GenericArgKind :: Const ( ct) => ct. try_fold_with ( folder) . map ( Into :: into) ,
323323 }
324324 }
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+ }
325333}
326334
327335impl < ' tcx > TypeVisitable < TyCtxt < ' tcx > > for GenericArg < ' tcx > {
@@ -591,6 +599,32 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
591599 }
592600 }
593601 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 ,
594628 _ => ty:: util:: fold_list ( self , folder, |tcx, v| tcx. mk_args ( v) ) ,
595629 }
596630 }
@@ -626,6 +660,36 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
626660 Ok ( folder. cx ( ) . mk_type_list ( & [ param0, param1] ) )
627661 }
628662 }
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+ }
629693 _ => ty:: util:: fold_list ( self , folder, |tcx, v| tcx. mk_type_list ( v) ) ,
630694 }
631695 }
0 commit comments