Skip to content

Commit 562d7dc

Browse files
authored
Merge pull request swiftlang#80438 from jckarter/substitute-away-escapable-lifetime-deps
Type substitution eliminates dependencies with Escapable targets.
2 parents d15f6c7 + 6b605f4 commit 562d7dc

16 files changed

+398
-56
lines changed

include/swift/AST/LifetimeDependence.h

+12
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,18 @@ class LifetimeDependenceInfo {
354354
std::optional<LifetimeDependenceInfo>
355355
getLifetimeDependenceFor(ArrayRef<LifetimeDependenceInfo> lifetimeDependencies,
356356
unsigned index);
357+
358+
/// Helper to remove lifetime dependencies whose target references an
359+
/// Escapable type.
360+
///
361+
/// Returns true if the set of output lifetime dependencies is different from
362+
/// the set of input lifetime dependencies, false if there was no change.
363+
bool
364+
filterEscapableLifetimeDependencies(GenericSignature sig,
365+
ArrayRef<LifetimeDependenceInfo> inputs,
366+
SmallVectorImpl<LifetimeDependenceInfo> &outputs,
367+
llvm::function_ref<Type (unsigned targetIndex)> getSubstTargetType);
368+
357369
} // namespace swift
358370

359371
#endif

include/swift/AST/TypeTransform.h

+68-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "swift/AST/GenericEnvironment.h"
2222
#include "swift/AST/SILLayout.h"
23+
#include "swift/AST/LifetimeDependence.h"
2324

2425
namespace swift {
2526

@@ -333,11 +334,37 @@ case TypeKind::Id:
333334
transErrorResult = result;
334335
}
335336

336-
if (!changed) return t;
337+
if (!changed) {
338+
return t;
339+
}
340+
341+
// Lifetime dependencies get eliminated if their target type was
342+
// substituted with an escapable type.
343+
auto extInfo = fnTy->getExtInfo();
344+
if (!extInfo.getLifetimeDependencies().empty()) {
345+
SmallVector<LifetimeDependenceInfo, 2> substDependenceInfos;
346+
bool didRemoveLifetimeDependencies
347+
= filterEscapableLifetimeDependencies(GenericSignature(),
348+
extInfo.getLifetimeDependencies(),
349+
substDependenceInfos,
350+
[&](unsigned targetIndex) {
351+
if (targetIndex >= transInterfaceParams.size()) {
352+
// Target is a return type.
353+
return transInterfaceResults[targetIndex - transInterfaceParams.size()]
354+
.getInterfaceType();
355+
} else {
356+
// Target is a parameter.
357+
return transInterfaceParams[targetIndex].getInterfaceType();
358+
}
359+
});
360+
if (didRemoveLifetimeDependencies) {
361+
extInfo = extInfo.withLifetimeDependencies(substDependenceInfos);
362+
}
363+
}
337364

338365
return SILFunctionType::get(
339366
fnTy->getInvocationGenericSignature(),
340-
fnTy->getExtInfo(),
367+
extInfo,
341368
fnTy->getCoroutineKind(),
342369
fnTy->getCalleeConvention(),
343370
transInterfaceParams,
@@ -809,7 +836,7 @@ case TypeKind::Id:
809836
}
810837

811838
// Transform result type.
812-
auto resultTy = doIt(function->getResult(), pos);
839+
Type resultTy = doIt(function->getResult(), pos);
813840
if (!resultTy)
814841
return Type();
815842

@@ -876,8 +903,45 @@ case TypeKind::Id:
876903
return GenericFunctionType::get(
877904
genericSig, substParams, resultTy, extInfo);
878905
}
906+
907+
if (isUnchanged) {
908+
return t;
909+
}
879910

880-
if (isUnchanged) return t;
911+
// Substitution may have replaced parameter or return types that had
912+
// lifetime dependencies with Escapable types, which render those
913+
// dependencies inactive.
914+
if (extInfo && !extInfo->getLifetimeDependencies().empty()) {
915+
SmallVector<LifetimeDependenceInfo, 2> substDependenceInfos;
916+
bool didRemoveLifetimeDependencies
917+
= filterEscapableLifetimeDependencies(GenericSignature(),
918+
extInfo->getLifetimeDependencies(),
919+
substDependenceInfos,
920+
[&](unsigned targetIndex) {
921+
// Traverse potentially-curried function types.
922+
ArrayRef<AnyFunctionType::Param> params = substParams;
923+
auto result = resultTy;
924+
while (targetIndex >= params.size()) {
925+
if (auto curriedTy = result->getAs<AnyFunctionType>()) {
926+
targetIndex -= params.size();
927+
params = curriedTy->getParams();
928+
result = curriedTy->getResult();
929+
continue;
930+
} else {
931+
// The last lifetime dependency targets the result at the end
932+
// of the curried chain.
933+
ASSERT(targetIndex == params.size()
934+
&& "invalid lifetime dependence target");
935+
return result;
936+
}
937+
}
938+
return params[targetIndex].getParameterType();
939+
});
940+
941+
if (didRemoveLifetimeDependencies) {
942+
extInfo = extInfo->withLifetimeDependencies(substDependenceInfos);
943+
}
944+
}
881945

882946
return FunctionType::get(substParams, resultTy, extInfo);
883947
}

include/swift/AST/Types.h

+24
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
688688
/// Returns true if this contextual type satisfies a conformance to Escapable.
689689
bool isEscapable();
690690

691+
/// Returns true if this type satisfies a conformance to Escapable in the
692+
/// given generic signature.
693+
bool isEscapable(GenericSignature sig);
694+
691695
/// Returns true if this contextual type is (Escapable && !isNoEscape).
692696
bool mayEscape() { return !isNoEscape() && isEscapable(); }
693697

@@ -3566,6 +3570,16 @@ class AnyFunctionType : public TypeBase {
35663570
}
35673571
Bits.AnyFunctionType.NumParams = NumParams;
35683572
assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!");
3573+
3574+
if (Info) {
3575+
unsigned maxLifetimeTarget = NumParams + 1;
3576+
if (auto outputFn = Output->getAs<AnyFunctionType>()) {
3577+
maxLifetimeTarget += outputFn->getNumParams();
3578+
}
3579+
for (auto &dep : Info->getLifetimeDependencies()) {
3580+
assert(dep.getTargetIndex() < maxLifetimeTarget);
3581+
}
3582+
}
35693583
}
35703584

35713585
public:
@@ -5170,6 +5184,16 @@ class SILFunctionType final
51705184
const ASTContext &ctx,
51715185
ProtocolConformanceRef witnessMethodConformance =
51725186
ProtocolConformanceRef());
5187+
5188+
/// Given an existing ExtInfo, and a set of interface parameters and results
5189+
/// destined for a new SILFunctionType, return a new ExtInfo with only the
5190+
/// lifetime dependencies relevant after substitution.
5191+
static ExtInfo
5192+
getSubstLifetimeDependencies(GenericSignature genericSig,
5193+
ExtInfo origExtInfo,
5194+
ArrayRef<SILParameterInfo> params,
5195+
ArrayRef<SILYieldInfo> yields,
5196+
ArrayRef<SILResultInfo> results);
51735197

51745198
/// Return a structurally-identical function type with a slightly tweaked
51755199
/// ExtInfo.

include/swift/SIL/AbstractionPattern.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1566,7 +1566,9 @@ class AbstractionPattern {
15661566
/// This may be true either because the type is structurally addressable for
15671567
/// dependencies, or because it was explicitly marked as `@_addressable`
15681568
/// in its declaration.
1569-
bool isFunctionParamAddressable(TypeConverter &TC, unsigned index) const;
1569+
bool isFunctionParamAddressable(unsigned index) const;
1570+
1571+
ArrayRef<LifetimeDependenceInfo> getLifetimeDependencies() const;
15701572

15711573
/// Given that the value being abstracted is a function type, and that
15721574
/// this is not an opaque abstraction pattern, return the number of

lib/AST/ConformanceLookup.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -916,3 +916,11 @@ bool TypeBase::isEscapable() {
916916
auto canType = preprocessTypeForInvertibleQuery(this);
917917
return conformsToInvertible(canType, InvertibleProtocolKind::Escapable);
918918
}
919+
920+
bool TypeBase::isEscapable(GenericSignature sig) {
921+
Type contextTy = this;
922+
if (sig) {
923+
contextTy = sig.getGenericEnvironment()->mapTypeIntoContext(contextTy);
924+
}
925+
return contextTy->isEscapable();
926+
}

lib/AST/LifetimeDependence.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,32 @@ getLifetimeDependenceFor(ArrayRef<LifetimeDependenceInfo> lifetimeDependencies,
4848
return std::nullopt;
4949
}
5050

51+
bool
52+
filterEscapableLifetimeDependencies(GenericSignature sig,
53+
ArrayRef<LifetimeDependenceInfo> inputs,
54+
SmallVectorImpl<LifetimeDependenceInfo> &outputs,
55+
llvm::function_ref<Type (unsigned targetIndex)> getSubstTargetType) {
56+
bool didRemoveLifetimeDependencies = false;
57+
58+
for (auto &depInfo : inputs) {
59+
auto targetIndex = depInfo.getTargetIndex();
60+
Type substTy = getSubstTargetType(targetIndex);
61+
62+
// Drop the dependency if the target type is Escapable.
63+
if (sig || !substTy->hasTypeParameter()) {
64+
if (substTy->isEscapable(sig)) {
65+
didRemoveLifetimeDependencies = true;
66+
continue;
67+
}
68+
}
69+
70+
// Otherwise, keep the dependency.
71+
outputs.push_back(depInfo);
72+
}
73+
74+
return didRemoveLifetimeDependencies;
75+
}
76+
5177
std::string LifetimeDependenceInfo::getString() const {
5278
std::string lifetimeDependenceString = "@lifetime(";
5379
auto addressable = getAddressableIndices();

lib/SIL/IR/AbstractionPattern.cpp

+41-24
Original file line numberDiff line numberDiff line change
@@ -1650,8 +1650,7 @@ AbstractionPattern::getFunctionParamFlags(unsigned index) const {
16501650
}
16511651

16521652
bool
1653-
AbstractionPattern::isFunctionParamAddressable(TypeConverter &TC,
1654-
unsigned index) const {
1653+
AbstractionPattern::isFunctionParamAddressable(unsigned index) const {
16551654
switch (getKind()) {
16561655
case Kind::Invalid:
16571656
case Kind::Tuple:
@@ -1661,7 +1660,7 @@ AbstractionPattern::isFunctionParamAddressable(TypeConverter &TC,
16611660
case Kind::OpaqueDerivativeFunction:
16621661
// If the function abstraction pattern is completely opaque, assume we
16631662
// may need to preserve the address for dependencies.
1664-
return true;
1663+
return false;
16651664

16661665
case Kind::ClangType:
16671666
case Kind::ObjCCompletionHandlerArgumentsType:
@@ -1685,29 +1684,47 @@ AbstractionPattern::isFunctionParamAddressable(TypeConverter &TC,
16851684
auto fnTy = cast<AnyFunctionType>(getType());
16861685

16871686
// The parameter might directly be marked addressable.
1688-
if (fnTy.getParams()[index].getParameterFlags().isAddressable()) {
1689-
return true;
1690-
}
1687+
return fnTy.getParams()[index].getParameterFlags().isAddressable();
1688+
}
1689+
}
1690+
llvm_unreachable("bad kind");
1691+
}
1692+
1693+
ArrayRef<LifetimeDependenceInfo>
1694+
AbstractionPattern::getLifetimeDependencies() const {
1695+
switch (getKind()) {
1696+
case Kind::Invalid:
1697+
case Kind::Tuple:
1698+
llvm_unreachable("not any kind of function!");
1699+
case Kind::Opaque:
1700+
case Kind::OpaqueFunction:
1701+
case Kind::OpaqueDerivativeFunction:
1702+
// If the function abstraction pattern is completely opaque, assume we
1703+
// may need to preserve the address for dependencies.
1704+
return {};
1705+
1706+
case Kind::ClangType:
1707+
case Kind::ObjCCompletionHandlerArgumentsType:
1708+
case Kind::CurriedObjCMethodType:
1709+
case Kind::PartialCurriedObjCMethodType:
1710+
case Kind::ObjCMethodType:
1711+
case Kind::CFunctionAsMethodType:
1712+
case Kind::CurriedCFunctionAsMethodType:
1713+
case Kind::PartialCurriedCFunctionAsMethodType:
1714+
case Kind::CXXMethodType:
1715+
case Kind::CurriedCXXMethodType:
1716+
case Kind::PartialCurriedCXXMethodType:
1717+
case Kind::Type:
1718+
case Kind::Discard: {
1719+
auto type = getType();
16911720

1692-
// The parameter could be of a type that is addressable for dependencies,
1693-
// in which case it becomes addressable when a return has a scoped
1694-
// dependency on it.
1695-
for (auto &dep : fnTy->getLifetimeDependencies()) {
1696-
auto scoped = dep.getScopeIndices();
1697-
if (!scoped) {
1698-
continue;
1699-
}
1700-
1701-
if (scoped->contains(index)) {
1702-
auto paramTy = getFunctionParamType(index);
1703-
1704-
return TC.getTypeLowering(paramTy, paramTy.getType(),
1705-
TypeExpansionContext::minimal())
1706-
.getRecursiveProperties().isAddressableForDependencies();
1707-
}
1721+
if (type->isTypeParameter() || type->is<ArchetypeType>()) {
1722+
return {};
17081723
}
1709-
1710-
return false;
1724+
1725+
auto fnTy = cast<AnyFunctionType>(getType());
1726+
1727+
return fnTy->getExtInfo().getLifetimeDependencies();
17111728
}
17121729
}
17131730
llvm_unreachable("bad kind");

0 commit comments

Comments
 (0)