Skip to content

Commit 43e1935

Browse files
authored
Merge pull request #76458 from xedin/rdar-131347583
[Concurrency] Allow global actor mismatches while overriding `@precon…
2 parents ffa1014 + 22b9dd7 commit 43e1935

9 files changed

+162
-41
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,6 +3329,9 @@ ERROR(override_multiple_decls_base,none,
33293329
ERROR(override_sendability_mismatch,none,
33303330
"declaration %0 has a type with different sendability from any potential "
33313331
"overrides", (DeclName))
3332+
ERROR(override_global_actor_isolation_mismatch,none,
3333+
"declaration %0 has a type with different global actor isolation from any potential "
3334+
"overrides", (DeclName))
33323335
ERROR(override_multiple_decls_arg_mismatch,none,
33333336
"declaration %0 has different argument labels from any potential "
33343337
"overrides", (DeclName))

include/swift/AST/Types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ enum class TypeMatchFlags {
362362
IgnoreFunctionSendability = 1 << 6,
363363
/// Ignore `any Sendable` and compositions with Sendable protocol.
364364
IgnoreSendability = 1 << 7,
365+
/// Ignore global actor isolation attributes on functions when matching types.
366+
IgnoreFunctionGlobalActorIsolation = 1 << 8,
365367
};
366368
using TypeMatchOptions = OptionSet<TypeMatchFlags>;
367369

lib/AST/Type.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,6 +3186,13 @@ static bool matchesFunctionType(CanAnyFunctionType fn1, CanAnyFunctionType fn2,
31863186
ext2 = ext2.withSendable(false);
31873187
}
31883188

3189+
if (matchMode.contains(TypeMatchFlags::IgnoreFunctionGlobalActorIsolation)) {
3190+
if (ext1.getGlobalActor())
3191+
ext1 = ext1.withoutIsolation();
3192+
if (ext2.getGlobalActor())
3193+
ext2 = ext2.withoutIsolation();
3194+
}
3195+
31893196
// If specified, allow an escaping function parameter to override a
31903197
// non-escaping function parameter when the parameter is optional.
31913198
// Note that this is checking 'ext2' rather than 'ext1' because parameters

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,10 @@ static bool noteFixableMismatchedTypes(ValueDecl *decl, const ValueDecl *base) {
522522
namespace {
523523
enum class OverrideCheckingAttempt {
524524
PerfectMatch,
525+
// Ignores only @Sendable and `any Sendable` annotations
525526
MismatchedSendability,
527+
// Ignores both sendability and global actor isolation annotations.
528+
MismatchedConcurrency,
526529
MismatchedOptional,
527530
MismatchedTypes,
528531
BaseName,
@@ -555,16 +558,36 @@ static void diagnoseGeneralOverrideFailure(ValueDecl *decl,
555558
case OverrideCheckingAttempt::MismatchedSendability: {
556559
SendableCheckContext fromContext(decl->getDeclContext(),
557560
SendableCheck::Explicit);
558-
auto baseDeclClass =
559-
decl->getOverriddenDecl()->getDeclContext()->getSelfClassDecl();
560561

561-
diagnoseSendabilityErrorBasedOn(baseDeclClass, fromContext,
562-
[&](DiagnosticBehavior limit) {
563-
diags.diagnose(decl, diag::override_sendability_mismatch, decl->getName())
564-
.limitBehaviorUntilSwiftVersion(limit, 6)
562+
for (const auto &match : matches) {
563+
auto baseDeclClass = match.Decl->getDeclContext()->getSelfClassDecl();
564+
565+
diagnoseSendabilityErrorBasedOn(
566+
baseDeclClass, fromContext, [&](DiagnosticBehavior limit) {
567+
diags
568+
.diagnose(decl, diag::override_sendability_mismatch,
569+
decl->getName())
570+
.limitBehaviorUntilSwiftVersion(limit, 6)
571+
.limitBehaviorIf(
572+
fromContext.preconcurrencyBehavior(baseDeclClass));
573+
return false;
574+
});
575+
}
576+
break;
577+
}
578+
case OverrideCheckingAttempt::MismatchedConcurrency: {
579+
SendableCheckContext fromContext(decl->getDeclContext(),
580+
SendableCheck::Explicit);
581+
582+
for (const auto &match : matches) {
583+
auto baseDeclClass = match.Decl->getDeclContext()->getSelfClassDecl();
584+
585+
diags
586+
.diagnose(decl, diag::override_global_actor_isolation_mismatch,
587+
decl->getName())
588+
.limitBehaviorUntilSwiftVersion(DiagnosticBehavior::Warning, 6)
565589
.limitBehaviorIf(fromContext.preconcurrencyBehavior(baseDeclClass));
566-
return false;
567-
});
590+
}
568591
break;
569592
}
570593
case OverrideCheckingAttempt::BaseName:
@@ -591,7 +614,7 @@ static void diagnoseGeneralOverrideFailure(ValueDecl *decl,
591614

592615
for (auto match : matches) {
593616
auto matchDecl = match.Decl;
594-
if (attempt == OverrideCheckingAttempt::PerfectMatch) {
617+
if (attempt <= OverrideCheckingAttempt::MismatchedConcurrency) {
595618
diags.diagnose(matchDecl, diag::overridden_here);
596619
continue;
597620
}
@@ -896,6 +919,7 @@ SmallVector<OverrideMatch, 2> OverrideMatcher::match(
896919
switch (attempt) {
897920
case OverrideCheckingAttempt::PerfectMatch:
898921
case OverrideCheckingAttempt::MismatchedSendability:
922+
case OverrideCheckingAttempt::MismatchedConcurrency:
899923
case OverrideCheckingAttempt::MismatchedOptional:
900924
case OverrideCheckingAttempt::MismatchedTypes:
901925
name = decl->getName();
@@ -993,6 +1017,11 @@ SmallVector<OverrideMatch, 2> OverrideMatcher::match(
9931017
if (attempt == OverrideCheckingAttempt::MismatchedSendability)
9941018
matchMode |= TypeMatchFlags::IgnoreFunctionSendability;
9951019

1020+
if (attempt == OverrideCheckingAttempt::MismatchedConcurrency) {
1021+
matchMode |= TypeMatchFlags::IgnoreFunctionSendability;
1022+
matchMode |= TypeMatchFlags::IgnoreFunctionGlobalActorIsolation;
1023+
}
1024+
9961025
auto declFnTy = getDeclComparisonType()->getAs<AnyFunctionType>();
9971026
auto parentDeclTy = getMemberTypeForComparison(parentDecl, decl);
9981027
auto parentDeclFnTy = parentDeclTy->getAs<AnyFunctionType>();
@@ -1199,29 +1228,13 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl,
11991228
Type declTy = getDeclComparisonType();
12001229
Type owningTy = dc->getDeclaredInterfaceType();
12011230
auto isClassContext = classDecl != nullptr;
1202-
bool allowsSendabilityMismatches =
1231+
bool allowsConcurrencyMismatches =
12031232
attempt == OverrideCheckingAttempt::MismatchedSendability ||
1233+
attempt == OverrideCheckingAttempt::MismatchedConcurrency ||
12041234
(attempt == OverrideCheckingAttempt::PerfectMatch &&
12051235
baseDecl->preconcurrency());
12061236
bool mismatchedOnSendability = false;
1207-
1208-
auto diagnoseSendabilityMismatch = [&]() {
1209-
SendableCheckContext fromContext(decl->getDeclContext(),
1210-
SendableCheck::Explicit);
1211-
auto baseDeclClass = baseDecl->getDeclContext()->getSelfClassDecl();
1212-
1213-
diagnoseSendabilityErrorBasedOn(
1214-
baseDeclClass, fromContext, [&](DiagnosticBehavior limit) {
1215-
diags
1216-
.diagnose(decl, diag::override_sendability_mismatch,
1217-
decl->getName())
1218-
.limitBehaviorUntilSwiftVersion(limit, 6)
1219-
.limitBehaviorIf(
1220-
fromContext.preconcurrencyBehavior(baseDeclClass));
1221-
diags.diagnose(baseDecl, diag::overridden_here);
1222-
return false;
1223-
});
1224-
};
1237+
bool mismatchedOnIsolation = false;
12251238

12261239
if (declIUOAttr == matchDeclIUOAttr && declTy->isEqual(baseTy)) {
12271240
// Nothing to do.
@@ -1289,15 +1302,21 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl,
12891302
TypeMatchOptions options;
12901303
options |= TypeMatchFlags::AllowOverride;
12911304
if (!propertyTy->matches(parentPropertyCanTy, options)) {
1292-
if (allowsSendabilityMismatches) {
1305+
if (allowsConcurrencyMismatches) {
12931306
options |= TypeMatchFlags::IgnoreSendability;
12941307
options |= TypeMatchFlags::IgnoreFunctionSendability;
12951308

12961309
mismatchedOnSendability =
12971310
propertyTy->matches(parentPropertyCanTy, options);
1311+
1312+
if (!mismatchedOnSendability) {
1313+
options |= TypeMatchFlags::IgnoreFunctionGlobalActorIsolation;
1314+
mismatchedOnIsolation =
1315+
propertyTy->matches(parentPropertyCanTy, options);
1316+
}
12981317
}
12991318

1300-
if (!mismatchedOnSendability) {
1319+
if (!mismatchedOnSendability && !mismatchedOnIsolation) {
13011320
diags.diagnose(property, diag::override_property_type_mismatch,
13021321
property->getName(), propertyTy, parentPropertyTy);
13031322
noteFixableMismatchedTypes(decl, baseDecl);
@@ -1316,28 +1335,36 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl,
13161335

13171336
// The overridden property must not be mutable.
13181337
if (cast<AbstractStorageDecl>(baseDecl)->supportsMutation() &&
1319-
!(optionalVsIUO || mismatchedOnSendability)) {
1338+
!(optionalVsIUO || mismatchedOnSendability || mismatchedOnIsolation)) {
13201339
diags.diagnose(property, diag::override_mutable_covariant_property,
1321-
property->getName(), parentPropertyTy, propertyTy);
1340+
property->getName(), parentPropertyTy, propertyTy);
13221341
diags.diagnose(baseDecl, diag::property_override_here);
13231342
return true;
13241343
}
1325-
1326-
if (mismatchedOnSendability && !emittedMatchError) {
1327-
diagnoseSendabilityMismatch();
1328-
return checkSingleOverride(decl, baseDecl);
1329-
}
13301344
}
13311345

13321346
if (emittedMatchError)
13331347
return true;
13341348

1335-
if (attempt == OverrideCheckingAttempt::MismatchedSendability) {
1336-
diagnoseSendabilityMismatch();
1349+
if (mismatchedOnSendability || mismatchedOnIsolation) {
1350+
OverrideMatch match{baseDecl, /*isExact=*/false};
1351+
1352+
if (mismatchedOnSendability) {
1353+
diagnoseGeneralOverrideFailure(
1354+
decl, match, OverrideCheckingAttempt::MismatchedSendability);
1355+
}
1356+
1357+
if (mismatchedOnIsolation) {
1358+
diagnoseGeneralOverrideFailure(
1359+
decl, match, OverrideCheckingAttempt::MismatchedConcurrency);
1360+
}
1361+
1362+
return checkSingleOverride(decl, baseDecl);
13371363
}
1364+
13381365
// Catch-all to make sure we don't silently accept something we shouldn't.
1339-
else if (attempt != OverrideCheckingAttempt::PerfectMatch) {
1340-
OverrideMatch match{decl, /*isExact=*/false};
1366+
if (attempt != OverrideCheckingAttempt::PerfectMatch) {
1367+
OverrideMatch match{baseDecl, /*isExact=*/false};
13411368
diagnoseGeneralOverrideFailure(decl, match, attempt);
13421369
}
13431370

@@ -1400,6 +1427,7 @@ checkPotentialOverrides(ValueDecl *decl,
14001427
case OverrideCheckingAttempt::PerfectMatch:
14011428
break;
14021429
case OverrideCheckingAttempt::MismatchedSendability:
1430+
case OverrideCheckingAttempt::MismatchedConcurrency:
14031431
// Don't keep looking if the user didn't indicate it's an override.
14041432
if (!decl->getAttrs().hasAttribute<OverrideAttr>())
14051433
return false;

test/Concurrency/predates_concurrency.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,19 @@ do {
271271
nil
272272
}
273273

274+
@preconcurrency
275+
open var test5: (@MainActor () -> Void)? { // expected-note {{overridden declaration is here}}
276+
nil
277+
}
278+
279+
open var test6: (@MainActor () -> Void)? { // expected-note {{attempt to override property here}}
280+
nil
281+
}
282+
283+
@preconcurrency
284+
func test7(_: (@MainActor () -> Void)? = nil) { // expected-note {{overridden declaration is here}}
285+
}
286+
274287
init() {
275288
self.test1 = nil
276289
self.test2 = [:]
@@ -301,6 +314,20 @@ do {
301314
// expected-warning@-1 {{declaration 'test4' has a type with different sendability from any potential overrides; this is an error in the Swift 6 language mode}}
302315
nil
303316
}
317+
318+
override var test5: (() -> Void)? {
319+
// expected-warning@-1 {{declaration 'test5' has a type with different global actor isolation from any potential overrides; this is an error in the Swift 6 language mode}}
320+
nil
321+
}
322+
323+
override var test6: (() -> Void)? {
324+
// expected-error@-1 {{property 'test6' with type '(() -> Void)?' cannot override a property with type '(@MainActor () -> Void)?'}}
325+
nil
326+
}
327+
328+
override func test7(_: (() -> Void)?) {
329+
// expected-warning@-1 {{declaration 'test7' has a type with different global actor isolation from any potential overrides; this is an error in the Swift 6 language mode}}
330+
}
304331
}
305332
}
306333

test/Concurrency/predates_concurrency_swift6.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ do {
130130
nil
131131
}
132132

133+
@preconcurrency
134+
open var test5: (@MainActor () -> Void)? { // expected-note {{overridden declaration is here}}
135+
nil
136+
}
137+
138+
@preconcurrency
139+
func test6(_: (@MainActor () -> Void)? = nil) { // expected-note {{overridden declaration is here}}
140+
}
141+
133142
init() {
134143
self.test1 = nil
135144
self.test2 = [:]
@@ -160,5 +169,14 @@ do {
160169
// expected-error@-1 {{declaration 'test4' has a type with different sendability from any potential overrides}}
161170
nil
162171
}
172+
173+
override var test5: (() -> Void)? {
174+
// expected-error@-1 {{declaration 'test5' has a type with different global actor isolation from any potential overrides}}
175+
nil
176+
}
177+
178+
override func test6(_: (() -> Void)?) {
179+
// expected-error@-1 {{declaration 'test6' has a type with different global actor isolation from any potential overrides}}
180+
}
163181
}
164182
}

test/Concurrency/sendable_objc_attr_in_type_context_swift5.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ typedef void (^CompletionHandler)(void (^ SWIFT_SENDABLE)(void)) SWIFT_SENDABLE;
4444
-(void) withSendableCustom: (void (^)(MyValue *_Nullable SWIFT_SENDABLE)) handler;
4545
-(void) withNonSendable:(NSString *)operation completionHandler:(void (^ _Nullable NONSENDABLE)(NSString *_Nullable, NSError * _Nullable)) handler;
4646
-(void) withAliasCompletionHandler:(CompletionHandler)handler;
47+
-(void) withMainActorId: (void (MAIN_ACTOR ^)(id)) handler;
4748
@end
4849

4950
// Placement of SWIFT_SENDABLE matters here
@@ -67,6 +68,17 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
6768

6869
//--- main.swift
6970

71+
do {
72+
class SubTestNoActor : Test {
73+
@objc override func withMainActorId(_: @escaping (Any) -> Void) {}
74+
// expected-warning@-1 {{declaration 'withMainActorId' has a type with different global actor isolation from any potential overrides; this is an error in the Swift 6 language mode}}
75+
}
76+
77+
class SubTestWithActor : Test {
78+
@objc override func withMainActorId(_: @MainActor @escaping (Any) -> Void) {} // Ok
79+
}
80+
}
81+
7082
func test_sendable_attr_in_type_context(test: Test) {
7183
let fn: (String?, (any Error)?) -> Void = { _,_ in }
7284

test/Concurrency/sendable_objc_attr_in_type_context_swift5_strict.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ typedef void (^CompletionHandler)(void (^ SWIFT_SENDABLE)(void)) SWIFT_SENDABLE;
4545
-(void) withSendableCustom: (void (^)(MyValue *_Nullable SWIFT_SENDABLE)) handler;
4646
-(void) withNonSendable:(NSString *)operation completionHandler:(void (^ _Nullable NONSENDABLE)(NSString *_Nullable, NSError * _Nullable)) handler;
4747
-(void) withAliasCompletionHandler:(CompletionHandler)handler;
48+
-(void) withMainActorId: (void (MAIN_ACTOR ^)(id)) handler;
4849
@end
4950

5051
// Placement of SWIFT_SENDABLE matters here
@@ -68,6 +69,17 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
6869

6970
//--- main.swift
7071

72+
do {
73+
class SubTestNoActor : Test {
74+
@objc override func withMainActorId(_: @escaping (Any) -> Void) {}
75+
// expected-warning@-1 {{declaration 'withMainActorId' has a type with different global actor isolation from any potential overrides; this is an error in the Swift 6 language mode}}
76+
}
77+
78+
class SubTestWithActor : Test {
79+
@objc override func withMainActorId(_: @MainActor @escaping (Any) -> Void) {} // Ok
80+
}
81+
}
82+
7183
func test_sendable_attr_in_type_context(test: Test) {
7284
let fn: (String?, (any Error)?) -> Void = { _,_ in }
7385

test/Concurrency/sendable_objc_attr_in_type_context_swift6.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ typedef void (^CompletionHandler)(void (^ SWIFT_SENDABLE)(void)) SWIFT_SENDABLE;
4444
-(void) withSendableCustom: (void (^)(MyValue *_Nullable SWIFT_SENDABLE)) handler;
4545
-(void) withNonSendable:(NSString *)operation completionHandler:(void (^ _Nullable NONSENDABLE)(NSString *_Nullable, NSError * _Nullable)) handler;
4646
-(void) withAliasCompletionHandler:(CompletionHandler)handler;
47+
-(void) withMainActorId: (void (MAIN_ACTOR ^)(id)) handler;
4748
@end
4849

4950
// Placement of SWIFT_SENDABLE matters here
@@ -67,6 +68,17 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
6768

6869
//--- main.swift
6970

71+
do {
72+
class SubTestNoActor : Test {
73+
@objc override func withMainActorId(_: @escaping (Any) -> Void) {}
74+
// expected-error@-1 {{declaration 'withMainActorId' has a type with different global actor isolation from any potential overrides}}
75+
}
76+
77+
class SubTestWithActor : Test {
78+
@objc override func withMainActorId(_: @MainActor @escaping (Any) -> Void) {} // Ok
79+
}
80+
}
81+
7082
func test_sendable_attr_in_type_context(test: Test) {
7183
let fn: (String?, (any Error)?) -> Void = { _,_ in }
7284

0 commit comments

Comments
 (0)