Skip to content

Commit 91fb149

Browse files
authored
Merge pull request #40388 from DougGregor/swift-6-stricter-concurrency-checking
Swift 6 stricter concurrency checking
2 parents 8bfaab9 + 5a6f58e commit 91fb149

12 files changed

+184
-132
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ class ActorIsolation {
132132

133133
friend bool operator==(const ActorIsolation &lhs,
134134
const ActorIsolation &rhs) {
135+
if (lhs.isGlobalActor() && rhs.isGlobalActor())
136+
return areTypesEqual(lhs.globalActor, rhs.globalActor);
137+
135138
if (lhs.kind != rhs.kind)
136139
return false;
137140

@@ -146,7 +149,7 @@ class ActorIsolation {
146149

147150
case GlobalActor:
148151
case GlobalActorUnsafe:
149-
return areTypesEqual(lhs.globalActor, rhs.globalActor);
152+
llvm_unreachable("Global actors handled above");
150153
}
151154
}
152155

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4550,10 +4550,6 @@ ERROR(actor_isolated_witness,none,
45504550
ERROR(distributed_actor_isolated_witness,none,
45514551
"distributed actor-isolated %0 %1 cannot be used to satisfy a protocol requirement",
45524552
(DescriptiveDeclKind, DeclName))
4553-
ERROR(global_actor_isolated_requirement,none,
4554-
"%0 %1 must be isolated to the global actor %2 to satisfy corresponding "
4555-
"requirement from protocol %3",
4556-
(DescriptiveDeclKind, DeclName, Type, Identifier))
45574553
ERROR(global_actor_isolated_witness,none,
45584554
"%0 %1 isolated to global actor %2 can not satisfy corresponding "
45594555
"requirement from protocol %3",

lib/SILGen/SILGenProlog.cpp

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -560,34 +560,30 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
560560
dyn_cast_or_null<AbstractFunctionDecl>(FunctionDC->getAsDecl())) {
561561
auto actorIsolation = getActorIsolation(funcDecl);
562562
switch (actorIsolation.getKind()) {
563-
case ActorIsolation::Unspecified:
564-
case ActorIsolation::Independent:
565-
// If this is an async function that has an isolated parameter, hop
566-
// to it.
567-
if (F.isAsync()) {
568-
for (auto param : *funcDecl->getParameters()) {
569-
if (param->isIsolated()) {
570-
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
571-
Type actorType = param->getType();
572-
RValue actorInstanceRV = emitRValueForDecl(
573-
loc, param, actorType, AccessSemantics::Ordinary);
574-
ManagedValue actorInstance =
575-
std::move(actorInstanceRV).getScalarValue();
576-
ExpectedExecutor = emitLoadActorExecutor(loc, actorInstance);
577-
break;
578-
}
563+
case ActorIsolation::Unspecified:
564+
case ActorIsolation::Independent:
565+
// If this is an async function that has an isolated parameter, hop
566+
// to it.
567+
if (F.isAsync()) {
568+
for (auto param : *funcDecl->getParameters()) {
569+
if (param->isIsolated()) {
570+
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
571+
Type actorType = param->getType();
572+
RValue actorInstanceRV = emitRValueForDecl(
573+
loc, param, actorType, AccessSemantics::Ordinary);
574+
ManagedValue actorInstance =
575+
std::move(actorInstanceRV).getScalarValue();
576+
ExpectedExecutor = emitLoadActorExecutor(loc, actorInstance);
577+
break;
579578
}
580579
}
581-
582-
break;
583-
584-
case ActorIsolation::GlobalActorUnsafe:
585-
break;
586-
587-
case ActorIsolation::DistributedActorInstance: {
588-
// TODO: perhaps here we can emit our special handling to make a message?
589-
LLVM_FALLTHROUGH;
590580
}
581+
break;
582+
583+
case ActorIsolation::DistributedActorInstance: {
584+
// TODO: perhaps here we can emit our special handling to make a message?
585+
LLVM_FALLTHROUGH;
586+
}
591587

592588
case ActorIsolation::ActorInstance: {
593589
assert(selfParam && "no self parameter for ActorInstance isolation");
@@ -605,6 +601,7 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
605601
}
606602

607603
case ActorIsolation::GlobalActor:
604+
case ActorIsolation::GlobalActorUnsafe:
608605
if (F.isAsync() || wantDataRaceChecks) {
609606
ExpectedExecutor =
610607
emitLoadGlobalActorExecutor(actorIsolation.getGlobalActor());

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,8 +2171,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
21712171

21722172
/// Whether to downgrade to a concurrency warning.
21732173
auto isConcurrencyWarning = [&] {
2174-
if (contextUsesConcurrencyFeatures(DC) ||
2175-
Context.LangOpts.isSwiftVersionAtLeast(6))
2174+
if (contextRequiresStrictConcurrencyChecking(DC))
21762175
return false;
21772176

21782177
switch (kind) {

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 17 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
605605
if (dc->getParentModule()->isConcurrencyChecked())
606606
return true;
607607

608-
return contextUsesConcurrencyFeatures(dc);
608+
return contextRequiresStrictConcurrencyChecking(dc);
609609
}
610610

611611
/// Determine the default diagnostic behavior for this language mode.
@@ -3518,7 +3518,13 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
35183518
if (isolation == overriddenIsolation)
35193519
return;
35203520

3521-
// If both are actor-instance isolated, we're done.
3521+
// If the overriding declaration is non-isolated, it's okay.
3522+
if (isolation.isIndependent() || isolation.isUnspecified())
3523+
return;
3524+
3525+
// If both are actor-instance isolated, we're done. This wasn't caught by
3526+
// the equality case above because the nominal type describing the actor
3527+
// will differ when we're overriding.
35223528
if (isolation.getKind() == overriddenIsolation.getKind() &&
35233529
(isolation.getKind() == ActorIsolation::ActorInstance ||
35243530
isolation.getKind() == ActorIsolation::DistributedActorInstance))
@@ -3529,64 +3535,18 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
35293535
if (overridden->hasClangNode() && !overriddenIsolation)
35303536
return;
35313537

3532-
// If the overridden declaration uses an unsafe global actor, we can do
3533-
// anything except be actor-isolated or have a different global actor.
3534-
if (overriddenIsolation == ActorIsolation::GlobalActorUnsafe) {
3535-
switch (isolation) {
3536-
case ActorIsolation::Independent:
3537-
case ActorIsolation::Unspecified:
3538-
return;
3539-
3540-
case ActorIsolation::ActorInstance:
3541-
case ActorIsolation::DistributedActorInstance:
3542-
// Diagnose below.
3543-
break;
3544-
3545-
case ActorIsolation::GlobalActor:
3546-
case ActorIsolation::GlobalActorUnsafe:
3547-
// The global actors don't match; diagnose it.
3548-
if (overriddenIsolation.getGlobalActor()->isEqual(
3549-
isolation.getGlobalActor()))
3550-
return;
3551-
3552-
// Diagnose below.
3553-
break;
3554-
}
3555-
}
3556-
3557-
// If the overriding declaration uses an unsafe global actor, we can do
3558-
// anything that doesn't actively conflict with the overridden isolation.
3559-
if (isolation == ActorIsolation::GlobalActorUnsafe) {
3560-
switch (overriddenIsolation) {
3561-
case ActorIsolation::Unspecified:
3562-
return;
3563-
3564-
case ActorIsolation::ActorInstance:
3565-
case ActorIsolation::DistributedActorInstance:
3566-
case ActorIsolation::Independent:
3567-
// Diagnose below.
3568-
break;
3569-
3570-
case ActorIsolation::GlobalActor:
3571-
case ActorIsolation::GlobalActorUnsafe:
3572-
// The global actors don't match; diagnose it.
3573-
if (overriddenIsolation.getGlobalActor()->isEqual(
3574-
isolation.getGlobalActor()))
3575-
return;
3576-
3577-
// Diagnose below.
3578-
break;
3579-
}
3580-
}
3581-
35823538
// Isolation mismatch. Diagnose it.
35833539
value->diagnose(
35843540
diag::actor_isolation_override_mismatch, isolation,
35853541
value->getDescriptiveKind(), value->getName(), overriddenIsolation);
35863542
overridden->diagnose(diag::overridden_here);
35873543
}
35883544

3589-
bool swift::contextUsesConcurrencyFeatures(const DeclContext *dc) {
3545+
bool swift::contextRequiresStrictConcurrencyChecking(const DeclContext *dc) {
3546+
// If Swift >= 6, everything uses strict concurrency checking.
3547+
if (dc->getASTContext().LangOpts.isSwiftVersionAtLeast(6))
3548+
return true;
3549+
35903550
while (!dc->isModuleScopeContext()) {
35913551
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
35923552
// A closure with an explicit global actor or nonindependent
@@ -4071,7 +4031,7 @@ Type swift::adjustVarTypeForConcurrency(
40714031
if (!var->predatesConcurrency())
40724032
return type;
40734033

4074-
if (contextUsesConcurrencyFeatures(dc))
4034+
if (contextRequiresStrictConcurrencyChecking(dc))
40754035
return type;
40764036

40774037
bool isLValue = false;
@@ -4193,7 +4153,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
41934153
unsigned numApplies, bool isMainDispatchQueue) {
41944154
// Apply unsafe concurrency features to the given function type.
41954155
fnType = applyUnsafeConcurrencyToFunctionType(
4196-
fnType, decl, contextUsesConcurrencyFeatures(dc), numApplies,
4156+
fnType, decl, contextRequiresStrictConcurrencyChecking(dc), numApplies,
41974157
isMainDispatchQueue);
41984158

41994159
Type globalActorType;
@@ -4208,7 +4168,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
42084168
case ActorIsolation::GlobalActorUnsafe:
42094169
// Only treat as global-actor-qualified within code that has adopted
42104170
// Swift Concurrency features.
4211-
if (!contextUsesConcurrencyFeatures(dc))
4171+
if (!contextRequiresStrictConcurrencyChecking(dc))
42124172
return fnType;
42134173

42144174
LLVM_FALLTHROUGH;
@@ -4250,7 +4210,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
42504210
}
42514211

42524212
bool swift::completionContextUsesConcurrencyFeatures(const DeclContext *dc) {
4253-
return contextUsesConcurrencyFeatures(dc);
4213+
return contextRequiresStrictConcurrencyChecking(dc);
42544214
}
42554215

42564216
AbstractFunctionDecl const *swift::isActorInitOrDeInitContext(

lib/Sema/TypeCheckConcurrency.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ class ActorIsolationRestriction {
211211
/// overridden declaration.
212212
void checkOverrideActorIsolation(ValueDecl *value);
213213

214-
/// Determine whether the given context uses concurrency features, such
215-
/// as async functions or actors.
216-
bool contextUsesConcurrencyFeatures(const DeclContext *dc);
214+
/// Determine whether the given context requires strict concurrency checking,
215+
/// e.g., because it uses concurrency features directly or because it's in
216+
/// code where strict checking has been enabled.
217+
bool contextRequiresStrictConcurrencyChecking(const DeclContext *dc);
217218

218219
/// Diagnose the presence of any non-sendable types when referencing a
219220
/// given declaration from a particular declaration context.

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2868,6 +2868,8 @@ bool ConformanceChecker::checkActorIsolation(
28682868
// unsuitable as a witness.
28692869
bool isCrossActor = false;
28702870
bool witnessIsUnsafe = false;
2871+
DiagnosticBehavior behavior = SendableCheckContext(
2872+
witness->getInnermostDeclContext()).defaultDiagnosticBehavior();
28712873
Type witnessGlobalActor;
28722874
switch (auto witnessRestriction =
28732875
ActorIsolationRestriction::forDeclaration(
@@ -3091,8 +3093,6 @@ bool ConformanceChecker::checkActorIsolation(
30913093
}
30923094

30933095
case ActorIsolationRestriction::Unsafe:
3094-
break;
3095-
30963096
case ActorIsolationRestriction::Unrestricted:
30973097
// The witness is completely unrestricted, so ignore any annotations on
30983098
// the requirement.
@@ -3155,53 +3155,34 @@ bool ConformanceChecker::checkActorIsolation(
31553155
// However, we allow this case when the requirement was imported, because
31563156
// it might not have been annotated.
31573157
if (witnessGlobalActor && !requirementGlobalActor) {
3158-
// If the requirement was imported from Objective-C, it may not have been
3159-
// annotated appropriately. Allow the mismatch.
3158+
// If the requirement was imported from Objective-C, downgrade to a warning
3159+
// because it may not have been annotated appropriately.
31603160
if (requirement->hasClangNode())
3161-
return false;
3162-
3163-
// If the witness is "unsafe", allow the mismatch.
3164-
if (witnessIsUnsafe)
3165-
return false;
3161+
behavior = std::max(behavior, DiagnosticBehavior::Warning);
31663162

31673163
witness->diagnose(
31683164
diag::global_actor_isolated_witness, witness->getDescriptiveKind(),
3169-
witness->getName(), witnessGlobalActor, Proto->getName());
3165+
witness->getName(), witnessGlobalActor, Proto->getName())
3166+
.limitBehavior(behavior);
31703167
requirement->diagnose(diag::decl_declared_here, requirement->getName());
3171-
return true;
3168+
return behavior == DiagnosticBehavior::Unspecified;
31723169
}
31733170

3174-
// If the requirement has a global actor but the witness does not, we have
3175-
// an isolation error.
3171+
// If the requirement has a global actor but the witness does not, it's
3172+
// fine.
31763173
if (requirementGlobalActor && !witnessGlobalActor) {
3177-
// If the requirement's global actor was "unsafe", we allow this.
3178-
if (requirementIsUnsafe)
3179-
return false;
3180-
3181-
if (isCrossActor) {
3182-
return diagnoseNonSendableTypesInReference(
3183-
witness, DC, witness->getLoc(),
3184-
ConcurrentReferenceKind::CrossActor);
3185-
}
3186-
3187-
witness->diagnose(
3188-
diag::global_actor_isolated_requirement, witness->getDescriptiveKind(),
3189-
witness->getName(), requirementGlobalActor, Proto->getName())
3190-
.fixItInsert(
3191-
witness->getAttributeInsertionLoc(/*forModifier=*/false),
3192-
"@" + requirementGlobalActor.getString());
3193-
requirement->diagnose(diag::decl_declared_here, requirement->getName());
3194-
return true;
3174+
return false;
31953175
}
31963176

31973177
// Both have global actors but they differ, so this is an isolation error.
31983178
assert(!witnessGlobalActor->isEqual(requirementGlobalActor));
31993179
witness->diagnose(
32003180
diag::global_actor_isolated_requirement_witness_conflict,
32013181
witness->getDescriptiveKind(), witness->getName(), witnessGlobalActor,
3202-
Proto->getName(), requirementGlobalActor);
3182+
Proto->getName(), requirementGlobalActor)
3183+
.limitBehavior(behavior);
32033184
requirement->diagnose(diag::decl_declared_here, requirement->getName());
3204-
return true;
3185+
return behavior == DiagnosticBehavior::Unspecified;
32053186
}
32063187

32073188
bool ConformanceChecker::checkObjCTypeErasedGenerics(

test/Concurrency/actor_isolation_unsafe.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct S3_P1: P1 {
3030
}
3131

3232
struct S4_P1: P1 {
33-
@SomeGlobalActor func onMainActor() { } // expected-error{{instance method 'onMainActor()' isolated to global actor 'SomeGlobalActor' can not satisfy corresponding requirement from protocol 'P1' isolated to global actor 'MainActor'}}
33+
@SomeGlobalActor func onMainActor() { } // expected-warning{{instance method 'onMainActor()' isolated to global actor 'SomeGlobalActor' can not satisfy corresponding requirement from protocol 'P1' isolated to global actor 'MainActor'}}
3434
}
3535

3636
@MainActor(unsafe)

test/Concurrency/global_actor_inference.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protocol P1 {
4747
}
4848

4949
protocol P2 {
50-
@SomeGlobalActor func method1() // expected-note {{'method1()' declared here}}
50+
@SomeGlobalActor func method1()
5151
func method2()
5252
}
5353

@@ -146,14 +146,12 @@ class C5 {
146146
}
147147

148148
protocol P3 {
149-
@OtherGlobalActor func method1() // expected-note{{'method1()' declared here}}
149+
@OtherGlobalActor func method1()
150150
func method2()
151151
}
152152

153153
class C6: P2, P3 {
154154
func method1() { }
155-
// expected-error@-1{{instance method 'method1()' must be isolated to the global actor 'SomeGlobalActor' to satisfy corresponding requirement from protocol 'P2'}}
156-
// expected-error@-2{{instance method 'method1()' must be isolated to the global actor 'OtherGlobalActor' to satisfy corresponding requirement from protocol 'P3'}}
157155
func method2() { }
158156

159157
func testMethod() {

0 commit comments

Comments
 (0)