Skip to content

Commit 30c5cf2

Browse files
committed
In Swift 6, every context requires strict concurrency checking
This ensures, among other things, that `@_predatesConcurrency` doesn't affect the types of entities anywhere in a module compiled in Swift 6, so we get stricter checking throughout.
1 parent c0f5502 commit 30c5cf2

File tree

4 files changed

+128
-11
lines changed

4 files changed

+128
-11
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,8 +2173,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
21732173

21742174
/// Whether to downgrade to a concurrency warning.
21752175
auto isConcurrencyWarning = [&] {
2176-
if (contextUsesConcurrencyFeatures(DC) ||
2177-
Context.LangOpts.isSwiftVersionAtLeast(6))
2176+
if (contextRequiresStrictConcurrencyChecking(DC))
21782177
return false;
21792178

21802179
switch (kind) {

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
605605
if (dc->getParentModule()->isConcurrencyChecked())
606606
return true;
607607

608-
return contextUsesConcurrencyFeatures(dc);
608+
return contextRequiresStrictConcurrencyChecking(dc);
609609
}
610610

611611
/// Determine the default diagnostic behavior for this language mode.
@@ -3586,7 +3586,11 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
35863586
overridden->diagnose(diag::overridden_here);
35873587
}
35883588

3589-
bool swift::contextUsesConcurrencyFeatures(const DeclContext *dc) {
3589+
bool swift::contextRequiresStrictConcurrencyChecking(const DeclContext *dc) {
3590+
// If Swift >= 6, everything uses strict concurrency checking.
3591+
if (dc->getASTContext().LangOpts.isSwiftVersionAtLeast(6))
3592+
return true;
3593+
35903594
while (!dc->isModuleScopeContext()) {
35913595
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
35923596
// A closure with an explicit global actor or nonindependent
@@ -4071,7 +4075,7 @@ Type swift::adjustVarTypeForConcurrency(
40714075
if (!var->predatesConcurrency())
40724076
return type;
40734077

4074-
if (contextUsesConcurrencyFeatures(dc))
4078+
if (contextRequiresStrictConcurrencyChecking(dc))
40754079
return type;
40764080

40774081
bool isLValue = false;
@@ -4193,7 +4197,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
41934197
unsigned numApplies, bool isMainDispatchQueue) {
41944198
// Apply unsafe concurrency features to the given function type.
41954199
fnType = applyUnsafeConcurrencyToFunctionType(
4196-
fnType, decl, contextUsesConcurrencyFeatures(dc), numApplies,
4200+
fnType, decl, contextRequiresStrictConcurrencyChecking(dc), numApplies,
41974201
isMainDispatchQueue);
41984202

41994203
Type globalActorType;
@@ -4208,7 +4212,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
42084212
case ActorIsolation::GlobalActorUnsafe:
42094213
// Only treat as global-actor-qualified within code that has adopted
42104214
// Swift Concurrency features.
4211-
if (!contextUsesConcurrencyFeatures(dc))
4215+
if (!contextRequiresStrictConcurrencyChecking(dc))
42124216
return fnType;
42134217

42144218
LLVM_FALLTHROUGH;
@@ -4250,7 +4254,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
42504254
}
42514255

42524256
bool swift::completionContextUsesConcurrencyFeatures(const DeclContext *dc) {
4253-
return contextUsesConcurrencyFeatures(dc);
4257+
return contextRequiresStrictConcurrencyChecking(dc);
42544258
}
42554259

42564260
AbstractFunctionDecl const *swift::isActorInitOrDeInitContext(

lib/Sema/TypeCheckConcurrency.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ class ActorIsolationRestriction {
211211
/// overridden declaration.
212212
void checkOverrideActorIsolation(ValueDecl *value);
213213

214-
/// Determine whether the given context uses concurrency features, such
215-
/// as async functions or actors.
216-
bool contextUsesConcurrencyFeatures(const DeclContext *dc);
214+
/// Determine whether the given context requires strict concurrency checking,
215+
/// e.g., because it uses concurrency features directly or because it's in
216+
/// code where strict checking has been enabled.
217+
bool contextRequiresStrictConcurrencyChecking(const DeclContext *dc);
217218

218219
/// Diagnose the presence of any non-sendable types when referencing a
219220
/// given declaration from a particular declaration context.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -swift-version 6
2+
// REQUIRES: concurrency
3+
4+
@_predatesConcurrency func unsafelySendableClosure(_ closure: @Sendable () -> Void) { }
5+
6+
@_predatesConcurrency func unsafelyMainActorClosure(_ closure: @MainActor () -> Void) { }
7+
8+
@_predatesConcurrency func unsafelyDoEverythingClosure(_ closure: @MainActor @Sendable () -> Void) { }
9+
10+
struct X {
11+
@_predatesConcurrency func unsafelyDoEverythingClosure(_ closure: @MainActor @Sendable () -> Void) { }
12+
13+
@_predatesConcurrency var sendableVar: @Sendable () -> Void
14+
@_predatesConcurrency var mainActorVar: @MainActor () -> Void
15+
16+
@_predatesConcurrency
17+
subscript(_: @MainActor () -> Void) -> (@Sendable () -> Void) { {} }
18+
19+
@_predatesConcurrency
20+
static subscript(statically _: @MainActor () -> Void) -> (@Sendable () -> Void) { { } }
21+
}
22+
23+
@MainActor func onMainActor() { }
24+
25+
func testInAsync(x: X) async {
26+
let _: Int = unsafelySendableClosure // expected-error{{type '(@Sendable () -> Void) -> ()'}}
27+
let _: Int = unsafelyMainActorClosure // expected-error{{type '(@MainActor () -> Void) -> ()'}}
28+
let _: Int = unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
29+
let _: Int = x.unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
30+
let _: Int = X.unsafelyDoEverythingClosure // expected-error{{type '(X) -> (@MainActor @Sendable () -> Void) -> ()'}}
31+
let _: Int = (X.unsafelyDoEverythingClosure)(x) // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
32+
33+
let _: Int = x.sendableVar // expected-error{{type '@Sendable () -> Void'}}
34+
let _: Int = x.mainActorVar // expected-error{{type '@MainActor () -> Void'}}
35+
36+
let _: Int = x[{ onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
37+
let _: Int = X[statically: { onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
38+
}
39+
40+
func testElsewhere(x: X) {
41+
let _: Int = unsafelySendableClosure // expected-error{{type '(@Sendable () -> Void) -> ()'}}
42+
let _: Int = unsafelyMainActorClosure // expected-error{{type '(@MainActor () -> Void) -> ()'}}
43+
let _: Int = unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
44+
let _: Int = x.unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
45+
let _: Int = X.unsafelyDoEverythingClosure // expected-error{{type '(X) -> (@MainActor @Sendable () -> Void) -> ()'}}
46+
let _: Int = (X.unsafelyDoEverythingClosure)(x) // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
47+
48+
let _: Int = x.sendableVar // expected-error{{type '@Sendable () -> Void'}}
49+
let _: Int = x.mainActorVar // expected-error{{type '@MainActor () -> Void'}}
50+
51+
let _: Int = x[{ onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
52+
let _: Int = X[statically: { onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
53+
}
54+
55+
@MainActor @_predatesConcurrency func onMainActorAlways() { }
56+
// expected-note@-1{{are implicitly asynchronous}}
57+
58+
@_predatesConcurrency @MainActor class MyModelClass {
59+
// expected-note@-1{{are implicitly asynchronous}}
60+
func f() { }
61+
// expected-note@-1{{are implicitly asynchronous}}
62+
}
63+
64+
func testCalls(x: X) {
65+
// expected-note@-1 3{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}}
66+
onMainActorAlways() // expected-error{{call to main actor-isolated global function 'onMainActorAlways()' in a synchronous nonisolated context}}
67+
68+
let _: () -> Void = onMainActorAlways // expected-error{{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}}
69+
70+
let c = MyModelClass() // expected-error{{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}}
71+
c.f() // expected-error{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
72+
}
73+
74+
func testCallsWithAsync() async {
75+
onMainActorAlways() // expected-error{{expression is 'async' but is not marked with 'await'}}
76+
// expected-note@-1{{calls to global function 'onMainActorAlways()' from outside of its actor context are implicitly asynchronous}}
77+
78+
let _: () -> Void = onMainActorAlways // expected-error{{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}}
79+
80+
let c = MyModelClass() // expected-error{{expression is 'async' but is not marked with 'await'}}
81+
// expected-note@-1{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}
82+
c.f() // expected-error{{expression is 'async' but is not marked with 'await'}}
83+
// expected-note@-1{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}
84+
}
85+
86+
// ---------------------------------------------------------------------------
87+
// Protocols that inherit Sendable and predate concurrency.
88+
// ---------------------------------------------------------------------------
89+
@_predatesConcurrency protocol P: Sendable { }
90+
protocol Q: P { }
91+
92+
class NS { } // expected-note 3{{class 'NS' does not conform to the 'Sendable' protocol}}
93+
94+
struct S1: P {
95+
var ns: NS // expected-error{{stored property 'ns' of 'Sendable'-conforming struct 'S1' has non-sendable type 'NS'}}
96+
}
97+
98+
struct S2: Q {
99+
var ns: NS // expected-error{{stored property 'ns' of 'Sendable'-conforming struct 'S2' has non-sendable type 'NS'}}
100+
}
101+
102+
struct S3: Q, Sendable {
103+
var ns: NS // expected-error{{stored property 'ns' of 'Sendable'-conforming struct 'S3' has non-sendable type 'NS'}}
104+
}
105+
106+
// ---------------------------------------------------------------------------
107+
// Historical attribute names do nothing (but are permitted)
108+
// ---------------------------------------------------------------------------
109+
func aFailedExperiment(@_unsafeSendable _ body: @escaping () -> Void) { }
110+
// expected-warning@-1{{'_unsafeSendable' attribute has been removed in favor of @_predatesConcurrency}}
111+
112+
func anothingFailedExperiment(@_unsafeMainActor _ body: @escaping () -> Void) { }
113+
// expected-warning@-1{{'_unsafeMainActor' attribute has been removed in favor of @_predatesConcurrency}}

0 commit comments

Comments
 (0)