Skip to content

Commit 663eb0e

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.
1 parent 08da68e commit 663eb0e

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
@@ -3396,34 +3396,79 @@ static bool checkClassGlobalActorIsolation(
33963396
return true;
33973397
}
33983398

3399+
namespace {
3400+
/// Describes the result of checking override isolation.
3401+
enum class OverrideIsolationResult {
3402+
/// The override is permitted.
3403+
Allowed,
3404+
/// The override is permitted, but requires a Sendable check.
3405+
Sendable,
3406+
/// The override is not permitted.
3407+
Disallowed,
3408+
};
3409+
}
3410+
3411+
/// Return the isolation of the declaration overridden by this declaration,
3412+
/// in the context of the
3413+
static ActorIsolation getOverriddenIsolationFor(ValueDecl *value) {
3414+
auto overridden = value->getOverriddenDecl();
3415+
assert(overridden && "Doesn't have an overridden declaration");
3416+
3417+
auto isolation = getActorIsolation(overridden);
3418+
if (!isolation.requiresSubstitution())
3419+
return isolation;
3420+
3421+
SubstitutionMap subs;
3422+
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3423+
subs = selfType->getMemberSubstitutionMap(
3424+
value->getModuleContext(), overridden);
3425+
}
3426+
return isolation.subst(subs);
3427+
}
3428+
33993429
/// Generally speaking, the isolation of the decl that overrides
34003430
/// must match the overridden decl. But there are a number of exceptions,
34013431
/// e.g., the decl that overrides can be nonisolated.
3402-
/// \param newIso the isolation of the overriding declaration.
3403-
static bool validOverrideIsolation(ActorIsolation newIso,
3404-
ValueDecl *overriddenDecl,
3405-
ActorIsolation overriddenIso) {
3406-
// If the isolation matches, we're done.
3407-
if (newIso == overriddenIso)
3408-
return true;
3409-
3410-
// If the overriding declaration is non-isolated, it's okay.
3411-
if (newIso.isIndependent() || newIso.isUnspecified())
3412-
return true;
3432+
/// \param isolation the isolation of the overriding declaration.
3433+
static OverrideIsolationResult validOverrideIsolation(
3434+
ValueDecl *value, ActorIsolation isolation,
3435+
ValueDecl *overridden, ActorIsolation overriddenIsolation) {
3436+
ConcreteDeclRef valueRef(value);
3437+
auto declContext = value->getInnermostDeclContext();
3438+
if (auto genericEnv = declContext->getGenericEnvironmentOfContext()) {
3439+
valueRef = ConcreteDeclRef(
3440+
value, genericEnv->getForwardingSubstitutionMap());
3441+
}
34133442

3414-
// If both are actor-instance isolated, we're done. This wasn't caught by
3415-
// the equality case above because the nominal type describing the actor
3416-
// will differ when we're overriding.
3417-
if (newIso.getKind() == overriddenIso.getKind() &&
3418-
newIso.getKind() == ActorIsolation::ActorInstance)
3419-
return true;
3443+
auto refResult = ActorReferenceResult::forReference(
3444+
valueRef, SourceLoc(), declContext, None, None,
3445+
isolation, overriddenIsolation);
3446+
switch (refResult) {
3447+
case ActorReferenceResult::SameConcurrencyDomain:
3448+
return OverrideIsolationResult::Allowed;
3449+
3450+
case ActorReferenceResult::ExitsActorToNonisolated:
3451+
return OverrideIsolationResult::Sendable;
3452+
3453+
case ActorReferenceResult::EntersActor:
3454+
// It's okay to enter the actor when the overridden declaration is
3455+
// asynchronous (because it will do the switch) or is accessible from
3456+
// anywhere.
3457+
if (isAsyncDecl(overridden) ||
3458+
isAccessibleAcrossActors(
3459+
overridden, refResult.isolation, declContext)) {
3460+
// FIXME: Perform Sendable checking here because we're entering an
3461+
// actor.
3462+
return OverrideIsolationResult::Allowed;
3463+
}
34203464

3421-
// If the overridden declaration is from Objective-C with no actor annotation,
3422-
// allow it.
3423-
if (overriddenDecl->hasClangNode() && !overriddenIso)
3424-
return true;
3465+
// If the overridden declaration is from Objective-C with no actor
3466+
// annotation, allow it.
3467+
if (overridden->hasClangNode() && !overriddenIsolation)
3468+
return OverrideIsolationResult::Allowed;
34253469

3426-
return false;
3470+
return OverrideIsolationResult::Disallowed;
3471+
}
34273472
}
34283473

34293474
ActorIsolation ActorIsolationRequest::evaluate(
@@ -3485,20 +3530,11 @@ ActorIsolation ActorIsolationRequest::evaluate(
34853530

34863531
// Look for and remember the overridden declaration's isolation.
34873532
Optional<ActorIsolation> overriddenIso;
3488-
ValueDecl *overriddenValue = nullptr;
3489-
if ( (overriddenValue = value->getOverriddenDecl()) ) {
3490-
auto iso = getActorIsolation(overriddenValue);
3491-
SubstitutionMap subs;
3492-
3493-
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3494-
subs = selfType->getMemberSubstitutionMap(
3495-
value->getModuleContext(), overriddenValue);
3496-
}
3497-
iso = iso.subst(subs);
3498-
3533+
ValueDecl *overriddenValue = value->getOverriddenDecl();
3534+
if (overriddenValue) {
34993535
// use the overridden decl's iso as the default isolation for this decl.
3500-
defaultIsolation = iso;
3501-
overriddenIso = iso;
3536+
defaultIsolation = getOverriddenIsolationFor(value);
3537+
overriddenIso = defaultIsolation;
35023538
}
35033539

35043540
// Function used when returning an inferred isolation.
@@ -3509,8 +3545,16 @@ ActorIsolation ActorIsolationRequest::evaluate(
35093545
if (overriddenValue) {
35103546
// if the inferred isolation is not valid, then carry-over the overridden
35113547
// declaration's isolation as this decl's inferred isolation.
3512-
if (!validOverrideIsolation(inferred, overriddenValue, *overriddenIso))
3548+
switch (validOverrideIsolation(
3549+
value, inferred, overriddenValue, *overriddenIso)) {
3550+
case OverrideIsolationResult::Allowed:
3551+
case OverrideIsolationResult::Sendable:
3552+
break;
3553+
3554+
case OverrideIsolationResult::Disallowed:
35133555
inferred = *overriddenIso;
3556+
break;
3557+
}
35143558
}
35153559

35163560
// Add an implicit attribute to capture the actor isolation that was
@@ -3779,29 +3823,36 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
37793823
if (!overridden)
37803824
return;
37813825

3782-
// Determine the actor isolation of this declaration.
3826+
// Determine the actor isolation of the overriding function.
37833827
auto isolation = getActorIsolation(value);
3828+
3829+
// Determine the actor isolation of the overridden function.
3830+
auto overriddenIsolation = getOverriddenIsolationFor(value);
3831+
switch (validOverrideIsolation(
3832+
value, isolation, overridden, overriddenIsolation)) {
3833+
case OverrideIsolationResult::Allowed:
3834+
return;
37843835

3785-
// Determine the actor isolation of the overridden function.=
3786-
auto overriddenIsolation = getActorIsolation(overridden);
3787-
3788-
if (overriddenIsolation.requiresSubstitution()) {
3789-
SubstitutionMap subs;
3790-
if (Type selfType = value->getDeclContext()->getSelfInterfaceType()) {
3791-
subs = selfType->getMemberSubstitutionMap(
3792-
value->getModuleContext(), overridden);
3793-
}
3836+
case OverrideIsolationResult::Sendable:
3837+
// FIXME: Do the Sendable check.
3838+
return;
37943839

3795-
overriddenIsolation = overriddenIsolation.subst(subs);
3840+
case OverrideIsolationResult::Disallowed:
3841+
// Diagnose below.
3842+
break;
37963843
}
37973844

3798-
if (validOverrideIsolation(isolation, overridden, overriddenIsolation))
3799-
return;
3800-
38013845
// Isolation mismatch. Diagnose it.
3846+
DiagnosticBehavior behavior = DiagnosticBehavior::Unspecified;
3847+
if (overridden->hasClangNode() && !overriddenIsolation) {
3848+
behavior = SendableCheckContext(value->getInnermostDeclContext())
3849+
.defaultDiagnosticBehavior();
3850+
}
3851+
38023852
value->diagnose(
38033853
diag::actor_isolation_override_mismatch, isolation,
3804-
value->getDescriptiveKind(), value->getName(), overriddenIsolation);
3854+
value->getDescriptiveKind(), value->getName(), overriddenIsolation)
3855+
.limitBehavior(behavior);
38053856
overridden->diagnose(diag::overridden_here);
38063857
}
38073858

@@ -4796,14 +4847,6 @@ ActorReferenceResult ActorReferenceResult::forExitsActorToNonisolated(
47964847
return ActorReferenceResult{ExitsActorToNonisolated, None, isolation};
47974848
}
47984849

4799-
ActorReferenceResult ActorReferenceResult::forReference(
4800-
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
4801-
Optional<VarRefUseEnv> useKind,
4802-
Optional<ReferencedActor> actorInstance) {
4803-
return forReference(declRef, declRefLoc, fromDC, useKind, actorInstance,
4804-
getInnermostIsolatedContext(fromDC));
4805-
}
4806-
48074850
// Determine if two actor isolation contexts are considered to be equivalent.
48084851
static bool equivalentIsolationContexts(
48094852
const ActorIsolation &lhs, const ActorIsolation &rhs) {
@@ -4822,11 +4865,26 @@ ActorReferenceResult ActorReferenceResult::forReference(
48224865
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
48234866
Optional<VarRefUseEnv> useKind,
48244867
Optional<ReferencedActor> actorInstance,
4825-
ActorIsolation contextIsolation) {
4826-
// Compute the isolation of the declaration, adjusted for references.
4827-
auto declIsolation = getActorIsolationForReference(declRef.getDecl(), fromDC);
4828-
if (auto subs = declRef.getSubstitutions())
4829-
declIsolation = declIsolation.subst(subs);
4868+
Optional<ActorIsolation> knownDeclIsolation,
4869+
Optional<ActorIsolation> knownContextIsolation) {
4870+
// If not provided, compute the isolation of the declaration, adjusted
4871+
// for references.
4872+
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
4873+
if (knownDeclIsolation) {
4874+
declIsolation = *knownDeclIsolation;
4875+
} else {
4876+
declIsolation = getActorIsolationForReference(declRef.getDecl(), fromDC);
4877+
if (declIsolation.requiresSubstitution())
4878+
declIsolation = declIsolation.subst(declRef.getSubstitutions());
4879+
}
4880+
4881+
// Compute the isolation of the context, if not provided.
4882+
ActorIsolation contextIsolation = ActorIsolation::forUnspecified();
4883+
if (knownContextIsolation) {
4884+
contextIsolation = *knownContextIsolation;
4885+
} else {
4886+
contextIsolation = getInnermostIsolatedContext(fromDC);
4887+
}
48304888

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