Skip to content

Commit 5abbf2e

Browse files
committed
[SE-0466] Under main actor default isolation, explicit nonisolated is not special
Given an explicitly-nonisolated type such as nonisolated struct S { } all extensions of S were also being treated as nonisolated. This meant that being implicitly nonisolated (i.e., when you're using nonisolated default isolation) was different from explicitly-writing nonisolated, which is unfortunate and confusing. Align the rules, such that an extension of S will get default isolation: extension S { func f() { } // @mainactor if we're in main actor default isolation }
1 parent 4ffe06e commit 5abbf2e

File tree

5 files changed

+60
-3
lines changed

5 files changed

+60
-3
lines changed

include/swift/Basic/Features.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ EXPERIMENTAL_FEATURE(LayoutPrespecialization, true)
332332

333333
EXPERIMENTAL_FEATURE(AccessLevelOnImport, true)
334334

335+
/// Disable the special behavior of of explicit 'nonisolated' vs. being
336+
/// implicitly nonisolated.
337+
EXPERIMENTAL_FEATURE(NoExplicitNonIsolated, true)
338+
335339
/// Enables a module to allow non resilient access from other
336340
/// modules within a package if built from source.
337341
EXPERIMENTAL_FEATURE(AllowNonResilientAccessInPackage, false)

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ UNINTERESTING_FEATURE(MacrosOnImports)
127127
UNINTERESTING_FEATURE(ExtensibleEnums)
128128
UNINTERESTING_FEATURE(NonisolatedNonsendingByDefault)
129129
UNINTERESTING_FEATURE(KeyPathWithMethodMembers)
130+
UNINTERESTING_FEATURE(NoExplicitNonIsolated)
130131

131132
static bool usesFeatureNonescapableTypes(Decl *decl) {
132133
auto containsNonEscapable =

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1878,8 +1878,10 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
18781878
Opts.DefaultIsolationBehavior = DefaultIsolation::Nonisolated;
18791879
}
18801880

1881-
if (Opts.DefaultIsolationBehavior == DefaultIsolation::MainActor)
1881+
if (Opts.DefaultIsolationBehavior == DefaultIsolation::MainActor) {
18821882
Opts.enableFeature(Feature::InferIsolatedConformances);
1883+
Opts.enableFeature(Feature::NoExplicitNonIsolated);
1884+
}
18831885

18841886
#if !defined(NDEBUG) && SWIFT_ENABLE_EXPERIMENTAL_PARSER_VALIDATION
18851887
/// Enable round trip parsing via the new swift parser unless it is disabled

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6297,6 +6297,39 @@ computeDefaultInferredActorIsolation(ValueDecl *value) {
62976297
return {{ActorIsolation::forUnspecified(), {}}, nullptr, {}};
62986298
}
62996299

6300+
/// Determines when the given "self" isolation should override default
6301+
/// isolation.
6302+
static bool shouldSelfIsolationOverrideDefault(
6303+
ASTContext &ctx, const DeclContext *dc,
6304+
const ActorIsolation &selfIsolation) {
6305+
switch (selfIsolation) {
6306+
case ActorIsolation::ActorInstance:
6307+
case ActorIsolation::Erased:
6308+
case ActorIsolation::GlobalActor:
6309+
// Actor isolation always overrides.
6310+
return true;
6311+
6312+
case ActorIsolation::Unspecified:
6313+
// Unspecified isolation never overrides.
6314+
return false;
6315+
6316+
case ActorIsolation::Nonisolated:
6317+
case ActorIsolation::NonisolatedUnsafe:
6318+
case ActorIsolation::CallerIsolationInheriting:
6319+
// Explicit nonisolated used to overwrite default isolation all the time,
6320+
// but under NoExplicitNonIsolated it doesn't affect extensions.
6321+
if (isa<NominalTypeDecl>(dc))
6322+
return true;
6323+
6324+
// The NoExplicitNonIsolated feature
6325+
if (ctx.LangOpts.hasFeature(Feature::NoExplicitNonIsolated))
6326+
return false;
6327+
6328+
// Suppress when the default isolation is nonisolated.
6329+
return getDefaultIsolationForContext(dc) == DefaultIsolation::Nonisolated;
6330+
}
6331+
}
6332+
63006333
static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
63016334
ValueDecl *value) {
63026335
// If this declaration has actor-isolated "self", it's isolated to that
@@ -6629,7 +6662,8 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
66296662
// has isolation, use that.
66306663
if (auto selfTypeDecl = value->getDeclContext()->getSelfNominalTypeDecl()) {
66316664
auto selfTypeIsolation = getInferredActorIsolation(selfTypeDecl);
6632-
if (selfTypeIsolation.isolation) {
6665+
if (shouldSelfIsolationOverrideDefault(
6666+
ctx, value->getDeclContext(), selfTypeIsolation.isolation)) {
66336667
auto isolation = selfTypeIsolation.isolation;
66346668

66356669
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&

test/Concurrency/assume_mainactor_typechecker_errors.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func testTaskDetached() async {
8282

8383
// @MainActor
8484
extension Int {
85-
func memberOfInt() { } // expected-note{{calls to instance method 'memberOfInt()' from outside of its actor context are implicitly asynchronous}}
85+
func memberOfInt() { } // expected-note 2{{calls to instance method 'memberOfInt()' from outside of its actor context are implicitly asynchronous}}
8686
}
8787

8888
nonisolated func testMemberOfInt(i: Int) {
@@ -100,3 +100,19 @@ extension MyStruct: CustomStringConvertible {
100100
return "hello"
101101
}
102102
}
103+
104+
nonisolated struct MyOtherStruct { }
105+
106+
extension MyOtherStruct {
107+
func f() {
108+
17.memberOfInt() // okay, on main actor
109+
}
110+
}
111+
112+
nonisolated
113+
extension MyOtherStruct {
114+
func g() {
115+
17.memberOfInt() // expected-swift5-warning{{call to main actor-isolated instance method 'memberOfInt()' in a synchronous nonisolated context}}
116+
// expected-swift6-error@-1{{call to main actor-isolated instance method 'memberOfInt()' in a synchronous nonisolated context}}
117+
}
118+
}

0 commit comments

Comments
 (0)