Skip to content

Commit 26a4077

Browse files
authored
Merge pull request #71737 from Jumhyn/fix-keypath-subtype-solution-application
Fix solution application for keypath function subtype conversions
2 parents a4e92e7 + 2b2f780 commit 26a4077

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

Diff for: lib/Sema/CSApply.cpp

+18-7
Original file line numberDiff line numberDiff line change
@@ -5116,7 +5116,7 @@ namespace {
51165116
!componentTy->getWithoutSpecifierType()->isEqual(leafTy)) {
51175117
auto component = KeyPathExpr::Component::forOptionalWrap(leafTy);
51185118
resolvedComponents.push_back(component);
5119-
componentTy = leafTy;
5119+
componentTy = OptionalType::get(componentTy);
51205120
}
51215121

51225122
// Set the resolved components, and cache their types.
@@ -5132,13 +5132,23 @@ namespace {
51325132

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

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

@@ -5153,9 +5163,10 @@ namespace {
51535163

51545164
FunctionType::ExtInfo closureInfo;
51555165
auto closureTy =
5156-
FunctionType::get({FunctionType::Param(baseTy)}, leafTy, closureInfo);
5166+
FunctionType::get({FunctionType::Param(baseTy)}, kpResultTy,
5167+
closureInfo);
51575168
auto closure = new (ctx)
5158-
AutoClosureExpr(/*set body later*/nullptr, leafTy, dc);
5169+
AutoClosureExpr(/*set body later*/nullptr, kpResultTy, dc);
51595170

51605171
auto param = new (ctx) ParamDecl(
51615172
SourceLoc(),
@@ -5207,7 +5218,7 @@ namespace {
52075218
auto *application = new (ctx)
52085219
KeyPathApplicationExpr(paramRef,
52095220
E->getStartLoc(), outerParamRef, E->getEndLoc(),
5210-
leafTy, /*implicit=*/true);
5221+
kpResultTy, /*implicit=*/true);
52115222
cs.cacheType(application);
52125223

52135224
// Finish up the inner closure.

Diff for: test/SILGen/keypaths.swift

+15
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)