Skip to content

Commit 436e965

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 e65eecb commit 436e965

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
@@ -334,6 +334,10 @@ EXPERIMENTAL_FEATURE(ConsumeSelfInDeinit, true)
334334

335335
EXPERIMENTAL_FEATURE(AccessLevelOnImport, true)
336336

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

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ UNINTERESTING_FEATURE(MacrosOnImports)
125125
UNINTERESTING_FEATURE(NonisolatedNonsendingByDefault)
126126
UNINTERESTING_FEATURE(KeyPathWithMethodMembers)
127127
UNINTERESTING_FEATURE(ImportMacroAliases)
128+
UNINTERESTING_FEATURE(NoExplicitNonIsolated)
128129

129130
// TODO: Return true for inlinable function bodies with module selectors in them
130131
UNINTERESTING_FEATURE(ModuleSelector)

lib/Frontend/CompilerInvocation.cpp

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

1855-
if (Opts.DefaultIsolationBehavior == DefaultIsolation::MainActor)
1855+
if (Opts.DefaultIsolationBehavior == DefaultIsolation::MainActor) {
18561856
Opts.enableFeature(Feature::InferIsolatedConformances);
1857+
Opts.enableFeature(Feature::NoExplicitNonIsolated);
1858+
}
18571859

18581860
#if !defined(NDEBUG) && SWIFT_ENABLE_EXPERIMENTAL_PARSER_VALIDATION
18591861
/// 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
@@ -6276,6 +6276,39 @@ computeDefaultInferredActorIsolation(ValueDecl *value) {
62766276
return {{ActorIsolation::forUnspecified(), {}}, nullptr, {}};
62776277
}
62786278

6279+
/// Determines when the given "self" isolation should override default
6280+
/// isolation.
6281+
static bool shouldSelfIsolationOverrideDefault(
6282+
ASTContext &ctx, const DeclContext *dc,
6283+
const ActorIsolation &selfIsolation) {
6284+
switch (selfIsolation) {
6285+
case ActorIsolation::ActorInstance:
6286+
case ActorIsolation::Erased:
6287+
case ActorIsolation::GlobalActor:
6288+
// Actor isolation always overrides.
6289+
return true;
6290+
6291+
case ActorIsolation::Unspecified:
6292+
// Unspecified isolation never overrides.
6293+
return false;
6294+
6295+
case ActorIsolation::Nonisolated:
6296+
case ActorIsolation::NonisolatedUnsafe:
6297+
case ActorIsolation::CallerIsolationInheriting:
6298+
// Explicit nonisolated used to overwrite default isolation all the time,
6299+
// but under NoExplicitNonIsolated it doesn't affect extensions.
6300+
if (isa<NominalTypeDecl>(dc))
6301+
return true;
6302+
6303+
// The NoExplicitNonIsolated feature
6304+
if (ctx.LangOpts.hasFeature(Feature::NoExplicitNonIsolated))
6305+
return false;
6306+
6307+
// Suppress when the default isolation is nonisolated.
6308+
return getDefaultIsolationForContext(dc) == DefaultIsolation::Nonisolated;
6309+
}
6310+
}
6311+
62796312
static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
62806313
ValueDecl *value) {
62816314
// If this declaration has actor-isolated "self", it's isolated to that
@@ -6608,7 +6641,8 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
66086641
// has isolation, use that.
66096642
if (auto selfTypeDecl = value->getDeclContext()->getSelfNominalTypeDecl()) {
66106643
auto selfTypeIsolation = getInferredActorIsolation(selfTypeDecl);
6611-
if (selfTypeIsolation.isolation) {
6644+
if (shouldSelfIsolationOverrideDefault(
6645+
ctx, value->getDeclContext(), selfTypeIsolation.isolation)) {
66126646
auto isolation = selfTypeIsolation.isolation;
66136647

66146648
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)