Skip to content

Commit 681d160

Browse files
committed
[CSSimplify] Allow type inference through marker protocol existential casts
```swift class A<T> { } class B<U> : A<U> { } func test(v: any B<Int> & Sendable) { _ = v as A // infers `Int` for `A.T` } ```
1 parent b17f0b5 commit 681d160

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9215,6 +9215,23 @@ ConstraintSystem::simplifyCheckedCastConstraint(
92159215
}
92169216
}
92179217

9218+
// Peel off marker protocol requirements if this is an existential->concrete
9219+
// cast. Handles cases like `WritableKeyPath<...> & Sendable as KeyPath`
9220+
// that require inference which is only attempted if both sides are classes.
9221+
if (fromType->isExistentialType() && !toType->isExistentialType()) {
9222+
if (auto *existential = fromType->getAs<ExistentialType>()) {
9223+
if (auto *PCT = existential->getConstraintType()
9224+
->getAs<ProtocolCompositionType>()) {
9225+
auto newConstraintTy = PCT->withoutMarkerProtocols();
9226+
if (!newConstraintTy->isEqual(PCT)) {
9227+
fromType = newConstraintTy->getClassOrBoundGenericClass()
9228+
? newConstraintTy
9229+
: ExistentialType::get(newConstraintTy);
9230+
}
9231+
}
9232+
}
9233+
}
9234+
92189235
// We've decomposed the types further, so adopt the subflags.
92199236
flags = subflags;
92209237

test/Concurrency/sendable_keypaths.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,11 @@ do {
230230
func forward<T>(_ v: T) -> T { v }
231231
let _: KeyPath<String, Int> = forward(kp()) // Ok
232232
}
233+
234+
do {
235+
final class C<T> {
236+
let immutable: String = ""
237+
}
238+
239+
_ = \C<Int>.immutable as? ReferenceWritableKeyPath // Ok
240+
}

test/expr/cast/as_coerce.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,16 @@ do {
201201
(fn as () -> Void)() // expected-error {{no exact matches in reference to local function 'fn'}}
202202
(fn_1 as () -> Void)() // expected-error {{cannot convert value of type '(Bool) -> ()' to type '() -> Void' in coercion}}
203203
}
204+
205+
// Test generic parameter inference through casts
206+
do {
207+
class A<T> {
208+
}
209+
210+
class B<U> : A<U> {
211+
}
212+
213+
func test(v: any B<Int> & Sendable) {
214+
_ = v as A // infers `Int` for `A.T`
215+
}
216+
}

0 commit comments

Comments
 (0)