Skip to content

Commit aa376a4

Browse files
Merge pull request #24224 from aschwaighofer/specialize_opaque_result_types
Add a pass to specialize opaque type archetypes.
2 parents 85a3098 + 0e313c7 commit aa376a4

24 files changed

+1407
-96
lines changed

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,6 @@ class ProtocolConformanceRef {
109109
LookupConformanceFn conformances,
110110
SubstOptions options = None) const;
111111

112-
/// Replace opaque types in the conforming type with their underlying types,
113-
/// and resolve opaque conformances to their underlying conformances.
114-
ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypes(Type origType) const;
115-
116112
/// Given a dependent type (expressed in terms of this conformance's
117113
/// protocol), follow it from the conforming type.
118114
Type getAssociatedType(Type origType, Type dependentType,

include/swift/AST/SubstitutionMap.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,6 @@ class SubstitutionMap {
175175
LookupConformanceFn conformances,
176176
SubstOptions options = None) const;
177177

178-
/// Replace opaque types in the replacement types in the map with their
179-
/// underlying types. Does not change keys.
180-
SubstitutionMap substOpaqueTypesWithUnderlyingTypes() const;
181-
182178
/// Create a substitution map for a protocol conformance.
183179
static SubstitutionMap
184180
getProtocolSubstitutions(ProtocolDecl *protocol,

include/swift/AST/Type.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,6 @@ class Type {
316316
/// Replace references to substitutable types with error types.
317317
Type substDependentTypesWithErrorTypes() const;
318318

319-
/// Replace opaque types with their underlying types when visible at the given
320-
/// resilience expansion.
321-
Type substOpaqueTypesWithUnderlyingTypes() const;
322-
323319
bool isPrivateStdlibType(bool treatNonBuiltinProtocolsAsPublic = true) const;
324320

325321
void dump() const;

include/swift/AST/Types.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4092,7 +4092,8 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
40924092
/// std::error_code. This is only meant to be used in assertions. When
40934093
/// assertions are disabled, this just returns true.
40944094
ABICompatibilityCheckResult
4095-
isABICompatibleWith(CanSILFunctionType other) const;
4095+
isABICompatibleWith(CanSILFunctionType other,
4096+
SILFunction *context = nullptr) const;
40964097

40974098
CanSILFunctionType substGenericArgs(SILModule &silModule,
40984099
SubstitutionMap subs);
@@ -4827,17 +4828,25 @@ END_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType)
48274828
/// to their underlying types.
48284829
class ReplaceOpaqueTypesWithUnderlyingTypes {
48294830
public:
4830-
ReplaceOpaqueTypesWithUnderlyingTypes() {}
4831-
4831+
SILFunction *context;
4832+
ReplaceOpaqueTypesWithUnderlyingTypes(
4833+
SILFunction *context)
4834+
: context(context) {}
4835+
48324836
/// TypeSubstitutionFn
48334837
Type operator()(SubstitutableType *maybeOpaqueType) const;
4834-
4838+
48354839
/// LookupConformanceFn
48364840
Optional<ProtocolConformanceRef> operator()(CanType maybeOpaqueType,
48374841
Type replacementType,
48384842
ProtocolDecl *protocol) const;
4843+
4844+
bool shouldPerformSubstitution(OpaqueTypeDecl *opaque) const;
4845+
4846+
static bool shouldPerformSubstitution(OpaqueTypeDecl *opaque,
4847+
SILFunction *context);
48394848
};
4840-
4849+
48414850
/// An archetype that represents the dynamic type of an opened existential.
48424851
class OpenedArchetypeType final : public ArchetypeType,
48434852
private ArchetypeTrailingObjects<OpenedArchetypeType>

include/swift/SIL/SILCloner.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
121121
/// after mapping all blocks.
122122
void cloneReachableBlocks(SILBasicBlock *startBB,
123123
ArrayRef<SILBasicBlock *> exitBlocks,
124-
SILBasicBlock *insertAfterBB = nullptr);
124+
SILBasicBlock *insertAfterBB = nullptr,
125+
bool havePrepopulatedFunctionArgs = false);
125126

126127
/// Clone all blocks in this function and all instructions in those
127128
/// blocks.
@@ -579,13 +580,15 @@ void SILCloner<ImplClass>::visitInstructionsInBlock(SILBasicBlock* BB) {
579580
template <typename ImplClass>
580581
void SILCloner<ImplClass>::cloneReachableBlocks(
581582
SILBasicBlock *startBB, ArrayRef<SILBasicBlock *> exitBlocks,
582-
SILBasicBlock *insertAfterBB) {
583+
SILBasicBlock *insertAfterBB,
584+
bool havePrepopulatedFunctionArgs) {
583585

584586
SILFunction *F = startBB->getParent();
585587
assert(F == &Builder.getFunction()
586588
&& "cannot clone region across functions.");
587589
assert(BBMap.empty() && "This API does not allow clients to map blocks.");
588-
assert(ValueMap.empty() && "Stale ValueMap.");
590+
assert((havePrepopulatedFunctionArgs || ValueMap.empty()) &&
591+
"Stale ValueMap.");
589592

590593
auto *clonedStartBB = insertAfterBB ? F->createBasicBlockAfter(insertAfterBB)
591594
: F->createBasicBlock();

include/swift/SIL/SILType.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,10 +444,10 @@ class SILType {
444444
///
445445
/// If the replacement types are generic, you must push a generic context
446446
/// first.
447-
SILType subst(SILModule &silModule,
448-
TypeSubstitutionFn subs,
447+
SILType subst(SILModule &silModule, TypeSubstitutionFn subs,
449448
LookupConformanceFn conformances,
450-
CanGenericSignature genericSig=CanGenericSignature()) const;
449+
CanGenericSignature genericSig = CanGenericSignature(),
450+
bool shouldSubstituteOpaqueArchetypes = false) const;
451451

452452
SILType subst(SILModule &silModule, SubstitutionMap subs) const;
453453

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ PASS(NoReturnFolding, "noreturn-folding",
226226
"Prune Control Flow at No-Return Calls Using SIL unreachable")
227227
PASS(ObjectOutliner, "object-outliner",
228228
"Outlining of Global Objects")
229+
PASS(OpaqueArchetypeSpecializer, "opaque-archetype-specializer",
230+
"Opaque archetype specializer")
229231
PASS(Outliner, "outliner",
230232
"Function Outlining Optimization")
231233
PASS(OwnershipModelEliminator, "ownership-model-eliminator",

lib/AST/ProtocolConformance.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,6 @@ ProtocolConformanceRef::subst(Type origType,
141141
llvm_unreachable("Invalid conformance substitution");
142142
}
143143

144-
ProtocolConformanceRef
145-
ProtocolConformanceRef::substOpaqueTypesWithUnderlyingTypes(Type origType) const {
146-
ReplaceOpaqueTypesWithUnderlyingTypes replacer;
147-
return subst(origType, replacer, replacer,
148-
SubstFlags::SubstituteOpaqueArchetypes);
149-
}
150-
151144
Type
152145
ProtocolConformanceRef::getTypeWitnessByName(Type type,
153146
ProtocolConformanceRef conformance,

lib/AST/SubstitutionMap.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -492,13 +492,6 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs,
492492
return SubstitutionMap(genericSig, newSubs, newConformances);
493493
}
494494

495-
SubstitutionMap
496-
SubstitutionMap::substOpaqueTypesWithUnderlyingTypes()
497-
const {
498-
ReplaceOpaqueTypesWithUnderlyingTypes replacer;
499-
return subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
500-
}
501-
502495
SubstitutionMap
503496
SubstitutionMap::getProtocolSubstitutions(ProtocolDecl *protocol,
504497
Type selfType,

lib/AST/Type.cpp

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,84 +2472,101 @@ getArchetypeAndRootOpaqueArchetype(Type maybeOpaqueType) {
24722472
return std::make_pair(archetype, opaqueRoot);
24732473
}
24742474

2475-
Type ReplaceOpaqueTypesWithUnderlyingTypes::operator()(
2476-
SubstitutableType *maybeOpaqueType) const {
2475+
bool ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution(
2476+
OpaqueTypeDecl *opaque) const {
2477+
return shouldPerformSubstitution(opaque, context);
2478+
}
2479+
2480+
static Type substOpaqueTypesWithUnderlyingTypes(
2481+
Type ty, SILFunction *context) {
2482+
ReplaceOpaqueTypesWithUnderlyingTypes replacer(context);
2483+
return ty.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
2484+
}
2485+
2486+
Type ReplaceOpaqueTypesWithUnderlyingTypes::
2487+
operator()(SubstitutableType *maybeOpaqueType) const {
24772488
auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype(maybeOpaqueType);
24782489
if (!archetypeAndRoot)
24792490
return maybeOpaqueType;
2480-
2491+
24812492
auto archetype = archetypeAndRoot->first;
24822493
auto opaqueRoot = archetypeAndRoot->second;
2494+
2495+
if (!shouldPerformSubstitution(opaqueRoot->getDecl())) {
2496+
return maybeOpaqueType;
2497+
}
2498+
24832499
auto subs = opaqueRoot->getDecl()->getUnderlyingTypeSubstitutions();
24842500
// TODO: Check the resilience expansion, and handle opaque types with
24852501
// unknown underlying types. For now, all opaque types are always
24862502
// fragile.
24872503
assert(subs.hasValue() && "resilient opaque types not yet supported");
2488-
2504+
24892505
// Apply the underlying type substitutions to the interface type of the
24902506
// archetype in question. This will map the inner generic signature of the
24912507
// opaque type to its outer signature.
24922508
auto partialSubstTy = archetype->getInterfaceType().subst(*subs);
24932509
// Then apply the substitutions from the root opaque archetype, to specialize
24942510
// for its type arguments.
24952511
auto substTy = partialSubstTy.subst(opaqueRoot->getSubstitutions());
2496-
2512+
24972513
// If the type still contains opaque types, recur.
24982514
if (substTy->hasOpaqueArchetype()) {
2499-
return substTy.substOpaqueTypesWithUnderlyingTypes();
2515+
return substOpaqueTypesWithUnderlyingTypes(substTy, context);
25002516
}
25012517
return substTy;
25022518
}
25032519

2504-
Optional<ProtocolConformanceRef>
2505-
ReplaceOpaqueTypesWithUnderlyingTypes::operator()(CanType maybeOpaqueType,
2506-
Type replacementType,
2507-
ProtocolDecl *protocol) const {
2520+
static ProtocolConformanceRef
2521+
substOpaqueTypesWithUnderlyingTypes(ProtocolConformanceRef ref, Type origType,
2522+
SILFunction *context) {
2523+
ReplaceOpaqueTypesWithUnderlyingTypes replacer(context);
2524+
return ref.subst(origType, replacer, replacer,
2525+
SubstFlags::SubstituteOpaqueArchetypes);
2526+
}
2527+
2528+
Optional<ProtocolConformanceRef> ReplaceOpaqueTypesWithUnderlyingTypes::
2529+
operator()(CanType maybeOpaqueType, Type replacementType,
2530+
ProtocolDecl *protocol) const {
25082531
auto abstractRef = ProtocolConformanceRef(protocol);
25092532

25102533
auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype(maybeOpaqueType);
25112534
if (!archetypeAndRoot) {
2512-
assert(maybeOpaqueType->isTypeParameter()
2513-
|| maybeOpaqueType->is<ArchetypeType>());
2535+
assert(maybeOpaqueType->isTypeParameter() ||
2536+
maybeOpaqueType->is<ArchetypeType>());
25142537
return abstractRef;
25152538
}
2516-
2539+
25172540
auto archetype = archetypeAndRoot->first;
25182541
auto opaqueRoot = archetypeAndRoot->second;
2542+
2543+
if (!shouldPerformSubstitution(opaqueRoot->getDecl())) {
2544+
return abstractRef;
2545+
}
2546+
25192547
auto subs = opaqueRoot->getDecl()->getUnderlyingTypeSubstitutions();
25202548
assert(subs.hasValue());
25212549

25222550
// Apply the underlying type substitutions to the interface type of the
25232551
// archetype in question. This will map the inner generic signature of the
25242552
// opaque type to its outer signature.
25252553
auto partialSubstTy = archetype->getInterfaceType().subst(*subs);
2526-
auto partialSubstRef = abstractRef.subst(archetype->getInterfaceType(),
2527-
*subs);
2528-
2554+
auto partialSubstRef =
2555+
abstractRef.subst(archetype->getInterfaceType(), *subs);
2556+
25292557
// Then apply the substitutions from the root opaque archetype, to specialize
25302558
// for its type arguments.
25312559
auto substTy = partialSubstTy.subst(opaqueRoot->getSubstitutions());
2532-
auto substRef = partialSubstRef.subst(partialSubstTy,
2533-
opaqueRoot->getSubstitutions());
2534-
2560+
auto substRef =
2561+
partialSubstRef.subst(partialSubstTy, opaqueRoot->getSubstitutions());
2562+
25352563
// If the type still contains opaque types, recur.
25362564
if (substTy->hasOpaqueArchetype()) {
2537-
return substRef.substOpaqueTypesWithUnderlyingTypes(substTy);
2565+
return substOpaqueTypesWithUnderlyingTypes(substRef, substTy, context);
25382566
}
25392567
return substRef;
25402568
}
25412569

2542-
Type Type::substOpaqueTypesWithUnderlyingTypes() const {
2543-
ReplaceOpaqueTypesWithUnderlyingTypes replacer;
2544-
return subst(replacer, replacer,
2545-
SubstFlags::SubstituteOpaqueArchetypes
2546-
// TODO(opaque): Currently lowered types always get opaque types
2547-
// substituted out of them. When we support opaque type resilience
2548-
// this won't be true anymore and we'll need to handle
2549-
// opaque type substitution in SILType::subst.
2550-
| SubstFlags::AllowLoweredTypes);
2551-
}
2552-
25532570
CanNestedArchetypeType NestedArchetypeType::getNew(
25542571
const ASTContext &Ctx,
25552572
ArchetypeType *Parent,

0 commit comments

Comments
 (0)