Skip to content

Commit 9ac5168

Browse files
committed
Reimplement isolation checking for overrides in terms of actor references.
As with other refactorings to use `ActorReferenceResult`, maintain the existing behavior even where it is technically wrong. (cherry picked from commit 663eb0e)
1 parent 14acd6a commit 9ac5168

File tree

3 files changed

+126
-85
lines changed

3 files changed

+126
-85
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 122 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3459,34 +3459,79 @@ static bool checkClassGlobalActorIsolation(
34593459
return true;
34603460
}
34613461

3462+
namespace {
3463+
/// Describes the result of checking override isolation.
3464+
enum class OverrideIsolationResult {
3465+
/// The override is permitted.
3466+
Allowed,
3467+
/// The override is permitted, but requires a Sendable check.
3468+
Sendable,
3469+
/// The override is not permitted.
3470+
Disallowed,
3471+
};
3472+
}
3473+
3474+
/// Return the isolation of the declaration overridden by this declaration,
3475+
/// in the context of the
3476+
static ActorIsolation getOverriddenIsolationFor(ValueDecl *value) {
3477+
auto overridden = value->getOverriddenDecl();
3478+
assert(overridden && "Doesn't have an overridden declaration");
3479+
3480+
auto isolation = getActorIsolation(overridden);
3481+
if (!isolation.requiresSubstitution())
3482+
return isolation;
3483+
3484+
SubstitutionMap subs;
3485+
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3486+
subs = selfType->getMemberSubstitutionMap(
3487+
value->getModuleContext(), overridden);
3488+
}
3489+
return isolation.subst(subs);
3490+
}
3491+
34623492
/// Generally speaking, the isolation of the decl that overrides
34633493
/// must match the overridden decl. But there are a number of exceptions,
34643494
/// e.g., the decl that overrides can be nonisolated.
3465-
/// \param newIso the isolation of the overriding declaration.
3466-
static bool validOverrideIsolation(ActorIsolation newIso,
3467-
ValueDecl *overriddenDecl,
3468-
ActorIsolation overriddenIso) {
3469-
// If the isolation matches, we're done.
3470-
if (newIso == overriddenIso)
3471-
return true;
3472-
3473-
// If the overriding declaration is non-isolated, it's okay.
3474-
if (newIso.isIndependent() || newIso.isUnspecified())
3475-
return true;
3495+
/// \param isolation the isolation of the overriding declaration.
3496+
static OverrideIsolationResult validOverrideIsolation(
3497+
ValueDecl *value, ActorIsolation isolation,
3498+
ValueDecl *overridden, ActorIsolation overriddenIsolation) {
3499+
ConcreteDeclRef valueRef(value);
3500+
auto declContext = value->getInnermostDeclContext();
3501+
if (auto genericEnv = declContext->getGenericEnvironmentOfContext()) {
3502+
valueRef = ConcreteDeclRef(
3503+
value, genericEnv->getForwardingSubstitutionMap());
3504+
}
34763505

3477-
// If both are actor-instance isolated, we're done. This wasn't caught by
3478-
// the equality case above because the nominal type describing the actor
3479-
// will differ when we're overriding.
3480-
if (newIso.getKind() == overriddenIso.getKind() &&
3481-
newIso.getKind() == ActorIsolation::ActorInstance)
3482-
return true;
3506+
auto refResult = ActorReferenceResult::forReference(
3507+
valueRef, SourceLoc(), declContext, None, None,
3508+
isolation, overriddenIsolation);
3509+
switch (refResult) {
3510+
case ActorReferenceResult::SameConcurrencyDomain:
3511+
return OverrideIsolationResult::Allowed;
3512+
3513+
case ActorReferenceResult::ExitsActorToNonisolated:
3514+
return OverrideIsolationResult::Sendable;
3515+
3516+
case ActorReferenceResult::EntersActor:
3517+
// It's okay to enter the actor when the overridden declaration is
3518+
// asynchronous (because it will do the switch) or is accessible from
3519+
// anywhere.
3520+
if (isAsyncDecl(overridden) ||
3521+
isAccessibleAcrossActors(
3522+
overridden, refResult.isolation, declContext)) {
3523+
// FIXME: Perform Sendable checking here because we're entering an
3524+
// actor.
3525+
return OverrideIsolationResult::Allowed;
3526+
}
34833527

3484-
// If the overridden declaration is from Objective-C with no actor annotation,
3485-
// allow it.
3486-
if (overriddenDecl->hasClangNode() && !overriddenIso)
3487-
return true;
3528+
// If the overridden declaration is from Objective-C with no actor
3529+
// annotation, allow it.
3530+
if (overridden->hasClangNode() && !overriddenIsolation)
3531+
return OverrideIsolationResult::Allowed;
34883532

3489-
return false;
3533+
return OverrideIsolationResult::Disallowed;
3534+
}
34903535
}
34913536

34923537
ActorIsolation ActorIsolationRequest::evaluate(
@@ -3548,20 +3593,11 @@ ActorIsolation ActorIsolationRequest::evaluate(
35483593

35493594
// Look for and remember the overridden declaration's isolation.
35503595
Optional<ActorIsolation> overriddenIso;
3551-
ValueDecl *overriddenValue = nullptr;
3552-
if ( (overriddenValue = value->getOverriddenDecl()) ) {
3553-
auto iso = getActorIsolation(overriddenValue);
3554-
SubstitutionMap subs;
3555-
3556-
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3557-
subs = selfType->getMemberSubstitutionMap(
3558-
value->getModuleContext(), overriddenValue);
3559-
}
3560-
iso = iso.subst(subs);
3561-
3596+
ValueDecl *overriddenValue = value->getOverriddenDecl();
3597+
if (overriddenValue) {
35623598
// use the overridden decl's iso as the default isolation for this decl.
3563-
defaultIsolation = iso;
3564-
overriddenIso = iso;
3599+
defaultIsolation = getOverriddenIsolationFor(value);
3600+
overriddenIso = defaultIsolation;
35653601
}
35663602

35673603
// Function used when returning an inferred isolation.
@@ -3572,8 +3608,16 @@ ActorIsolation ActorIsolationRequest::evaluate(
35723608
if (overriddenValue) {
35733609
// if the inferred isolation is not valid, then carry-over the overridden
35743610
// declaration's isolation as this decl's inferred isolation.
3575-
if (!validOverrideIsolation(inferred, overriddenValue, *overriddenIso))
3611+
switch (validOverrideIsolation(
3612+
value, inferred, overriddenValue, *overriddenIso)) {
3613+
case OverrideIsolationResult::Allowed:
3614+
case OverrideIsolationResult::Sendable:
3615+
break;
3616+
3617+
case OverrideIsolationResult::Disallowed:
35763618
inferred = *overriddenIso;
3619+
break;
3620+
}
35773621
}
35783622

35793623
// Add an implicit attribute to capture the actor isolation that was
@@ -3843,29 +3887,36 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
38433887
if (!overridden)
38443888
return;
38453889

3846-
// Determine the actor isolation of this declaration.
3890+
// Determine the actor isolation of the overriding function.
38473891
auto isolation = getActorIsolation(value);
3892+
3893+
// Determine the actor isolation of the overridden function.
3894+
auto overriddenIsolation = getOverriddenIsolationFor(value);
3895+
switch (validOverrideIsolation(
3896+
value, isolation, overridden, overriddenIsolation)) {
3897+
case OverrideIsolationResult::Allowed:
3898+
return;
38483899

3849-
// Determine the actor isolation of the overridden function.=
3850-
auto overriddenIsolation = getActorIsolation(overridden);
3851-
3852-
if (overriddenIsolation.requiresSubstitution()) {
3853-
SubstitutionMap subs;
3854-
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3855-
subs = selfType->getMemberSubstitutionMap(
3856-
value->getModuleContext(), overridden);
3857-
}
3900+
case OverrideIsolationResult::Sendable:
3901+
// FIXME: Do the Sendable check.
3902+
return;
38583903

3859-
overriddenIsolation = overriddenIsolation.subst(subs);
3904+
case OverrideIsolationResult::Disallowed:
3905+
// Diagnose below.
3906+
break;
38603907
}
38613908

3862-
if (validOverrideIsolation(isolation, overridden, overriddenIsolation))
3863-
return;
3864-
38653909
// Isolation mismatch. Diagnose it.
3910+
DiagnosticBehavior behavior = DiagnosticBehavior::Unspecified;
3911+
if (overridden->hasClangNode() && !overriddenIsolation) {
3912+
behavior = SendableCheckContext(value->getInnermostDeclContext())
3913+
.defaultDiagnosticBehavior();
3914+
}
3915+
38663916
value->diagnose(
38673917
diag::actor_isolation_override_mismatch, isolation,
3868-
value->getDescriptiveKind(), value->getName(), overriddenIsolation);
3918+
value->getDescriptiveKind(), value->getName(), overriddenIsolation)
3919+
.limitBehavior(behavior);
38693920
overridden->diagnose(diag::overridden_here);
38703921
}
38713922

@@ -4866,14 +4917,6 @@ ActorReferenceResult ActorReferenceResult::forExitsActorToNonisolated(
48664917
return ActorReferenceResult{ExitsActorToNonisolated, None, isolation};
48674918
}
48684919

4869-
ActorReferenceResult ActorReferenceResult::forReference(
4870-
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
4871-
Optional<VarRefUseEnv> useKind,
4872-
Optional<ReferencedActor> actorInstance) {
4873-
return forReference(declRef, declRefLoc, fromDC, useKind, actorInstance,
4874-
getInnermostIsolatedContext(fromDC));
4875-
}
4876-
48774920
// Determine if two actor isolation contexts are considered to be equivalent.
48784921
static bool equivalentIsolationContexts(
48794922
const ActorIsolation &lhs, const ActorIsolation &rhs) {
@@ -4892,11 +4935,26 @@ ActorReferenceResult ActorReferenceResult::forReference(
48924935
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
48934936
Optional<VarRefUseEnv> useKind,
48944937
Optional<ReferencedActor> actorInstance,
4895-
ActorIsolation contextIsolation) {
4896-
// Compute the isolation of the declaration, adjusted for references.
4897-
auto declIsolation = getActorIsolationForReference(declRef.getDecl(), fromDC);
4898-
if (auto subs = declRef.getSubstitutions())
4899-
declIsolation = declIsolation.subst(subs);
4938+
Optional<ActorIsolation> knownDeclIsolation,
4939+
Optional<ActorIsolation> knownContextIsolation) {
4940+
// If not provided, compute the isolation of the declaration, adjusted
4941+
// for references.
4942+
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
4943+
if (knownDeclIsolation) {
4944+
declIsolation = *knownDeclIsolation;
4945+
} else {
4946+
declIsolation = getActorIsolationForReference(declRef.getDecl(), fromDC);
4947+
if (declIsolation.requiresSubstitution())
4948+
declIsolation = declIsolation.subst(declRef.getSubstitutions());
4949+
}
4950+
4951+
// Compute the isolation of the context, if not provided.
4952+
ActorIsolation contextIsolation = ActorIsolation::forUnspecified();
4953+
if (knownContextIsolation) {
4954+
contextIsolation = *knownContextIsolation;
4955+
} else {
4956+
contextIsolation = getInnermostIsolatedContext(fromDC);
4957+
}
49004958

49014959
// When the declaration is not actor-isolated, it can always be accessed
49024960
// directly.

lib/Sema/TypeCheckConcurrency.h

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -238,26 +238,9 @@ struct ActorReferenceResult {
238238
SourceLoc declRefLoc,
239239
const DeclContext *fromDC,
240240
Optional<VarRefUseEnv> useKind = None,
241-
Optional<ReferencedActor> actorInstance = None);
242-
243-
/// Determine what happens when referencing the given declaration from the
244-
/// given declaration context.
245-
///
246-
///
247-
/// \param declRef The declaration that is being referenced.
248-
///
249-
/// \param fromDC The declaration context from which the reference occurs.
250-
///
251-
/// \param actorInstance When not \c None, the actor instance value that is
252-
/// provided when referencing the declaration. This can be either the base
253-
/// of a member access or a parameter passed to a function.
254-
static ActorReferenceResult forReference(
255-
ConcreteDeclRef declRef,
256-
SourceLoc declRefLoc,
257-
const DeclContext *fromDC,
258-
Optional<VarRefUseEnv> useKind,
259-
Optional<ReferencedActor> actorInstance,
260-
ActorIsolation contextIsolation);
241+
Optional<ReferencedActor> actorInstance = None,
242+
Optional<ActorIsolation> knownDeclIsolation = None,
243+
Optional<ActorIsolation> knownContextIsolation = None);
261244

262245
operator Kind() const { return kind; }
263246
};

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2956,7 +2956,7 @@ bool ConformanceChecker::checkActorIsolation(
29562956

29572957
auto refResult = ActorReferenceResult::forReference(
29582958
getConcreteWitness(), witness->getLoc(), DC, None, None,
2959-
requirementIsolation);
2959+
None, requirementIsolation);
29602960
bool sameConcurrencyDomain = false;
29612961
switch (refResult) {
29622962
case ActorReferenceResult::SameConcurrencyDomain:

0 commit comments

Comments
 (0)