@@ -8,6 +8,7 @@ use crate::mir::interpret::{sign_extend, truncate};
88use crate :: ich:: NodeIdHashingMode ;
99use crate :: traits:: { self , ObligationCause } ;
1010use crate :: ty:: { self , DefIdTree , Ty , TyCtxt , GenericParamDefKind , TypeFoldable } ;
11+ use crate :: ty:: fold:: TypeFolder ;
1112use crate :: ty:: subst:: { Subst , InternalSubsts , SubstsRef , GenericArgKind } ;
1213use crate :: ty:: query:: TyCtxtAt ;
1314use crate :: ty:: TyKind :: * ;
@@ -699,81 +700,32 @@ impl<'tcx> TyCtxt<'tcx> {
699700 }
700701 }
701702
703+ /// Normalizes all opaque types in the given value, replacing them
704+ /// with their underlying types.
705+ pub fn normalize_impl_trait_types < T : TypeFoldable < ' tcx > > ( self , val : & T ) -> T {
706+ let mut visitor = OpaqueTypeExpander {
707+ seen_opaque_tys : FxHashSet :: default ( ) ,
708+ expanded_cache : FxHashMap :: default ( ) ,
709+ primary_def_id : None ,
710+ found_recursion : false ,
711+ check_recursion : false ,
712+ tcx : self ,
713+ } ;
714+ val. fold_with ( & mut visitor)
715+ }
716+
702717 /// Expands the given impl trait type, stopping if the type is recursive.
703718 pub fn try_expand_impl_trait_type (
704719 self ,
705720 def_id : DefId ,
706721 substs : SubstsRef < ' tcx > ,
707722 ) -> Result < Ty < ' tcx > , Ty < ' tcx > > {
708- use crate :: ty:: fold:: TypeFolder ;
709-
710- struct OpaqueTypeExpander < ' tcx > {
711- // Contains the DefIds of the opaque types that are currently being
712- // expanded. When we expand an opaque type we insert the DefId of
713- // that type, and when we finish expanding that type we remove the
714- // its DefId.
715- seen_opaque_tys : FxHashSet < DefId > ,
716- // Cache of all expansions we've seen so far. This is a critical
717- // optimization for some large types produced by async fn trees.
718- expanded_cache : FxHashMap < ( DefId , SubstsRef < ' tcx > ) , Ty < ' tcx > > ,
719- primary_def_id : DefId ,
720- found_recursion : bool ,
721- tcx : TyCtxt < ' tcx > ,
722- }
723-
724- impl < ' tcx > OpaqueTypeExpander < ' tcx > {
725- fn expand_opaque_ty (
726- & mut self ,
727- def_id : DefId ,
728- substs : SubstsRef < ' tcx > ,
729- ) -> Option < Ty < ' tcx > > {
730- if self . found_recursion {
731- return None ;
732- }
733- let substs = substs. fold_with ( self ) ;
734- if self . seen_opaque_tys . insert ( def_id) {
735- let expanded_ty = match self . expanded_cache . get ( & ( def_id, substs) ) {
736- Some ( expanded_ty) => expanded_ty,
737- None => {
738- let generic_ty = self . tcx . type_of ( def_id) ;
739- let concrete_ty = generic_ty. subst ( self . tcx , substs) ;
740- let expanded_ty = self . fold_ty ( concrete_ty) ;
741- self . expanded_cache . insert ( ( def_id, substs) , expanded_ty) ;
742- expanded_ty
743- }
744- } ;
745- self . seen_opaque_tys . remove ( & def_id) ;
746- Some ( expanded_ty)
747- } else {
748- // If another opaque type that we contain is recursive, then it
749- // will report the error, so we don't have to.
750- self . found_recursion = def_id == self . primary_def_id ;
751- None
752- }
753- }
754- }
755-
756- impl < ' tcx > TypeFolder < ' tcx > for OpaqueTypeExpander < ' tcx > {
757- fn tcx ( & self ) -> TyCtxt < ' tcx > {
758- self . tcx
759- }
760-
761- fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
762- if let ty:: Opaque ( def_id, substs) = t. kind {
763- self . expand_opaque_ty ( def_id, substs) . unwrap_or ( t)
764- } else if t. has_projections ( ) {
765- t. super_fold_with ( self )
766- } else {
767- t
768- }
769- }
770- }
771-
772723 let mut visitor = OpaqueTypeExpander {
773724 seen_opaque_tys : FxHashSet :: default ( ) ,
774725 expanded_cache : FxHashMap :: default ( ) ,
775- primary_def_id : def_id,
726+ primary_def_id : Some ( def_id) ,
776727 found_recursion : false ,
728+ check_recursion : true ,
777729 tcx : self ,
778730 } ;
779731 let expanded_type = visitor. expand_opaque_ty ( def_id, substs) . unwrap ( ) ;
@@ -785,6 +737,77 @@ impl<'tcx> TyCtxt<'tcx> {
785737 }
786738}
787739
740+ /// Expands any nested opaque types, caching the expansion
741+ /// of each (DefId, SubstsRef) pair
742+ struct OpaqueTypeExpander < ' tcx > {
743+ /// Contains the `DefId`s of the opaque types that are currently being
744+ /// expanded. When we expand an opaque type we insert the `DefId` of
745+ /// that type, and when we finish expanding that type we remove the
746+ /// its `DefId`.
747+ seen_opaque_tys : FxHashSet < DefId > ,
748+ /// Cache of all expansions we've seen so far. This is a critical
749+ /// optimization for some large types produced by `async fn` trees.
750+ expanded_cache : FxHashMap < ( DefId , SubstsRef < ' tcx > ) , Ty < ' tcx > > ,
751+ primary_def_id : Option < DefId > ,
752+ found_recursion : bool ,
753+ /// Whether or not to check for recursive opaque types.
754+ /// This is `true` when we're explicitly checking for opaque type
755+ /// recursion, and 'false' otherwise to avoid unecessary work.
756+ check_recursion : bool ,
757+ tcx : TyCtxt < ' tcx > ,
758+ }
759+
760+ impl < ' tcx > OpaqueTypeExpander < ' tcx > {
761+ fn expand_opaque_ty (
762+ & mut self ,
763+ def_id : DefId ,
764+ substs : SubstsRef < ' tcx > ,
765+ ) -> Option < Ty < ' tcx > > {
766+ if self . found_recursion {
767+ return None ;
768+ }
769+ let substs = substs. fold_with ( self ) ;
770+ if !self . check_recursion || self . seen_opaque_tys . insert ( def_id) {
771+ let expanded_ty = match self . expanded_cache . get ( & ( def_id, substs) ) {
772+ Some ( expanded_ty) => expanded_ty,
773+ None => {
774+ let generic_ty = self . tcx . type_of ( def_id) ;
775+ let concrete_ty = generic_ty. subst ( self . tcx , substs) ;
776+ let expanded_ty = self . fold_ty ( concrete_ty) ;
777+ self . expanded_cache . insert ( ( def_id, substs) , expanded_ty) ;
778+ expanded_ty
779+ }
780+ } ;
781+ if self . check_recursion {
782+ self . seen_opaque_tys . remove ( & def_id) ;
783+ }
784+ Some ( expanded_ty)
785+ } else {
786+ // If another opaque type that we contain is recursive, then it
787+ // will report the error, so we don't have to.
788+ self . found_recursion = def_id == * self . primary_def_id . as_ref ( ) . unwrap ( ) ;
789+ None
790+ }
791+ }
792+ }
793+
794+ impl < ' tcx > TypeFolder < ' tcx > for OpaqueTypeExpander < ' tcx > {
795+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
796+ self . tcx
797+ }
798+
799+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
800+ if let ty:: Opaque ( def_id, substs) = t. kind {
801+ self . expand_opaque_ty ( def_id, substs) . unwrap_or ( t)
802+ } else if t. has_projections ( ) {
803+ t. super_fold_with ( self )
804+ } else {
805+ t
806+ }
807+ }
808+ }
809+
810+
788811impl < ' tcx > ty:: TyS < ' tcx > {
789812 /// Checks whether values of this type `T` are *moved* or *copied*
790813 /// when referenced -- this amounts to a check for whether `T:
0 commit comments