Skip to content

Commit 9b8b12e

Browse files
authored
Merge pull request #42307 from slavapestov/rqm-sendable-conformance
RequirementMachine: Fix handling of Sendable conformances for superclass requirements
2 parents a410a48 + 9170378 commit 9b8b12e

File tree

4 files changed

+62
-28
lines changed

4 files changed

+62
-28
lines changed

lib/AST/RequirementMachine/ConcreteContraction.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,25 @@ ConcreteContraction::substRequirement(const Requirement &req) const {
363363

364364
auto *proto = req.getProtocolDecl();
365365
auto *module = proto->getParentModule();
366+
367+
// For conformance to 'Sendable', allow synthesis of a missing conformance
368+
// if the generic parameter is concrete, that is, if we're looking at a
369+
// signature of the form 'T == Foo, T : Sendable'.
370+
//
371+
// Otherwise, we have a superclass requirement, like 'T : C, T : Sendable';
372+
// don't synthesize the conformance in this case since dropping
373+
// 'T : Sendable' would be incorrect; we want to ensure that we only admit
374+
// subclasses of 'C' which are 'Sendable'.
375+
bool allowMissing = false;
376+
if (auto *rootParam = firstType->getAs<GenericTypeParamType>()) {
377+
auto key = GenericParamKey(rootParam);
378+
if (ConcreteTypes.count(key) > 0)
379+
allowMissing = true;
380+
}
381+
366382
if (!substFirstType->isTypeParameter() &&
367383
!module->lookupConformance(substFirstType, proto,
368-
/*allowMissing=*/true)) {
384+
allowMissing)) {
369385
// Handle the case of <T where T : P, T : C> where C is a class and
370386
// C does not conform to P by leaving the conformance requirement
371387
// unsubstituted.

lib/AST/RequirementMachine/ConcreteTypeWitness.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,19 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
143143
// or pass the correct one down in here.
144144
auto *module = proto->getParentModule();
145145

146+
// For conformance to 'Sendable', allow synthesis of a missing conformance
147+
// if the requirement is a concrete type requirement, that is, if we're
148+
// looking at a signature of the form 'T == Foo, T : Sendable'.
149+
//
150+
// Otherwise, we have a superclass requirement, like 'T : C, T : Sendable'.
151+
// Don't synthesize the conformance in this case since dropping
152+
// 'T : Sendable' would be incorrect; we want to ensure that we only admit
153+
// subclasses of 'C' which are 'Sendable'.
154+
bool allowMissing = (requirementKind == RequirementKind::SameType);
155+
146156
auto conformance = module->lookupConformance(concreteType,
147157
const_cast<ProtocolDecl *>(proto),
148-
/*allowMissing=*/true);
158+
allowMissing);
149159
if (conformance.isInvalid()) {
150160
// For superclass rules, it is totally fine to have a signature like:
151161
//

test/Concurrency/sendable_conformance_checking.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -165,29 +165,3 @@ extension SendableExtSub: @unchecked Sendable {}
165165
// Still want to know about same-class redundancy
166166
class MultiConformance: @unchecked Sendable {} // expected-note {{'MultiConformance' declares conformance to protocol 'Sendable' here}}
167167
extension MultiConformance: @unchecked Sendable {} // expected-error {{redundant conformance of 'MultiConformance' to protocol 'Sendable'}}
168-
169-
// rdar://91174106 - allow missing Sendable conformances when extending a
170-
// type generically.
171-
// FIXME: Should warn because of missing Sendable, but currently is silent
172-
// because we aren't checking conformance availability here yet.
173-
struct X<T: Sendable> { }
174-
enum Y {}
175-
extension X where T == Y {}
176-
177-
protocol P2 {
178-
associatedtype A: Sendable
179-
}
180-
181-
enum Y2: P2, P3 {
182-
typealias A = Y
183-
}
184-
185-
struct X2<T: P2> { }
186-
extension X2 where T == Y2 { }
187-
188-
protocol P3 {
189-
associatedtype A
190-
}
191-
192-
struct X3<T: P3> where T.A: Sendable { }
193-
extension X3 where T == Y2 { }
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures 2>&1 | %FileCheck %s
3+
4+
// REQUIRES: concurrency
5+
6+
// rdar://91174106 - allow missing Sendable conformances when extending a
7+
// type generically.
8+
// FIXME: Should warn because of missing Sendable, but currently is silent
9+
// because we aren't checking conformance availability here yet.
10+
class C {}
11+
12+
struct G1<T: Sendable> {}
13+
14+
// CHECK-LABEL: ExtensionDecl line={{.*}} base=G1
15+
// CHECK-NEXT: Generic signature: <T where T == C>
16+
extension G1 where T == C {}
17+
18+
// CHECK-LABEL: ExtensionDecl line={{.*}} base=G1
19+
// CHECK-NEXT: Generic signature: <T where T : C, T : Sendable>
20+
extension G1 where T : C {}
21+
22+
protocol P {
23+
associatedtype A
24+
}
25+
26+
struct G2<T : P> where T.A : Sendable {}
27+
28+
// CHECK-LABEL: ExtensionDecl line={{.*}} base=G2
29+
// CHECK-NEXT: Generic signature: <T where T : P, T.[P]A == C>
30+
extension G2 where T.A == C {}
31+
32+
// CHECK-LABEL: ExtensionDecl line={{.*}} base=G2
33+
// CHECK-NEXT: Generic signature: <T where T : P, T.[P]A : C, T.[P]A : Sendable>
34+
extension G2 where T.A : C {}

0 commit comments

Comments
 (0)