Skip to content

Commit 8b43ac6

Browse files
Merge pull request #75761 from sophiapoirier/global-concurrency-checking-refactor
[Concurrency] refactor GlobalConcurrency checking from ActorIsolationRequest to DeclChecker
2 parents 2dd1ef2 + 9c1299c commit 8b43ac6

File tree

3 files changed

+122
-136
lines changed

3 files changed

+122
-136
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 117 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -5457,70 +5457,6 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
54575457
};
54585458
}
54595459

5460-
// Diagnose global state that is not either immutable plus Sendable or
5461-
// isolated to a global actor.
5462-
auto checkGlobalIsolation = [var = dyn_cast<VarDecl>(value), &ctx](
5463-
ActorIsolation isolation) {
5464-
// Diagnose only declarations in the same module.
5465-
//
5466-
// TODO: This should be factored out from ActorIsolationRequest into
5467-
// either ActorIsolationChecker or DeclChecker.
5468-
if (var && var->getLoc(/*SerializedOK*/false) &&
5469-
var->getASTContext().LangOpts.hasFeature(Feature::GlobalConcurrency) &&
5470-
!isolation.isGlobalActor() &&
5471-
(isolation != ActorIsolation::NonisolatedUnsafe)) {
5472-
auto *classDecl = var->getDeclContext()->getSelfClassDecl();
5473-
const bool isActorType = classDecl && classDecl->isAnyActor();
5474-
if (var->isGlobalStorage() && !isActorType) {
5475-
auto *diagVar = var;
5476-
if (auto *originalVar = var->getOriginalWrappedProperty()) {
5477-
diagVar = originalVar;
5478-
}
5479-
5480-
bool diagnosed = false;
5481-
if (var->isLet()) {
5482-
auto type = var->getInterfaceType();
5483-
diagnosed = diagnoseIfAnyNonSendableTypes(
5484-
type, SendableCheckContext(var->getDeclContext()),
5485-
/*inDerivedConformance=*/Type(), /*typeLoc=*/SourceLoc(),
5486-
/*diagnoseLoc=*/var->getLoc(),
5487-
diag::shared_immutable_state_decl, diagVar);
5488-
} else {
5489-
diagVar->diagnose(diag::shared_mutable_state_decl, diagVar)
5490-
.warnUntilSwiftVersion(6);
5491-
diagnosed = true;
5492-
}
5493-
5494-
// If we diagnosed this global, tack on notes to suggest potential
5495-
// courses of action.
5496-
if (diagnosed) {
5497-
if (!var->isLet()) {
5498-
auto diag = diagVar->diagnose(diag::shared_state_make_immutable,
5499-
diagVar);
5500-
SourceLoc fixItLoc = getFixItLocForVarToLet(diagVar);
5501-
if (fixItLoc.isValid()) {
5502-
diag.fixItReplace(fixItLoc, "let");
5503-
}
5504-
}
5505-
5506-
auto mainActor = ctx.getMainActorType();
5507-
if (mainActor) {
5508-
diagVar->diagnose(diag::add_globalactor_to_decl,
5509-
mainActor->getWithoutParens().getString(),
5510-
diagVar, mainActor)
5511-
.fixItInsert(diagVar->getAttributeInsertionLoc(false),
5512-
diag::insert_globalactor_attr, mainActor);
5513-
}
5514-
diagVar->diagnose(diag::shared_state_nonisolated_unsafe,
5515-
diagVar)
5516-
.fixItInsert(diagVar->getAttributeInsertionLoc(true),
5517-
"nonisolated(unsafe) ");
5518-
}
5519-
}
5520-
}
5521-
return isolation;
5522-
};
5523-
55245460
auto isolationFromAttr = getIsolationFromAttributes(value);
55255461
if (isolationFromAttr && isolationFromAttr->preconcurrency() &&
55265462
!value->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
@@ -5557,10 +5493,8 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
55575493
checkClassGlobalActorIsolation(classDecl, *isolationFromAttr);
55585494
}
55595495

5560-
return {
5561-
checkGlobalIsolation(*isolationFromAttr),
5562-
IsolationSource(/*source*/nullptr, IsolationSource::Explicit)
5563-
};
5496+
return {*isolationFromAttr,
5497+
IsolationSource(/*source*/ nullptr, IsolationSource::Explicit)};
55645498
}
55655499

55665500
// Determine the default isolation for this declaration, which may still be
@@ -5596,83 +5530,77 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
55965530
// Function used when returning an inferred isolation.
55975531
auto inferredIsolation = [&](ActorIsolation inferred,
55985532
bool onlyGlobal = false) {
5599-
// Invoke the body within checkGlobalIsolation to check the result.
5600-
return checkGlobalIsolation([&] {
5601-
// check if the inferred isolation is valid in the context of
5602-
// its overridden isolation.
5603-
if (overriddenValue) {
5604-
// if the inferred isolation is not valid, then carry-over the
5605-
// overridden declaration's isolation as this decl's inferred isolation.
5606-
switch (validOverrideIsolation(value, inferred, overriddenValue,
5607-
*overriddenIso)) {
5608-
case OverrideIsolationResult::Allowed:
5609-
case OverrideIsolationResult::Sendable:
5610-
break;
5533+
// check if the inferred isolation is valid in the context of its overridden
5534+
// isolation.
5535+
if (overriddenValue) {
5536+
// if the inferred isolation is not valid, then carry-over the overridden
5537+
// declaration's isolation as this decl's inferred isolation.
5538+
switch (validOverrideIsolation(value, inferred, overriddenValue,
5539+
*overriddenIso)) {
5540+
case OverrideIsolationResult::Allowed:
5541+
case OverrideIsolationResult::Sendable:
5542+
break;
56115543

5612-
case OverrideIsolationResult::Disallowed:
5613-
if (overriddenValue->hasClangNode() &&
5614-
overriddenIso->isUnspecified()) {
5615-
inferred = overriddenIso->withPreconcurrency(true);
5616-
} else {
5617-
inferred = *overriddenIso;
5618-
}
5619-
break;
5544+
case OverrideIsolationResult::Disallowed:
5545+
if (overriddenValue->hasClangNode() && overriddenIso->isUnspecified()) {
5546+
inferred = overriddenIso->withPreconcurrency(true);
5547+
} else {
5548+
inferred = *overriddenIso;
56205549
}
5550+
break;
56215551
}
5552+
}
56225553

5623-
// Add an implicit attribute to capture the actor isolation that was
5624-
// inferred, so that (e.g.) it will be printed and serialized.
5625-
switch (inferred) {
5626-
case ActorIsolation::Nonisolated:
5627-
case ActorIsolation::NonisolatedUnsafe:
5628-
// Stored properties cannot be non-isolated, so don't infer it.
5629-
if (auto var = dyn_cast<VarDecl>(value)) {
5630-
if (!var->isStatic() && var->hasStorage())
5631-
return ActorIsolation::forUnspecified().withPreconcurrency(
5632-
inferred.preconcurrency());
5633-
}
5634-
5635-
if (onlyGlobal) {
5554+
// Add an implicit attribute to capture the actor isolation that was
5555+
// inferred, so that (e.g.) it will be printed and serialized.
5556+
switch (inferred) {
5557+
case ActorIsolation::Nonisolated:
5558+
case ActorIsolation::NonisolatedUnsafe:
5559+
// Stored properties cannot be non-isolated, so don't infer it.
5560+
if (auto var = dyn_cast<VarDecl>(value)) {
5561+
if (!var->isStatic() && var->hasStorage())
56365562
return ActorIsolation::forUnspecified().withPreconcurrency(
56375563
inferred.preconcurrency());
5638-
}
5564+
}
56395565

5640-
value->getAttrs().add(new (ctx) NonisolatedAttr(
5641-
inferred == ActorIsolation::NonisolatedUnsafe, /*implicit=*/true));
5642-
break;
5566+
if (onlyGlobal) {
5567+
return ActorIsolation::forUnspecified().withPreconcurrency(
5568+
inferred.preconcurrency());
5569+
}
56435570

5644-
case ActorIsolation::Erased:
5645-
llvm_unreachable("cannot infer erased isolation");
5571+
value->getAttrs().add(new (ctx) NonisolatedAttr(
5572+
inferred == ActorIsolation::NonisolatedUnsafe, /*implicit=*/true));
5573+
break;
56465574

5647-
case ActorIsolation::GlobalActor: {
5648-
auto typeExpr =
5649-
TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
5650-
auto attr =
5651-
CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true);
5652-
value->getAttrs().add(attr);
5653-
5654-
if (inferred.preconcurrency() &&
5655-
!value->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
5656-
auto preconcurrency =
5657-
new (ctx) PreconcurrencyAttr(/*isImplicit*/true);
5658-
value->getAttrs().add(preconcurrency);
5659-
}
5575+
case ActorIsolation::Erased:
5576+
llvm_unreachable("cannot infer erased isolation");
56605577

5661-
break;
5578+
case ActorIsolation::GlobalActor: {
5579+
auto typeExpr = TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
5580+
auto attr =
5581+
CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true);
5582+
value->getAttrs().add(attr);
5583+
5584+
if (inferred.preconcurrency() &&
5585+
!value->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
5586+
auto preconcurrency = new (ctx) PreconcurrencyAttr(/*isImplicit*/ true);
5587+
value->getAttrs().add(preconcurrency);
56625588
}
56635589

5664-
case ActorIsolation::ActorInstance:
5665-
case ActorIsolation::Unspecified:
5666-
if (onlyGlobal)
5667-
return ActorIsolation::forUnspecified().withPreconcurrency(
5668-
inferred.preconcurrency());
5590+
break;
5591+
}
56695592

5670-
// Nothing to do.
5671-
break;
5672-
}
5593+
case ActorIsolation::ActorInstance:
5594+
case ActorIsolation::Unspecified:
5595+
if (onlyGlobal)
5596+
return ActorIsolation::forUnspecified().withPreconcurrency(
5597+
inferred.preconcurrency());
5598+
5599+
// Nothing to do.
5600+
break;
5601+
}
56735602

5674-
return inferred;
5675-
}());
5603+
return inferred;
56765604
};
56775605

56785606
// If this is a local function, inherit the actor isolation from its
@@ -5874,10 +5802,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
58745802
}
58755803

58765804
// Default isolation for this member.
5877-
return {
5878-
checkGlobalIsolation(defaultIsolation),
5879-
defaultIsolationSource
5880-
};
5805+
return {defaultIsolation, defaultIsolationSource};
58815806
}
58825807

58835808
bool HasIsolatedSelfRequest::evaluate(
@@ -6075,6 +6000,63 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
60756000
overridden->diagnose(diag::overridden_here);
60766001
}
60776002

6003+
void swift::checkGlobalIsolation(VarDecl *var) {
6004+
const auto isolation = getActorIsolation(var);
6005+
if (var->getLoc() &&
6006+
var->getASTContext().LangOpts.hasFeature(Feature::GlobalConcurrency) &&
6007+
!isolation.isGlobalActor() &&
6008+
(isolation != ActorIsolation::NonisolatedUnsafe)) {
6009+
auto *classDecl = var->getDeclContext()->getSelfClassDecl();
6010+
const bool isActorType = classDecl && classDecl->isAnyActor();
6011+
if (var->isGlobalStorage() && !isActorType) {
6012+
auto *diagVar = var;
6013+
if (auto *originalVar = var->getOriginalWrappedProperty()) {
6014+
diagVar = originalVar;
6015+
}
6016+
6017+
bool diagnosed = false;
6018+
if (var->isLet()) {
6019+
auto type = var->getInterfaceType();
6020+
diagnosed = diagnoseIfAnyNonSendableTypes(
6021+
type, SendableCheckContext(var->getDeclContext()),
6022+
/*inDerivedConformance=*/Type(), /*typeLoc=*/SourceLoc(),
6023+
/*diagnoseLoc=*/var->getLoc(), diag::shared_immutable_state_decl,
6024+
diagVar);
6025+
} else {
6026+
diagVar->diagnose(diag::shared_mutable_state_decl, diagVar)
6027+
.warnUntilSwiftVersion(6);
6028+
diagnosed = true;
6029+
}
6030+
6031+
// If we diagnosed this global, tack on notes to suggest potential courses
6032+
// of action.
6033+
if (diagnosed) {
6034+
if (!var->isLet()) {
6035+
auto diag =
6036+
diagVar->diagnose(diag::shared_state_make_immutable, diagVar);
6037+
SourceLoc fixItLoc = getFixItLocForVarToLet(diagVar);
6038+
if (fixItLoc.isValid()) {
6039+
diag.fixItReplace(fixItLoc, "let");
6040+
}
6041+
}
6042+
6043+
auto mainActor = var->getASTContext().getMainActorType();
6044+
if (mainActor) {
6045+
diagVar
6046+
->diagnose(diag::add_globalactor_to_decl,
6047+
mainActor->getWithoutParens().getString(), diagVar,
6048+
mainActor)
6049+
.fixItInsert(diagVar->getAttributeInsertionLoc(false),
6050+
diag::insert_globalactor_attr, mainActor);
6051+
}
6052+
diagVar->diagnose(diag::shared_state_nonisolated_unsafe, diagVar)
6053+
.fixItInsert(diagVar->getAttributeInsertionLoc(true),
6054+
"nonisolated(unsafe) ");
6055+
}
6056+
}
6057+
}
6058+
}
6059+
60786060
bool swift::contextRequiresStrictConcurrencyChecking(
60796061
const DeclContext *dc,
60806062
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,

lib/Sema/TypeCheckConcurrency.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ enum class SendableCheckReason {
8989
/// overridden declaration.
9090
void checkOverrideActorIsolation(ValueDecl *value);
9191

92+
/// Diagnose global state that is not either immutable plus Sendable or isolated
93+
/// to a global actor.
94+
void checkGlobalIsolation(VarDecl *var);
95+
9296
/// Determine whether the given context requires strict concurrency checking,
9397
/// e.g., because it uses concurrency features directly or because it's in
9498
/// code where strict checking has been enabled.

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2535,7 +2535,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25352535
(void) VD->getPropertyWrapperAuxiliaryVariables();
25362536
(void) VD->getPropertyWrapperInitializerInfo();
25372537
(void) VD->getImplInfo();
2538-
(void) getActorIsolation(VD);
2538+
checkGlobalIsolation(VD);
25392539

25402540
// Visit auxiliary decls first
25412541
VD->visitAuxiliaryDecls([&](VarDecl *var) {

0 commit comments

Comments
 (0)