Skip to content
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/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4601,6 +4601,9 @@ ERROR(effectful_keypath_component,none,
ERROR(local_function_executed_concurrently,none,
"concurrently-executed %0 %1 must be marked as '@Sendable'",
(DescriptiveDeclKind, DeclName))
ERROR(sendable_isolated_sync_function,none,
"%0 synchronous %1 %2 cannot be marked as '@Sendable'",
(ActorIsolation, DescriptiveDeclKind, DeclName))
ERROR(concurrent_access_of_local_capture,none,
"%select{mutation of|reference to}0 captured %1 %2 in "
"concurrently-executing code",
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
/// Break an existential down into a set of constraints.
ExistentialLayout getExistentialLayout();

/// If this is an actor or distributed type, get the nominal type declaration
/// for the actor.
NominalTypeDecl *getAnyActor();

/// Determines whether this type is an actor type.
bool isActorType();

Expand Down
11 changes: 5 additions & 6 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9152,12 +9152,11 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {

case ClosureActorIsolation::ActorInstance: {
auto selfDecl = isolation.getActorInstance();
auto actorClass = selfDecl->getType()->getReferenceStorageReferent()
->getClassOrBoundGenericClass();
// FIXME: Doesn't work properly with generics #59356
assert(actorClass && "Bad closure actor isolation?");
return ActorIsolation::forActorInstance(actorClass)
.withPreconcurrency(isolation.preconcurrency());
auto actor = selfDecl->getType()->getReferenceStorageReferent()
->getAnyActor();
assert(actor && "Bad closure actor isolation?");
return ActorIsolation::forActorInstance(actor)
.withPreconcurrency(isolation.preconcurrency());
}
}
}
Expand Down
81 changes: 24 additions & 57 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,84 +391,51 @@ bool CanType::isTypeErasedGenericClassTypeImpl(CanType type) {
return false;
}

static bool archetypeConformsTo(ArchetypeType *archetype, KnownProtocolKind protocol) {
auto &ctx = archetype->getASTContext();
auto expectedProto = ctx.getProtocol(protocol);
if (!expectedProto)
return false;

for (auto proto : archetype->getConformsTo()) {
if (proto == expectedProto || proto->inheritsFrom(expectedProto))
return true;
}

return false;
}

bool TypeBase::isActorType() {
NominalTypeDecl *TypeBase::getAnyActor() {
// Nominal types: check whether the declaration is an actor.
if (auto nominal = getAnyNominal())
return nominal->isActor();
if (auto nominal = getAnyNominal()) {
if (nominal->isAnyActor())
return nominal;
}

// Archetypes check for conformance to Actor.
if (auto archetype = getAs<ArchetypeType>()) {
return archetypeConformsTo(archetype, KnownProtocolKind::Actor);
for (auto proto : archetype->getConformsTo()) {
if (proto->isAnyActor())
return proto;
}

return nullptr;
}

// Existential types: check for Actor protocol.
if (isExistentialType()) {
auto actorProto = getASTContext().getProtocol(KnownProtocolKind::Actor);
if (!actorProto)
return false;

auto layout = getExistentialLayout();
if (auto superclass = layout.getSuperclass()) {
if (superclass->isActorType())
return true;
if (auto actor = superclass->getAnyActor())
return actor;
}

for (auto proto : layout.getProtocols()) {
if (proto->isActor())
return true;
if (proto->isAnyActor())
return proto;
}

return false;
return nullptr;
}

return nullptr;
}

bool TypeBase::isActorType() {
if (auto actor = getAnyActor())
return actor->isActor();
return false;
}

bool TypeBase::isDistributedActor() {
// Nominal types: check whether the declaration is an actor.
if (auto *nominal = getAnyNominal()) {
if (auto *classDecl = dyn_cast<ClassDecl>(nominal))
return classDecl->isDistributedActor();

if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal))
return false;
}

// Archetypes check for conformance to DistributedActor.
if (auto archetype = getAs<ArchetypeType>()) {
return archetypeConformsTo(archetype, KnownProtocolKind::DistributedActor);
}

// Existential types: check for DistributedActor protocol conformance.
if (isExistentialType()) {
auto actorProto = getASTContext().getDistributedActorDecl();
if (!actorProto)
return false;

// TODO(distributed): Inheritance is not yet supported.

auto layout = getExistentialLayout();
return llvm::any_of(layout.getProtocols(),
[&actorProto](ProtocolDecl *protocol) {
return protocol == actorProto ||
protocol->inheritsFrom(actorProto);
});
}

if (auto actor = getAnyActor())
return actor->isDistributedActor();
return false;
}

Expand Down
18 changes: 17 additions & 1 deletion lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
IGNORED_ATTR(OriginallyDefinedIn)
IGNORED_ATTR(NoDerivative)
IGNORED_ATTR(SpecializeExtension)
IGNORED_ATTR(Sendable)
IGNORED_ATTR(NonSendable)
IGNORED_ATTR(AtRethrows)
IGNORED_ATTR(AtReasync)
Expand Down Expand Up @@ -321,6 +320,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
void checkBackDeployAttrs(ArrayRef<BackDeployAttr *> Attrs);

void visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr);

void visitSendableAttr(SendableAttr *attr);
};

} // end anonymous namespace
Expand Down Expand Up @@ -5801,6 +5802,21 @@ void AttributeChecker::visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr) {
}
}

void AttributeChecker::visitSendableAttr(SendableAttr *attr) {

if ((isa<AbstractFunctionDecl>(D) || isa<AbstractStorageDecl>(D)) &&
!isAsyncDecl(cast<ValueDecl>(D))) {
auto value = cast<ValueDecl>(D);
ActorIsolation isolation = getActorIsolation(value);
if (isolation.isActorIsolated()) {
diagnoseAndRemoveAttr(
attr, diag::sendable_isolated_sync_function,
isolation, value->getDescriptiveKind(), value->getName())
.warnUntilSwiftVersion(6);
}
}
}

void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
// 'nonisolated' can be applied to global and static/class variables
// that do not have storage.
Expand Down
2 changes: 1 addition & 1 deletion test/Concurrency/Backdeploy/mangling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 %s -o %t/test_mangling -Xfrontend -disable-availability-checking
// RUN: %target-run %t/test_mangling

// REQUIRESx: CPU=x86_64
// REQUIRES: OS=macosx
// REQUIRES: executable_test
// REQUIRES: concurrency_runtime
// UNSUPPORTED: back_deployment_runtime

actor MyActor { }

Expand Down
1 change: 1 addition & 0 deletions test/Concurrency/Backdeploy/objc_actor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// REQUIRES: OS=macosx
// REQUIRES: executable_test
// REQUIRES: concurrency_runtime
// UNSUPPORTED: back_deployment_runtime

import Foundation

Expand Down
26 changes: 26 additions & 0 deletions test/Concurrency/sendable_functions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %target-typecheck-verify-swift
// REQUIRES: concurrency


@Sendable func globalFunc() { }

@available(SwiftStdlib 5.1, *)
actor A {
var state: Bool = false

@Sendable func f() { // expected-warning{{actor-isolated synchronous instance method 'f()' cannot be marked as '@Sendable'}}
state = true
}

@Sendable nonisolated func g() { }

@Sendable func fAsync() async {
state = true
}
}

@available(SwiftStdlib 5.1, *)
@MainActor @Sendable func globalActorFunc() { } // expected-warning{{main actor-isolated synchronous global function 'globalActorFunc()' cannot be marked as '@Sendable'}}

@available(SwiftStdlib 5.1, *)
@MainActor @Sendable func globalActorFuncAsync() async { }
18 changes: 8 additions & 10 deletions test/Distributed/distributed_protocol_isolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,10 @@ func test_watchingDA<WDA: TerminationWatchingDA>(da: WDA) async throws {
// expected-warning@-2{{no calls to throwing functions occur within 'try' expression}}

let __secretlyKnownToBeLocal = da
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK // FIXME(#59356): (the __secretlyKnown is a hack, but the whenLocal crashes now on pending isolation getting with generic actors for closures)
// FIXME: pending fix of closure isolation checking with actors #59356
// await da.whenLocal { __secretlyKnownToBeLocal in
// await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
// }
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
await da.whenLocal { __secretlyKnownToBeLocal in
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
}
}

func test_watchingDA_erased(da: DA_TerminationWatchingDA) async throws {
Expand All @@ -238,11 +237,10 @@ func test_watchingDA_erased(da: DA_TerminationWatchingDA) async throws {
// expected-warning@-2{{no calls to throwing functions occur within 'try' expression}}

let __secretlyKnownToBeLocal = wda
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK // FIXME(#59356): (the __secretlyKnown is a hack, but the whenLocal crashes now on pending isolation getting with generic actors for closures)
// FIXME: pending fix of closure isolation checking with actors #59356
// await wda.whenLocal { __secretlyKnownToBeLocal in
// await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
// }
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
await wda.whenLocal { __secretlyKnownToBeLocal in
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
}
}

func test_watchingDA_any(da: any TerminationWatchingDA) async throws {
Expand Down
14 changes: 14 additions & 0 deletions validation-test/compiler_crashers_2_fixed/rdar94976378.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-swift-frontend -typecheck %s

// REQUIRES: concurrency

@available(SwiftStdlib 5.1, *)
extension Actor {
func f() { }

func g(a: [Int]) {
a.forEach { i in
f()
}
}
}