diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index f3145e09554ff..db66fa8f4dda9 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5116,7 +5116,8 @@ namespace { !componentTy->getWithoutSpecifierType()->isEqual(leafTy)) { auto component = KeyPathExpr::Component::forOptionalWrap(leafTy); resolvedComponents.push_back(component); - componentTy = OptionalType::get(componentTy); + // Optional chaining forces the component to be r-value. + componentTy = OptionalType::get(componentTy->getWithoutSpecifierType()); } // Set the resolved components, and cache their types. diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift index c45191840b2bd..b6881a4d58c2b 100644 --- a/test/SILGen/keypaths.swift +++ b/test/SILGen/keypaths.swift @@ -652,3 +652,23 @@ struct Test { var codingPath: [any CodingKey] { codingStack.map(\.key) } // CHECK: keypath $KeyPath, (root $CodingStackEntry; stored_property #CodingStackEntry.key : $URICoderCodingKey) } + +// rdar://123638701 - Make sure that optional chaining forces loads. +func test_optional_chaining_with_function_conversion() { + class Storage {} + + class Elements { + var db: Storage = Storage() + } + + class Source { + var elements: Elements? = nil + } + + func test(data: [Source]) { + // CHECK: {{.*}} = keypath $KeyPath> + _ = data.compactMap(\.elements?.db) + // CHECK: {{.*}} = keypath $KeyPath + _ = data.compactMap(\.elements!.db) + } +}