@@ -402,14 +402,41 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
402
402
403
403
impl < ' tcx > TypeFoldable < ' tcx > for SubstsRef < ' tcx > {
404
404
fn super_fold_with < F : TypeFolder < ' tcx > > ( & self , folder : & mut F ) -> Self {
405
- let params: SmallVec < [ _ ; 8 ] > = self . iter ( ) . map ( |k| k. fold_with ( folder) ) . collect ( ) ;
406
-
407
- // If folding doesn't change the substs, it's faster to avoid
408
- // calling `mk_substs` and instead reuse the existing substs.
409
- if params[ ..] == self [ ..] {
410
- self
411
- } else {
412
- folder. tcx ( ) . intern_substs ( & params)
405
+ // This code is hot enough that it's worth specializing for the most
406
+ // common length lists, to avoid the overhead of `SmallVec` creation.
407
+ // The match arms are in order of frequency. The 1, 2, and 0 cases are
408
+ // typically hit in 90--99.99% of cases. When folding doesn't change
409
+ // the substs, it's faster to reuse the existing substs rather than
410
+ // calling `intern_substs`.
411
+ match self . len ( ) {
412
+ 1 => {
413
+ let param0 = self [ 0 ] . fold_with ( folder) ;
414
+ if param0 == self [ 0 ] {
415
+ self
416
+ } else {
417
+ folder. tcx ( ) . intern_substs ( & [ param0] )
418
+ }
419
+ }
420
+ 2 => {
421
+ let param0 = self [ 0 ] . fold_with ( folder) ;
422
+ let param1 = self [ 1 ] . fold_with ( folder) ;
423
+ if param0 == self [ 0 ] && param1 == self [ 1 ] {
424
+ self
425
+ } else {
426
+ folder. tcx ( ) . intern_substs ( & [ param0, param1] )
427
+ }
428
+ }
429
+ 0 => {
430
+ self
431
+ }
432
+ _ => {
433
+ let params: SmallVec < [ _ ; 8 ] > = self . iter ( ) . map ( |k| k. fold_with ( folder) ) . collect ( ) ;
434
+ if params[ ..] == self [ ..] {
435
+ self
436
+ } else {
437
+ folder. tcx ( ) . intern_substs ( & params)
438
+ }
439
+ }
413
440
}
414
441
}
415
442
0 commit comments