@@ -3381,6 +3381,7 @@ getArchetypeAndRootOpaqueArchetype(Type maybeOpaqueType) {
33813381OpaqueSubstitutionKind
33823382ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution (
33833383 OpaqueTypeDecl *opaque) const {
3384+ const auto *inContext = getContext ();
33843385 auto inModule = inContext ? inContext->getParentModule ()
33853386 : opaque->getParentModule ();
33863387 return shouldPerformSubstitution (opaque, inModule, contextExpansion);
@@ -3424,12 +3425,11 @@ ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution(
34243425 return OpaqueSubstitutionKind::SubstituteNonResilientModule;
34253426}
34263427
3427- static Type
3428- substOpaqueTypesWithUnderlyingTypes (Type ty, const DeclContext *inContext,
3429- ResilienceExpansion contextExpansion,
3430- bool isWholeModuleContext) {
3428+ static Type substOpaqueTypesWithUnderlyingTypesRec (
3429+ Type ty, const DeclContext *inContext, ResilienceExpansion contextExpansion,
3430+ bool isWholeModuleContext, SmallPtrSetImpl<OpaqueTypeDecl *> &decls) {
34313431 ReplaceOpaqueTypesWithUnderlyingTypes replacer (inContext, contextExpansion,
3432- isWholeModuleContext);
3432+ isWholeModuleContext, decls );
34333433 return ty.subst (replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
34343434}
34353435
@@ -3489,6 +3489,13 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc,
34893489 llvm_unreachable (" invalid subsitution kind" );
34903490}
34913491
3492+ ReplaceOpaqueTypesWithUnderlyingTypes::ReplaceOpaqueTypesWithUnderlyingTypes (
3493+ const DeclContext *inContext, ResilienceExpansion contextExpansion,
3494+ bool isWholeModuleContext, llvm::SmallPtrSetImpl<OpaqueTypeDecl *> &seen)
3495+ : contextExpansion(contextExpansion),
3496+ inContextAndIsWholeModule(inContext, isWholeModuleContext),
3497+ seenDecls(&seen) {}
3498+
34923499Type ReplaceOpaqueTypesWithUnderlyingTypes::
34933500operator ()(SubstitutableType *maybeOpaqueType) const {
34943501 auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype (maybeOpaqueType);
@@ -3516,8 +3523,8 @@ operator()(SubstitutableType *maybeOpaqueType) const {
35163523
35173524 // Check that we are allowed to substitute the underlying type into the
35183525 // context.
3519- auto inContext = this ->inContext ;
3520- auto isContextWholeModule = this ->isContextWholeModule ;
3526+ auto inContext = this ->getContext () ;
3527+ auto isContextWholeModule = this ->isWholeModule () ;
35213528 if (inContext &&
35223529 partialSubstTy.findIf (
35233530 [inContext, substitutionKind, isContextWholeModule](Type t) -> bool {
@@ -3536,18 +3543,39 @@ operator()(SubstitutableType *maybeOpaqueType) const {
35363543
35373544 // If the type changed, but still contains opaque types, recur.
35383545 if (!substTy->isEqual (maybeOpaqueType) && substTy->hasOpaqueArchetype ()) {
3539- return ::substOpaqueTypesWithUnderlyingTypes (
3540- substTy, inContext, contextExpansion, isContextWholeModule);
3546+ if (auto *alreadySeen = this ->seenDecls ) {
3547+ // Detect substitution loops. If we find one, just bounce the original
3548+ // type back to the caller. This substitution will fail at runtime
3549+ // instead.
3550+ if (!alreadySeen->insert (opaqueRoot->getDecl ()).second ) {
3551+ return maybeOpaqueType;
3552+ }
3553+
3554+ auto res = ::substOpaqueTypesWithUnderlyingTypesRec (
3555+ substTy, inContext, contextExpansion, isContextWholeModule,
3556+ *alreadySeen);
3557+ alreadySeen->erase (opaqueRoot->getDecl ());
3558+ return res;
3559+ } else {
3560+ // We're the top of the stack for the recursion check. Allocate a set of
3561+ // opaque result type decls we've already seen for the rest of the check.
3562+ SmallPtrSet<OpaqueTypeDecl *, 8 > seenDecls;
3563+ seenDecls.insert (opaqueRoot->getDecl ());
3564+ return ::substOpaqueTypesWithUnderlyingTypesRec (
3565+ substTy, inContext, contextExpansion, isContextWholeModule,
3566+ seenDecls);
3567+ }
35413568 }
35423569
35433570 return substTy;
35443571}
35453572
3546- static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypes (
3573+ static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypesRec (
35473574 ProtocolConformanceRef ref, Type origType, const DeclContext *inContext,
3548- ResilienceExpansion contextExpansion, bool isWholeModuleContext) {
3575+ ResilienceExpansion contextExpansion, bool isWholeModuleContext,
3576+ SmallPtrSetImpl<OpaqueTypeDecl *> &decls) {
35493577 ReplaceOpaqueTypesWithUnderlyingTypes replacer (inContext, contextExpansion,
3550- isWholeModuleContext);
3578+ isWholeModuleContext, decls );
35513579 return ref.subst (origType, replacer, replacer,
35523580 SubstFlags::SubstituteOpaqueArchetypes);
35533581}
@@ -3575,6 +3603,7 @@ operator()(CanType maybeOpaqueType, Type replacementType,
35753603 // SIL type lowering may have already substituted away the opaque type, in
35763604 // which case we'll end up "substituting" the same type.
35773605 if (maybeOpaqueType->isEqual (replacementType)) {
3606+ const auto *inContext = getContext ();
35783607 assert (inContext && " Need context for already-substituted opaque types" );
35793608 return inContext->getParentModule ()
35803609 ->lookupConformance (replacementType, protocol);
@@ -3604,8 +3633,8 @@ operator()(CanType maybeOpaqueType, Type replacementType,
36043633
36053634 // Check that we are allowed to substitute the underlying type into the
36063635 // context.
3607- auto inContext = this ->inContext ;
3608- auto isContextWholeModule = this ->isContextWholeModule ;
3636+ auto inContext = this ->getContext () ;
3637+ auto isContextWholeModule = this ->isWholeModule () ;
36093638 if (partialSubstTy.findIf (
36103639 [inContext, substitutionKind, isContextWholeModule](Type t) -> bool {
36113640 if (!canSubstituteTypeInto (t, inContext, substitutionKind,
@@ -3628,8 +3657,28 @@ operator()(CanType maybeOpaqueType, Type replacementType,
36283657
36293658 // If the type still contains opaque types, recur.
36303659 if (substTy->hasOpaqueArchetype ()) {
3631- return ::substOpaqueTypesWithUnderlyingTypes (
3632- substRef, substTy, inContext, contextExpansion, isContextWholeModule);
3660+ if (auto *alreadySeen = this ->seenDecls ) {
3661+ // Detect substitution loops. If we find one, just bounce the original
3662+ // type back to the caller. This substitution will fail at runtime
3663+ // instead.
3664+ if (!alreadySeen->insert (opaqueRoot->getDecl ()).second ) {
3665+ return abstractRef;
3666+ }
3667+
3668+ auto res = ::substOpaqueTypesWithUnderlyingTypesRec (
3669+ substRef, substTy, inContext, contextExpansion, isContextWholeModule,
3670+ *alreadySeen);
3671+ alreadySeen->erase (opaqueRoot->getDecl ());
3672+ return res;
3673+ } else {
3674+ // We're the top of the stack for the recursion check. Allocate a set of
3675+ // opaque result type decls we've already seen for the rest of the check.
3676+ SmallPtrSet<OpaqueTypeDecl *, 8 > seenDecls;
3677+ seenDecls.insert (opaqueRoot->getDecl ());
3678+ return ::substOpaqueTypesWithUnderlyingTypesRec (
3679+ substRef, substTy, inContext, contextExpansion, isContextWholeModule,
3680+ seenDecls);
3681+ }
36333682 }
36343683 return substRef;
36353684}
0 commit comments