diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 772f2976ea358..e311b681ea5e7 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -620,6 +620,18 @@ bool SubstitutionMap::isIdentity() const { SubstitutionMap swift::substOpaqueTypesWithUnderlyingTypes( SubstitutionMap subs, TypeExpansionContext context) { + if (!context.shouldLookThroughOpaqueTypeArchetypes()) + return subs; + + if (!subs.getRecursiveProperties().hasOpaqueArchetype() && + !llvm::any_of(subs.getConformances(), + [&](ProtocolConformanceRef ref) { + return (!ref.isInvalid() && + ref.getType()->hasOpaqueArchetype()); + })) { + return subs; + } + ReplaceOpaqueTypesWithUnderlyingTypes replacer( context.getContext(), context.getResilienceExpansion(), context.isWholeModuleContext()); diff --git a/lib/AST/TypeSubstitution.cpp b/lib/AST/TypeSubstitution.cpp index 3eaf3cd55e5ab..410f633650194 100644 --- a/lib/AST/TypeSubstitution.cpp +++ b/lib/AST/TypeSubstitution.cpp @@ -1089,11 +1089,19 @@ swift::substOpaqueTypesWithUnderlyingTypes(CanType ty, ProtocolConformanceRef swift::substOpaqueTypesWithUnderlyingTypes( ProtocolConformanceRef ref, TypeExpansionContext context) { + if (ref.isInvalid()) + return ref; + + if (!context.shouldLookThroughOpaqueTypeArchetypes() || + !ref.getType()->hasOpaqueArchetype()) + return ref; + ReplaceOpaqueTypesWithUnderlyingTypes replacer( context.getContext(), context.getResilienceExpansion(), context.isWholeModuleContext()); InFlightSubstitution IFS(replacer, replacer, - SubstFlags::SubstituteOpaqueArchetypes); + SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); auto substRef = ref.subst(IFS); diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 96b2960d37fae..0f394856bef32 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3761,8 +3761,8 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF, // Look through any opaque types we're allowed to. if (srcType->hasOpaqueArchetype()) { - std::tie(srcType, conformance) = - IGF.IGM.substOpaqueTypesWithUnderlyingTypes(srcType, conformance); + srcType = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(srcType); + conformance = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(conformance); } // If we don't have concrete conformance information, the type must be diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 848731fe1088e..8b0f5860a55a4 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -583,8 +583,7 @@ std::pair IRGenModule::getLoweredTypeRef(SILType loweredType, CanGenericSignature genericSig, MangledTypeRefRole role) { - auto substTy = - substOpaqueTypesWithUnderlyingTypes(loweredType, genericSig); + auto substTy = substOpaqueTypesWithUnderlyingTypes(loweredType); auto type = substTy.getASTType(); return getTypeRefImpl(*this, type, genericSig, role); } @@ -600,8 +599,8 @@ IRGenModule::emitWitnessTableRefString(CanType type, ProtocolConformanceRef conformance, GenericSignature origGenericSig, bool shouldSetLowBit) { - std::tie(type, conformance) - = substOpaqueTypesWithUnderlyingTypes(type, conformance); + type = substOpaqueTypesWithUnderlyingTypes(type); + conformance = substOpaqueTypesWithUnderlyingTypes(conformance); auto origType = type; auto genericSig = origGenericSig.getCanonicalSignature(); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 736b66bdbd67b..68f7076feb006 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1162,10 +1162,9 @@ class IRGenModule { CanType getRuntimeReifiedType(CanType type); Type substOpaqueTypesWithUnderlyingTypes(Type type); CanType substOpaqueTypesWithUnderlyingTypes(CanType type); - SILType substOpaqueTypesWithUnderlyingTypes(SILType type, CanGenericSignature genericSig); - std::pair - substOpaqueTypesWithUnderlyingTypes(CanType type, - ProtocolConformanceRef conformance); + SILType substOpaqueTypesWithUnderlyingTypes(SILType type); + ProtocolConformanceRef + substOpaqueTypesWithUnderlyingTypes(ProtocolConformanceRef conformance); bool isResilient(NominalTypeDecl *decl, ResilienceExpansion expansion, ClassDecl *asViewedFromRootClass = nullptr); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 3ef16b323c058..92c10012361c4 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -494,12 +494,8 @@ CanType IRGenModule::getRuntimeReifiedType(CanType type) { Type IRGenModule::substOpaqueTypesWithUnderlyingTypes(Type type) { // Substitute away opaque types whose underlying types we're allowed to // assume are constant. - if (type->hasOpaqueArchetype()) { - auto context = getMaximalTypeExpansionContext(); - return swift::substOpaqueTypesWithUnderlyingTypes(type, context); - } - - return type; + auto context = getMaximalTypeExpansionContext(); + return swift::substOpaqueTypesWithUnderlyingTypes(type, context); } CanType IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type) { @@ -507,33 +503,20 @@ CanType IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type) { ->getCanonicalType(); } -SILType IRGenModule::substOpaqueTypesWithUnderlyingTypes( - SILType type, CanGenericSignature genericSig) { +SILType IRGenModule::substOpaqueTypesWithUnderlyingTypes(SILType type) { // Substitute away opaque types whose underlying types we're allowed to // assume are constant. - if (type.getASTType()->hasOpaqueArchetype()) { - auto context = getMaximalTypeExpansionContext(); - return SILType::getPrimitiveType( - swift::substOpaqueTypesWithUnderlyingTypes(type.getASTType(), context), - type.getCategory()); - } - - return type; + auto context = getMaximalTypeExpansionContext(); + return SILType::getPrimitiveType( + swift::substOpaqueTypesWithUnderlyingTypes(type.getASTType(), context), + type.getCategory()); } -std::pair -IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type, - ProtocolConformanceRef conformance) { - // Substitute away opaque types whose underlying types we're allowed to - // assume are constant. - if (type->hasOpaqueArchetype()) { - auto context = getMaximalTypeExpansionContext(); - return std::make_pair( - swift::substOpaqueTypesWithUnderlyingTypes(type, context), - swift::substOpaqueTypesWithUnderlyingTypes(conformance, context)); - } - - return std::make_pair(type, conformance); +ProtocolConformanceRef +IRGenModule::substOpaqueTypesWithUnderlyingTypes( + ProtocolConformanceRef conformance) { + auto context = getMaximalTypeExpansionContext(); + return swift::substOpaqueTypesWithUnderlyingTypes(conformance, context); } diff --git a/lib/IRGen/Outlining.cpp b/lib/IRGen/Outlining.cpp index 96df2cc45c6c8..1b84a1256286a 100644 --- a/lib/IRGen/Outlining.cpp +++ b/lib/IRGen/Outlining.cpp @@ -68,7 +68,7 @@ void OutliningMetadataCollector::collectTypeMetadata(SILType ty) { } // Substitute opaque types if allowed. - ty = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(ty, CanGenericSignature()); + ty = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(ty); collectTypeMetadataForLayout(ty); collectTypeMetadataForDeinit(ty); diff --git a/lib/SIL/IR/SILTypeSubstitution.cpp b/lib/SIL/IR/SILTypeSubstitution.cpp index dab536f664c83..2e4d6a4ddc5d9 100644 --- a/lib/SIL/IR/SILTypeSubstitution.cpp +++ b/lib/SIL/IR/SILTypeSubstitution.cpp @@ -273,9 +273,10 @@ class SILTypeSubstituter : // Substitute the underlying conformance of opaque type archetypes if we // should look through opaque archetypes. if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { - auto substType = IFS.withNewOptions(std::nullopt, [&] { - return selfType.subst(IFS)->getCanonicalType(); - }); + auto substType = IFS.withNewOptions( + SubstFlags::PreservePackExpansionLevel, [&] { + return selfType.subst(IFS)->getCanonicalType(); + }); if (substType->hasOpaqueArchetype()) { substConformance = substOpaqueTypesWithUnderlyingTypes( substConformance, typeExpansionContext); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 3a9ac674a8a45..9f4bf072c2d25 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1047,7 +1047,8 @@ findMissingGenericRequirementForSolutionFix( return env->mapTypeIntoContext(gp); }, - LookUpConformanceInModule()); + LookUpConformanceInModule(), + SubstFlags::PreservePackExpansionLevel); }; type = getTypeInConformanceContext(type); diff --git a/test/Generics/rdar160804717.swift b/test/Generics/rdar160804717.swift new file mode 100644 index 0000000000000..8b8429cc390cf --- /dev/null +++ b/test/Generics/rdar160804717.swift @@ -0,0 +1,27 @@ +// RUN: %target-swift-frontend -emit-ir %s -target %target-swift-5.9-abi-triple +// REQUIRES: objc_interop + +// This used to trigger an infinite loop in conformance substitution +// when emitting the opaque type descriptor in IRGen. + +// rdar://160804717 + +import SwiftUI + +public struct CategorySplitView: View { + let titleKey: LocalizedStringKey + let groups: (repeat each Destination) + + public var body: some View { + TupleView((repeat CategoryGroupSidebar(group: each groups))).navigationTitle(titleKey) + } +} + +public struct CategoryGroupSidebar: View { + let group: Destination + + public var body: some View { + Text("Hi") + } +} +