Skip to content

Commit ab3c5de

Browse files
committed
[Concurrency] Introduce Actor protocol to which actor classes all conform.
Introduce a new Actor protocol, which is a class-bound protocol with only one requirement: func enqueue(partialTask: PartialAsyncTask) All actor classes implicitly conform to this protocol, and will synthesize a (currently empty) definition of `enqueue(partialTask:)` unless a suitable one is provided explicitly.
1 parent d96ea28 commit ab3c5de

18 files changed

+282
-3
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4175,6 +4175,7 @@ enum class KnownDerivableProtocolKind : uint8_t {
41754175
Decodable,
41764176
AdditiveArithmetic,
41774177
Differentiable,
4178+
Actor,
41784179
};
41794180

41804181
/// ProtocolDecl - A declaration of a protocol, for example:

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4195,6 +4195,13 @@ ERROR(actorisolated_not_actor_instance_member,none,
41954195
"'@actorIsolated' can only be applied to instance members of actors",
41964196
())
41974197

4198+
ERROR(partial_task_type_missing,none,
4199+
"missing 'PartialAsyncTask' type, probably because the '_Concurrency' "
4200+
"module was not imported", ())
4201+
ERROR(enqueue_partial_task_not_in_context,none,
4202+
"'enqueue(partialTask:)' can only be implemented in the definition of "
4203+
"actor class %0", (Type))
4204+
41984205
//------------------------------------------------------------------------------
41994206
// MARK: Type Check Types
42004207
//------------------------------------------------------------------------------

include/swift/AST/KnownIdentifiers.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ IDENTIFIER(Change)
4444
IDENTIFIER_WITH_NAME(code_, "_code")
4545
IDENTIFIER(CodingKeys)
4646
IDENTIFIER(combine)
47+
IDENTIFIER_(Concurrency)
4748
IDENTIFIER(container)
4849
IDENTIFIER(CoreGraphics)
4950
IDENTIFIER(CoreMedia)
@@ -67,6 +68,7 @@ IDENTIFIER(encode)
6768
IDENTIFIER(encodeIfPresent)
6869
IDENTIFIER(Encoder)
6970
IDENTIFIER(encoder)
71+
IDENTIFIER(enqueue)
7072
IDENTIFIER(erasing)
7173
IDENTIFIER(error)
7274
IDENTIFIER(errorDomain)
@@ -105,6 +107,8 @@ IDENTIFIER(oldValue)
105107
IDENTIFIER(Optional)
106108
IDENTIFIER_(OptionalNilComparisonType)
107109
IDENTIFIER(parameter)
110+
IDENTIFIER(partialTask)
111+
IDENTIFIER(PartialAsyncTask)
108112
IDENTIFIER(projected)
109113
IDENTIFIER(projectedValue)
110114
IDENTIFIER(Protocol)

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#define BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_(name) \
5959
BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, "_" #name)
6060

61+
PROTOCOL(Actor)
6162
PROTOCOL(Sequence)
6263
PROTOCOL(IteratorProtocol)
6364
PROTOCOL(RawRepresentable)

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,9 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
947947
case KnownProtocolKind::Differentiable:
948948
M = getLoadedModule(Id_Differentiation);
949949
break;
950+
case KnownProtocolKind::Actor:
951+
M = getLoadedModule(Id_Concurrency);
952+
break;
950953
default:
951954
M = getStdlibModule();
952955
break;

lib/AST/Decl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5047,7 +5047,8 @@ void ProtocolDecl::computeKnownProtocolKind() const {
50475047
auto module = getModuleContext();
50485048
if (module != module->getASTContext().getStdlibModule() &&
50495049
!module->getName().is("Foundation") &&
5050-
!module->getName().is("_Differentiation")) {
5050+
!module->getName().is("_Differentiation") &&
5051+
!module->getName().is("_Concurrency")) {
50515052
const_cast<ProtocolDecl *>(this)->Bits.ProtocolDecl.KnownProtocol = 1;
50525053
return;
50535054
}
@@ -5093,6 +5094,8 @@ Optional<KnownDerivableProtocolKind>
50935094
return KnownDerivableProtocolKind::AdditiveArithmetic;
50945095
case KnownProtocolKind::Differentiable:
50955096
return KnownDerivableProtocolKind::Differentiable;
5097+
case KnownProtocolKind::Actor:
5098+
return KnownDerivableProtocolKind::Actor;
50965099
default: return None;
50975100
}
50985101
}

lib/AST/ProtocolConformance.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,12 @@ void NominalTypeDecl::prepareConformanceTable() const {
12561256
addSynthesized(KnownProtocolKind::RawRepresentable);
12571257
}
12581258
}
1259+
1260+
// Actor classes conform to the actor protocol.
1261+
if (auto classDecl = dyn_cast<ClassDecl>(mutableThis)) {
1262+
if (classDecl->isActor())
1263+
addSynthesized(KnownProtocolKind::Actor);
1264+
}
12591265
}
12601266

12611267
bool NominalTypeDecl::lookupConformance(

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5045,6 +5045,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
50455045
case KnownProtocolKind::AdditiveArithmetic:
50465046
case KnownProtocolKind::Differentiable:
50475047
case KnownProtocolKind::FloatingPoint:
5048+
case KnownProtocolKind::Actor:
50485049
return SpecialProtocol::None;
50495050
}
50505051

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_swift_host_library(swiftSema STATIC
1717
ConstraintLocator.cpp
1818
ConstraintSystem.cpp
1919
DebuggerTestingTransform.cpp
20+
DerivedConformanceActor.cpp
2021
DerivedConformanceAdditiveArithmetic.cpp
2122
DerivedConformanceCaseIterable.cpp
2223
DerivedConformanceCodable.cpp

lib/Sema/DerivedConformanceActor.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===--- DerivedConformanceEquatableHashable.cpp - Derived Equatable & co -===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements implicit derivation of the Actor protocol.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
#include "DerivedConformances.h"
17+
#include "TypeChecker.h"
18+
#include "swift/AST/ParameterList.h"
19+
20+
using namespace swift;
21+
22+
bool DerivedConformance::canDeriveActor(
23+
NominalTypeDecl *nominal, DeclContext *dc) {
24+
auto classDecl = dyn_cast<ClassDecl>(nominal);
25+
return classDecl && classDecl->isActor() && dc == nominal;
26+
}
27+
28+
static DeclName getEnqueuePartialTaskName(ASTContext &ctx) {
29+
return DeclName(ctx, ctx.Id_enqueue, { ctx.Id_partialTask });
30+
}
31+
32+
static Type getPartialAsyncTaskType(ASTContext &ctx) {
33+
auto concurrencyModule = ctx.getLoadedModule(ctx.Id_Concurrency);
34+
if (!concurrencyModule)
35+
return Type();
36+
37+
SmallVector<ValueDecl *, 2> decls;
38+
concurrencyModule->lookupQualified(
39+
concurrencyModule, DeclNameRef(ctx.Id_PartialAsyncTask),
40+
NL_QualifiedDefault, decls);
41+
for (auto decl : decls) {
42+
if (auto typeDecl = dyn_cast<TypeDecl>(decl))
43+
return typeDecl->getDeclaredInterfaceType();
44+
}
45+
46+
return Type();
47+
}
48+
49+
static std::pair<BraceStmt *, bool>
50+
deriveBodyActor_enqueuePartialTask(
51+
AbstractFunctionDecl *enqueuePartialTask, void *) {
52+
ASTContext &ctx = enqueuePartialTask->getASTContext();
53+
54+
// FIXME: Call into runtime API to enqueue the task, once we figure out
55+
// what that runtime API should look like.
56+
57+
auto body = BraceStmt::create(
58+
ctx, SourceLoc(), { }, SourceLoc(), /*implicit=*/true);
59+
return { body, /*isTypeChecked=*/true };
60+
}
61+
62+
/// Derive the declaration of Actor's enqueue(partialTask:).
63+
static ValueDecl *deriveActor_enqueuePartialTask(DerivedConformance &derived) {
64+
ASTContext &ctx = derived.Context;
65+
66+
Type partialTaskType = getPartialAsyncTaskType(ctx);
67+
if (!partialTaskType) {
68+
derived.Nominal->diagnose(diag::partial_task_type_missing);
69+
return nullptr;
70+
}
71+
72+
auto parentDC = derived.getConformanceContext();
73+
auto partialTaskParamDecl = new (ctx) ParamDecl(
74+
SourceLoc(), SourceLoc(), ctx.Id_partialTask,
75+
SourceLoc(), ctx.Id_partialTask, parentDC);
76+
partialTaskParamDecl->setInterfaceType(partialTaskType);
77+
partialTaskParamDecl->setSpecifier(ParamSpecifier::Default);
78+
79+
ParameterList *params = ParameterList::createWithoutLoc(partialTaskParamDecl);
80+
auto func = FuncDecl::createImplicit(
81+
ctx, StaticSpellingKind::None, getEnqueuePartialTaskName(ctx),
82+
SourceLoc(), /*Async=*/false, /*Throws=*/false, /*GenericParams=*/nullptr,
83+
params, TupleType::getEmpty(ctx), parentDC);
84+
func->copyFormalAccessFrom(derived.Nominal);
85+
func->setBodySynthesizer(deriveBodyActor_enqueuePartialTask);
86+
87+
// FIXME: This function should be "actor-unsafe", not "actor-independent", but
88+
// the latter is all we have at the moment.
89+
func->getAttrs().add(new (ctx) ActorIndependentAttr(/*IsImplicit=*/true));
90+
91+
derived.addMembersToConformanceContext({func});
92+
return func;
93+
}
94+
95+
ValueDecl *DerivedConformance::deriveActor(ValueDecl *requirement) {
96+
auto func = dyn_cast<FuncDecl>(requirement);
97+
if (!func)
98+
return nullptr;
99+
100+
if (func->getName() == getEnqueuePartialTaskName(Context))
101+
return deriveActor_enqueuePartialTask(*this);
102+
103+
return nullptr;
104+
}

0 commit comments

Comments
 (0)