Skip to content

Commit b7015c8

Browse files
committed
Simplify keypath checking for actor isolation.
(cherry picked from commit 29656b8)
1 parent d34063b commit b7015c8

File tree

1 file changed

+31
-50
lines changed

1 file changed

+31
-50
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,10 @@ static void noteGlobalActorOnContext(DeclContext *dc, Type globalActor) {
16511651
}
16521652
}
16531653

1654+
static bool isAccessibleAcrossActors(
1655+
ValueDecl *value, const ActorIsolation &isolation,
1656+
const DeclContext *fromDC, Optional<ReferencedActor> actorInstance);
1657+
16541658
namespace {
16551659
/// Check for adherence to the actor isolation rules, emitting errors
16561660
/// when actor-isolated declarations are used in an unsafe manner.
@@ -2758,72 +2762,49 @@ namespace {
27582762
bool checkKeyPathExpr(KeyPathExpr *keyPath) {
27592763
bool diagnosed = false;
27602764

2761-
// returns None if it is not a 'let'-bound var decl. Otherwise,
2762-
// the bool indicates whether a diagnostic was emitted.
2763-
auto checkLetBoundVarDecl = [&](KeyPathExpr::Component const& component)
2764-
-> Optional<bool> {
2765-
auto decl = component.getDeclRef().getDecl();
2766-
if (auto varDecl = dyn_cast<VarDecl>(decl)) {
2767-
if (varDecl->isLet()) {
2768-
auto type = component.getComponentType();
2769-
if (shouldDiagnoseExistingDataRaces(getDeclContext()) &&
2770-
diagnoseNonSendableTypes(
2771-
type, getDeclContext(), component.getLoc(),
2772-
diag::non_sendable_keypath_access))
2773-
return true;
2774-
2775-
return false;
2776-
}
2777-
}
2778-
return None;
2779-
};
2780-
27812765
// check the components of the keypath.
27822766
for (const auto &component : keyPath->getComponents()) {
27832767
// The decl referred to by the path component cannot be within an actor.
27842768
if (component.hasDeclRef()) {
27852769
auto concDecl = component.getDeclRef();
2786-
auto isolation = ActorIsolationRestriction::forDeclaration(
2787-
concDecl, getDeclContext());
2788-
2789-
switch (isolation.getKind()) {
2790-
case ActorIsolationRestriction::Unsafe:
2791-
case ActorIsolationRestriction::Unrestricted:
2792-
break; // OK. Does not refer to an actor-isolated member.
2793-
2794-
case ActorIsolationRestriction::GlobalActorUnsafe:
2795-
// Only check if we're in code that's adopted concurrency features.
2796-
if (!shouldDiagnoseExistingDataRaces(getDeclContext()))
2797-
break; // do not check
2798-
2799-
LLVM_FALLTHROUGH; // otherwise, perform checking
2770+
auto decl = concDecl.getDecl();
2771+
auto isolation = getActorIsolationForReference(
2772+
decl, getDeclContext());
2773+
switch (isolation) {
2774+
case ActorIsolation::Independent:
2775+
case ActorIsolation::Unspecified:
2776+
break;
28002777

2801-
case ActorIsolationRestriction::GlobalActor:
2778+
case ActorIsolation::GlobalActor:
2779+
case ActorIsolation::GlobalActorUnsafe:
28022780
// Disable global actor checking for now.
2803-
if (!ctx.LangOpts.isSwiftVersionAtLeast(6))
2781+
if (isolation.isGlobalActor() &&
2782+
!ctx.LangOpts.isSwiftVersionAtLeast(6))
28042783
break;
28052784

2806-
LLVM_FALLTHROUGH; // otherwise, it's invalid so diagnose it.
2785+
LLVM_FALLTHROUGH;
28072786

2808-
case ActorIsolationRestriction::CrossActorSelf:
2809-
// 'let'-bound decls with this isolation are OK, just check them.
2810-
if (auto wasLetBound = checkLetBoundVarDecl(component)) {
2811-
diagnosed = wasLetBound.getValue();
2787+
case ActorIsolation::ActorInstance:
2788+
// If this entity is always accessible across actors, just check
2789+
// Sendable.
2790+
if (isAccessibleAcrossActors(
2791+
decl, isolation, getDeclContext(), None)) {
2792+
if (diagnoseNonSendableTypes(
2793+
component.getComponentType(), getDeclContext(),
2794+
component.getLoc(),
2795+
diag::non_sendable_keypath_access)) {
2796+
diagnosed = true;
2797+
}
28122798
break;
28132799
}
2814-
LLVM_FALLTHROUGH; // otherwise, it's invalid so diagnose it.
28152800

2816-
case ActorIsolationRestriction::ActorSelf: {
2817-
auto decl = concDecl.getDecl();
28182801
ctx.Diags.diagnose(component.getLoc(),
28192802
diag::actor_isolated_keypath_component,
2820-
isolation.getKind() ==
2821-
ActorIsolationRestriction::CrossActorSelf,
2803+
isolation.isDistributedActor(),
28222804
decl->getDescriptiveKind(), decl->getName());
28232805
diagnosed = true;
28242806
break;
28252807
}
2826-
}; // end switch
28272808
}
28282809

28292810
// Captured values in a path component must conform to Sendable.
@@ -4937,12 +4918,12 @@ static bool isThrowsDecl(ConcreteDeclRef declRef) {
49374918
}
49384919

49394920
/// Determine whether the given value can be accessed across actors
4940-
/// without requiring async promotion.
4921+
/// without from normal synchronous code.
49414922
///
49424923
/// \param value The value we are checking.
49434924
/// \param isolation The actor isolation of the value.
49444925
/// \param fromDC The context where we are performing the access.
4945-
static bool isAccessibleAcrossActorsWithoutAsyncPromotion(
4926+
static bool isAccessibleAcrossActors(
49464927
ValueDecl *value, const ActorIsolation &isolation,
49474928
const DeclContext *fromDC, Optional<ReferencedActor> actorInstance) {
49484929
switch (value->getKind()) {
@@ -5094,7 +5075,7 @@ ActorReferenceResult ActorReferenceResult::forReference(
50945075
// At this point, we are accessing the target from outside the actor.
50955076
// First, check whether it is something that can be accessed directly,
50965077
// without any kind of promotion.
5097-
if (isAccessibleAcrossActorsWithoutAsyncPromotion(
5078+
if (isAccessibleAcrossActors(
50985079
declRef.getDecl(), declIsolation, fromDC, actorInstance))
50995080
return forEntersActor(declIsolation, None);
51005081

0 commit comments

Comments
 (0)