From 774a94f69d9fb089e07f2eabe231e2bc6039c4e2 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 14 Jun 2022 10:01:42 -0700 Subject: [PATCH] Make sure we can dig out the (distributed) actor from an archetype. Fixes #59356 / rdar://94976378. --- include/swift/AST/Types.h | 4 + lib/AST/Decl.cpp | 11 ++- lib/AST/Type.cpp | 81 ++++++------------- .../distributed_protocol_isolation.swift | 18 ++--- .../rdar94976378.swift | 14 ++++ 5 files changed, 55 insertions(+), 73 deletions(-) create mode 100644 validation-test/compiler_crashers_2_fixed/rdar94976378.swift diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 3c8de0914bf09..9947a26917ccf 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -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(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 60cda1b9c097a..bfd41a4547a4a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -9222,12 +9222,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()); } } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 23a16f71b35a0..cecaa0bec6cc8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -400,84 +400,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()) { - 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(nominal)) - return classDecl->isDistributedActor(); - - if (isa(nominal) || isa(nominal)) - return false; - } - - // Archetypes check for conformance to DistributedActor. - if (auto archetype = getAs()) { - 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; } diff --git a/test/Distributed/distributed_protocol_isolation.swift b/test/Distributed/distributed_protocol_isolation.swift index bc89aa51e9355..caba2fd4a686d 100644 --- a/test/Distributed/distributed_protocol_isolation.swift +++ b/test/Distributed/distributed_protocol_isolation.swift @@ -224,11 +224,10 @@ func test_watchingDA(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 { @@ -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 { diff --git a/validation-test/compiler_crashers_2_fixed/rdar94976378.swift b/validation-test/compiler_crashers_2_fixed/rdar94976378.swift new file mode 100644 index 0000000000000..3bd280ffd624b --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar94976378.swift @@ -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() + } + } +}