@@ -2541,6 +2541,22 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
2541
2541
ComplainLoc, diag::unchecked_conformance_not_special, ProtoType);
2542
2542
}
2543
2543
2544
+ // Complain if the conformance is isolated but the conforming type is
2545
+ // not global-actor-isolated.
2546
+ if (conformance->isIsolated()) {
2547
+ auto enclosingNominal = DC->getSelfNominalTypeDecl();
2548
+ if (!enclosingNominal ||
2549
+ !getActorIsolation(enclosingNominal).isGlobalActor()) {
2550
+ Context.Diags.diagnose(
2551
+ ComplainLoc, diag::isolated_conformance_not_global_actor_isolated);
2552
+ }
2553
+
2554
+ if (!Context.LangOpts.hasFeature(Feature::IsolatedConformances)) {
2555
+ Context.Diags.diagnose(
2556
+ ComplainLoc, diag::isolated_conformance_experimental_feature);
2557
+ }
2558
+ }
2559
+
2544
2560
bool allowImpliedConditionalConformance = false;
2545
2561
if (Proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
2546
2562
// In -swift-version 5 mode, a conditional conformance to a protocol can imply
@@ -3313,6 +3329,14 @@ static bool hasExplicitGlobalActorAttr(ValueDecl *decl) {
3313
3329
return !globalActorAttr->first->isImplicit();
3314
3330
}
3315
3331
3332
+ /// Determine whether the given actor isolation matches that of the enclosing
3333
+ /// type.
3334
+ static bool isolationMatchesEnclosingType(
3335
+ ActorIsolation isolation, NominalTypeDecl *nominal) {
3336
+ auto nominalIsolation = getActorIsolation(nominal);
3337
+ return isolation == nominalIsolation;
3338
+ }
3339
+
3316
3340
std::optional<ActorIsolation>
3317
3341
ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
3318
3342
ValueDecl *witness,
@@ -3342,7 +3366,8 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
3342
3366
Conformance->isPreconcurrency() &&
3343
3367
!(requirementIsolation.isActorIsolated() ||
3344
3368
requirement->getAttrs().hasAttribute<NonisolatedAttr>());
3345
-
3369
+ bool isIsolatedConformance = false;
3370
+
3346
3371
switch (refResult) {
3347
3372
case ActorReferenceResult::SameConcurrencyDomain:
3348
3373
// If the witness has distributed-actor isolation, we have extra
@@ -3374,6 +3399,17 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
3374
3399
3375
3400
return std::nullopt;
3376
3401
case ActorReferenceResult::EntersActor:
3402
+ // If the conformance itself is isolated, and the witness isolation
3403
+ // matches the enclosing type's isolation, treat this as being in the
3404
+ // same concurrency domain.
3405
+ if (Conformance->isIsolated() &&
3406
+ refResult.isolation.isGlobalActor() &&
3407
+ isolationMatchesEnclosingType(
3408
+ refResult.isolation, DC->getSelfNominalTypeDecl())) {
3409
+ sameConcurrencyDomain = true;
3410
+ isIsolatedConformance = true;
3411
+ }
3412
+
3377
3413
// Handled below.
3378
3414
break;
3379
3415
}
@@ -3446,7 +3482,12 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
3446
3482
3447
3483
// If we aren't missing anything or this is a witness to a `@preconcurrency`
3448
3484
// conformance, do a Sendable check and move on.
3449
- if (!missingOptions || isPreconcurrency) {
3485
+ if (!missingOptions || isPreconcurrency || isIsolatedConformance) {
3486
+ // An isolated conformance won't ever leave the isolation domain in which
3487
+ // it was created, so there is nothing to check.
3488
+ if (isIsolatedConformance)
3489
+ return std::nullopt;
3490
+
3450
3491
// FIXME: Disable Sendable checking when the witness is an initializer
3451
3492
// that is explicitly marked nonisolated.
3452
3493
if (isa<ConstructorDecl>(witness) &&
@@ -3546,18 +3587,26 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
3546
3587
witness->diagnose(diag::note_add_nonisolated_to_decl, witness)
3547
3588
.fixItInsert(witness->getAttributeInsertionLoc(true), "nonisolated ");
3548
3589
}
3549
-
3590
+
3550
3591
// Another way to address the issue is to mark the conformance as
3551
- // "preconcurrency".
3592
+ // "isolated" or "@ preconcurrency".
3552
3593
if (Conformance->getSourceKind() == ConformanceEntryKind::Explicit &&
3553
- !Conformance->isPreconcurrency() &&
3554
- !suggestedPreconcurrency &&
3594
+ !Conformance->isIsolated() && !Conformance-> isPreconcurrency() &&
3595
+ !suggestedPreconcurrencyOrIsolated &&
3555
3596
!requirementIsolation.isActorIsolated()) {
3597
+ if (Context.LangOpts.hasFeature(Feature::IsolatedConformances)) {
3598
+ Context.Diags.diagnose(Conformance->getProtocolNameLoc(),
3599
+ diag::add_isolated_to_conformance,
3600
+ Proto->getName(), refResult.isolation)
3601
+ .fixItInsert(Conformance->getProtocolNameLoc(), "isolated ");
3602
+ }
3603
+
3556
3604
Context.Diags.diagnose(Conformance->getProtocolNameLoc(),
3557
3605
diag::add_preconcurrency_to_conformance,
3558
3606
Proto->getName())
3559
3607
.fixItInsert(Conformance->getProtocolNameLoc(), "@preconcurrency ");
3560
- suggestedPreconcurrency = true;
3608
+
3609
+ suggestedPreconcurrencyOrIsolated = true;
3561
3610
}
3562
3611
}
3563
3612
0 commit comments