Skip to content

Commit b00c07b

Browse files
authored
Merge pull request #42407 from DougGregor/override-actor-isolation-rewrite
2 parents 8d8c652 + 663eb0e commit b00c07b

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
@@ -3428,34 +3428,79 @@ static bool checkClassGlobalActorIsolation(
34283428
return true;
34293429
}
34303430

3431+
namespace {
3432+
/// Describes the result of checking override isolation.
3433+
enum class OverrideIsolationResult {
3434+
/// The override is permitted.
3435+
Allowed,
3436+
/// The override is permitted, but requires a Sendable check.
3437+
Sendable,
3438+
/// The override is not permitted.
3439+
Disallowed,
3440+
};
3441+
}
3442+
3443+
/// Return the isolation of the declaration overridden by this declaration,
3444+
/// in the context of the
3445+
static ActorIsolation getOverriddenIsolationFor(ValueDecl *value) {
3446+
auto overridden = value->getOverriddenDecl();
3447+
assert(overridden && "Doesn't have an overridden declaration");
3448+
3449+
auto isolation = getActorIsolation(overridden);
3450+
if (!isolation.requiresSubstitution())
3451+
return isolation;
3452+
3453+
SubstitutionMap subs;
3454+
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3455+
subs = selfType->getMemberSubstitutionMap(
3456+
value->getModuleContext(), overridden);
3457+
}
3458+
return isolation.subst(subs);
3459+
}
3460+
34313461
/// Generally speaking, the isolation of the decl that overrides
34323462
/// must match the overridden decl. But there are a number of exceptions,
34333463
/// e.g., the decl that overrides can be nonisolated.
3434-
/// \param newIso the isolation of the overriding declaration.
3435-
static bool validOverrideIsolation(ActorIsolation newIso,
3436-
ValueDecl *overriddenDecl,
3437-
ActorIsolation overriddenIso) {
3438-
// If the isolation matches, we're done.
3439-
if (newIso == overriddenIso)
3440-
return true;
3441-
3442-
// If the overriding declaration is non-isolated, it's okay.
3443-
if (newIso.isIndependent() || newIso.isUnspecified())
3444-
return true;
3464+
/// \param isolation the isolation of the overriding declaration.
3465+
static OverrideIsolationResult validOverrideIsolation(
3466+
ValueDecl *value, ActorIsolation isolation,
3467+
ValueDecl *overridden, ActorIsolation overriddenIsolation) {
3468+
ConcreteDeclRef valueRef(value);
3469+
auto declContext = value->getInnermostDeclContext();
3470+
if (auto genericEnv = declContext->getGenericEnvironmentOfContext()) {
3471+
valueRef = ConcreteDeclRef(
3472+
value, genericEnv->getForwardingSubstitutionMap());
3473+
}
34453474

3446-
// If both are actor-instance isolated, we're done. This wasn't caught by
3447-
// the equality case above because the nominal type describing the actor
3448-
// will differ when we're overriding.
3449-
if (newIso.getKind() == overriddenIso.getKind() &&
3450-
newIso.getKind() == ActorIsolation::ActorInstance)
3451-
return true;
3475+
auto refResult = ActorReferenceResult::forReference(
3476+
valueRef, SourceLoc(), declContext, None, None,
3477+
isolation, overriddenIsolation);
3478+
switch (refResult) {
3479+
case ActorReferenceResult::SameConcurrencyDomain:
3480+
return OverrideIsolationResult::Allowed;
3481+
3482+
case ActorReferenceResult::ExitsActorToNonisolated:
3483+
return OverrideIsolationResult::Sendable;
3484+
3485+
case ActorReferenceResult::EntersActor:
3486+
// It's okay to enter the actor when the overridden declaration is
3487+
// asynchronous (because it will do the switch) or is accessible from
3488+
// anywhere.
3489+
if (isAsyncDecl(overridden) ||
3490+
isAccessibleAcrossActors(
3491+
overridden, refResult.isolation, declContext)) {
3492+
// FIXME: Perform Sendable checking here because we're entering an
3493+
// actor.
3494+
return OverrideIsolationResult::Allowed;
3495+
}
34523496

3453-
// If the overridden declaration is from Objective-C with no actor annotation,
3454-
// allow it.
3455-
if (overriddenDecl->hasClangNode() && !overriddenIso)
3456-
return true;
3497+
// If the overridden declaration is from Objective-C with no actor
3498+
// annotation, allow it.
3499+
if (overridden->hasClangNode() && !overriddenIsolation)
3500+
return OverrideIsolationResult::Allowed;
34573501

3458-
return false;
3502+
return OverrideIsolationResult::Disallowed;
3503+
}
34593504
}
34603505

34613506
ActorIsolation ActorIsolationRequest::evaluate(
@@ -3517,20 +3562,11 @@ ActorIsolation ActorIsolationRequest::evaluate(
35173562

35183563
// Look for and remember the overridden declaration's isolation.
35193564
Optional<ActorIsolation> overriddenIso;
3520-
ValueDecl *overriddenValue = nullptr;
3521-
if ( (overriddenValue = value->getOverriddenDecl()) ) {
3522-
auto iso = getActorIsolation(overriddenValue);
3523-
SubstitutionMap subs;
3524-
3525-
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3526-
subs = selfType->getMemberSubstitutionMap(
3527-
value->getModuleContext(), overriddenValue);
3528-
}
3529-
iso = iso.subst(subs);
3530-
3565+
ValueDecl *overriddenValue = value->getOverriddenDecl();
3566+
if (overriddenValue) {
35313567
// use the overridden decl's iso as the default isolation for this decl.
3532-
defaultIsolation = iso;
3533-
overriddenIso = iso;
3568+
defaultIsolation = getOverriddenIsolationFor(value);
3569+
overriddenIso = defaultIsolation;
35343570
}
35353571

35363572
// Function used when returning an inferred isolation.
@@ -3541,8 +3577,16 @@ ActorIsolation ActorIsolationRequest::evaluate(
35413577
if (overriddenValue) {
35423578
// if the inferred isolation is not valid, then carry-over the overridden
35433579
// declaration's isolation as this decl's inferred isolation.
3544-
if (!validOverrideIsolation(inferred, overriddenValue, *overriddenIso))
3580+
switch (validOverrideIsolation(
3581+
value, inferred, overriddenValue, *overriddenIso)) {
3582+
case OverrideIsolationResult::Allowed:
3583+
case OverrideIsolationResult::Sendable:
3584+
break;
3585+
3586+
case OverrideIsolationResult::Disallowed:
35453587
inferred = *overriddenIso;
3588+
break;
3589+
}
35463590
}
35473591

35483592
// Add an implicit attribute to capture the actor isolation that was
@@ -3811,29 +3855,36 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
38113855
if (!overridden)
38123856
return;
38133857

3814-
// Determine the actor isolation of this declaration.
3858+
// Determine the actor isolation of the overriding function.
38153859
auto isolation = getActorIsolation(value);
3860+
3861+
// Determine the actor isolation of the overridden function.
3862+
auto overriddenIsolation = getOverriddenIsolationFor(value);
3863+
switch (validOverrideIsolation(
3864+
value, isolation, overridden, overriddenIsolation)) {
3865+
case OverrideIsolationResult::Allowed:
3866+
return;
38163867

3817-
// Determine the actor isolation of the overridden function.=
3818-
auto overriddenIsolation = getActorIsolation(overridden);
3819-
3820-
if (overriddenIsolation.requiresSubstitution()) {
3821-
SubstitutionMap subs;
3822-
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3823-
subs = selfType->getMemberSubstitutionMap(
3824-
value->getModuleContext(), overridden);
3825-
}
3868+
case OverrideIsolationResult::Sendable:
3869+
// FIXME: Do the Sendable check.
3870+
return;
38263871

3827-
overriddenIsolation = overriddenIsolation.subst(subs);
3872+
case OverrideIsolationResult::Disallowed:
3873+
// Diagnose below.
3874+
break;
38283875
}
38293876

3830-
if (validOverrideIsolation(isolation, overridden, overriddenIsolation))
3831-
return;
3832-
38333877
// Isolation mismatch. Diagnose it.
3878+
DiagnosticBehavior behavior = DiagnosticBehavior::Unspecified;
3879+
if (overridden->hasClangNode() && !overriddenIsolation) {
3880+
behavior = SendableCheckContext(value->getInnermostDeclContext())
3881+
.defaultDiagnosticBehavior();
3882+
}
3883+
38343884
value->diagnose(
38353885
diag::actor_isolation_override_mismatch, isolation,
3836-
value->getDescriptiveKind(), value->getName(), overriddenIsolation);
3886+
value->getDescriptiveKind(), value->getName(), overriddenIsolation)
3887+
.limitBehavior(behavior);
38373888
overridden->diagnose(diag::overridden_here);
38383889
}
38393890

@@ -4828,14 +4879,6 @@ ActorReferenceResult ActorReferenceResult::forExitsActorToNonisolated(
48284879
return ActorReferenceResult{ExitsActorToNonisolated, None, isolation};
48294880
}
48304881

4831-
ActorReferenceResult ActorReferenceResult::forReference(
4832-
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
4833-
Optional<VarRefUseEnv> useKind,
4834-
Optional<ReferencedActor> actorInstance) {
4835-
return forReference(declRef, declRefLoc, fromDC, useKind, actorInstance,
4836-
getInnermostIsolatedContext(fromDC));
4837-
}
4838-
48394882
// Determine if two actor isolation contexts are considered to be equivalent.
48404883
static bool equivalentIsolationContexts(
48414884
const ActorIsolation &lhs, const ActorIsolation &rhs) {
@@ -4854,11 +4897,26 @@ ActorReferenceResult ActorReferenceResult::forReference(
48544897
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
48554898
Optional<VarRefUseEnv> useKind,
48564899
Optional<ReferencedActor> actorInstance,
4857-
ActorIsolation contextIsolation) {
4858-
// Compute the isolation of the declaration, adjusted for references.
4859-
auto declIsolation = getActorIsolationForReference(declRef.getDecl(), fromDC);
4860-
if (auto subs = declRef.getSubstitutions())
4861-
declIsolation = declIsolation.subst(subs);
4900+
Optional<ActorIsolation> knownDeclIsolation,
4901+
Optional<ActorIsolation> knownContextIsolation) {
4902+
// If not provided, compute the isolation of the declaration, adjusted
4903+
// for references.
4904+
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
4905+
if (knownDeclIsolation) {
4906+
declIsolation = *knownDeclIsolation;
4907+
} else {
4908+
declIsolation = getActorIsolationForReference(declRef.getDecl(), fromDC);
4909+
if (declIsolation.requiresSubstitution())
4910+
declIsolation = declIsolation.subst(declRef.getSubstitutions());
4911+
}
4912+
4913+
// Compute the isolation of the context, if not provided.
4914+
ActorIsolation contextIsolation = ActorIsolation::forUnspecified();
4915+
if (knownContextIsolation) {
4916+
contextIsolation = *knownContextIsolation;
4917+
} else {
4918+
contextIsolation = getInnermostIsolatedContext(fromDC);
4919+
}
48624920

48634921
// When the declaration is not actor-isolated, it can always be accessed
48644922
// 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)