Skip to content

Commit 6eb7905

Browse files
committed
[Isolated conformances] Infer main actor isolation under UnspecifiedMeansMainActorIsolated
When code in the current module defaults to main actor (under SE-0466), also infer main-actor isolation for protocol conformances of main-actor isolated types.
1 parent c58e22f commit 6eb7905

File tree

5 files changed

+92
-26
lines changed

5 files changed

+92
-26
lines changed

lib/AST/TypeCheckRequests.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,11 @@ bool ConformanceIsolationRequest::isCached() const {
13811381
if (!rootNormal)
13821382
return false;
13831383

1384+
// We know this is nonisolated.
1385+
if (rootNormal->getOptions().contains(ProtocolConformanceFlags::Nonisolated))
1386+
return false;
1387+
1388+
// Explicit global actor isolation needs to be checked.
13841389
if (rootNormal->globalActorIsolation)
13851390
return true;
13861391

lib/AST/TypeRepr.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,13 @@ SourceLoc TypeRepr::findAttrLoc(TypeAttrKind kind) const {
151151
while (auto attrTypeRepr = dyn_cast<AttributedTypeRepr>(typeRepr)) {
152152
for (auto attr : attrTypeRepr->getAttrs()) {
153153
if (auto typeAttr = attr.dyn_cast<TypeAttribute*>())
154-
if (typeAttr->getKind() == kind)
155-
return typeAttr->getStartLoc();
154+
if (typeAttr->getKind() == kind) {
155+
auto startLoc = typeAttr->getStartLoc();
156+
if (startLoc.isValid())
157+
return startLoc;
158+
159+
return typeAttr->getAttrLoc();
160+
}
156161
}
157162

158163
typeRepr = attrTypeRepr->getTypeRepr();

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7878,37 +7878,56 @@ ActorIsolation ProtocolConformance::getIsolation() const {
78787878

78797879
ActorIsolation
78807880
ConformanceIsolationRequest::evaluate(Evaluator &evaluator, ProtocolConformance *conformance) const {
7881+
// Only normal protocol conformances can be isolated.
78817882
auto rootNormal =
78827883
dyn_cast<NormalProtocolConformance>(conformance->getRootConformance());
78837884
if (!rootNormal)
78847885
return ActorIsolation::forNonisolated(false);
78857886

7886-
if (!rootNormal->globalActorIsolation)
7887+
// If the conformance is explicitly non-isolated, report that.
7888+
if (rootNormal->getOptions().contains(ProtocolConformanceFlags::Nonisolated))
78877889
return ActorIsolation::forNonisolated(false);
78887890

7889-
auto globalActorTypeExpr = rootNormal->globalActorIsolation;
7890-
assert(globalActorTypeExpr && "global actor type is out-of-sync");
7891-
7892-
// If we don't already have a resolved global actor type, resolve it now.
7893-
Type globalActorType = globalActorTypeExpr->getInstanceType();
7894-
if (!globalActorType) {
7895-
const auto resolution = TypeResolution::forInterface(
7896-
rootNormal->getDeclContext(), std::nullopt,
7897-
/*unboundTyOpener*/ nullptr,
7898-
/*placeholderHandler*/ nullptr,
7899-
/*packElementOpener*/ nullptr);
7900-
globalActorType = resolution.resolveType(globalActorTypeExpr->getTypeRepr());
7901-
if (!globalActorType)
7902-
return ActorIsolation::forNonisolated(false);
7891+
// If there is an explicitly-specified global actor on the isolation,
7892+
// resolve it and report it.
7893+
if (auto globalActorTypeExpr = rootNormal->globalActorIsolation) {
7894+
// If we don't already have a resolved global actor type, resolve it now.
7895+
Type globalActorType = globalActorTypeExpr->getInstanceType();
7896+
if (!globalActorType) {
7897+
const auto resolution = TypeResolution::forInterface(
7898+
rootNormal->getDeclContext(), std::nullopt,
7899+
/*unboundTyOpener*/ nullptr,
7900+
/*placeholderHandler*/ nullptr,
7901+
/*packElementOpener*/ nullptr);
7902+
globalActorType = resolution.resolveType(globalActorTypeExpr->getTypeRepr());
7903+
if (!globalActorType)
7904+
return ActorIsolation::forNonisolated(false);
7905+
7906+
// Cache the resolved type.
7907+
globalActorTypeExpr->setType(MetatypeType::get(globalActorType));
7908+
}
7909+
7910+
// FIXME: Make sure the type actually is a global actor type, map it into
7911+
// context, etc.
79037912

7904-
// Cache the resolved type.
7905-
globalActorTypeExpr->setType(MetatypeType::get(globalActorType));
7913+
return ActorIsolation::forGlobalActor(globalActorType);
79067914
}
79077915

7908-
// FIXME: Make sure the type actually is a global actor type, map it into
7909-
// context, etc.
7916+
// In a context where we are inferring @MainActor, if the conforming type
7917+
// is on the main actor, then the conformance is, too.
7918+
auto dc = rootNormal->getDeclContext();
7919+
ASTContext &ctx = dc->getASTContext();
7920+
auto nominal = dc->getSelfNominalTypeDecl();
7921+
if (ctx.LangOpts.hasFeature(Feature::UnspecifiedMeansMainActorIsolated) &&
7922+
nominal) {
7923+
auto nominalIsolation = getActorIsolation(nominal);
7924+
if (nominalIsolation.isMainActor()) {
7925+
rootNormal->setGlobalActorIsolation(nominalIsolation.getGlobalActor());
7926+
return nominalIsolation;
7927+
}
7928+
}
79107929

7911-
return ActorIsolation::forGlobalActor(globalActorType);
7930+
return ActorIsolation::forNonisolated(false);
79127931
}
79137932

79147933
namespace {

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,10 +1929,7 @@ void Serializer::writeLocalNormalProtocolConformance(
19291929

19301930
// Figure out the isolation of the conformance.
19311931
Type globalActorType;
1932-
auto isolation = evaluateOrDefault(
1933-
getASTContext().evaluator,
1934-
ConformanceIsolationRequest{conformance}, swift::ActorIsolation());
1935-
switch (isolation) {
1932+
switch (auto isolation = conformance->getIsolation()) {
19361933
case swift::ActorIsolation::Unspecified:
19371934
case swift::ActorIsolation::Nonisolated:
19381935
break;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances -enable-experimental-feature UnspecifiedMeansMainActorIsolated %s
2+
3+
// REQUIRES: swift_feature_IsolatedConformances
4+
// REQUIRES: swift_feature_UnspecifiedMeansMainActorIsolated
5+
// REQUIRES: concurrency
6+
7+
nonisolated
8+
protocol P {
9+
func f() // expected-note{{mark the protocol requirement 'f()' 'async' to allow actor-isolated conformances}}
10+
}
11+
12+
class CImplicitMainActorNonisolatedConformance: nonisolated P {
13+
func f() { } // error: explicitly nonisolated conformance
14+
}
15+
16+
17+
@MainActor
18+
class CExplicitMainActor: P {
19+
func f() { } // okay! conformance above is isolated
20+
}
21+
22+
class CImplicitMainActor: P {
23+
func f() { } // okay! conformance above is isolated
24+
}
25+
26+
// expected-note@+2{{add '@preconcurrency' to the 'P' conformance to defer isolation checking to run time}}
27+
// expected-note@+1{{add '@MainActor' to the 'P' conformance to restrict it to main actor-isolated code}}
28+
nonisolated class CNonIsolated: P {
29+
@MainActor func f() { } // expected-error{{main actor-isolated instance method 'f()' cannot be used to satisfy nonisolated requirement from protocol 'P'}}
30+
}
31+
32+
func acceptSendablePMeta<T: Sendable & P>(_: T.Type) { }
33+
34+
nonisolated func testConformancesFromNonisolated() {
35+
let _: any P = CExplicitMainActor() // expected-error{{main actor-isolated conformance of 'CExplicitMainActor' to 'P' cannot be used in nonisolated context}}
36+
let _: any P = CImplicitMainActor() // expected-error{{main actor-isolated conformance of 'CImplicitMainActor' to 'P' cannot be used in nonisolated context}}
37+
38+
let _: any P = CNonIsolated()
39+
let _: any P = CImplicitMainActorNonisolatedConformance()
40+
}

0 commit comments

Comments
 (0)