Skip to content

Pack expansion closures, part 6 #73712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
9 changes: 6 additions & 3 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class RecursiveTypeProperties {
/// Contains a PackType.
HasPack = 0x10000,

/// Contains a PackArchetypeType.
/// Contains a PackArchetypeType. Also implies HasPrimaryArchetype.
HasPackArchetype = 0x20000,

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

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

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

/// Determine whether the type involves a primary archetype.
/// Determine whether the type involves a PrimaryArchetypeType *or* a
/// PackArchetypeType. These are the archetypes instantiated from a
/// primary generic environment.
bool hasPrimaryArchetype() const {
return getRecursiveProperties().hasPrimaryArchetype();
}
Expand Down
12 changes: 5 additions & 7 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,9 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {

SILLocation remapLocation(SILLocation Loc) { return Loc; }
const SILDebugScope *remapScope(const SILDebugScope *DS) { return DS; }

SILType remapType(SILType Ty) {
// Substitute local archetypes, if we have any.
if (Ty.hasLocalArchetype()) {
if (Functor.SubsMap || Ty.hasLocalArchetype()) {
Ty = Ty.subst(Builder.getModule(), Functor, Functor,
CanGenericSignature());
}
Expand All @@ -459,16 +459,14 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
}

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

return ty;
}

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

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

SubstitutionMap remapSubstitutionMap(SubstitutionMap Subs) {
// If we have local archetypes to substitute, do so now.
if (Subs.hasLocalArchetypes())
if (Subs.hasLocalArchetypes() || Functor.SubsMap)
Subs = Subs.subst(Functor, Functor);

return Subs;
Expand Down
5 changes: 5 additions & 0 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,11 @@ class SILModule {
/// This should only be the case during parsing or deserialization.
bool hasUnresolvedLocalArchetypeDefinitions();

/// If we added any instructions that reference unresolved local archetypes
/// and then deleted those instructions without resolving those archetypes,
/// we must reclaim those unresolved local archetypes.
void reclaimUnresolvedLocalArchetypeDefinitions();

/// Get a unique index for a struct or class field in layout order.
///
/// Precondition: \p decl must be a non-resilient struct or class.
Expand Down
6 changes: 6 additions & 0 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,12 @@ class TypeConverter {
GenericSignatureWithCapturedEnvironments
getGenericSignatureWithCapturedEnvironments(SILDeclRef constant);

/// Get the substitution map for calling a constant.
SubstitutionMap
getSubstitutionMapWithCapturedEnvironments(SILDeclRef constant,
const CaptureInfo &captureInfo,
SubstitutionMap subs);

/// Get the generic environment for a constant.
GenericEnvironment *getConstantGenericEnvironment(SILDeclRef constant);

Expand Down
9 changes: 7 additions & 2 deletions lib/SIL/IR/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -687,13 +687,16 @@ SILValue SILModule::getRootLocalArchetypeDef(CanLocalArchetypeType archetype,
return def;
}

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

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

std::swap(newLocalArchetypeDefs, RootLocalArchetypeDefs);
}

bool SILModule::hasUnresolvedLocalArchetypeDefinitions() {
return numUnresolvedLocalArchetypes != 0;
}

Expand Down
17 changes: 16 additions & 1 deletion lib/SIL/IR/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4104,12 +4104,27 @@ TypeConverter::getGenericSignatureWithCapturedEnvironments(SILDeclRef c) {
vd->getDeclContext()->getGenericSignatureOfContext());
case SILDeclRef::Kind::EntryPoint:
case SILDeclRef::Kind::AsyncEntryPoint:
llvm_unreachable("Doesn't have generic signature");
return GenericSignatureWithCapturedEnvironments();
}

llvm_unreachable("Unhandled SILDeclRefKind in switch.");
}

SubstitutionMap
TypeConverter::getSubstitutionMapWithCapturedEnvironments(
SILDeclRef constant, const CaptureInfo &captureInfo,
SubstitutionMap subs) {
auto sig = getGenericSignatureWithCapturedEnvironments(constant);
if (!sig.genericSig) {
assert(!sig.baseGenericSig);
assert(sig.capturedEnvs.empty());
return SubstitutionMap();
}

return buildSubstitutionMapWithCapturedEnvironments(
subs, sig.genericSig, sig.capturedEnvs);
}

GenericEnvironment *
TypeConverter::getConstantGenericEnvironment(SILDeclRef c) {
return getGenericSignatureWithCapturedEnvironments(c)
Expand Down
1 change: 1 addition & 0 deletions lib/SILGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_swift_host_library(swiftSILGen STATIC
SILGenFunction.cpp
SILGenGlobalVariable.cpp
SILGenLazyConformance.cpp
SILGenLocalArchetype.cpp
SILGenLValue.cpp
SILGenPack.cpp
SILGenPattern.cpp
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,9 @@ void SILGenModule::postEmitFunction(SILDeclRef constant,
SILFunction *F) {
emitLazyConformancesForFunction(F);

auto sig = Types.getGenericSignatureWithCapturedEnvironments(constant);
recontextualizeCapturedLocalArchetypes(F, sig);

assert(!F->isExternalDeclaration() && "did not emit any function body?!");
LLVM_DEBUG(llvm::dbgs() << "lowered sil:\n";
F->print(llvm::dbgs()));
Expand Down
5 changes: 5 additions & 0 deletions lib/SILGen/SILGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
/// Emit a property descriptor for the given storage decl if it needs one.
void tryEmitPropertyDescriptor(AbstractStorageDecl *decl);

/// Replace local archetypes captured from outer AST contexts with primary
/// archetypes.
void recontextualizeCapturedLocalArchetypes(
SILFunction *F, GenericSignatureWithCapturedEnvironments sig);

private:
/// The most recent declaration we considered for emission.
SILDeclRef lastEmittedFunction;
Expand Down
23 changes: 7 additions & 16 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1225,9 +1225,8 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant);
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);

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

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

// A directly-called closure can be emitted as a direct call instead of
// really producing a closure object.

auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant);

SubstitutionMap subs;
if (captureInfo.hasGenericParamCaptures())
subs = SGF.getForwardingSubstitutionMap();
std::tie(std::ignore, std::ignore, subs)
= SGF.SGM.Types.getForwardingSubstitutionsForLowering(constant);

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

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

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

// If this is a method in a protocol, generate it as a protocol call.
if (isa<ProtocolDecl>(decl->getDeclContext())) {
Expand Down
7 changes: 2 additions & 5 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3028,14 +3028,11 @@ RValueEmitter::emitClosureReference(AbstractClosureExpr *e,
// Emit the closure body.
SGF.SGM.emitClosure(e, contextInfo);

SubstitutionMap subs;
if (e->getCaptureInfo().hasGenericParamCaptures())
subs = SGF.getForwardingSubstitutionMap();

// Generate the closure value (if any) for the closure expr's function
// reference.
SILLocation loc = e;
return SGF.emitClosureValue(loc, SILDeclRef(e), contextInfo, subs);
return SGF.emitClosureValue(loc, SILDeclRef(e), contextInfo,
SubstitutionMap());
}

RValue RValueEmitter::
Expand Down
24 changes: 11 additions & 13 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,28 +977,26 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
// Apply substitutions.
auto pft = constantInfo.SILFnType;

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

bool wasSpecialized = false;
if (!subs.empty()) {
if (subs) {
auto specialized =
pft->substGenericArgs(F.getModule(), subs, getTypeExpansionContext());
functionTy = SILType::getPrimitiveObjectType(specialized);
wasSpecialized = true;
}

auto closure = *constant.getAnyFunctionRef();
auto *dc = closure.getAsDeclContext()->getParent();

// If we're in top-level code, we don't need to physically capture script
// globals, but we still need to mark them as escaping so that DI can flag
// uninitialized uses.
Expand All @@ -1011,7 +1009,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
typeContext.ExpectedLoweredType->hasErasedIsolation();

ManagedValue result;
if (loweredCaptureInfo.getCaptures().empty() && !wasSpecialized &&
if (loweredCaptureInfo.getCaptures().empty() && !subs &&
!hasErasedIsolation) {
result = ManagedValue::forObjectRValueWithoutOwnership(functionRef);
} else {
Expand Down
5 changes: 5 additions & 0 deletions lib/SILGen/SILGenLazyConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file forces emission of lazily-generated ClangImporter-synthesized
// conformances.
//
//===----------------------------------------------------------------------===//

#include "SILGen.h"
#include "swift/AST/Decl.h"
Expand Down
Loading