Skip to content

Commit 5a6f58e

Browse files
committed
Teach witness matching to apply minimal/strict diagnostics rules.
This downgrades some errors to warnings in Swift 5 mode, and ensures that we diagnose all conditions in Swift 6 mode.
1 parent 43ce118 commit 5a6f58e

File tree

5 files changed

+19
-44
lines changed

5 files changed

+19
-44
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4553,10 +4553,6 @@ ERROR(actor_isolated_witness,none,
45534553
ERROR(distributed_actor_isolated_witness,none,
45544554
"distributed actor-isolated %0 %1 cannot be used to satisfy a protocol requirement",
45554555
(DescriptiveDeclKind, DeclName))
4556-
ERROR(global_actor_isolated_requirement,none,
4557-
"%0 %1 must be isolated to the global actor %2 to satisfy corresponding "
4558-
"requirement from protocol %3",
4559-
(DescriptiveDeclKind, DeclName, Type, Identifier))
45604556
ERROR(global_actor_isolated_witness,none,
45614557
"%0 %1 isolated to global actor %2 can not satisfy corresponding "
45624558
"requirement from protocol %3",

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2868,6 +2868,8 @@ bool ConformanceChecker::checkActorIsolation(
28682868
// unsuitable as a witness.
28692869
bool isCrossActor = false;
28702870
bool witnessIsUnsafe = false;
2871+
DiagnosticBehavior behavior = SendableCheckContext(
2872+
witness->getInnermostDeclContext()).defaultDiagnosticBehavior();
28712873
Type witnessGlobalActor;
28722874
switch (auto witnessRestriction =
28732875
ActorIsolationRestriction::forDeclaration(
@@ -3091,8 +3093,6 @@ bool ConformanceChecker::checkActorIsolation(
30913093
}
30923094

30933095
case ActorIsolationRestriction::Unsafe:
3094-
break;
3095-
30963096
case ActorIsolationRestriction::Unrestricted:
30973097
// The witness is completely unrestricted, so ignore any annotations on
30983098
// the requirement.
@@ -3155,53 +3155,34 @@ bool ConformanceChecker::checkActorIsolation(
31553155
// However, we allow this case when the requirement was imported, because
31563156
// it might not have been annotated.
31573157
if (witnessGlobalActor && !requirementGlobalActor) {
3158-
// If the requirement was imported from Objective-C, it may not have been
3159-
// annotated appropriately. Allow the mismatch.
3158+
// If the requirement was imported from Objective-C, downgrade to a warning
3159+
// because it may not have been annotated appropriately.
31603160
if (requirement->hasClangNode())
3161-
return false;
3162-
3163-
// If the witness is "unsafe", allow the mismatch.
3164-
if (witnessIsUnsafe)
3165-
return false;
3161+
behavior = std::max(behavior, DiagnosticBehavior::Warning);
31663162

31673163
witness->diagnose(
31683164
diag::global_actor_isolated_witness, witness->getDescriptiveKind(),
3169-
witness->getName(), witnessGlobalActor, Proto->getName());
3165+
witness->getName(), witnessGlobalActor, Proto->getName())
3166+
.limitBehavior(behavior);
31703167
requirement->diagnose(diag::decl_declared_here, requirement->getName());
3171-
return true;
3168+
return behavior == DiagnosticBehavior::Unspecified;
31723169
}
31733170

3174-
// If the requirement has a global actor but the witness does not, we have
3175-
// an isolation error.
3171+
// If the requirement has a global actor but the witness does not, it's
3172+
// fine.
31763173
if (requirementGlobalActor && !witnessGlobalActor) {
3177-
// If the requirement's global actor was "unsafe", we allow this.
3178-
if (requirementIsUnsafe)
3179-
return false;
3180-
3181-
if (isCrossActor) {
3182-
return diagnoseNonSendableTypesInReference(
3183-
witness, DC, witness->getLoc(),
3184-
ConcurrentReferenceKind::CrossActor);
3185-
}
3186-
3187-
witness->diagnose(
3188-
diag::global_actor_isolated_requirement, witness->getDescriptiveKind(),
3189-
witness->getName(), requirementGlobalActor, Proto->getName())
3190-
.fixItInsert(
3191-
witness->getAttributeInsertionLoc(/*forModifier=*/false),
3192-
"@" + requirementGlobalActor.getString());
3193-
requirement->diagnose(diag::decl_declared_here, requirement->getName());
3194-
return true;
3174+
return false;
31953175
}
31963176

31973177
// Both have global actors but they differ, so this is an isolation error.
31983178
assert(!witnessGlobalActor->isEqual(requirementGlobalActor));
31993179
witness->diagnose(
32003180
diag::global_actor_isolated_requirement_witness_conflict,
32013181
witness->getDescriptiveKind(), witness->getName(), witnessGlobalActor,
3202-
Proto->getName(), requirementGlobalActor);
3182+
Proto->getName(), requirementGlobalActor)
3183+
.limitBehavior(behavior);
32033184
requirement->diagnose(diag::decl_declared_here, requirement->getName());
3204-
return true;
3185+
return behavior == DiagnosticBehavior::Unspecified;
32053186
}
32063187

32073188
bool ConformanceChecker::checkObjCTypeErasedGenerics(

test/Concurrency/actor_isolation_unsafe.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct S3_P1: P1 {
3030
}
3131

3232
struct S4_P1: P1 {
33-
@SomeGlobalActor func onMainActor() { } // expected-error{{instance method 'onMainActor()' isolated to global actor 'SomeGlobalActor' can not satisfy corresponding requirement from protocol 'P1' isolated to global actor 'MainActor'}}
33+
@SomeGlobalActor func onMainActor() { } // expected-warning{{instance method 'onMainActor()' isolated to global actor 'SomeGlobalActor' can not satisfy corresponding requirement from protocol 'P1' isolated to global actor 'MainActor'}}
3434
}
3535

3636
@MainActor(unsafe)

test/Concurrency/global_actor_inference.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protocol P1 {
4747
}
4848

4949
protocol P2 {
50-
@SomeGlobalActor func method1() // expected-note {{'method1()' declared here}}
50+
@SomeGlobalActor func method1()
5151
func method2()
5252
}
5353

@@ -146,14 +146,12 @@ class C5 {
146146
}
147147

148148
protocol P3 {
149-
@OtherGlobalActor func method1() // expected-note{{'method1()' declared here}}
149+
@OtherGlobalActor func method1()
150150
func method2()
151151
}
152152

153153
class C6: P2, P3 {
154154
func method1() { }
155-
// expected-error@-1{{instance method 'method1()' must be isolated to the global actor 'SomeGlobalActor' to satisfy corresponding requirement from protocol 'P2'}}
156-
// expected-error@-2{{instance method 'method1()' must be isolated to the global actor 'OtherGlobalActor' to satisfy corresponding requirement from protocol 'P3'}}
157155
func method2() { }
158156

159157
func testMethod() {

test/decl/class/actor/global_actor_conformance.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ class C1 : P1, P2 {
3333

3434
func method1() { }
3535

36-
@GenericGlobalActor<String> func method2() { } // expected-error{{instance method 'method2()' isolated to global actor 'GenericGlobalActor<String>' can not satisfy corresponding requirement from protocol 'P1' isolated to global actor 'GenericGlobalActor<Int>'}}
36+
@GenericGlobalActor<String> func method2() { } // expected-warning{{instance method 'method2()' isolated to global actor 'GenericGlobalActor<String>' can not satisfy corresponding requirement from protocol 'P1' isolated to global actor 'GenericGlobalActor<Int>'}}
3737
@GenericGlobalActor<String >func method3() { }
38-
@GlobalActor func method4() { } // expected-error{{instance method 'method4()' isolated to global actor 'GlobalActor' can not satisfy corresponding requirement from protocol 'P1'}}
38+
@GlobalActor func method4() { } // expected-warning{{instance method 'method4()' isolated to global actor 'GlobalActor' can not satisfy corresponding requirement from protocol 'P1'}}
3939

4040
// Okay: we can ignore the mismatch in global actor types for 'async' methods.
4141
func asyncMethod1() async { }

0 commit comments

Comments
 (0)