Skip to content

Commit 2b2f780

Browse files
committed
Fix solution application for keypath function subtype conversions
In swiftlang#39612 we added subtyping for keypaths-as-functions, but during application the implementation naively coerced the keypath expression itself to the inferred supertype, resulting in erroneous results. This patch updates the solution application logic to build the keypath-function conversion expression based entirely on the 'natural' keypath type, only converting to the inferred supertype at the end via the usual coerceToType machinery for function conversions.
1 parent d35dcc8 commit 2b2f780

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

lib/Sema/CSApply.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5117,7 +5117,7 @@ namespace {
51175117
!componentTy->getWithoutSpecifierType()->isEqual(leafTy)) {
51185118
auto component = KeyPathExpr::Component::forOptionalWrap(leafTy);
51195119
resolvedComponents.push_back(component);
5120-
componentTy = leafTy;
5120+
componentTy = OptionalType::get(componentTy);
51215121
}
51225122

51235123
// Set the resolved components, and cache their types.
@@ -5133,13 +5133,23 @@ namespace {
51335133

51345134
// If we've gotten here, the user has used key path literal syntax to form
51355135
// a closure. The type checker has given E a function type to indicate
5136-
// this; we're going to change E's type to KeyPath<baseTy, leafTy> and
5137-
// then wrap it in a larger closure expression with the appropriate type.
5136+
// this.
5137+
//
5138+
// Since functions support more conversions than generic types, we may
5139+
// have ended up with a type of (baseTy) -> leafTy, where the actual type
5140+
// of the key path is some subclass of KeyPath<baseTy, componentTy>, and
5141+
// with componentTy: leafTy.
5142+
//
5143+
// We're going to change E's type to KeyPath<baseTy, componentTy> and
5144+
// then wrap it in a larger closure expression which we will convert to
5145+
// appropriate type.
5146+
5147+
auto kpResultTy = componentTy->getWithoutSpecifierType();
51385148

51395149
// Compute KeyPath<baseTy, leafTy> and set E's type back to it.
51405150
auto kpDecl = cs.getASTContext().getKeyPathDecl();
51415151
auto keyPathTy =
5142-
BoundGenericType::get(kpDecl, nullptr, { baseTy, leafTy });
5152+
BoundGenericType::get(kpDecl, nullptr, { baseTy, kpResultTy });
51435153
E->setType(keyPathTy);
51445154
cs.cacheType(E);
51455155

@@ -5154,9 +5164,10 @@ namespace {
51545164

51555165
FunctionType::ExtInfo closureInfo;
51565166
auto closureTy =
5157-
FunctionType::get({FunctionType::Param(baseTy)}, leafTy, closureInfo);
5167+
FunctionType::get({FunctionType::Param(baseTy)}, kpResultTy,
5168+
closureInfo);
51585169
auto closure = new (ctx)
5159-
AutoClosureExpr(/*set body later*/nullptr, leafTy, dc);
5170+
AutoClosureExpr(/*set body later*/nullptr, kpResultTy, dc);
51605171

51615172
auto param = new (ctx) ParamDecl(
51625173
SourceLoc(),
@@ -5208,7 +5219,7 @@ namespace {
52085219
auto *application = new (ctx)
52095220
KeyPathApplicationExpr(paramRef,
52105221
E->getStartLoc(), outerParamRef, E->getEndLoc(),
5211-
leafTy, /*implicit=*/true);
5222+
kpResultTy, /*implicit=*/true);
52125223
cs.cacheType(application);
52135224

52145225
// Finish up the inner closure.

test/SILGen/keypaths.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,3 +637,18 @@ struct TestKeyPathWithSomeType : DefineSomeType {
637637

638638
}
639639
}
640+
641+
// apple/swift#71423
642+
protocol CodingKey {}
643+
644+
struct URICoderCodingKey : CodingKey {}
645+
646+
struct CodingStackEntry {
647+
var key: URICoderCodingKey
648+
}
649+
650+
struct Test {
651+
var codingStack: [CodingStackEntry]
652+
var codingPath: [any CodingKey] { codingStack.map(\.key) }
653+
// CHECK: keypath $KeyPath<CodingStackEntry, URICoderCodingKey>, (root $CodingStackEntry; stored_property #CodingStackEntry.key : $URICoderCodingKey)
654+
}

0 commit comments

Comments
 (0)