@@ -697,6 +697,9 @@ impl<'tcx> TyCtxt<'tcx> {
697
697
// that type, and when we finish expanding that type we remove the
698
698
// its DefId.
699
699
seen_opaque_tys : FxHashSet < DefId > ,
700
+ // Cache of all expansions we've seen so far. This is a critical
701
+ // optimization for some large types produced by async fn trees.
702
+ expanded_cache : FxHashMap < ( DefId , SubstsRef < ' tcx > ) , Ty < ' tcx > > ,
700
703
primary_def_id : DefId ,
701
704
found_recursion : bool ,
702
705
tcx : TyCtxt < ' tcx > ,
@@ -713,9 +716,16 @@ impl<'tcx> TyCtxt<'tcx> {
713
716
}
714
717
let substs = substs. fold_with ( self ) ;
715
718
if self . seen_opaque_tys . insert ( def_id) {
716
- let generic_ty = self . tcx . type_of ( def_id) ;
717
- let concrete_ty = generic_ty. subst ( self . tcx , substs) ;
718
- let expanded_ty = self . fold_ty ( concrete_ty) ;
719
+ let expanded_ty = match self . expanded_cache . get ( & ( def_id, substs) ) {
720
+ Some ( expanded_ty) => expanded_ty,
721
+ None => {
722
+ let generic_ty = self . tcx . type_of ( def_id) ;
723
+ let concrete_ty = generic_ty. subst ( self . tcx , substs) ;
724
+ let expanded_ty = self . fold_ty ( concrete_ty) ;
725
+ self . expanded_cache . insert ( ( def_id, substs) , expanded_ty) ;
726
+ expanded_ty
727
+ }
728
+ } ;
719
729
self . seen_opaque_tys . remove ( & def_id) ;
720
730
Some ( expanded_ty)
721
731
} else {
@@ -743,6 +753,7 @@ impl<'tcx> TyCtxt<'tcx> {
743
753
744
754
let mut visitor = OpaqueTypeExpander {
745
755
seen_opaque_tys : FxHashSet :: default ( ) ,
756
+ expanded_cache : FxHashMap :: default ( ) ,
746
757
primary_def_id : def_id,
747
758
found_recursion : false ,
748
759
tcx : self ,
0 commit comments