@@ -3333,6 +3333,7 @@ getArchetypeAndRootOpaqueArchetype(Type maybeOpaqueType) {
33333333OpaqueSubstitutionKind
33343334ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution (
33353335 OpaqueTypeDecl *opaque) const {
3336+ const auto *inContext = getContext ();
33363337 auto inModule = inContext ? inContext->getParentModule ()
33373338 : opaque->getParentModule ();
33383339 return shouldPerformSubstitution (opaque, inModule, contextExpansion);
@@ -3376,12 +3377,11 @@ ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution(
33763377 return OpaqueSubstitutionKind::SubstituteNonResilientModule;
33773378}
33783379
3379- static Type
3380- substOpaqueTypesWithUnderlyingTypes (Type ty, const DeclContext *inContext,
3381- ResilienceExpansion contextExpansion,
3382- bool isWholeModuleContext) {
3380+ static Type substOpaqueTypesWithUnderlyingTypesRec (
3381+ Type ty, const DeclContext *inContext, ResilienceExpansion contextExpansion,
3382+ bool isWholeModuleContext, SmallPtrSetImpl<OpaqueTypeDecl *> &decls) {
33833383 ReplaceOpaqueTypesWithUnderlyingTypes replacer (inContext, contextExpansion,
3384- isWholeModuleContext);
3384+ isWholeModuleContext, decls );
33853385 return ty.subst (replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
33863386}
33873387
@@ -3441,6 +3441,13 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc,
34413441 llvm_unreachable (" invalid subsitution kind" );
34423442}
34433443
3444+ ReplaceOpaqueTypesWithUnderlyingTypes::ReplaceOpaqueTypesWithUnderlyingTypes (
3445+ const DeclContext *inContext, ResilienceExpansion contextExpansion,
3446+ bool isWholeModuleContext, llvm::SmallPtrSetImpl<OpaqueTypeDecl *> &seen)
3447+ : contextExpansion(contextExpansion),
3448+ inContextAndIsWholeModule(inContext, isWholeModuleContext),
3449+ seenDecls(&seen) {}
3450+
34443451Type ReplaceOpaqueTypesWithUnderlyingTypes::
34453452operator ()(SubstitutableType *maybeOpaqueType) const {
34463453 auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype (maybeOpaqueType);
@@ -3468,8 +3475,8 @@ operator()(SubstitutableType *maybeOpaqueType) const {
34683475
34693476 // Check that we are allowed to substitute the underlying type into the
34703477 // context.
3471- auto inContext = this ->inContext ;
3472- auto isContextWholeModule = this ->isContextWholeModule ;
3478+ auto inContext = this ->getContext () ;
3479+ auto isContextWholeModule = this ->isWholeModule () ;
34733480 if (inContext &&
34743481 partialSubstTy.findIf (
34753482 [inContext, substitutionKind, isContextWholeModule](Type t) -> bool {
@@ -3488,18 +3495,39 @@ operator()(SubstitutableType *maybeOpaqueType) const {
34883495
34893496 // If the type changed, but still contains opaque types, recur.
34903497 if (!substTy->isEqual (maybeOpaqueType) && substTy->hasOpaqueArchetype ()) {
3491- return ::substOpaqueTypesWithUnderlyingTypes (
3492- substTy, inContext, contextExpansion, isContextWholeModule);
3498+ if (auto *alreadySeen = this ->seenDecls ) {
3499+ // Detect substitution loops. If we find one, just bounce the original
3500+ // type back to the caller. This substitution will fail at runtime
3501+ // instead.
3502+ if (!alreadySeen->insert (opaqueRoot->getDecl ()).second ) {
3503+ return maybeOpaqueType;
3504+ }
3505+
3506+ auto res = ::substOpaqueTypesWithUnderlyingTypesRec (
3507+ substTy, inContext, contextExpansion, isContextWholeModule,
3508+ *alreadySeen);
3509+ alreadySeen->erase (opaqueRoot->getDecl ());
3510+ return res;
3511+ } else {
3512+ // We're the top of the stack for the recursion check. Allocate a set of
3513+ // opaque result type decls we've already seen for the rest of the check.
3514+ SmallPtrSet<OpaqueTypeDecl *, 8 > seenDecls;
3515+ seenDecls.insert (opaqueRoot->getDecl ());
3516+ return ::substOpaqueTypesWithUnderlyingTypesRec (
3517+ substTy, inContext, contextExpansion, isContextWholeModule,
3518+ seenDecls);
3519+ }
34933520 }
34943521
34953522 return substTy;
34963523}
34973524
3498- static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypes (
3525+ static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypesRec (
34993526 ProtocolConformanceRef ref, Type origType, const DeclContext *inContext,
3500- ResilienceExpansion contextExpansion, bool isWholeModuleContext) {
3527+ ResilienceExpansion contextExpansion, bool isWholeModuleContext,
3528+ SmallPtrSetImpl<OpaqueTypeDecl *> &decls) {
35013529 ReplaceOpaqueTypesWithUnderlyingTypes replacer (inContext, contextExpansion,
3502- isWholeModuleContext);
3530+ isWholeModuleContext, decls );
35033531 return ref.subst (origType, replacer, replacer,
35043532 SubstFlags::SubstituteOpaqueArchetypes);
35053533}
@@ -3527,6 +3555,7 @@ operator()(CanType maybeOpaqueType, Type replacementType,
35273555 // SIL type lowering may have already substituted away the opaque type, in
35283556 // which case we'll end up "substituting" the same type.
35293557 if (maybeOpaqueType->isEqual (replacementType)) {
3558+ const auto *inContext = getContext ();
35303559 assert (inContext && " Need context for already-substituted opaque types" );
35313560 return inContext->getParentModule ()
35323561 ->lookupConformance (replacementType, protocol);
@@ -3556,8 +3585,8 @@ operator()(CanType maybeOpaqueType, Type replacementType,
35563585
35573586 // Check that we are allowed to substitute the underlying type into the
35583587 // context.
3559- auto inContext = this ->inContext ;
3560- auto isContextWholeModule = this ->isContextWholeModule ;
3588+ auto inContext = this ->getContext () ;
3589+ auto isContextWholeModule = this ->isWholeModule () ;
35613590 if (partialSubstTy.findIf (
35623591 [inContext, substitutionKind, isContextWholeModule](Type t) -> bool {
35633592 if (!canSubstituteTypeInto (t, inContext, substitutionKind,
@@ -3580,8 +3609,28 @@ operator()(CanType maybeOpaqueType, Type replacementType,
35803609
35813610 // If the type still contains opaque types, recur.
35823611 if (substTy->hasOpaqueArchetype ()) {
3583- return ::substOpaqueTypesWithUnderlyingTypes (
3584- substRef, substTy, inContext, contextExpansion, isContextWholeModule);
3612+ if (auto *alreadySeen = this ->seenDecls ) {
3613+ // Detect substitution loops. If we find one, just bounce the original
3614+ // type back to the caller. This substitution will fail at runtime
3615+ // instead.
3616+ if (!alreadySeen->insert (opaqueRoot->getDecl ()).second ) {
3617+ return abstractRef;
3618+ }
3619+
3620+ auto res = ::substOpaqueTypesWithUnderlyingTypesRec (
3621+ substRef, substTy, inContext, contextExpansion, isContextWholeModule,
3622+ *alreadySeen);
3623+ alreadySeen->erase (opaqueRoot->getDecl ());
3624+ return res;
3625+ } else {
3626+ // We're the top of the stack for the recursion check. Allocate a set of
3627+ // opaque result type decls we've already seen for the rest of the check.
3628+ SmallPtrSet<OpaqueTypeDecl *, 8 > seenDecls;
3629+ seenDecls.insert (opaqueRoot->getDecl ());
3630+ return ::substOpaqueTypesWithUnderlyingTypesRec (
3631+ substRef, substTy, inContext, contextExpansion, isContextWholeModule,
3632+ seenDecls);
3633+ }
35853634 }
35863635 return substRef;
35873636}
0 commit comments