Skip to content

[Concurrency] Introduce Actor protocol to which actor classes all conform #34111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,9 @@ namespace SpecialPointerAuthDiscriminators {

/// Resilient class stub initializer callback
const uint16_t ResilientClassStubInitCallback = 0xC671;

/// Actor enqueue(partialTask:).
const uint16_t ActorEnqueuePartialTask = 0x8f3d;
}

/// The number of arguments that will be passed directly to a generic
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler,
101)

CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
OnClass | ConcurrencyOnly |
DeclModifier | OnClass | ConcurrencyOnly |
ABIBreakingToAdd | ABIBreakingToRemove |
APIBreakingToAdd | APIBreakingToRemove,
102)
Expand Down
9 changes: 9 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4175,6 +4175,7 @@ enum class KnownDerivableProtocolKind : uint8_t {
Decodable,
AdditiveArithmetic,
Differentiable,
Actor,
};

/// ProtocolDecl - A declaration of a protocol, for example:
Expand Down Expand Up @@ -6328,6 +6329,14 @@ class FuncDecl : public AbstractFunctionDecl {

bool isMainTypeMainMethod() const;

/// Whether the given name is enqueue(partialTask:), which is used for
/// actors.
static bool isEnqueuePartialTaskName(ASTContext &ctx, DeclName name);

/// Determine whether this function is the witness to the Actor protocol's
/// enqueue(partialTask:) operation within an actor.
bool isActorEnqueuePartialTaskWitness() const;

SelfAccessKind getSelfAccessKind() const;

void setSelfAccessKind(SelfAccessKind mod) {
Expand Down
10 changes: 10 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4101,6 +4101,9 @@ ERROR(not_objc_function_async,none,
"'async' function cannot be represented in Objective-C", ())
NOTE(not_objc_function_type_async,none,
"'async' function types cannot be represented in Objective-C", ())
ERROR(actor_isolated_objc,none,
"actor-isolated %0 %1 cannot be @objc",
(DescriptiveDeclKind, DeclName))
NOTE(protocol_witness_async_conflict,none,
"candidate is %select{not |}0'async', but protocol requirement is%select{| not}0",
(bool))
Expand Down Expand Up @@ -4195,6 +4198,13 @@ ERROR(actorisolated_not_actor_instance_member,none,
"'@actorIsolated' can only be applied to instance members of actors",
())

ERROR(concurrency_lib_missing,none,
"missing '%0' declaration, probably because the '_Concurrency' "
"module was not imported", (StringRef))
ERROR(enqueue_partial_task_not_in_context,none,
"'enqueue(partialTask:)' can only be implemented in the definition of "
"actor class %0", (Type))

//------------------------------------------------------------------------------
// MARK: Type Check Types
//------------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ IDENTIFIER(Change)
IDENTIFIER_WITH_NAME(code_, "_code")
IDENTIFIER(CodingKeys)
IDENTIFIER(combine)
IDENTIFIER_(Concurrency)
IDENTIFIER(container)
IDENTIFIER(CoreGraphics)
IDENTIFIER(CoreMedia)
Expand All @@ -67,6 +68,7 @@ IDENTIFIER(encode)
IDENTIFIER(encodeIfPresent)
IDENTIFIER(Encoder)
IDENTIFIER(encoder)
IDENTIFIER(enqueue)
IDENTIFIER(erasing)
IDENTIFIER(error)
IDENTIFIER(errorDomain)
Expand Down Expand Up @@ -105,6 +107,8 @@ IDENTIFIER(oldValue)
IDENTIFIER(Optional)
IDENTIFIER_(OptionalNilComparisonType)
IDENTIFIER(parameter)
IDENTIFIER(partialTask)
IDENTIFIER(PartialAsyncTask)
IDENTIFIER(projected)
IDENTIFIER(projectedValue)
IDENTIFIER(Protocol)
Expand Down Expand Up @@ -137,6 +141,7 @@ IDENTIFIER(withKeywordArguments)
IDENTIFIER(wrapped)
IDENTIFIER(wrappedValue)
IDENTIFIER(wrapperValue)
IDENTIFIER_WITH_NAME(actorStorage, "$__actor_storage")

// Kinds of layout constraints
IDENTIFIER_WITH_NAME(UnknownLayout, "_UnknownLayout")
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/KnownProtocols.def
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#define BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_(name) \
BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, "_" #name)

PROTOCOL(Actor)
PROTOCOL(Sequence)
PROTOCOL(IteratorProtocol)
PROTOCOL(RawRepresentable)
Expand Down
3 changes: 3 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,9 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
case KnownProtocolKind::Differentiable:
M = getLoadedModule(Id_Differentiation);
break;
case KnownProtocolKind::Actor:
M = getLoadedModule(Id_Concurrency);
break;
default:
M = getStdlibModule();
break;
Expand Down
55 changes: 54 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5047,7 +5047,8 @@ void ProtocolDecl::computeKnownProtocolKind() const {
auto module = getModuleContext();
if (module != module->getASTContext().getStdlibModule() &&
!module->getName().is("Foundation") &&
!module->getName().is("_Differentiation")) {
!module->getName().is("_Differentiation") &&
!module->getName().is("_Concurrency")) {
const_cast<ProtocolDecl *>(this)->Bits.ProtocolDecl.KnownProtocol = 1;
return;
}
Expand Down Expand Up @@ -5093,6 +5094,8 @@ Optional<KnownDerivableProtocolKind>
return KnownDerivableProtocolKind::AdditiveArithmetic;
case KnownProtocolKind::Differentiable:
return KnownDerivableProtocolKind::Differentiable;
case KnownProtocolKind::Actor:
return KnownDerivableProtocolKind::Actor;
default: return None;
}
}
Expand Down Expand Up @@ -7505,6 +7508,56 @@ bool FuncDecl::isMainTypeMainMethod() const {
getParameters()->size() == 0;
}

bool FuncDecl::isEnqueuePartialTaskName(ASTContext &ctx, DeclName name) {
if (name.isCompoundName() && name.getBaseName() == ctx.Id_enqueue) {
auto argumentNames = name.getArgumentNames();
return argumentNames.size() == 1 && argumentNames[0] == ctx.Id_partialTask;
}

return false;
}

bool FuncDecl::isActorEnqueuePartialTaskWitness() const {
if (!isEnqueuePartialTaskName(getASTContext(), getName()))
return false;

auto classDecl = getDeclContext()->getSelfClassDecl();
if (!classDecl)
return false;

if (!classDecl->isActor())
return false;

ASTContext &ctx = getASTContext();
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
if (!actorProto)
return false;

FuncDecl *requirement = nullptr;
for (auto protoMember : actorProto->getParsedMembers()) {
if (auto protoFunc = dyn_cast<FuncDecl>(protoMember)) {
if (isEnqueuePartialTaskName(ctx, protoFunc->getName())) {
requirement = protoFunc;
break;
}
}
}

if (!requirement)
return false;

SmallVector<ProtocolConformance *, 1> conformances;
classDecl->lookupConformance(
classDecl->getModuleContext(), actorProto, conformances);
for (auto conformance : conformances) {
auto witness = conformance->getWitnessDecl(requirement);
if (witness == this)
return true;
}

return false;
}

ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
bool Failable, SourceLoc FailabilityLoc,
bool Throws,
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,12 @@ void NominalTypeDecl::prepareConformanceTable() const {
addSynthesized(KnownProtocolKind::RawRepresentable);
}
}

// Actor classes conform to the actor protocol.
if (auto classDecl = dyn_cast<ClassDecl>(mutableThis)) {
if (classDecl->isActor())
addSynthesized(KnownProtocolKind::Actor);
}
}

bool NominalTypeDecl::lookupConformance(
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5045,6 +5045,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
case KnownProtocolKind::AdditiveArithmetic:
case KnownProtocolKind::Differentiable:
case KnownProtocolKind::FloatingPoint:
case KnownProtocolKind::Actor:
return SpecialProtocol::None;
}

Expand Down
11 changes: 11 additions & 0 deletions lib/IRGen/GenPointerAuth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,17 @@ PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const {
assert(!constant.isForeign &&
"discriminator for foreign declaration not supported yet!");

// Special case: methods that are witnesses to Actor.enqueue(partialTask:)
// have their own descriminator, which is shared across all actor classes.
if (constant.hasFuncDecl()) {
auto func = dyn_cast<FuncDecl>(constant.getFuncDecl());
if (func->isActorEnqueuePartialTaskWitness()) {
cache = IGM.getSize(
Size(SpecialPointerAuthDiscriminators::ActorEnqueuePartialTask));
return cache;
}
}

auto mangling = constant.mangle();
cache = getDiscriminatorForString(IGM, mangling);
return cache;
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_swift_host_library(swiftSema STATIC
ConstraintLocator.cpp
ConstraintSystem.cpp
DebuggerTestingTransform.cpp
DerivedConformanceActor.cpp
DerivedConformanceAdditiveArithmetic.cpp
DerivedConformanceCaseIterable.cpp
DerivedConformanceCodable.cpp
Expand Down
Loading