Skip to content

Commit 29656b8

Browse files
committed
Simplify keypath checking for actor isolation.
1 parent 32c1832 commit 29656b8

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
@@ -1597,6 +1597,10 @@ static void noteGlobalActorOnContext(DeclContext *dc, Type globalActor) {
15971597
}
15981598
}
15991599

1600+
static bool isAccessibleAcrossActors(
1601+
ValueDecl *value, const ActorIsolation &isolation,
1602+
const DeclContext *fromDC, Optional<ReferencedActor> actorInstance);
1603+
16001604
namespace {
16011605
/// Check for adherence to the actor isolation rules, emitting errors
16021606
/// when actor-isolated declarations are used in an unsafe manner.
@@ -2696,72 +2700,49 @@ namespace {
26962700
bool checkKeyPathExpr(KeyPathExpr *keyPath) {
26972701
bool diagnosed = false;
26982702

2699-
// returns None if it is not a 'let'-bound var decl. Otherwise,
2700-
// the bool indicates whether a diagnostic was emitted.
2701-
auto checkLetBoundVarDecl = [&](KeyPathExpr::Component const& component)
2702-
-> Optional<bool> {
2703-
auto decl = component.getDeclRef().getDecl();
2704-
if (auto varDecl = dyn_cast<VarDecl>(decl)) {
2705-
if (varDecl->isLet()) {
2706-
auto type = component.getComponentType();
2707-
if (shouldDiagnoseExistingDataRaces(getDeclContext()) &&
2708-
diagnoseNonSendableTypes(
2709-
type, getDeclContext(), component.getLoc(),
2710-
diag::non_sendable_keypath_access))
2711-
return true;
2712-
2713-
return false;
2714-
}
2715-
}
2716-
return None;
2717-
};
2718-
27192703
// check the components of the keypath.
27202704
for (const auto &component : keyPath->getComponents()) {
27212705
// The decl referred to by the path component cannot be within an actor.
27222706
if (component.hasDeclRef()) {
27232707
auto concDecl = component.getDeclRef();
2724-
auto isolation = ActorIsolationRestriction::forDeclaration(
2725-
concDecl, getDeclContext());
2726-
2727-
switch (isolation.getKind()) {
2728-
case ActorIsolationRestriction::Unsafe:
2729-
case ActorIsolationRestriction::Unrestricted:
2730-
break; // OK. Does not refer to an actor-isolated member.
2731-
2732-
case ActorIsolationRestriction::GlobalActorUnsafe:
2733-
// Only check if we're in code that's adopted concurrency features.
2734-
if (!shouldDiagnoseExistingDataRaces(getDeclContext()))
2735-
break; // do not check
2736-
2737-
LLVM_FALLTHROUGH; // otherwise, perform checking
2708+
auto decl = concDecl.getDecl();
2709+
auto isolation = getActorIsolationForReference(
2710+
decl, getDeclContext());
2711+
switch (isolation) {
2712+
case ActorIsolation::Independent:
2713+
case ActorIsolation::Unspecified:
2714+
break;
27382715

2739-
case ActorIsolationRestriction::GlobalActor:
2716+
case ActorIsolation::GlobalActor:
2717+
case ActorIsolation::GlobalActorUnsafe:
27402718
// Disable global actor checking for now.
2741-
if (!ctx.LangOpts.isSwiftVersionAtLeast(6))
2719+
if (isolation.isGlobalActor() &&
2720+
!ctx.LangOpts.isSwiftVersionAtLeast(6))
27422721
break;
27432722

2744-
LLVM_FALLTHROUGH; // otherwise, it's invalid so diagnose it.
2723+
LLVM_FALLTHROUGH;
27452724

2746-
case ActorIsolationRestriction::CrossActorSelf:
2747-
// 'let'-bound decls with this isolation are OK, just check them.
2748-
if (auto wasLetBound = checkLetBoundVarDecl(component)) {
2749-
diagnosed = wasLetBound.getValue();
2725+
case ActorIsolation::ActorInstance:
2726+
// If this entity is always accessible across actors, just check
2727+
// Sendable.
2728+
if (isAccessibleAcrossActors(
2729+
decl, isolation, getDeclContext(), None)) {
2730+
if (diagnoseNonSendableTypes(
2731+
component.getComponentType(), getDeclContext(),
2732+
component.getLoc(),
2733+
diag::non_sendable_keypath_access)) {
2734+
diagnosed = true;
2735+
}
27502736
break;
27512737
}
2752-
LLVM_FALLTHROUGH; // otherwise, it's invalid so diagnose it.
27532738

2754-
case ActorIsolationRestriction::ActorSelf: {
2755-
auto decl = concDecl.getDecl();
27562739
ctx.Diags.diagnose(component.getLoc(),
27572740
diag::actor_isolated_keypath_component,
2758-
isolation.getKind() ==
2759-
ActorIsolationRestriction::CrossActorSelf,
2741+
isolation.isDistributedActor(),
27602742
decl->getDescriptiveKind(), decl->getName());
27612743
diagnosed = true;
27622744
break;
27632745
}
2764-
}; // end switch
27652746
}
27662747

27672748
// Captured values in a path component must conform to Sendable.
@@ -4867,12 +4848,12 @@ static bool isThrowsDecl(ConcreteDeclRef declRef) {
48674848
}
48684849

48694850
/// Determine whether the given value can be accessed across actors
4870-
/// without requiring async promotion.
4851+
/// without from normal synchronous code.
48714852
///
48724853
/// \param value The value we are checking.
48734854
/// \param isolation The actor isolation of the value.
48744855
/// \param fromDC The context where we are performing the access.
4875-
static bool isAccessibleAcrossActorsWithoutAsyncPromotion(
4856+
static bool isAccessibleAcrossActors(
48764857
ValueDecl *value, const ActorIsolation &isolation,
48774858
const DeclContext *fromDC, Optional<ReferencedActor> actorInstance) {
48784859
switch (value->getKind()) {
@@ -5024,7 +5005,7 @@ ActorReferenceResult ActorReferenceResult::forReference(
50245005
// At this point, we are accessing the target from outside the actor.
50255006
// First, check whether it is something that can be accessed directly,
50265007
// without any kind of promotion.
5027-
if (isAccessibleAcrossActorsWithoutAsyncPromotion(
5008+
if (isAccessibleAcrossActors(
50285009
declRef.getDecl(), declIsolation, fromDC, actorInstance))
50295010
return forEntersActor(declIsolation, None);
50305011

0 commit comments

Comments
 (0)