Skip to content

Commit 9c1299c

Browse files
committed
[Concurrency] refactor GlobalConcurrency checking from ActorIsolationRequest to DeclChecker (resolves swiftlang#74622)
1 parent d433919 commit 9c1299c

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
@@ -5366,70 +5366,6 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
53665366
};
53675367
}
53685368

5369-
// Diagnose global state that is not either immutable plus Sendable or
5370-
// isolated to a global actor.
5371-
auto checkGlobalIsolation = [var = dyn_cast<VarDecl>(value), &ctx](
5372-
ActorIsolation isolation) {
5373-
// Diagnose only declarations in the same module.
5374-
//
5375-
// TODO: This should be factored out from ActorIsolationRequest into
5376-
// either ActorIsolationChecker or DeclChecker.
5377-
if (var && var->getLoc(/*SerializedOK*/false) &&
5378-
var->getASTContext().LangOpts.hasFeature(Feature::GlobalConcurrency) &&
5379-
!isolation.isGlobalActor() &&
5380-
(isolation != ActorIsolation::NonisolatedUnsafe)) {
5381-
auto *classDecl = var->getDeclContext()->getSelfClassDecl();
5382-
const bool isActorType = classDecl && classDecl->isAnyActor();
5383-
if (var->isGlobalStorage() && !isActorType) {
5384-
auto *diagVar = var;
5385-
if (auto *originalVar = var->getOriginalWrappedProperty()) {
5386-
diagVar = originalVar;
5387-
}
5388-
5389-
bool diagnosed = false;
5390-
if (var->isLet()) {
5391-
auto type = var->getInterfaceType();
5392-
diagnosed = diagnoseIfAnyNonSendableTypes(
5393-
type, SendableCheckContext(var->getDeclContext()),
5394-
/*inDerivedConformance=*/Type(), /*typeLoc=*/SourceLoc(),
5395-
/*diagnoseLoc=*/var->getLoc(),
5396-
diag::shared_immutable_state_decl, diagVar);
5397-
} else {
5398-
diagVar->diagnose(diag::shared_mutable_state_decl, diagVar)
5399-
.warnUntilSwiftVersion(6);
5400-
diagnosed = true;
5401-
}
5402-
5403-
// If we diagnosed this global, tack on notes to suggest potential
5404-
// courses of action.
5405-
if (diagnosed) {
5406-
if (!var->isLet()) {
5407-
auto diag = diagVar->diagnose(diag::shared_state_make_immutable,
5408-
diagVar);
5409-
SourceLoc fixItLoc = getFixItLocForVarToLet(diagVar);
5410-
if (fixItLoc.isValid()) {
5411-
diag.fixItReplace(fixItLoc, "let");
5412-
}
5413-
}
5414-
5415-
auto mainActor = ctx.getMainActorType();
5416-
if (mainActor) {
5417-
diagVar->diagnose(diag::add_globalactor_to_decl,
5418-
mainActor->getWithoutParens().getString(),
5419-
diagVar, mainActor)
5420-
.fixItInsert(diagVar->getAttributeInsertionLoc(false),
5421-
diag::insert_globalactor_attr, mainActor);
5422-
}
5423-
diagVar->diagnose(diag::shared_state_nonisolated_unsafe,
5424-
diagVar)
5425-
.fixItInsert(diagVar->getAttributeInsertionLoc(true),
5426-
"nonisolated(unsafe) ");
5427-
}
5428-
}
5429-
}
5430-
return isolation;
5431-
};
5432-
54335369
auto isolationFromAttr = getIsolationFromAttributes(value);
54345370
if (isolationFromAttr && isolationFromAttr->preconcurrency() &&
54355371
!value->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
@@ -5466,10 +5402,8 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
54665402
checkClassGlobalActorIsolation(classDecl, *isolationFromAttr);
54675403
}
54685404

5469-
return {
5470-
checkGlobalIsolation(*isolationFromAttr),
5471-
IsolationSource(/*source*/nullptr, IsolationSource::Explicit)
5472-
};
5405+
return {*isolationFromAttr,
5406+
IsolationSource(/*source*/ nullptr, IsolationSource::Explicit)};
54735407
}
54745408

54755409
// Determine the default isolation for this declaration, which may still be
@@ -5505,83 +5439,77 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
55055439
// Function used when returning an inferred isolation.
55065440
auto inferredIsolation = [&](ActorIsolation inferred,
55075441
bool onlyGlobal = false) {
5508-
// Invoke the body within checkGlobalIsolation to check the result.
5509-
return checkGlobalIsolation([&] {
5510-
// check if the inferred isolation is valid in the context of
5511-
// its overridden isolation.
5512-
if (overriddenValue) {
5513-
// if the inferred isolation is not valid, then carry-over the
5514-
// overridden declaration's isolation as this decl's inferred isolation.
5515-
switch (validOverrideIsolation(value, inferred, overriddenValue,
5516-
*overriddenIso)) {
5517-
case OverrideIsolationResult::Allowed:
5518-
case OverrideIsolationResult::Sendable:
5519-
break;
5442+
// check if the inferred isolation is valid in the context of its overridden
5443+
// isolation.
5444+
if (overriddenValue) {
5445+
// if the inferred isolation is not valid, then carry-over the overridden
5446+
// declaration's isolation as this decl's inferred isolation.
5447+
switch (validOverrideIsolation(value, inferred, overriddenValue,
5448+
*overriddenIso)) {
5449+
case OverrideIsolationResult::Allowed:
5450+
case OverrideIsolationResult::Sendable:
5451+
break;
55205452

5521-
case OverrideIsolationResult::Disallowed:
5522-
if (overriddenValue->hasClangNode() &&
5523-
overriddenIso->isUnspecified()) {
5524-
inferred = overriddenIso->withPreconcurrency(true);
5525-
} else {
5526-
inferred = *overriddenIso;
5527-
}
5528-
break;
5453+
case OverrideIsolationResult::Disallowed:
5454+
if (overriddenValue->hasClangNode() && overriddenIso->isUnspecified()) {
5455+
inferred = overriddenIso->withPreconcurrency(true);
5456+
} else {
5457+
inferred = *overriddenIso;
55295458
}
5459+
break;
55305460
}
5461+
}
55315462

5532-
// Add an implicit attribute to capture the actor isolation that was
5533-
// inferred, so that (e.g.) it will be printed and serialized.
5534-
switch (inferred) {
5535-
case ActorIsolation::Nonisolated:
5536-
case ActorIsolation::NonisolatedUnsafe:
5537-
// Stored properties cannot be non-isolated, so don't infer it.
5538-
if (auto var = dyn_cast<VarDecl>(value)) {
5539-
if (!var->isStatic() && var->hasStorage())
5540-
return ActorIsolation::forUnspecified().withPreconcurrency(
5541-
inferred.preconcurrency());
5542-
}
5543-
5544-
if (onlyGlobal) {
5463+
// Add an implicit attribute to capture the actor isolation that was
5464+
// inferred, so that (e.g.) it will be printed and serialized.
5465+
switch (inferred) {
5466+
case ActorIsolation::Nonisolated:
5467+
case ActorIsolation::NonisolatedUnsafe:
5468+
// Stored properties cannot be non-isolated, so don't infer it.
5469+
if (auto var = dyn_cast<VarDecl>(value)) {
5470+
if (!var->isStatic() && var->hasStorage())
55455471
return ActorIsolation::forUnspecified().withPreconcurrency(
55465472
inferred.preconcurrency());
5547-
}
5473+
}
55485474

5549-
value->getAttrs().add(new (ctx) NonisolatedAttr(
5550-
inferred == ActorIsolation::NonisolatedUnsafe, /*implicit=*/true));
5551-
break;
5475+
if (onlyGlobal) {
5476+
return ActorIsolation::forUnspecified().withPreconcurrency(
5477+
inferred.preconcurrency());
5478+
}
55525479

5553-
case ActorIsolation::Erased:
5554-
llvm_unreachable("cannot infer erased isolation");
5480+
value->getAttrs().add(new (ctx) NonisolatedAttr(
5481+
inferred == ActorIsolation::NonisolatedUnsafe, /*implicit=*/true));
5482+
break;
55555483

5556-
case ActorIsolation::GlobalActor: {
5557-
auto typeExpr =
5558-
TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
5559-
auto attr =
5560-
CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true);
5561-
value->getAttrs().add(attr);
5562-
5563-
if (inferred.preconcurrency() &&
5564-
!value->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
5565-
auto preconcurrency =
5566-
new (ctx) PreconcurrencyAttr(/*isImplicit*/true);
5567-
value->getAttrs().add(preconcurrency);
5568-
}
5484+
case ActorIsolation::Erased:
5485+
llvm_unreachable("cannot infer erased isolation");
55695486

5570-
break;
5487+
case ActorIsolation::GlobalActor: {
5488+
auto typeExpr = TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
5489+
auto attr =
5490+
CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true);
5491+
value->getAttrs().add(attr);
5492+
5493+
if (inferred.preconcurrency() &&
5494+
!value->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
5495+
auto preconcurrency = new (ctx) PreconcurrencyAttr(/*isImplicit*/ true);
5496+
value->getAttrs().add(preconcurrency);
55715497
}
55725498

5573-
case ActorIsolation::ActorInstance:
5574-
case ActorIsolation::Unspecified:
5575-
if (onlyGlobal)
5576-
return ActorIsolation::forUnspecified().withPreconcurrency(
5577-
inferred.preconcurrency());
5499+
break;
5500+
}
55785501

5579-
// Nothing to do.
5580-
break;
5581-
}
5502+
case ActorIsolation::ActorInstance:
5503+
case ActorIsolation::Unspecified:
5504+
if (onlyGlobal)
5505+
return ActorIsolation::forUnspecified().withPreconcurrency(
5506+
inferred.preconcurrency());
5507+
5508+
// Nothing to do.
5509+
break;
5510+
}
55825511

5583-
return inferred;
5584-
}());
5512+
return inferred;
55855513
};
55865514

55875515
// If this is a local function, inherit the actor isolation from its
@@ -5783,10 +5711,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
57835711
}
57845712

57855713
// Default isolation for this member.
5786-
return {
5787-
checkGlobalIsolation(defaultIsolation),
5788-
defaultIsolationSource
5789-
};
5714+
return {defaultIsolation, defaultIsolationSource};
57905715
}
57915716

57925717
bool HasIsolatedSelfRequest::evaluate(
@@ -5984,6 +5909,63 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
59845909
overridden->diagnose(diag::overridden_here);
59855910
}
59865911

5912+
void swift::checkGlobalIsolation(VarDecl *var) {
5913+
const auto isolation = getActorIsolation(var);
5914+
if (var->getLoc() &&
5915+
var->getASTContext().LangOpts.hasFeature(Feature::GlobalConcurrency) &&
5916+
!isolation.isGlobalActor() &&
5917+
(isolation != ActorIsolation::NonisolatedUnsafe)) {
5918+
auto *classDecl = var->getDeclContext()->getSelfClassDecl();
5919+
const bool isActorType = classDecl && classDecl->isAnyActor();
5920+
if (var->isGlobalStorage() && !isActorType) {
5921+
auto *diagVar = var;
5922+
if (auto *originalVar = var->getOriginalWrappedProperty()) {
5923+
diagVar = originalVar;
5924+
}
5925+
5926+
bool diagnosed = false;
5927+
if (var->isLet()) {
5928+
auto type = var->getInterfaceType();
5929+
diagnosed = diagnoseIfAnyNonSendableTypes(
5930+
type, SendableCheckContext(var->getDeclContext()),
5931+
/*inDerivedConformance=*/Type(), /*typeLoc=*/SourceLoc(),
5932+
/*diagnoseLoc=*/var->getLoc(), diag::shared_immutable_state_decl,
5933+
diagVar);
5934+
} else {
5935+
diagVar->diagnose(diag::shared_mutable_state_decl, diagVar)
5936+
.warnUntilSwiftVersion(6);
5937+
diagnosed = true;
5938+
}
5939+
5940+
// If we diagnosed this global, tack on notes to suggest potential courses
5941+
// of action.
5942+
if (diagnosed) {
5943+
if (!var->isLet()) {
5944+
auto diag =
5945+
diagVar->diagnose(diag::shared_state_make_immutable, diagVar);
5946+
SourceLoc fixItLoc = getFixItLocForVarToLet(diagVar);
5947+
if (fixItLoc.isValid()) {
5948+
diag.fixItReplace(fixItLoc, "let");
5949+
}
5950+
}
5951+
5952+
auto mainActor = var->getASTContext().getMainActorType();
5953+
if (mainActor) {
5954+
diagVar
5955+
->diagnose(diag::add_globalactor_to_decl,
5956+
mainActor->getWithoutParens().getString(), diagVar,
5957+
mainActor)
5958+
.fixItInsert(diagVar->getAttributeInsertionLoc(false),
5959+
diag::insert_globalactor_attr, mainActor);
5960+
}
5961+
diagVar->diagnose(diag::shared_state_nonisolated_unsafe, diagVar)
5962+
.fixItInsert(diagVar->getAttributeInsertionLoc(true),
5963+
"nonisolated(unsafe) ");
5964+
}
5965+
}
5966+
}
5967+
}
5968+
59875969
bool swift::contextRequiresStrictConcurrencyChecking(
59885970
const DeclContext *dc,
59895971
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)