Skip to content

Commit d540f48

Browse files
authored
Merge pull request swiftlang#70522 from xedin/csbindings-support-superclass-of-existential
[CSBindings] Make it possible to enumerate supertypes of existentials
2 parents 24d54a8 + a288b1e commit d540f48

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6389,6 +6389,11 @@ class TypeVarRefCollector : public ASTWalker {
63896389
/// for a key path `{Any, Partial, Writable, ReferenceWritable}KeyPath`.
63906390
bool isKnownKeyPathType(Type type);
63916391

6392+
/// Determine whether the given type is a PartialKeyPath and
6393+
/// AnyKeyPath or existential type thererof, for example,
6394+
/// `PartialKeyPath<...> & Sendable`.
6395+
bool isTypeErasedKeyPathType(Type type);
6396+
63926397
/// Determine whether given declaration is one for a key path
63936398
/// `{Writable, ReferenceWritable}KeyPath`.
63946399
bool isKnownKeyPathDecl(ASTContext &ctx, ValueDecl *decl);

lib/Sema/CSBindings.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,10 +2172,43 @@ static Type getOptionalSuperclass(Type type) {
21722172
type = underlying;
21732173
}
21742174

2175-
if (!type->mayHaveSuperclass())
2176-
return Type();
2175+
Type superclass;
2176+
if (auto *existential = type->getAs<ExistentialType>()) {
2177+
auto constraintTy = existential->getConstraintType();
2178+
if (auto *compositionTy = constraintTy->getAs<ProtocolCompositionType>()) {
2179+
SmallVector<Type, 2> members;
2180+
bool found = false;
2181+
// Preserve all of the protocol requirements of the type i.e.
2182+
// if the type was `any B & P` where `B : A` the supertype is
2183+
// going to be `any A & P`.
2184+
//
2185+
// This is especially important for Sendable key paths because
2186+
// to reserve sendability of the original type.
2187+
for (auto member : compositionTy->getMembers()) {
2188+
if (member->getClassOrBoundGenericClass()) {
2189+
member = member->getSuperclass();
2190+
if (!member)
2191+
return Type();
2192+
found = true;
2193+
}
2194+
members.push_back(member);
2195+
}
2196+
2197+
if (!found)
2198+
return Type();
2199+
2200+
superclass = ExistentialType::get(
2201+
ProtocolCompositionType::get(type->getASTContext(), members,
2202+
compositionTy->hasExplicitAnyObject()));
2203+
} else {
2204+
// Avoid producing superclass for situations like `any P` where `P` is
2205+
// `protocol P : C`.
2206+
return Type();
2207+
}
2208+
} else {
2209+
superclass = type->getSuperclass();
2210+
}
21772211

2178-
auto superclass = type->getSuperclass();
21792212
if (!superclass)
21802213
return Type();
21812214

@@ -2326,7 +2359,7 @@ bool TypeVarBindingProducer::computeNext() {
23262359
auto supertype = *simplifiedSuper;
23272360
// A key path type cannot be bound to type-erased key path variants.
23282361
if (TypeVar->getImpl().isKeyPathType() &&
2329-
(supertype->isPartialKeyPath() || supertype->isAnyKeyPath()))
2362+
isTypeErasedKeyPathType(supertype))
23302363
continue;
23312364

23322365
addNewBinding(binding.withType(supertype));

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6676,6 +6676,19 @@ bool constraints::isKnownKeyPathType(Type type) {
66766676
type->isAnyKeyPath();
66776677
}
66786678

6679+
bool constraints::isTypeErasedKeyPathType(Type type) {
6680+
assert(type);
6681+
6682+
if (type->isPartialKeyPath() || type->isAnyKeyPath())
6683+
return true;
6684+
6685+
if (!type->isExistentialType())
6686+
return false;
6687+
6688+
auto superclass = type->getSuperclass();
6689+
return superclass ? isTypeErasedKeyPathType(superclass) : false;
6690+
}
6691+
66796692
bool constraints::hasExplicitResult(ClosureExpr *closure) {
66806693
auto &ctx = closure->getASTContext();
66816694
return evaluateOrDefault(ctx.evaluator,

test/Concurrency/sendable_keypaths.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,20 @@ func testReferencesToDifferentGlobalActorIsolatedMembers() {
200200
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'name'; this is an error in Swift 6}}
201201
}
202202
}
203+
204+
do {
205+
struct S {
206+
var a: Int
207+
var b: String?
208+
}
209+
210+
func test<T: Sendable>(_: T) {}
211+
212+
let kp = [\S.a, \S.b]
213+
214+
test(kp) // Ok
215+
test([\S.a, \S.b]) // Ok
216+
217+
let _: [PartialKeyPath<S>] = [\.a, \.b] // Ok
218+
let _: [any PartialKeyPath<S> & Sendable] = [\.a, \.b] // Ok
219+
}

0 commit comments

Comments
 (0)