Skip to content

Commit 2989770

Browse files
authored
Merge pull request swiftlang#79352 from DougGregor/strict-sendable-metatypes
Add StrictSendableMetatypes to require Sendable requirements on metatypes
2 parents 2afa5ab + e24598b commit 2989770

27 files changed

+438
-61
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/Basic/LLVM.h"
1818
#include "swift/Basic/OptionSet.h"
1919
#include "swift/Basic/SourceLoc.h"
20+
#include "swift/AST/Type.h"
2021
#include "swift/AST/TypeAlignments.h"
2122
#include "llvm/ADT/ArrayRef.h"
2223
#include "llvm/ADT/PointerIntPair.h"
@@ -129,6 +130,18 @@ class CapturedValue {
129130
unsigned getFlags() const { return Value.getInt(); }
130131
};
131132

133+
/// Describes a type that has been captured by a closure or local function.
134+
class CapturedType {
135+
Type type;
136+
SourceLoc loc;
137+
138+
public:
139+
CapturedType(Type type, SourceLoc loc) : type(type), loc(loc) { }
140+
141+
Type getType() const { return type; }
142+
SourceLoc getLoc() const { return loc; }
143+
};
144+
132145
} // end swift namespace
133146

134147
namespace swift {
@@ -140,26 +153,32 @@ class CaptureInfo {
140153
class CaptureInfoStorage final
141154
: public llvm::TrailingObjects<CaptureInfoStorage,
142155
CapturedValue,
143-
GenericEnvironment *> {
156+
GenericEnvironment *,
157+
CapturedType> {
144158

145159
DynamicSelfType *DynamicSelf;
146160
OpaqueValueExpr *OpaqueValue;
147161
unsigned NumCapturedValues;
148162
unsigned NumGenericEnvironments;
163+
unsigned NumCapturedTypes;
149164

150165
public:
151166
explicit CaptureInfoStorage(DynamicSelfType *dynamicSelf,
152167
OpaqueValueExpr *opaqueValue,
153168
unsigned numCapturedValues,
154-
unsigned numGenericEnvironments)
169+
unsigned numGenericEnvironments,
170+
unsigned numCapturedTypes)
155171
: DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue),
156172
NumCapturedValues(numCapturedValues),
157-
NumGenericEnvironments(numGenericEnvironments) { }
173+
NumGenericEnvironments(numGenericEnvironments),
174+
NumCapturedTypes(numCapturedTypes) { }
158175

159176
ArrayRef<CapturedValue> getCaptures() const;
160177

161178
ArrayRef<GenericEnvironment *> getGenericEnvironments() const;
162179

180+
ArrayRef<CapturedType> getCapturedTypes() const;
181+
163182
DynamicSelfType *getDynamicSelfType() const {
164183
return DynamicSelf;
165184
}
@@ -171,6 +190,14 @@ class CaptureInfo {
171190
unsigned numTrailingObjects(OverloadToken<CapturedValue>) const {
172191
return NumCapturedValues;
173192
}
193+
194+
unsigned numTrailingObjects(OverloadToken<GenericEnvironment *>) const {
195+
return NumGenericEnvironments;
196+
}
197+
198+
unsigned numTrailingObjects(OverloadToken<CapturedType>) const {
199+
return NumCapturedTypes;
200+
}
174201
};
175202

176203
enum class Flags : unsigned {
@@ -187,7 +214,8 @@ class CaptureInfo {
187214
ArrayRef<CapturedValue> captures,
188215
DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue,
189216
bool genericParamCaptures,
190-
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>());
217+
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>(),
218+
ArrayRef<CapturedType> capturedTypes = ArrayRef<CapturedType>());
191219

192220
/// A CaptureInfo representing no captures at all.
193221
static CaptureInfo empty();
@@ -196,11 +224,7 @@ class CaptureInfo {
196224
return StorageAndFlags.getPointer();
197225
}
198226

199-
bool isTrivial() const {
200-
assert(hasBeenComputed());
201-
return getCaptures().empty() && !hasGenericParamCaptures() &&
202-
!hasDynamicSelfCapture() && !hasOpaqueValueCapture();
203-
}
227+
bool isTrivial() const;
204228

205229
/// Returns all captured values and opaque expressions.
206230
ArrayRef<CapturedValue> getCaptures() const {
@@ -214,6 +238,12 @@ class CaptureInfo {
214238
return StorageAndFlags.getPointer()->getGenericEnvironments();
215239
}
216240

241+
/// Returns all captured values and opaque expressions.
242+
ArrayRef<CapturedType> getCapturedTypes() const {
243+
assert(hasBeenComputed());
244+
return StorageAndFlags.getPointer()->getCapturedTypes();
245+
}
246+
217247
/// \returns true if the function captures the primary generic environment
218248
/// from its innermost declaration context.
219249
bool hasGenericParamCaptures() const {

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5607,6 +5607,10 @@ ERROR(non_sendable_isolated_capture,none,
56075607
"capture of %1 with non-sendable type %0 in an isolated "
56085608
"%select{local function|closure}2",
56095609
(Type, DeclName, bool))
5610+
ERROR(non_sendable_metatype_capture,none,
5611+
"capture of non-sendable type %0 in an isolated "
5612+
"%select{local function|closure}1",
5613+
(Type, bool))
56105614
ERROR(self_capture_deinit_task,none,
56115615
"capture of 'self' in a closure that outlives deinit",
56125616
())

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ PROTOCOL(Encodable)
107107
PROTOCOL(Decodable)
108108

109109
PROTOCOL(Sendable)
110+
PROTOCOL(SendableMetatype)
110111
PROTOCOL(UnsafeSendable)
111112

112113
PROTOCOL_(ObjectiveCBridgeable)

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ EXPERIMENTAL_FEATURE(NonIsolatedAsyncInheritsIsolationFromContext, false)
446446
/// Allow custom availability domains to be defined and referenced.
447447
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(CustomAvailability, true)
448448

449+
/// Be strict about the Sendable conformance of metatypes.
450+
EXPERIMENTAL_FEATURE(StrictSendableMetatypes, true)
451+
449452
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
450453
#undef EXPERIMENTAL_FEATURE
451454
#undef UPCOMING_FEATURE

lib/AST/CaptureInfo.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ CaptureInfo::CaptureInfoStorage::getGenericEnvironments() const {
5454
return llvm::ArrayRef(this->getTrailingObjects<GenericEnvironment *>(), NumGenericEnvironments);
5555
}
5656

57+
ArrayRef<CapturedType>
58+
CaptureInfo::CaptureInfoStorage::getCapturedTypes() const {
59+
return llvm::ArrayRef(this->getTrailingObjects<CapturedType>(), NumCapturedTypes);
60+
}
61+
5762
//===----------------------------------------------------------------------===//
5863
// MARK: CaptureInfo
5964
//===----------------------------------------------------------------------===//
@@ -62,7 +67,8 @@ CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef<CapturedValue> captures,
6267
DynamicSelfType *dynamicSelf,
6368
OpaqueValueExpr *opaqueValue,
6469
bool genericParamCaptures,
65-
ArrayRef<GenericEnvironment *> genericEnv) {
70+
ArrayRef<GenericEnvironment *> genericEnv,
71+
ArrayRef<CapturedType> capturedTypes) {
6672
static_assert(IsTriviallyDestructible<CapturedValue>::value,
6773
"Capture info is alloc'd on the ASTContext and not destroyed");
6874
static_assert(IsTriviallyDestructible<CaptureInfo::CaptureInfoStorage>::value,
@@ -79,37 +85,49 @@ CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef<CapturedValue> captures,
7985
if (genericParamCaptures)
8086
flags |= Flags::HasGenericParamCaptures;
8187

82-
if (captures.empty() && genericEnv.empty() && !dynamicSelf && !opaqueValue) {
88+
if (captures.empty() && genericEnv.empty() && !dynamicSelf && !opaqueValue &&
89+
capturedTypes.empty()) {
8390
*this = CaptureInfo::empty();
8491
StorageAndFlags.setInt(flags);
8592
return;
8693
}
8794

8895
size_t storageToAlloc =
8996
CaptureInfoStorage::totalSizeToAlloc<CapturedValue,
90-
GenericEnvironment *>(captures.size(),
91-
genericEnv.size());
97+
GenericEnvironment *,
98+
CapturedType>(captures.size(),
99+
genericEnv.size(),
100+
capturedTypes.size());
92101
void *storageBuf = ctx.Allocate(storageToAlloc, alignof(CaptureInfoStorage));
93102
auto *storage = new (storageBuf) CaptureInfoStorage(dynamicSelf,
94103
opaqueValue,
95104
captures.size(),
96-
genericEnv.size());
105+
genericEnv.size(),
106+
capturedTypes.size());
97107
StorageAndFlags.setPointerAndInt(storage, flags);
98108
std::uninitialized_copy(captures.begin(), captures.end(),
99109
storage->getTrailingObjects<CapturedValue>());
100110
std::uninitialized_copy(genericEnv.begin(), genericEnv.end(),
101111
storage->getTrailingObjects<GenericEnvironment *>());
112+
std::uninitialized_copy(capturedTypes.begin(), capturedTypes.end(),
113+
storage->getTrailingObjects<CapturedType>());
102114
}
103115

104116
CaptureInfo CaptureInfo::empty() {
105117
static const CaptureInfoStorage empty{/*dynamicSelf*/nullptr,
106118
/*opaqueValue*/nullptr,
107-
0, 0};
119+
0, 0, 0};
108120
CaptureInfo result;
109121
result.StorageAndFlags.setPointer(&empty);
110122
return result;
111123
}
112124

125+
bool CaptureInfo::isTrivial() const {
126+
assert(hasBeenComputed());
127+
return getCaptures().empty() && !hasGenericParamCaptures() &&
128+
!hasDynamicSelfCapture() && !hasOpaqueValueCapture();
129+
}
130+
113131
VarDecl *CaptureInfo::getIsolatedParamCapture() const {
114132
for (const auto &capture : getCaptures()) {
115133
// NOTE: isLocalCapture() returns false if we have dynamic self metadata
@@ -178,6 +196,12 @@ void CaptureInfo::print(raw_ostream &OS) const {
178196
OS << genericEnv->getOpenedElementShapeClass();
179197
},
180198
[&] { OS << ","; });
199+
200+
interleave(getCapturedTypes(),
201+
[&](CapturedType type) {
202+
OS << " type=" << type.getType().getString();
203+
},
204+
[&] { OS << ","; });
181205
OS << ')';
182206
}
183207

lib/AST/ConformanceLookup.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
367367
if (isBitwiseCopyableFunctionType(functionType))
368368
return synthesizeConformance();
369369
break;
370+
case KnownProtocolKind::SendableMetatype:
371+
return synthesizeConformance();
370372
default:
371373
break;
372374
}
@@ -381,13 +383,41 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
381383
Type type, const AnyMetatypeType *metatypeType, ProtocolDecl *protocol) {
382384
ASTContext &ctx = protocol->getASTContext();
383385

384-
// All metatypes are Sendable, Copyable, Escapable, and BitwiseCopyable.
386+
// All metatypes are Copyable, Escapable, and BitwiseCopyable.
385387
if (auto kp = protocol->getKnownProtocolKind()) {
386388
switch (*kp) {
387389
case KnownProtocolKind::Sendable:
390+
// Metatypes are generally Sendable, but under StrictSendableMetatypes we
391+
// cannot assume that metatypes based on type parameters are Sendable.
392+
// Therefore, check for conformance to SendableMetatype.
393+
if (ctx.LangOpts.hasFeature(Feature::StrictSendableMetatypes)) {
394+
auto sendableMetatypeProto =
395+
ctx.getProtocol(KnownProtocolKind::SendableMetatype);
396+
if (sendableMetatypeProto) {
397+
Type instanceType = metatypeType->getInstanceType();
398+
399+
// If the instance type is a type parameter, it is not necessarily
400+
// Sendable. There will need to be a Sendable requirement.
401+
if (instanceType->isTypeParameter())
402+
break;
403+
404+
// If the instance type conforms to SendableMetatype, then its
405+
// metatype is Sendable.
406+
auto instanceConformance = lookupConformance(
407+
instanceType, sendableMetatypeProto);
408+
if (instanceConformance.isInvalid() ||
409+
instanceConformance.hasMissingConformance())
410+
break;
411+
}
412+
413+
// Every other metatype is Sendable.
414+
}
415+
LLVM_FALLTHROUGH;
416+
388417
case KnownProtocolKind::Copyable:
389418
case KnownProtocolKind::Escapable:
390419
case KnownProtocolKind::BitwiseCopyable:
420+
case KnownProtocolKind::SendableMetatype:
391421
return ProtocolConformanceRef(
392422
ctx.getBuiltinConformance(type, protocol,
393423
BuiltinConformanceKind::Synthesized));
@@ -407,6 +437,7 @@ getBuiltinBuiltinTypeConformance(Type type, const BuiltinType *builtinType,
407437
if (auto kp = protocol->getKnownProtocolKind()) {
408438
switch (*kp) {
409439
case KnownProtocolKind::Sendable:
440+
case KnownProtocolKind::SendableMetatype:
410441
case KnownProtocolKind::Copyable:
411442
case KnownProtocolKind::Escapable: {
412443
ASTContext &ctx = protocol->getASTContext();
@@ -421,7 +452,8 @@ getBuiltinBuiltinTypeConformance(Type type, const BuiltinType *builtinType,
421452
break;
422453
}
423454

424-
// All other builtin types are Sendable, Copyable, and Escapable.
455+
// All other builtin types are Sendable, SendableMetatype, Copyable, and
456+
// Escapable.
425457
return ProtocolConformanceRef(
426458
ctx.getBuiltinConformance(type, protocol,
427459
BuiltinConformanceKind::Synthesized));
@@ -590,6 +622,13 @@ LookupConformanceInModuleRequest::evaluate(
590622
if (!nominal || isa<ProtocolDecl>(nominal))
591623
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
592624

625+
// All nominal types implicitly conform to SendableMetatype.
626+
if (protocol->isSpecificProtocol(KnownProtocolKind::SendableMetatype)) {
627+
return ProtocolConformanceRef(
628+
ctx.getBuiltinConformance(type, protocol,
629+
BuiltinConformanceKind::Synthesized));
630+
}
631+
593632
// Expand conformances added by extension macros.
594633
//
595634
// FIXME: This expansion should only be done if the

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ UNINTERESTING_FEATURE(NonfrozenEnumExhaustivity)
269269
UNINTERESTING_FEATURE(ClosureIsolation)
270270
UNINTERESTING_FEATURE(Extern)
271271
UNINTERESTING_FEATURE(ConsumeSelfInDeinit)
272+
UNINTERESTING_FEATURE(StrictSendableMetatypes)
272273

273274
static bool usesFeatureBitwiseCopyable2(Decl *decl) {
274275
if (!decl->getModuleContext()->isStdlibModule()) {

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6985,6 +6985,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
69856985
case KnownProtocolKind::Copyable:
69866986
case KnownProtocolKind::Escapable:
69876987
case KnownProtocolKind::BitwiseCopyable:
6988+
case KnownProtocolKind::SendableMetatype:
69886989
return SpecialProtocol::None;
69896990
}
69906991

lib/SIL/IR/TypeLowering.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4425,6 +4425,10 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
44254425
// Captured pack element environments.
44264426
llvm::SetVector<GenericEnvironment *> genericEnv;
44274427

4428+
// Captured types.
4429+
SmallVector<CapturedType, 4> capturedTypes;
4430+
llvm::SmallDenseSet<CanType, 4> alreadyCapturedTypes;
4431+
44284432
bool capturesGenericParams = false;
44294433
DynamicSelfType *capturesDynamicSelf = nullptr;
44304434
OpaqueValueExpr *capturesOpaqueValue = nullptr;
@@ -4620,6 +4624,13 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
46204624
// Collect non-function captures.
46214625
recordCapture(capture);
46224626
}
4627+
4628+
for (const auto &capturedType : captureInfo.getCapturedTypes()) {
4629+
if (alreadyCapturedTypes.insert(capturedType.getType()->getCanonicalType())
4630+
.second) {
4631+
capturedTypes.push_back(capturedType);
4632+
}
4633+
}
46234634
};
46244635

46254636
collectFunctionCaptures = [&](AnyFunctionRef curFn) {
@@ -4697,7 +4708,8 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
46974708
// Cache the result.
46984709
CaptureInfo info(Context, resultingCaptures,
46994710
capturesDynamicSelf, capturesOpaqueValue,
4700-
capturesGenericParams, genericEnv.getArrayRef());
4711+
capturesGenericParams, genericEnv.getArrayRef(),
4712+
capturedTypes);
47014713
auto inserted = LoweredCaptures.insert({fn, info});
47024714
assert(inserted.second && "already in map?!");
47034715
(void)inserted;

0 commit comments

Comments
 (0)