Skip to content

Commit fcc7d0f

Browse files
committed
[Concurrency] Don't skip conformance derivation for types with isolated stored
properties. Otherwise, types that rely on derived conformances to Equatable and friends will fail to compile if a library adds a `@preconcurrency @MainActor` annotation. There is no need to prevent conformance derivation, because the actor isolation checker still runs on derived witnesses and will diagnose any concurrecy violations (with appropriate downgrading behavior for `@preconcurrency`).
1 parent 56c2b34 commit fcc7d0f

File tree

5 files changed

+70
-47
lines changed

5 files changed

+70
-47
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5564,6 +5564,9 @@ ERROR(isolation_macro_experimental,none,
55645564
NOTE(in_derived_conformance, none,
55655565
"in derived conformance to %0",
55665566
(Type))
5567+
NOTE(in_derived_witness, none,
5568+
"in %0 %1 for derived conformance to %2",
5569+
(DescriptiveDeclKind, DeclName, Type))
55675570
ERROR(non_sendable_param_type,none,
55685571
"non-sendable type %0 %select{passed in call to %3 %kind2|"
55695572
"exiting %3 context in call to non-isolated %kind2|"

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,12 +2086,6 @@ static bool canDeriveCodable(NominalTypeDecl *NTD,
20862086
return false;
20872087
}
20882088

2089-
// Actor-isolated structs and classes cannot derive encodable/decodable
2090-
// unless all of their stored properties are immutable.
2091-
if ((isa<StructDecl>(NTD) || isa<ClassDecl>(NTD)) &&
2092-
memberwiseAccessorsRequireActorIsolation(NTD))
2093-
return false;
2094-
20952089
return true;
20962090
}
20972091

lib/Sema/DerivedConformanceEquatableHashable.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,6 @@ static bool canDeriveConformance(DeclContext *DC,
5050
DC, structDecl, protocol).empty())
5151
return false;
5252

53-
// If the struct is actor-isolated, we cannot derive Equatable/Hashable
54-
// conformance if any of the stored properties are mutable.
55-
if (memberwiseAccessorsRequireActorIsolation(structDecl))
56-
return false;
57-
5853
return true;
5954
}
6055

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3909,38 +3909,61 @@ namespace {
39093909
bool preconcurrencyContext =
39103910
result.options.contains(ActorReferenceResult::Flags::Preconcurrency);
39113911

3912-
if (ctx.LangOpts.hasFeature(Feature::GroupActorErrors)) {
3913-
IsolationError mismatch = IsolationError(loc, Diagnostic(diag::actor_isolated_non_self_reference,
3914-
decl,
3915-
useKind,
3916-
refKind + 1, refGlobalActor,
3917-
result.isolation));
3918-
3919-
auto iter = refErrors.find(std::make_pair(refKind,result.isolation));
3920-
if (iter != refErrors.end()){
3921-
iter->second.push_back(mismatch);
3922-
} else {
3923-
DiagnosticList list;
3924-
list.push_back(mismatch);
3925-
auto keyPair = std::make_pair(refKind,result.isolation);
3926-
refErrors.insert(std::make_pair(keyPair, list));
3912+
Type derivedConformanceType;
3913+
DeclName requirementName;
3914+
if (loc.isInvalid()) {
3915+
auto *decl = getDeclContext()->getAsDecl();
3916+
if (decl && decl->isImplicit()) {
3917+
auto *parentDC = decl->getDeclContext();
3918+
loc = parentDC->getAsDecl()->getLoc();
3919+
3920+
if (auto *implements = decl->getAttrs().getAttribute<ImplementsAttr>()) {
3921+
derivedConformanceType =
3922+
implements->getProtocol(parentDC)->getDeclaredInterfaceType();
3923+
requirementName = implements->getMemberName();
39273924
}
3925+
}
3926+
}
3927+
3928+
if (ctx.LangOpts.hasFeature(Feature::GroupActorErrors)) {
3929+
IsolationError mismatch = IsolationError(loc,
3930+
Diagnostic(diag::actor_isolated_non_self_reference,
3931+
decl, useKind, refKind + 1, refGlobalActor,
3932+
result.isolation));
3933+
3934+
auto iter = refErrors.find(std::make_pair(refKind,result.isolation));
3935+
if (iter != refErrors.end()) {
3936+
iter->second.push_back(mismatch);
39283937
} else {
3929-
ctx.Diags.diagnose(
3930-
loc, diag::actor_isolated_non_self_reference,
3931-
decl,
3932-
useKind,
3933-
refKind + 1, refGlobalActor,
3934-
result.isolation)
3935-
.warnUntilSwiftVersionIf(preconcurrencyContext, 6);
3936-
3937-
noteIsolatedActorMember(decl, context);
3938-
if (result.isolation.isGlobalActor()) {
3939-
missingGlobalActorOnContext(
3940-
const_cast<DeclContext *>(getDeclContext()),
3941-
result.isolation.getGlobalActor(), DiagnosticBehavior::Note);
3942-
}
3938+
DiagnosticList list;
3939+
list.push_back(mismatch);
3940+
auto keyPair = std::make_pair(refKind,result.isolation);
3941+
refErrors.insert(std::make_pair(keyPair, list));
39433942
}
3943+
} else {
3944+
ctx.Diags.diagnose(
3945+
loc, diag::actor_isolated_non_self_reference,
3946+
decl, useKind,
3947+
refKind + 1, refGlobalActor,
3948+
result.isolation)
3949+
.warnUntilSwiftVersionIf(preconcurrencyContext, 6);
3950+
3951+
if (derivedConformanceType) {
3952+
auto *decl = dyn_cast<ValueDecl>(getDeclContext()->getAsDecl());
3953+
ctx.Diags.diagnose(loc, diag::in_derived_witness,
3954+
decl->getDescriptiveKind(),
3955+
requirementName,
3956+
derivedConformanceType);
3957+
}
3958+
3959+
noteIsolatedActorMember(decl, context);
3960+
if (result.isolation.isGlobalActor()) {
3961+
missingGlobalActorOnContext(
3962+
const_cast<DeclContext *>(getDeclContext()),
3963+
result.isolation.getGlobalActor(), DiagnosticBehavior::Note);
3964+
}
3965+
}
3966+
39443967
return true;
39453968
}
39463969
}
Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
// RUN: %target-swift-frontend -disable-availability-checking -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify
2-
// RUN: %target-swift-frontend -disable-availability-checking -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted
3-
// RUN: %target-swift-frontend -disable-availability-checking -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -strict-concurrency=complete
42
// RUN: %target-swift-frontend -disable-availability-checking -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-experimental-feature RegionBasedIsolation
53

64
// REQUIRES: concurrency
@@ -12,18 +10,28 @@ struct X1: Equatable, Hashable, Codable {
1210
let y: String
1311
}
1412

15-
// expected-error@+5{{type 'X2' does not conform to protocol 'Encodable'}}
16-
// expected-error@+4{{type 'X2' does not conform to protocol 'Decodable'}}
17-
// expected-error@+3{{type 'X2' does not conform to protocol 'Equatable'}}
18-
// expected-error@+2{{type 'X2' does not conform to protocol 'Hashable'}}
13+
// expected-error@+5 3{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
14+
// expected-note@+4{{in static method '==' for derived conformance to 'Equatable'}}
15+
// expected-error@+3{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
16+
// expected-note@+2{{in static method '==' for derived conformance to 'Equatable'}}
1917
@MainActor
2018
struct X2: Equatable, Hashable, Codable {
2119
let x: Int
22-
var y: String
20+
var y: String // expected-note 4 {{property declared here}}
2321
}
2422

2523
@MainActor
2624
enum X3: Hashable, Comparable, Codable {
2725
case a
2826
case b(Int)
2927
}
28+
29+
// expected-warning@+5{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
30+
// expected-note@+4{{in static method '==' for derived conformance to 'Equatable'}}
31+
// expected-warning@+3{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
32+
// expected-note@+2{{in static method '==' for derived conformance to 'Equatable'}}
33+
@preconcurrency @MainActor
34+
struct X4: Equatable {
35+
let x: Int
36+
var y: String // expected-note 2 {{property declared here}}
37+
}

0 commit comments

Comments
 (0)