Skip to content

Commit 215fe8c

Browse files
authored
Merge pull request #59440 from DougGregor/concurrency-fixes-5.7
Minor concurrency fixes for 5.7
2 parents 0eb649d + f970ef7 commit 215fe8c

File tree

10 files changed

+103
-75
lines changed

10 files changed

+103
-75
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4601,6 +4601,9 @@ ERROR(effectful_keypath_component,none,
46014601
ERROR(local_function_executed_concurrently,none,
46024602
"concurrently-executed %0 %1 must be marked as '@Sendable'",
46034603
(DescriptiveDeclKind, DeclName))
4604+
ERROR(sendable_isolated_sync_function,none,
4605+
"%0 synchronous %1 %2 cannot be marked as '@Sendable'",
4606+
(ActorIsolation, DescriptiveDeclKind, DeclName))
46044607
ERROR(concurrent_access_of_local_capture,none,
46054608
"%select{mutation of|reference to}0 captured %1 %2 in "
46064609
"concurrently-executing code",

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
786786
/// Break an existential down into a set of constraints.
787787
ExistentialLayout getExistentialLayout();
788788

789+
/// If this is an actor or distributed type, get the nominal type declaration
790+
/// for the actor.
791+
NominalTypeDecl *getAnyActor();
792+
789793
/// Determines whether this type is an actor type.
790794
bool isActorType();
791795

lib/AST/Decl.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9152,12 +9152,11 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
91529152

91539153
case ClosureActorIsolation::ActorInstance: {
91549154
auto selfDecl = isolation.getActorInstance();
9155-
auto actorClass = selfDecl->getType()->getReferenceStorageReferent()
9156-
->getClassOrBoundGenericClass();
9157-
// FIXME: Doesn't work properly with generics #59356
9158-
assert(actorClass && "Bad closure actor isolation?");
9159-
return ActorIsolation::forActorInstance(actorClass)
9160-
.withPreconcurrency(isolation.preconcurrency());
9155+
auto actor = selfDecl->getType()->getReferenceStorageReferent()
9156+
->getAnyActor();
9157+
assert(actor && "Bad closure actor isolation?");
9158+
return ActorIsolation::forActorInstance(actor)
9159+
.withPreconcurrency(isolation.preconcurrency());
91619160
}
91629161
}
91639162
}

lib/AST/Type.cpp

Lines changed: 24 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -391,84 +391,51 @@ bool CanType::isTypeErasedGenericClassTypeImpl(CanType type) {
391391
return false;
392392
}
393393

394-
static bool archetypeConformsTo(ArchetypeType *archetype, KnownProtocolKind protocol) {
395-
auto &ctx = archetype->getASTContext();
396-
auto expectedProto = ctx.getProtocol(protocol);
397-
if (!expectedProto)
398-
return false;
399-
400-
for (auto proto : archetype->getConformsTo()) {
401-
if (proto == expectedProto || proto->inheritsFrom(expectedProto))
402-
return true;
403-
}
404-
405-
return false;
406-
}
407-
408-
bool TypeBase::isActorType() {
394+
NominalTypeDecl *TypeBase::getAnyActor() {
409395
// Nominal types: check whether the declaration is an actor.
410-
if (auto nominal = getAnyNominal())
411-
return nominal->isActor();
396+
if (auto nominal = getAnyNominal()) {
397+
if (nominal->isAnyActor())
398+
return nominal;
399+
}
412400

413401
// Archetypes check for conformance to Actor.
414402
if (auto archetype = getAs<ArchetypeType>()) {
415-
return archetypeConformsTo(archetype, KnownProtocolKind::Actor);
403+
for (auto proto : archetype->getConformsTo()) {
404+
if (proto->isAnyActor())
405+
return proto;
406+
}
407+
408+
return nullptr;
416409
}
417410

418411
// Existential types: check for Actor protocol.
419412
if (isExistentialType()) {
420-
auto actorProto = getASTContext().getProtocol(KnownProtocolKind::Actor);
421-
if (!actorProto)
422-
return false;
423-
424413
auto layout = getExistentialLayout();
425414
if (auto superclass = layout.getSuperclass()) {
426-
if (superclass->isActorType())
427-
return true;
415+
if (auto actor = superclass->getAnyActor())
416+
return actor;
428417
}
429418

430419
for (auto proto : layout.getProtocols()) {
431-
if (proto->isActor())
432-
return true;
420+
if (proto->isAnyActor())
421+
return proto;
433422
}
434423

435-
return false;
424+
return nullptr;
436425
}
437426

427+
return nullptr;
428+
}
429+
430+
bool TypeBase::isActorType() {
431+
if (auto actor = getAnyActor())
432+
return actor->isActor();
438433
return false;
439434
}
440435

441436
bool TypeBase::isDistributedActor() {
442-
// Nominal types: check whether the declaration is an actor.
443-
if (auto *nominal = getAnyNominal()) {
444-
if (auto *classDecl = dyn_cast<ClassDecl>(nominal))
445-
return classDecl->isDistributedActor();
446-
447-
if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal))
448-
return false;
449-
}
450-
451-
// Archetypes check for conformance to DistributedActor.
452-
if (auto archetype = getAs<ArchetypeType>()) {
453-
return archetypeConformsTo(archetype, KnownProtocolKind::DistributedActor);
454-
}
455-
456-
// Existential types: check for DistributedActor protocol conformance.
457-
if (isExistentialType()) {
458-
auto actorProto = getASTContext().getDistributedActorDecl();
459-
if (!actorProto)
460-
return false;
461-
462-
// TODO(distributed): Inheritance is not yet supported.
463-
464-
auto layout = getExistentialLayout();
465-
return llvm::any_of(layout.getProtocols(),
466-
[&actorProto](ProtocolDecl *protocol) {
467-
return protocol == actorProto ||
468-
protocol->inheritsFrom(actorProto);
469-
});
470-
}
471-
437+
if (auto actor = getAnyActor())
438+
return actor->isDistributedActor();
472439
return false;
473440
}
474441

lib/Sema/TypeCheckAttr.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
149149
IGNORED_ATTR(OriginallyDefinedIn)
150150
IGNORED_ATTR(NoDerivative)
151151
IGNORED_ATTR(SpecializeExtension)
152-
IGNORED_ATTR(Sendable)
153152
IGNORED_ATTR(NonSendable)
154153
IGNORED_ATTR(AtRethrows)
155154
IGNORED_ATTR(AtReasync)
@@ -321,6 +320,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
321320
void checkBackDeployAttrs(ArrayRef<BackDeployAttr *> Attrs);
322321

323322
void visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr);
323+
324+
void visitSendableAttr(SendableAttr *attr);
324325
};
325326

326327
} // end anonymous namespace
@@ -5801,6 +5802,21 @@ void AttributeChecker::visitKnownToBeLocalAttr(KnownToBeLocalAttr *attr) {
58015802
}
58025803
}
58035804

5805+
void AttributeChecker::visitSendableAttr(SendableAttr *attr) {
5806+
5807+
if ((isa<AbstractFunctionDecl>(D) || isa<AbstractStorageDecl>(D)) &&
5808+
!isAsyncDecl(cast<ValueDecl>(D))) {
5809+
auto value = cast<ValueDecl>(D);
5810+
ActorIsolation isolation = getActorIsolation(value);
5811+
if (isolation.isActorIsolated()) {
5812+
diagnoseAndRemoveAttr(
5813+
attr, diag::sendable_isolated_sync_function,
5814+
isolation, value->getDescriptiveKind(), value->getName())
5815+
.warnUntilSwiftVersion(6);
5816+
}
5817+
}
5818+
}
5819+
58045820
void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
58055821
// 'nonisolated' can be applied to global and static/class variables
58065822
// that do not have storage.

test/Concurrency/Backdeploy/mangling.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 %s -o %t/test_mangling -Xfrontend -disable-availability-checking
1313
// RUN: %target-run %t/test_mangling
1414

15-
// REQUIRESx: CPU=x86_64
1615
// REQUIRES: OS=macosx
1716
// REQUIRES: executable_test
1817
// REQUIRES: concurrency_runtime
18+
// UNSUPPORTED: back_deployment_runtime
1919

2020
actor MyActor { }
2121

test/Concurrency/Backdeploy/objc_actor.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// REQUIRES: OS=macosx
66
// REQUIRES: executable_test
77
// REQUIRES: concurrency_runtime
8+
// UNSUPPORTED: back_deployment_runtime
89

910
import Foundation
1011

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// REQUIRES: concurrency
3+
4+
5+
@Sendable func globalFunc() { }
6+
7+
@available(SwiftStdlib 5.1, *)
8+
actor A {
9+
var state: Bool = false
10+
11+
@Sendable func f() { // expected-warning{{actor-isolated synchronous instance method 'f()' cannot be marked as '@Sendable'}}
12+
state = true
13+
}
14+
15+
@Sendable nonisolated func g() { }
16+
17+
@Sendable func fAsync() async {
18+
state = true
19+
}
20+
}
21+
22+
@available(SwiftStdlib 5.1, *)
23+
@MainActor @Sendable func globalActorFunc() { } // expected-warning{{main actor-isolated synchronous global function 'globalActorFunc()' cannot be marked as '@Sendable'}}
24+
25+
@available(SwiftStdlib 5.1, *)
26+
@MainActor @Sendable func globalActorFuncAsync() async { }

test/Distributed/distributed_protocol_isolation.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,10 @@ func test_watchingDA<WDA: TerminationWatchingDA>(da: WDA) async throws {
224224
// expected-warning@-2{{no calls to throwing functions occur within 'try' expression}}
225225

226226
let __secretlyKnownToBeLocal = da
227-
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)
228-
// FIXME: pending fix of closure isolation checking with actors #59356
229-
// await da.whenLocal { __secretlyKnownToBeLocal in
230-
// await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
231-
// }
227+
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
228+
await da.whenLocal { __secretlyKnownToBeLocal in
229+
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
230+
}
232231
}
233232

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

240239
let __secretlyKnownToBeLocal = wda
241-
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)
242-
// FIXME: pending fix of closure isolation checking with actors #59356
243-
// await wda.whenLocal { __secretlyKnownToBeLocal in
244-
// await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
245-
// }
240+
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
241+
await wda.whenLocal { __secretlyKnownToBeLocal in
242+
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK
243+
}
246244
}
247245

248246
func test_watchingDA_any(da: any TerminationWatchingDA) async throws {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-frontend -typecheck %s
2+
3+
// REQUIRES: concurrency
4+
5+
@available(SwiftStdlib 5.1, *)
6+
extension Actor {
7+
func f() { }
8+
9+
func g(a: [Int]) {
10+
a.forEach { i in
11+
f()
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)