Skip to content

Commit 43776ce

Browse files
authored
Merge pull request #38669 from DougGregor/structural-sendable-conformances
[SE-0302] Implement structural conformances to Sendable.
2 parents 9edd190 + 7c0bdff commit 43776ce

17 files changed

+464
-158
lines changed

include/swift/AST/ASTContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ namespace swift {
105105
class InheritedProtocolConformance;
106106
class SelfProtocolConformance;
107107
class SpecializedProtocolConformance;
108+
class BuiltinProtocolConformance;
108109
enum class ProtocolConformanceState;
109110
class Pattern;
110111
enum PointerTypeKind : unsigned;
@@ -1029,6 +1030,12 @@ class ASTContext final {
10291030
SelfProtocolConformance *
10301031
getSelfConformance(ProtocolDecl *protocol);
10311032

1033+
/// Produce the builtin conformance for some structural type to some protocol.
1034+
BuiltinProtocolConformance *
1035+
getBuiltinConformance(Type type, ProtocolDecl *protocol,
1036+
GenericSignature genericSig,
1037+
ArrayRef<Requirement> conditionalRequirements);
1038+
10321039
/// A callback used to produce a diagnostic for an ill-formed protocol
10331040
/// conformance that was type-checked before we're actually walking the
10341041
/// conformance itself, along with a bit indicating whether this diagnostic

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,12 @@ ERROR(type_cannot_conform, none,
19231923
NOTE(only_concrete_types_conform_to_protocols,none,
19241924
"only concrete types such as structs, enums and classes can conform to protocols",
19251925
())
1926+
NOTE(nonsendable_function_type,none,
1927+
"a function type must be marked '@Sendable' to conform to 'Sendable'", ())
1928+
NOTE(nonsendable_tuple_type,none,
1929+
"a tuple type must be composed of 'Sendable' elements to conform to "
1930+
"'Sendable'", ())
1931+
19261932
NOTE(required_by_opaque_return,none,
19271933
"required by opaque return type of %0 %1", (DescriptiveDeclKind, DeclName))
19281934
NOTE(required_by_decl,none,

include/swift/AST/ProtocolConformance.h

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -66,7 +66,10 @@ enum class ProtocolConformanceKind {
6666
Specialized,
6767
/// Conformance of a generic class type projected through one of its
6868
/// superclass's conformances.
69-
Inherited
69+
Inherited,
70+
/// Builtin conformances are special conformaces that the runtime handles
71+
/// and isn't implemented directly in Swift.
72+
Builtin
7073
};
7174

7275
/// Describes the state of a protocol conformance, which may be complete,
@@ -329,7 +332,9 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
329332
/// - the type is directly declared to conform to the protocol (a
330333
/// normal conformance) or
331334
/// - the protocol's existential type is known to conform to itself (a
332-
/// self-conformance).
335+
/// self-conformance) or
336+
/// - the type's conformance is declared within the runtime (a builtin
337+
/// conformance).
333338
class RootProtocolConformance : public ProtocolConformance {
334339
protected:
335340
RootProtocolConformance(ProtocolConformanceKind kind, Type conformingType)
@@ -380,7 +385,8 @@ class RootProtocolConformance : public ProtocolConformance {
380385

381386
static bool classof(const ProtocolConformance *conformance) {
382387
return conformance->getKind() == ProtocolConformanceKind::Normal ||
383-
conformance->getKind() == ProtocolConformanceKind::Self;
388+
conformance->getKind() == ProtocolConformanceKind::Self ||
389+
conformance->getKind() == ProtocolConformanceKind::Builtin;
384390
}
385391
};
386392

@@ -987,6 +993,103 @@ class InheritedProtocolConformance : public ProtocolConformance,
987993
}
988994
};
989995

996+
/// A builtin conformance appears when a non-nominal type has a
997+
/// conformance that is synthesized by the implementation.
998+
class BuiltinProtocolConformance final : public RootProtocolConformance,
999+
private llvm::TrailingObjects<BuiltinProtocolConformance, Requirement> {
1000+
friend ASTContext;
1001+
friend TrailingObjects;
1002+
1003+
ProtocolDecl *protocol;
1004+
GenericSignature genericSig;
1005+
size_t numConditionalRequirements;
1006+
1007+
size_t numTrailingObjects(OverloadToken<Requirement>) const {
1008+
return numConditionalRequirements;
1009+
}
1010+
1011+
BuiltinProtocolConformance(Type conformingType, ProtocolDecl *protocol,
1012+
GenericSignature genericSig,
1013+
ArrayRef<Requirement> conditionalRequirements);
1014+
1015+
public:
1016+
/// Get the protocol being conformed to.
1017+
ProtocolDecl *getProtocol() const {
1018+
return protocol;
1019+
}
1020+
1021+
/// Retrieve the generic signature that describes the type parameters used
1022+
/// within the conforming type.
1023+
GenericSignature getGenericSignature() const {
1024+
return genericSig;
1025+
}
1026+
1027+
/// Get any requirements that must be satisfied for this conformance to apply.
1028+
Optional<ArrayRef<Requirement>>
1029+
getConditionalRequirementsIfAvailable() const {
1030+
return getConditionalRequirements();
1031+
}
1032+
1033+
/// Get any requirements that must be satisfied for this conformance to apply.
1034+
ArrayRef<Requirement> getConditionalRequirements() const {
1035+
return {getTrailingObjects<Requirement>(), numConditionalRequirements};
1036+
}
1037+
1038+
/// Get the declaration context that contains the nominal type declaration.
1039+
DeclContext *getDeclContext() const {
1040+
return getProtocol();
1041+
}
1042+
1043+
/// Retrieve the state of this conformance.
1044+
ProtocolConformanceState getState() const {
1045+
return ProtocolConformanceState::Complete;
1046+
}
1047+
1048+
/// Get the kind of source from which this conformance comes.
1049+
ConformanceEntryKind getSourceKind() const {
1050+
return ConformanceEntryKind::Synthesized;
1051+
}
1052+
/// Get the protocol conformance which implied this implied conformance.
1053+
NormalProtocolConformance *getImplyingConformance() const {
1054+
return nullptr;
1055+
}
1056+
1057+
bool hasTypeWitness(AssociatedTypeDecl *assocType) const {
1058+
llvm_unreachable("builtin-conformances never have associated types");
1059+
}
1060+
1061+
/// Retrieve the type witness and type decl (if one exists)
1062+
/// for the given associated type.
1063+
TypeWitnessAndDecl
1064+
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
1065+
SubstOptions options=None) const {
1066+
llvm_unreachable("builtin-conformances never have associated types");
1067+
}
1068+
1069+
/// Given that the requirement signature of the protocol directly states
1070+
/// that the given dependent type must conform to the given protocol,
1071+
/// return its associated conformance.
1072+
ProtocolConformanceRef
1073+
getAssociatedConformance(Type assocType, ProtocolDecl *protocol) const {
1074+
llvm_unreachable("builtin-conformances never have associated types");
1075+
}
1076+
1077+
/// Retrieve the witness corresponding to the given value requirement.
1078+
ConcreteDeclRef getWitnessDeclRef(ValueDecl *requirement) const {
1079+
return ConcreteDeclRef(requirement);
1080+
}
1081+
1082+
/// Determine whether the witness for the given requirement
1083+
/// is either the default definition or was otherwise deduced.
1084+
bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
1085+
llvm_unreachable("builtin-conformances never have associated types");
1086+
}
1087+
1088+
static bool classof(const ProtocolConformance *conformance) {
1089+
return conformance->getKind() == ProtocolConformanceKind::Builtin;
1090+
}
1091+
};
1092+
9901093
inline bool ProtocolConformance::isInvalid() const {
9911094
return getRootConformance()->isInvalid();
9921095
}

lib/AST/ASTContext.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,10 @@ struct ASTContext::Implementation {
439439
/// The set of inherited protocol conformances.
440440
llvm::FoldingSet<InheritedProtocolConformance> InheritedConformances;
441441

442+
/// The set of builtin protocol conformances.
443+
llvm::DenseMap<std::pair<Type, ProtocolDecl *>,
444+
BuiltinProtocolConformance *> BuiltinConformances;
445+
442446
/// The set of substitution maps (uniqued by their storage).
443447
llvm::FoldingSet<SubstitutionMap::Storage> SubstitutionMaps;
444448

@@ -2243,6 +2247,28 @@ ASTContext::getSelfConformance(ProtocolDecl *protocol) {
22432247
return entry;
22442248
}
22452249

2250+
/// Produce the builtin conformance for some non-nominal to some protocol.
2251+
BuiltinProtocolConformance *
2252+
ASTContext::getBuiltinConformance(
2253+
Type type, ProtocolDecl *protocol,
2254+
GenericSignature genericSig,
2255+
ArrayRef<Requirement> conditionalRequirements
2256+
) {
2257+
auto key = std::make_pair(type, protocol);
2258+
AllocationArena arena = getArena(type->getRecursiveProperties());
2259+
auto &builtinConformances = getImpl().getArena(arena).BuiltinConformances;
2260+
2261+
auto &entry = builtinConformances[key];
2262+
if (!entry) {
2263+
auto size = BuiltinProtocolConformance::
2264+
totalSizeToAlloc<Requirement>(conditionalRequirements.size());
2265+
auto mem = this->Allocate(size, alignof(BuiltinProtocolConformance), arena);
2266+
entry = new (mem) BuiltinProtocolConformance(
2267+
type, protocol, genericSig, conditionalRequirements);
2268+
}
2269+
return entry;
2270+
}
2271+
22462272
/// If one of the ancestor conformances already has a matching type, use
22472273
/// that instead.
22482274
static ProtocolConformance *collapseSpecializedConformance(
@@ -2259,6 +2285,7 @@ static ProtocolConformance *collapseSpecializedConformance(
22592285
case ProtocolConformanceKind::Normal:
22602286
case ProtocolConformanceKind::Inherited:
22612287
case ProtocolConformanceKind::Self:
2288+
case ProtocolConformanceKind::Builtin:
22622289
// If the conformance matches, return it.
22632290
if (conformance->getType()->isEqual(type)) {
22642291
for (auto subConformance : substitutions.getConformances())
@@ -2496,6 +2523,7 @@ size_t ASTContext::Implementation::Arena::getTotalMemory() const {
24962523
// NormalConformances ?
24972524
// SpecializedConformances ?
24982525
// InheritedConformances ?
2526+
// BuiltinConformances ?
24992527
}
25002528

25012529
void AbstractFunctionDecl::setForeignErrorConvention(

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -3262,6 +3262,10 @@ static void dumpProtocolConformanceRec(
32623262
visited);
32633263
break;
32643264
}
3265+
3266+
case ProtocolConformanceKind::Builtin: {
3267+
printCommon("builtin");
3268+
}
32653269
}
32663270

32673271
PrintWithColorRAII(out, ParenthesisColor) << ')';

lib/AST/ASTMangler.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -209,9 +209,11 @@ std::string ASTMangler::mangleWitnessTable(const RootProtocolConformance *C) {
209209
if (isa<NormalProtocolConformance>(C)) {
210210
appendProtocolConformance(C);
211211
appendOperator("WP");
212-
} else {
212+
} else if (isa<SelfProtocolConformance>(C)) {
213213
appendProtocolName(cast<SelfProtocolConformance>(C)->getProtocol());
214214
appendOperator("WS");
215+
} else {
216+
llvm_unreachable("mangling unknown conformance kind");
215217
}
216218
return finalize();
217219
}
@@ -235,7 +237,11 @@ std::string ASTMangler::mangleWitnessThunk(
235237
}
236238

237239
if (Conformance) {
238-
appendOperator(isa<SelfProtocolConformance>(Conformance) ? "TS" : "TW");
240+
if (isa<SelfProtocolConformance>(Conformance)) {
241+
appendOperator("TS");
242+
} else {
243+
appendOperator("TW");
244+
}
239245
}
240246
return finalize();
241247
}
@@ -1556,7 +1562,8 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
15561562
static bool conformanceHasIdentity(const RootProtocolConformance *root) {
15571563
auto conformance = dyn_cast<NormalProtocolConformance>(root);
15581564
if (!conformance) {
1559-
assert(isa<SelfProtocolConformance>(root));
1565+
assert(isa<SelfProtocolConformance>(root) ||
1566+
isa<BuiltinProtocolConformance>(root));
15601567
return true;
15611568
}
15621569

@@ -1577,8 +1584,9 @@ static bool conformanceHasIdentity(const RootProtocolConformance *root) {
15771584
static bool isRetroactiveConformance(const RootProtocolConformance *root) {
15781585
auto conformance = dyn_cast<NormalProtocolConformance>(root);
15791586
if (!conformance) {
1580-
assert(isa<SelfProtocolConformance>(root));
1581-
return false; // self-conformances are never retroactive.
1587+
assert(isa<SelfProtocolConformance>(root) ||
1588+
isa<BuiltinProtocolConformance>(root));
1589+
return false; // self-conformances are never retroactive. nor are builtin.
15821590
}
15831591

15841592
return conformance->isRetroactive();
@@ -3058,6 +3066,10 @@ ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance) {
30583066
appendModule(Mod, DC->getAsDecl()->getAlternateModuleName());
30593067
}
30603068

3069+
// If this is a non-nominal type, we're done.
3070+
if (!conformingType->getAnyNominal())
3071+
return;
3072+
30613073
contextSig =
30623074
conformingType->getAnyNominal()->getGenericSignatureOfContext();
30633075

@@ -3082,6 +3094,9 @@ void ASTMangler::appendProtocolConformanceRef(
30823094
assert(DC->getAsDecl());
30833095
appendModule(conformance->getDeclContext()->getParentModule(),
30843096
DC->getAsDecl()->getAlternateModuleName());
3097+
// Builtin conformances are always from the Swift module.
3098+
} else if (isa<BuiltinProtocolConformance>(conformance)) {
3099+
appendOperator("HP");
30853100
} else if (conformance->getDeclContext()->getParentModule() ==
30863101
conformance->getType()->getAnyNominal()->getParentModule()) {
30873102
appendOperator("HP");

lib/AST/ASTPrinter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -5699,6 +5699,12 @@ void ProtocolConformance::printName(llvm::raw_ostream &os,
56995699
os << ")";
57005700
break;
57015701
}
5702+
case ProtocolConformanceKind::Builtin: {
5703+
auto builtin = cast<BuiltinProtocolConformance>(this);
5704+
os << builtin->getProtocol()->getName()
5705+
<< " type " << builtin->getType();
5706+
break;
5707+
}
57025708
}
57035709
}
57045710

0 commit comments

Comments
 (0)