Skip to content

Commit c7c244e

Browse files
authoredMay 18, 2024
Merge pull request swiftlang#73712 from slavapestov/pack-expansion-closures-part-6
Pack expansion closures, part 6
2 parents d759ec9 + 4aa0008 commit c7c244e

22 files changed

+446
-48
lines changed
 

‎include/swift/AST/Types.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class RecursiveTypeProperties {
182182
/// Contains a PackType.
183183
HasPack = 0x10000,
184184

185-
/// Contains a PackArchetypeType.
185+
/// Contains a PackArchetypeType. Also implies HasPrimaryArchetype.
186186
HasPackArchetype = 0x20000,
187187

188188
Last_Property = HasPackArchetype
@@ -205,7 +205,8 @@ class RecursiveTypeProperties {
205205
bool hasTypeVariable() const { return Bits & HasTypeVariable; }
206206

207207
/// Does a type with these properties structurally contain a primary
208-
/// archetype?
208+
/// or pack archetype? These are the archetypes instantiated from a
209+
/// primary generic environment.
209210
bool hasPrimaryArchetype() const { return Bits & HasPrimaryArchetype; }
210211

211212
/// Does a type with these properties structurally contain an
@@ -695,7 +696,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
695696
return getRecursiveProperties().hasPlaceholder();
696697
}
697698

698-
/// Determine whether the type involves a primary archetype.
699+
/// Determine whether the type involves a PrimaryArchetypeType *or* a
700+
/// PackArchetypeType. These are the archetypes instantiated from a
701+
/// primary generic environment.
699702
bool hasPrimaryArchetype() const {
700703
return getRecursiveProperties().hasPrimaryArchetype();
701704
}

‎include/swift/SIL/SILCloner.h

+5-7
Original file line numberDiff line numberDiff line change
@@ -448,9 +448,9 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
448448

449449
SILLocation remapLocation(SILLocation Loc) { return Loc; }
450450
const SILDebugScope *remapScope(const SILDebugScope *DS) { return DS; }
451+
451452
SILType remapType(SILType Ty) {
452-
// Substitute local archetypes, if we have any.
453-
if (Ty.hasLocalArchetype()) {
453+
if (Functor.SubsMap || Ty.hasLocalArchetype()) {
454454
Ty = Ty.subst(Builder.getModule(), Functor, Functor,
455455
CanGenericSignature());
456456
}
@@ -459,16 +459,14 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
459459
}
460460

461461
CanType remapASTType(CanType ty) {
462-
// Substitute local archetypes, if we have any.
463-
if (ty->hasLocalArchetype())
462+
if (Functor.SubsMap || ty->hasLocalArchetype())
464463
ty = ty.subst(Functor, Functor)->getCanonicalType();
465464

466465
return ty;
467466
}
468467

469468
ProtocolConformanceRef remapConformance(Type Ty, ProtocolConformanceRef C) {
470-
// If we have local archetypes to substitute, do so now.
471-
if (Ty->hasLocalArchetype())
469+
if (Functor.SubsMap || Ty->hasLocalArchetype())
472470
C = C.subst(Ty, Functor, Functor);
473471

474472
return C;
@@ -485,7 +483,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
485483

486484
SubstitutionMap remapSubstitutionMap(SubstitutionMap Subs) {
487485
// If we have local archetypes to substitute, do so now.
488-
if (Subs.hasLocalArchetypes())
486+
if (Subs.hasLocalArchetypes() || Functor.SubsMap)
489487
Subs = Subs.subst(Functor, Functor);
490488

491489
return Subs;

‎include/swift/SIL/SILModule.h

+5
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,11 @@ class SILModule {
477477
/// This should only be the case during parsing or deserialization.
478478
bool hasUnresolvedLocalArchetypeDefinitions();
479479

480+
/// If we added any instructions that reference unresolved local archetypes
481+
/// and then deleted those instructions without resolving those archetypes,
482+
/// we must reclaim those unresolved local archetypes.
483+
void reclaimUnresolvedLocalArchetypeDefinitions();
484+
480485
/// Get a unique index for a struct or class field in layout order.
481486
///
482487
/// Precondition: \p decl must be a non-resilient struct or class.

‎include/swift/SIL/TypeLowering.h

+6
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,12 @@ class TypeConverter {
10731073
GenericSignatureWithCapturedEnvironments
10741074
getGenericSignatureWithCapturedEnvironments(SILDeclRef constant);
10751075

1076+
/// Get the substitution map for calling a constant.
1077+
SubstitutionMap
1078+
getSubstitutionMapWithCapturedEnvironments(SILDeclRef constant,
1079+
const CaptureInfo &captureInfo,
1080+
SubstitutionMap subs);
1081+
10761082
/// Get the generic environment for a constant.
10771083
GenericEnvironment *getConstantGenericEnvironment(SILDeclRef constant);
10781084

‎lib/SIL/IR/SILModule.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -687,13 +687,16 @@ SILValue SILModule::getRootLocalArchetypeDef(CanLocalArchetypeType archetype,
687687
return def;
688688
}
689689

690-
bool SILModule::hasUnresolvedLocalArchetypeDefinitions() {
691-
// Garbage collect dead placeholders first.
690+
void SILModule::reclaimUnresolvedLocalArchetypeDefinitions() {
692691
llvm::DenseMap<LocalArchetypeKey, SILValue> newLocalArchetypeDefs;
693692

694693
for (auto pair : RootLocalArchetypeDefs) {
695694
if (auto *placeholder = dyn_cast<PlaceholderValue>(pair.second)) {
695+
// If a placeholder has no uses, the instruction that introduced it
696+
// was deleted before the local archetype was resolved. Reclaim the
697+
// placeholder so that we don't complain.
696698
if (placeholder->use_empty()) {
699+
assert(numUnresolvedLocalArchetypes > 0);
697700
--numUnresolvedLocalArchetypes;
698701
::delete placeholder;
699702
continue;
@@ -704,7 +707,9 @@ bool SILModule::hasUnresolvedLocalArchetypeDefinitions() {
704707
}
705708

706709
std::swap(newLocalArchetypeDefs, RootLocalArchetypeDefs);
710+
}
707711

712+
bool SILModule::hasUnresolvedLocalArchetypeDefinitions() {
708713
return numUnresolvedLocalArchetypes != 0;
709714
}
710715

‎lib/SIL/IR/TypeLowering.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -4104,12 +4104,27 @@ TypeConverter::getGenericSignatureWithCapturedEnvironments(SILDeclRef c) {
41044104
vd->getDeclContext()->getGenericSignatureOfContext());
41054105
case SILDeclRef::Kind::EntryPoint:
41064106
case SILDeclRef::Kind::AsyncEntryPoint:
4107-
llvm_unreachable("Doesn't have generic signature");
4107+
return GenericSignatureWithCapturedEnvironments();
41084108
}
41094109

41104110
llvm_unreachable("Unhandled SILDeclRefKind in switch.");
41114111
}
41124112

4113+
SubstitutionMap
4114+
TypeConverter::getSubstitutionMapWithCapturedEnvironments(
4115+
SILDeclRef constant, const CaptureInfo &captureInfo,
4116+
SubstitutionMap subs) {
4117+
auto sig = getGenericSignatureWithCapturedEnvironments(constant);
4118+
if (!sig.genericSig) {
4119+
assert(!sig.baseGenericSig);
4120+
assert(sig.capturedEnvs.empty());
4121+
return SubstitutionMap();
4122+
}
4123+
4124+
return buildSubstitutionMapWithCapturedEnvironments(
4125+
subs, sig.genericSig, sig.capturedEnvs);
4126+
}
4127+
41134128
GenericEnvironment *
41144129
TypeConverter::getConstantGenericEnvironment(SILDeclRef c) {
41154130
return getGenericSignatureWithCapturedEnvironments(c)

‎lib/SILGen/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_swift_host_library(swiftSILGen STATIC
2828
SILGenFunction.cpp
2929
SILGenGlobalVariable.cpp
3030
SILGenLazyConformance.cpp
31+
SILGenLocalArchetype.cpp
3132
SILGenLValue.cpp
3233
SILGenPack.cpp
3334
SILGenPattern.cpp

‎lib/SILGen/SILGen.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,9 @@ void SILGenModule::postEmitFunction(SILDeclRef constant,
12601260
SILFunction *F) {
12611261
emitLazyConformancesForFunction(F);
12621262

1263+
auto sig = Types.getGenericSignatureWithCapturedEnvironments(constant);
1264+
recontextualizeCapturedLocalArchetypes(F, sig);
1265+
12631266
assert(!F->isExternalDeclaration() && "did not emit any function body?!");
12641267
LLVM_DEBUG(llvm::dbgs() << "lowered sil:\n";
12651268
F->print(llvm::dbgs()));

‎lib/SILGen/SILGen.h

+5
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
625625
/// Emit a property descriptor for the given storage decl if it needs one.
626626
void tryEmitPropertyDescriptor(AbstractStorageDecl *decl);
627627

628+
/// Replace local archetypes captured from outer AST contexts with primary
629+
/// archetypes.
630+
void recontextualizeCapturedLocalArchetypes(
631+
SILFunction *F, GenericSignatureWithCapturedEnvironments sig);
632+
628633
private:
629634
/// The most recent declaration we considered for emission.
630635
SILDeclRef lastEmittedFunction;

‎lib/SILGen/SILGenApply.cpp

+7-16
Original file line numberDiff line numberDiff line change
@@ -1225,9 +1225,8 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12251225
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant);
12261226
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);
12271227

1228-
if (afd->getDeclContext()->isLocalContext() &&
1229-
!captureInfo.hasGenericParamCaptures())
1230-
subs = SubstitutionMap();
1228+
subs = SGF.SGM.Types.getSubstitutionMapWithCapturedEnvironments(
1229+
constant, captureInfo, subs);
12311230

12321231
// Check whether we have to dispatch to the original implementation of a
12331232
// dynamically_replaceable inside of a dynamic_replacement(for:) function.
@@ -1304,17 +1303,14 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
13041303

13051304
// A directly-called closure can be emitted as a direct call instead of
13061305
// really producing a closure object.
1307-
1308-
auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant);
1309-
13101306
SubstitutionMap subs;
1311-
if (captureInfo.hasGenericParamCaptures())
1312-
subs = SGF.getForwardingSubstitutionMap();
1307+
std::tie(std::ignore, std::ignore, subs)
1308+
= SGF.SGM.Types.getForwardingSubstitutionsForLowering(constant);
13131309

13141310
setCallee(Callee::forDirect(SGF, constant, subs, e));
13151311

13161312
// If the closure requires captures, emit them.
1317-
if (!captureInfo.getCaptures().empty()) {
1313+
if (SGF.SGM.Types.hasLoweredLocalCaptures(constant)) {
13181314
SmallVector<ManagedValue, 4> captures;
13191315
SGF.emitCaptures(e, constant, CaptureEmission::ImmediateApplication,
13201316
captures);
@@ -6712,14 +6708,9 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF,
67126708
subs, loc, true);
67136709
}
67146710

6715-
// The accessor might be a local function that does not capture any
6716-
// generic parameters, in which case we don't want to pass in any
6717-
// substitutions.
67186711
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant);
6719-
if (decl->getDeclContext()->isLocalContext() &&
6720-
!captureInfo.hasGenericParamCaptures()) {
6721-
subs = SubstitutionMap();
6722-
}
6712+
subs = SGF.SGM.Types.getSubstitutionMapWithCapturedEnvironments(
6713+
constant, captureInfo, subs);
67236714

67246715
// If this is a method in a protocol, generate it as a protocol call.
67256716
if (isa<ProtocolDecl>(decl->getDeclContext())) {

‎lib/SILGen/SILGenExpr.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -3028,14 +3028,11 @@ RValueEmitter::emitClosureReference(AbstractClosureExpr *e,
30283028
// Emit the closure body.
30293029
SGF.SGM.emitClosure(e, contextInfo);
30303030

3031-
SubstitutionMap subs;
3032-
if (e->getCaptureInfo().hasGenericParamCaptures())
3033-
subs = SGF.getForwardingSubstitutionMap();
3034-
30353031
// Generate the closure value (if any) for the closure expr's function
30363032
// reference.
30373033
SILLocation loc = e;
3038-
return SGF.emitClosureValue(loc, SILDeclRef(e), contextInfo, subs);
3034+
return SGF.emitClosureValue(loc, SILDeclRef(e), contextInfo,
3035+
SubstitutionMap());
30393036
}
30403037

30413038
RValue RValueEmitter::

‎lib/SILGen/SILGenFunction.cpp

+11-13
Original file line numberDiff line numberDiff line change
@@ -977,28 +977,26 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
977977
// Apply substitutions.
978978
auto pft = constantInfo.SILFnType;
979979

980-
auto closure = *constant.getAnyFunctionRef();
981-
auto *dc = closure.getAsDeclContext()->getParent();
982-
if (dc->isLocalContext() && !loweredCaptureInfo.hasGenericParamCaptures()) {
983-
// If the lowered function type is not polymorphic but we were given
984-
// substitutions, we have a closure in a generic context which does not
985-
// capture generic parameters. Just drop the substitutions.
986-
subs = { };
987-
} else if (closure.getAbstractClosureExpr()) {
980+
if (constant.getAbstractClosureExpr()) {
988981
// If we have a closure expression in generic context, Sema won't give
989982
// us substitutions, so we just use the forwarding substitutions from
990983
// context.
991-
subs = getForwardingSubstitutionMap();
984+
std::tie(std::ignore, std::ignore, subs)
985+
= SGM.Types.getForwardingSubstitutionsForLowering(constant);
986+
} else {
987+
subs = SGM.Types.getSubstitutionMapWithCapturedEnvironments(
988+
constant, loweredCaptureInfo, subs);
992989
}
993990

994-
bool wasSpecialized = false;
995-
if (!subs.empty()) {
991+
if (subs) {
996992
auto specialized =
997993
pft->substGenericArgs(F.getModule(), subs, getTypeExpansionContext());
998994
functionTy = SILType::getPrimitiveObjectType(specialized);
999-
wasSpecialized = true;
1000995
}
1001996

997+
auto closure = *constant.getAnyFunctionRef();
998+
auto *dc = closure.getAsDeclContext()->getParent();
999+
10021000
// If we're in top-level code, we don't need to physically capture script
10031001
// globals, but we still need to mark them as escaping so that DI can flag
10041002
// uninitialized uses.
@@ -1011,7 +1009,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
10111009
typeContext.ExpectedLoweredType->hasErasedIsolation();
10121010

10131011
ManagedValue result;
1014-
if (loweredCaptureInfo.getCaptures().empty() && !wasSpecialized &&
1012+
if (loweredCaptureInfo.getCaptures().empty() && !subs &&
10151013
!hasErasedIsolation) {
10161014
result = ManagedValue::forObjectRValueWithoutOwnership(functionRef);
10171015
} else {

‎lib/SILGen/SILGenLazyConformance.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
//
13+
// This file forces emission of lazily-generated ClangImporter-synthesized
14+
// conformances.
15+
//
16+
//===----------------------------------------------------------------------===//
1217

1318
#include "SILGen.h"
1419
#include "swift/AST/Decl.h"

0 commit comments

Comments
 (0)