Skip to content

Commit 5c2cd18

Browse files
committed
Teach SILGen to try to peephole a function conversion into the emission of
a closure expression, then don't actually do it. The long term plan is to actually do this, which should just be a matter of taking some of the code out of reabstraction thunk emission and using it in prolog/epilog/return emission. In the short term, the goal is just to get the conversion information down to the closure emitter so that we can see that we're erasing into an `@isolated(any)` type and then actually erase the closure's isolation properly instead of relying on type-based erasure, which can't handle parameter/capture isolation correctly.
1 parent 83850ef commit 5c2cd18

19 files changed

+569
-343
lines changed

include/swift/SIL/TypeLowering.h

+23-19
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,21 @@ enum class CaptureKind {
695695
Immutable
696696
};
697697

698+
/// Interesting information about the lowering of a function type.
699+
struct FunctionTypeInfo {
700+
/// The abstraction pattern that the type has been lowered under.
701+
AbstractionPattern OrigType;
702+
703+
/// The formal type that the function is being used as. When this
704+
/// type is used to specify a type context (e.g. as the contextual
705+
/// type info of a closure; see `TypeConverter::getClosureTypeInfo`),
706+
/// this may be a subtype of the closure's formal type.
707+
CanAnyFunctionType FormalType;
708+
709+
/// The expected lowered type.
710+
CanSILFunctionType ExpectedLoweredType;
711+
};
712+
698713
/// TypeConverter - helper class for creating and managing TypeLowerings.
699714
class TypeConverter {
700715
friend class TypeLowering;
@@ -825,8 +840,7 @@ class TypeConverter {
825840
/// Second element is a ResilienceExpansion.
826841
llvm::DenseMap<std::pair<SILType, unsigned>, unsigned> TypeFields;
827842

828-
llvm::DenseMap<AbstractClosureExpr *, std::optional<AbstractionPattern>>
829-
ClosureAbstractionPatterns;
843+
llvm::DenseMap<AbstractClosureExpr *, FunctionTypeInfo> ClosureInfos;
830844
llvm::DenseMap<SILDeclRef, TypeExpansionContext>
831845
CaptureTypeExpansionContexts;
832846

@@ -1226,27 +1240,17 @@ class TypeConverter {
12261240
SILType enumType,
12271241
EnumElementDecl *elt);
12281242

1229-
/// Get the preferred abstraction pattern, if any, by which to lower a
1230-
/// declaration.
1231-
///
1232-
/// This can be set using \c setAbstractionPattern , but only before
1233-
/// the abstraction pattern is queried using this function. Once the
1234-
/// abstraction pattern has been asked for, it may not be changed.
1235-
std::optional<AbstractionPattern>
1236-
getConstantAbstractionPattern(SILDeclRef constant);
12371243
TypeExpansionContext getCaptureTypeExpansionContext(SILDeclRef constant);
1238-
1239-
/// Set the preferred abstraction pattern for a closure.
1240-
///
1241-
/// The abstraction pattern can only be set before any calls to
1242-
/// \c getConstantAbstractionPattern on the same closure. It may not be
1243-
/// changed once it has been read.
1244-
void setAbstractionPattern(AbstractClosureExpr *closure,
1245-
AbstractionPattern pattern);
1246-
12471244
void setCaptureTypeExpansionContext(SILDeclRef constant,
12481245
SILModule &M);
12491246

1247+
const FunctionTypeInfo *getClosureTypeInfo(SILDeclRef constant);
1248+
const FunctionTypeInfo &getClosureTypeInfo(AbstractClosureExpr *closure);
1249+
1250+
void withClosureTypeInfo(AbstractClosureExpr *closure,
1251+
const FunctionTypeInfo &closureInfo,
1252+
llvm::function_ref<void()> operation);
1253+
12501254
void setLoweredAddresses();
12511255

12521256
private:

lib/SIL/IR/SILFunctionType.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -3980,11 +3980,11 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant(
39803980
auto proto = constant.getDecl()->getDeclContext()->getSelfProtocolDecl();
39813981
witnessMethodConformance = ProtocolConformanceRef(proto);
39823982
}
3983-
3983+
39843984
// Does this constant have a preferred abstraction pattern set?
39853985
AbstractionPattern origType = [&]{
3986-
if (auto abstraction = TC.getConstantAbstractionPattern(constant)) {
3987-
return *abstraction;
3986+
if (auto closureInfo = TC.getClosureTypeInfo(constant)) {
3987+
return closureInfo->OrigType;
39883988
} else {
39893989
return AbstractionPattern(origLoweredInterfaceType);
39903990
}
@@ -4036,6 +4036,9 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant(
40364036
CanSILFunctionType TypeConverter::getUncachedSILFunctionTypeForConstant(
40374037
TypeExpansionContext context, SILDeclRef constant,
40384038
CanAnyFunctionType origInterfaceType) {
4039+
// This entrypoint is only used for computing a type for dynamic dispatch.
4040+
assert(!constant.getAbstractClosureExpr());
4041+
40394042
auto bridgedTypes = getLoweredFormalTypes(constant, origInterfaceType);
40404043
return ::getUncachedSILFunctionTypeForConstant(*this, context, constant,
40414044
bridgedTypes);
@@ -4168,7 +4171,6 @@ getLoweredResultIndices(const SILFunctionType *functionType,
41684171
numResults, resultIndices);
41694172
}
41704173

4171-
41724174
const SILConstantInfo &
41734175
TypeConverter::getConstantInfo(TypeExpansionContext expansion,
41744176
SILDeclRef constant) {

lib/SIL/IR/TypeLowering.cpp

+32-18
Original file line numberDiff line numberDiff line change
@@ -4784,15 +4784,40 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(
47844784
return boxTy;
47854785
}
47864786

4787-
std::optional<AbstractionPattern>
4788-
TypeConverter::getConstantAbstractionPattern(SILDeclRef constant) {
4787+
const FunctionTypeInfo *TypeConverter::getClosureTypeInfo(SILDeclRef constant) {
47894788
if (auto closure = constant.getAbstractClosureExpr()) {
4790-
// Using operator[] here creates an entry in the map if one doesn't exist
4791-
// yet, marking the fact that the lack of abstraction pattern has been
4792-
// established and cannot be overridden by `setAbstractionPattern` later.
4793-
return ClosureAbstractionPatterns[closure];
4789+
return &getClosureTypeInfo(closure);
47944790
}
4795-
return std::nullopt;
4791+
return nullptr;
4792+
}
4793+
4794+
const FunctionTypeInfo &
4795+
TypeConverter::getClosureTypeInfo(AbstractClosureExpr *closure) {
4796+
auto it = ClosureInfos.find(closure);
4797+
assert(it != ClosureInfos.end() &&
4798+
"looking for closure info for closure without any set");
4799+
return it->second;
4800+
}
4801+
4802+
void TypeConverter::withClosureTypeInfo(AbstractClosureExpr *closure,
4803+
const FunctionTypeInfo &info,
4804+
llvm::function_ref<void()> operation) {
4805+
auto insertResult = ClosureInfos.insert({closure, info});
4806+
(void) insertResult;
4807+
#ifndef NDEBUG
4808+
if (!insertResult.second) {
4809+
auto &existing = insertResult.first->second;
4810+
assert(existing.FormalType == info.FormalType);
4811+
assert(existing.ExpectedLoweredType == info.ExpectedLoweredType);
4812+
}
4813+
#endif
4814+
4815+
operation();
4816+
4817+
// TODO: figure out a way to clear this out so that emitting a closure
4818+
// doesn't require permanent memory use. Right now we have too much
4819+
// code relying on not emitting this in a scoped pattern.
4820+
//ClosureInfos.erase(closure);
47964821
}
47974822

47984823
TypeExpansionContext
@@ -4808,17 +4833,6 @@ TypeConverter::getCaptureTypeExpansionContext(SILDeclRef constant) {
48084833
return minimal;
48094834
}
48104835

4811-
void TypeConverter::setAbstractionPattern(AbstractClosureExpr *closure,
4812-
AbstractionPattern pattern) {
4813-
auto existing = ClosureAbstractionPatterns.find(closure);
4814-
if (existing != ClosureAbstractionPatterns.end()) {
4815-
assert(*existing->second == pattern
4816-
&& "closure shouldn't be emitted at different abstraction level contexts");
4817-
} else {
4818-
ClosureAbstractionPatterns[closure] = pattern;
4819-
}
4820-
}
4821-
48224836
void TypeConverter::setCaptureTypeExpansionContext(SILDeclRef constant,
48234837
SILModule &M) {
48244838
if (!hasLoweredLocalCaptures(constant)) {

0 commit comments

Comments
 (0)