Skip to content

Commit aff95bf

Browse files
authored
Merge pull request #38691 from DougGregor/missing-sendable-conformances
2 parents ba0536f + f9c3475 commit aff95bf

25 files changed

+234
-72
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ namespace swift {
106106
class InheritedProtocolConformance;
107107
class SelfProtocolConformance;
108108
class SpecializedProtocolConformance;
109+
enum class BuiltinConformanceKind;
109110
class BuiltinProtocolConformance;
110111
enum class ProtocolConformanceState;
111112
class Pattern;
@@ -1046,7 +1047,8 @@ class ASTContext final {
10461047
BuiltinProtocolConformance *
10471048
getBuiltinConformance(Type type, ProtocolDecl *protocol,
10481049
GenericSignature genericSig,
1049-
ArrayRef<Requirement> conditionalRequirements);
1050+
ArrayRef<Requirement> conditionalRequirements,
1051+
BuiltinConformanceKind kind);
10501052

10511053
/// A callback used to produce a diagnostic for an ill-formed protocol
10521054
/// conformance that was type-checked before we're actually walking the

include/swift/AST/Decl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3251,7 +3251,8 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
32513251
///
32523252
/// This is used by deserialization of module files to report
32533253
/// conformances.
3254-
void registerProtocolConformance(ProtocolConformance *conformance);
3254+
void registerProtocolConformance(ProtocolConformance *conformance,
3255+
bool synthesized = false);
32553256

32563257
void setConformanceLoader(LazyMemberLoader *resolver, uint64_t contextData);
32573258

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4518,6 +4518,11 @@ ERROR(concurrent_value_inherit,none,
45184518
"`Sendable` class %1 cannot inherit from another class"
45194519
"%select{| other than 'NSObject'}0",
45204520
(bool, DeclName))
4521+
ERROR(non_sendable_type,none,
4522+
"type %0 does not conform to the 'Sendable' protocol", (Type))
4523+
ERROR(non_sendable_function_type,none,
4524+
"function type %0 must be marked '@Sendable' to conform to 'Sendable'",
4525+
(Type))
45214526

45224527
WARNING(unchecked_conformance_not_special,none,
45234528
"@unchecked conformance to %0 has no meaning", (Type))

include/swift/AST/GenericSignature.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
373373
/// T: Foo or T == U (etc.) with the information it knows. This includes
374374
/// checking against global state, if any/all of the types in the requirement
375375
/// are concrete, not type parameters.
376-
bool isRequirementSatisfied(Requirement requirement) const;
376+
bool isRequirementSatisfied(
377+
Requirement requirement, bool allowMissing = false) const;
377378

378379
/// Return the requirements of this generic signature that are not also
379380
/// satisfied by \c otherSig.

include/swift/AST/Module.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,10 +578,15 @@ class ModuleDecl : public DeclContext, public TypeDecl {
578578
///
579579
/// \param protocol The protocol to which we are computing conformance.
580580
///
581+
/// \param allowMissing When \c true, the resulting conformance reference
582+
/// might include "missing" conformances, which are synthesized for some
583+
/// protocols as an error recovery mechanism.
584+
///
581585
/// \returns The result of the conformance search, which will be
582586
/// None if the type does not conform to the protocol or contain a
583587
/// ProtocolConformanceRef if it does conform.
584-
ProtocolConformanceRef lookupConformance(Type type, ProtocolDecl *protocol);
588+
ProtocolConformanceRef lookupConformance(Type type, ProtocolDecl *protocol,
589+
bool allowMissing = false);
585590

586591
/// Look for the conformance of the given existential type to the given
587592
/// protocol.

include/swift/AST/ProtocolConformance.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,15 @@ class InheritedProtocolConformance : public ProtocolConformance,
993993
}
994994
};
995995

996+
/// Describes the kind of a builtin conformance.
997+
enum class BuiltinConformanceKind {
998+
// A builtin conformance that has been synthesized by the implementation.
999+
Synthesized = 0,
1000+
// A missing conformance that we have nonetheless synthesized so that
1001+
// we can diagnose it later.
1002+
Missing,
1003+
};
1004+
9961005
/// A builtin conformance appears when a non-nominal type has a
9971006
/// conformance that is synthesized by the implementation.
9981007
class BuiltinProtocolConformance final : public RootProtocolConformance,
@@ -1002,15 +1011,17 @@ class BuiltinProtocolConformance final : public RootProtocolConformance,
10021011

10031012
ProtocolDecl *protocol;
10041013
GenericSignature genericSig;
1005-
size_t numConditionalRequirements;
1014+
size_t numConditionalRequirements : 31;
1015+
unsigned builtinConformanceKind : 1;
10061016

10071017
size_t numTrailingObjects(OverloadToken<Requirement>) const {
10081018
return numConditionalRequirements;
10091019
}
10101020

10111021
BuiltinProtocolConformance(Type conformingType, ProtocolDecl *protocol,
10121022
GenericSignature genericSig,
1013-
ArrayRef<Requirement> conditionalRequirements);
1023+
ArrayRef<Requirement> conditionalRequirements,
1024+
BuiltinConformanceKind kind);
10141025

10151026
public:
10161027
/// Get the protocol being conformed to.
@@ -1024,6 +1035,16 @@ class BuiltinProtocolConformance final : public RootProtocolConformance,
10241035
return genericSig;
10251036
}
10261037

1038+
BuiltinConformanceKind getBuiltinConformanceKind() const {
1039+
return static_cast<BuiltinConformanceKind>(builtinConformanceKind);
1040+
}
1041+
1042+
/// Whether this represents a "missing" conformance that should be diagnosed
1043+
/// later.
1044+
bool isMissing() const {
1045+
return getBuiltinConformanceKind() == BuiltinConformanceKind::Missing;
1046+
}
1047+
10271048
/// Get any requirements that must be satisfied for this conformance to apply.
10281049
Optional<ArrayRef<Requirement>>
10291050
getConditionalRequirementsIfAvailable() const {

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ class ProtocolConformanceRef {
9898
return Union.get<ProtocolDecl*>();
9999
}
100100

101+
/// Determine whether this conformance (or a conformance it depends on)
102+
/// involves a "missing" conformance anywhere. Such conformances
103+
/// cannot be depended on to always exist.
104+
bool hasMissingConformance(ModuleDecl *module) const;
105+
101106
using OpaqueValue = void*;
102107
OpaqueValue getOpaqueValue() const { return Union.getOpaqueValue(); }
103108
static ProtocolConformanceRef getFromOpaqueValue(OpaqueValue value) {

include/swift/AST/Requirement.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ class Requirement
8181
/// \param conditionalRequirements An out parameter initialized to an
8282
/// array of requirements that the caller must check to ensure this
8383
/// requirement is completely satisfied.
84-
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements) const;
84+
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
85+
bool allowMissing = false) const;
8586

8687
/// Determines if this substituted requirement can ever be satisfied,
8788
/// possibly with additional substitutions.

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2331,7 +2331,8 @@ BuiltinProtocolConformance *
23312331
ASTContext::getBuiltinConformance(
23322332
Type type, ProtocolDecl *protocol,
23332333
GenericSignature genericSig,
2334-
ArrayRef<Requirement> conditionalRequirements
2334+
ArrayRef<Requirement> conditionalRequirements,
2335+
BuiltinConformanceKind kind
23352336
) {
23362337
auto key = std::make_pair(type, protocol);
23372338
AllocationArena arena = getArena(type->getRecursiveProperties());
@@ -2343,7 +2344,7 @@ ASTContext::getBuiltinConformance(
23432344
totalSizeToAlloc<Requirement>(conditionalRequirements.size());
23442345
auto mem = this->Allocate(size, alignof(BuiltinProtocolConformance), arena);
23452346
entry = new (mem) BuiltinProtocolConformance(
2346-
type, protocol, genericSig, conditionalRequirements);
2347+
type, protocol, genericSig, conditionalRequirements, kind);
23472348
}
23482349
return entry;
23492350
}

lib/AST/GenericSignature.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1,
937937
}
938938

939939
bool GenericSignatureImpl::isRequirementSatisfied(
940-
Requirement requirement) const {
940+
Requirement requirement, bool allowMissing) const {
941941
if (requirement.getFirstType()->hasTypeParameter()) {
942942
auto *genericEnv = getGenericEnvironment();
943943

@@ -959,7 +959,7 @@ bool GenericSignatureImpl::isRequirementSatisfied(
959959
// FIXME: Need to check conditional requirements here.
960960
ArrayRef<Requirement> conditionalRequirements;
961961

962-
return requirement.isSatisfied(conditionalRequirements);
962+
return requirement.isSatisfied(conditionalRequirements, allowMissing);
963963
}
964964

965965
SmallVector<Requirement, 4> GenericSignatureImpl::requirementsNotSatisfiedBy(
@@ -1391,12 +1391,14 @@ ProtocolDecl *Requirement::getProtocolDecl() const {
13911391
}
13921392

13931393
bool
1394-
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements) const {
1394+
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
1395+
bool allowMissing) const {
13951396
switch (getKind()) {
13961397
case RequirementKind::Conformance: {
13971398
auto *proto = getProtocolDecl();
13981399
auto *module = proto->getParentModule();
1399-
auto conformance = module->lookupConformance(getFirstType(), proto);
1400+
auto conformance = module->lookupConformance(
1401+
getFirstType(), proto, allowMissing);
14001402
if (!conformance)
14011403
return false;
14021404

lib/AST/Module.cpp

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,14 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
970970
return ProtocolConformanceRef::forInvalid();
971971
}
972972

973+
/// Whether we should create missing conformances to the given protocol.
974+
static bool shouldCreateMissingConformances(ProtocolDecl *proto) {
975+
return proto->isSpecificProtocol(KnownProtocolKind::Sendable);
976+
}
977+
973978
ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
974-
ProtocolDecl *protocol) {
979+
ProtocolDecl *protocol,
980+
bool allowMissing) {
975981
// If we are recursively checking for implicit conformance of a nominal
976982
// type to Sendable, fail without evaluating this request. This
977983
// squashes cycles.
@@ -985,14 +991,41 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
985991
}
986992
}
987993

988-
return evaluateOrDefault(
994+
auto result = evaluateOrDefault(
989995
getASTContext().evaluator, request, ProtocolConformanceRef::forInvalid());
996+
997+
// If we aren't supposed to allow missing conformances through for this
998+
// protocol, replace the result with an "invalid" result.
999+
if (!allowMissing &&
1000+
shouldCreateMissingConformances(protocol) &&
1001+
result.hasMissingConformance(this))
1002+
return ProtocolConformanceRef::forInvalid();
1003+
1004+
return result;
1005+
}
1006+
1007+
/// Retrieve an invalid or missing conformance, as appropriate, when a
1008+
/// legitimate conformance doesn't exist.
1009+
static ProtocolConformanceRef getInvalidOrMissingConformance(
1010+
Type type, ProtocolDecl *proto) {
1011+
// Introduce "missing" conformances when appropriate, so that type checking
1012+
// (and even code generation) can continue.
1013+
ASTContext &ctx = proto->getASTContext();
1014+
if (shouldCreateMissingConformances(proto)) {
1015+
return ProtocolConformanceRef(
1016+
ctx.getBuiltinConformance(
1017+
type, proto, GenericSignature(), { },
1018+
BuiltinConformanceKind::Missing));
1019+
}
1020+
1021+
return ProtocolConformanceRef::forInvalid();
9901022
}
9911023

9921024
/// Synthesize a builtin tuple type conformance to the given protocol, if
9931025
/// appropriate.
9941026
static ProtocolConformanceRef getBuiltinTupleTypeConformance(
995-
Type type, const TupleType *tupleType, ProtocolDecl *protocol) {
1027+
Type type, const TupleType *tupleType, ProtocolDecl *protocol,
1028+
ModuleDecl *module) {
9961029
// Tuple type are Sendable when all of their element types are Sendable.
9971030
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
9981031
ASTContext &ctx = protocol->getASTContext();
@@ -1016,26 +1049,38 @@ static ProtocolConformanceRef getBuiltinTupleTypeConformance(
10161049
// If there were no generic parameters, just form the builtin conformance.
10171050
if (genericParams.empty()) {
10181051
return ProtocolConformanceRef(
1019-
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { }));
1052+
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
1053+
BuiltinConformanceKind::Synthesized));
10201054
}
10211055

10221056
// Form a generic conformance of (T1, T2, ..., TN): Sendable with signature
10231057
// <T1, T2, ..., TN> and conditional requirements T1: Sendable,
10241058
// T2: Sendable, ..., TN: Sendable.
10251059
auto genericTupleType = TupleType::get(genericElements, ctx);
1026-
auto genericSig = GenericSignature::get(genericParams, { });
1060+
auto genericSig = GenericSignature::get(
1061+
genericParams, conditionalRequirements);
10271062
auto genericConformance = ctx.getBuiltinConformance(
1028-
genericTupleType, protocol, genericSig, conditionalRequirements);
1063+
genericTupleType, protocol, genericSig, conditionalRequirements,
1064+
BuiltinConformanceKind::Synthesized);
10291065

10301066
// Compute the substitution map from the generic parameters of the
10311067
// generic conformance to actual types that were in the tuple type.
10321068
// Form a specialized conformance from that.
1033-
auto subMap = SubstitutionMap::get(genericSig, typeSubstitutions, { });
1069+
auto subMap = SubstitutionMap::get(
1070+
genericSig, [&](SubstitutableType *type) {
1071+
if (auto gp = dyn_cast<GenericTypeParamType>(type)) {
1072+
if (gp->getDepth() == 0)
1073+
return typeSubstitutions[gp->getIndex()];
1074+
}
1075+
1076+
return Type(type);
1077+
},
1078+
LookUpConformanceInModule(module));
10341079
return ProtocolConformanceRef(
10351080
ctx.getSpecializedConformance(type, genericConformance, subMap));
10361081
}
10371082

1038-
return ProtocolConformanceRef::forInvalid();
1083+
return getInvalidOrMissingConformance(type, protocol);
10391084
}
10401085

10411086
/// Whether the given function type conforms to Sendable.
@@ -1064,10 +1109,11 @@ static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
10641109
isSendableFunctionType(functionType)) {
10651110
ASTContext &ctx = protocol->getASTContext();
10661111
return ProtocolConformanceRef(
1067-
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { }));
1112+
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
1113+
BuiltinConformanceKind::Synthesized));
10681114
}
10691115

1070-
return ProtocolConformanceRef::forInvalid();
1116+
return getInvalidOrMissingConformance(type, protocol);
10711117
}
10721118

10731119
/// Synthesize a builtin metatype type conformance to the given protocol, if
@@ -1078,10 +1124,11 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
10781124
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
10791125
ASTContext &ctx = protocol->getASTContext();
10801126
return ProtocolConformanceRef(
1081-
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { }));
1127+
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
1128+
BuiltinConformanceKind::Synthesized));
10821129
}
10831130

1084-
return ProtocolConformanceRef::forInvalid();
1131+
return getInvalidOrMissingConformance(type, protocol);
10851132
}
10861133

10871134
/// Synthesize a builtin type conformance to the given protocol, if
@@ -1092,10 +1139,11 @@ static ProtocolConformanceRef getBuiltinBuiltinTypeConformance(
10921139
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
10931140
ASTContext &ctx = protocol->getASTContext();
10941141
return ProtocolConformanceRef(
1095-
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { }));
1142+
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
1143+
BuiltinConformanceKind::Synthesized));
10961144
}
10971145

1098-
return ProtocolConformanceRef::forInvalid();
1146+
return getInvalidOrMissingConformance(type, protocol);
10991147
}
11001148

11011149
ProtocolConformanceRef
@@ -1133,14 +1181,18 @@ LookupConformanceInModuleRequest::evaluate(
11331181
return ProtocolConformanceRef(protocol);
11341182
}
11351183

1136-
return ProtocolConformanceRef::forInvalid();
1184+
return getInvalidOrMissingConformance(type, protocol);
11371185
}
11381186

11391187
// An existential conforms to a protocol if the protocol is listed in the
11401188
// existential's list of conformances and the existential conforms to
11411189
// itself.
1142-
if (type->isExistentialType())
1143-
return mod->lookupExistentialConformance(type, protocol);
1190+
if (type->isExistentialType()) {
1191+
auto result = mod->lookupExistentialConformance(type, protocol);
1192+
if (result.isInvalid())
1193+
return getInvalidOrMissingConformance(type, protocol);
1194+
return result;
1195+
}
11441196

11451197
// Type variables have trivial conformances.
11461198
if (type->isTypeVariableOrMember())
@@ -1154,7 +1206,7 @@ LookupConformanceInModuleRequest::evaluate(
11541206

11551207
// Tuple types can conform to protocols.
11561208
if (auto tupleType = type->getAs<TupleType>()) {
1157-
return getBuiltinTupleTypeConformance(type, tupleType, protocol);
1209+
return getBuiltinTupleTypeConformance(type, tupleType, protocol, mod);
11581210
}
11591211

11601212
// Function types can conform to protocols.
@@ -1176,13 +1228,13 @@ LookupConformanceInModuleRequest::evaluate(
11761228

11771229
// If we don't have a nominal type, there are no conformances.
11781230
if (!nominal || isa<ProtocolDecl>(nominal))
1179-
return ProtocolConformanceRef::forInvalid();
1231+
return getInvalidOrMissingConformance(type, protocol);
11801232

11811233
// Find the (unspecialized) conformance.
11821234
SmallVector<ProtocolConformance *, 2> conformances;
11831235
if (!nominal->lookupConformance(mod, protocol, conformances)) {
11841236
if (!protocol->isSpecificProtocol(KnownProtocolKind::Sendable))
1185-
return ProtocolConformanceRef::forInvalid();
1237+
return getInvalidOrMissingConformance(type, protocol);
11861238

11871239
// Try to infer Sendable conformance.
11881240
GetImplicitSendableRequest cvRequest{nominal};
@@ -1191,7 +1243,7 @@ LookupConformanceInModuleRequest::evaluate(
11911243
conformances.clear();
11921244
conformances.push_back(conformance);
11931245
} else {
1194-
return ProtocolConformanceRef::forInvalid();
1246+
return getInvalidOrMissingConformance(type, protocol);
11951247
}
11961248
}
11971249

0 commit comments

Comments
 (0)