Skip to content

Commit 66afe77

Browse files
authored
[CS] Fix resolution of key path component callees (#28569)
[CS] Fix resolution of key path component callees
2 parents 5a6343f + 7e1a963 commit 66afe77

File tree

2 files changed

+74
-27
lines changed

2 files changed

+74
-27
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6802,22 +6802,6 @@ ConstraintSystem::simplifyKeyPathConstraint(
68026802
// The constraint ought to have been anchored on a KeyPathExpr.
68036803
auto keyPath = cast<KeyPathExpr>(locator.getBaseLocator()->getAnchor());
68046804

6805-
// Gather overload choices for any key path components associated with this
6806-
// key path.
6807-
SmallVector<OverloadChoice, 4> choices;
6808-
choices.resize(keyPath->getComponents().size());
6809-
for (auto resolvedItem = resolvedOverloadSets; resolvedItem;
6810-
resolvedItem = resolvedItem->Previous) {
6811-
auto locator = resolvedItem->Locator;
6812-
auto path = locator->getPath();
6813-
if (locator->getAnchor() != keyPath || path.size() > 2)
6814-
continue;
6815-
6816-
if (auto kpElt = path[0].getAs<LocatorPathElt::KeyPathComponent>()) {
6817-
choices[kpElt->getIndex()] = resolvedItem->Choice;
6818-
}
6819-
}
6820-
68216805
keyPathTy = getFixedTypeRecursive(keyPathTy, /*want rvalue*/ true);
68226806
bool definitelyFunctionType = false;
68236807
bool definitelyKeyPathType = false;
@@ -6879,6 +6863,30 @@ ConstraintSystem::simplifyKeyPathConstraint(
68796863
return SolutionKind::Error;
68806864
}
68816865

6866+
// First gather the callee locators for the individual components.
6867+
SmallVector<std::pair<ConstraintLocator *, OverloadChoice>, 4> choices;
6868+
for (unsigned i : indices(keyPath->getComponents())) {
6869+
auto *componentLoc = getConstraintLocator(
6870+
locator.withPathElement(LocatorPathElt::KeyPathComponent(i)));
6871+
auto *calleeLoc = getCalleeLocator(componentLoc);
6872+
choices.push_back({calleeLoc, OverloadChoice()});
6873+
}
6874+
6875+
// Then search for the resolved overloads.
6876+
for (auto resolvedItem = resolvedOverloadSets; resolvedItem;
6877+
resolvedItem = resolvedItem->Previous) {
6878+
auto locator = resolvedItem->Locator;
6879+
auto kpElt = locator->getFirstElementAs<LocatorPathElt::KeyPathComponent>();
6880+
if (!kpElt || locator->getAnchor() != keyPath)
6881+
continue;
6882+
6883+
auto &choice = choices[kpElt->getIndex()];
6884+
if (choice.first == locator) {
6885+
assert(choice.second.isInvalid() && "Resolved same component twice?");
6886+
choice.second = resolvedItem->Choice;
6887+
}
6888+
}
6889+
68826890
// See if we resolved overloads for all the components involved.
68836891
enum {
68846892
ReadOnly,
@@ -6900,12 +6908,15 @@ ConstraintSystem::simplifyKeyPathConstraint(
69006908
case KeyPathExpr::Component::Kind::Subscript:
69016909
case KeyPathExpr::Component::Kind::UnresolvedProperty:
69026910
case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
6911+
auto *calleeLoc = choices[i].first;
6912+
auto choice = choices[i].second;
6913+
69036914
// If no choice was made, leave the constraint unsolved. But when
69046915
// generating constraints, we may already have enough information
69056916
// to determine whether the result will be a function type vs BGT KeyPath
69066917
// type, so continue through components to create new constraint at the
69076918
// end.
6908-
if (choices[i].isInvalid() || anyComponentsUnresolved) {
6919+
if (choice.isInvalid() || anyComponentsUnresolved) {
69096920
if (flags.contains(TMF_GenerateConstraints)) {
69106921
anyComponentsUnresolved = true;
69116922
continue;
@@ -6937,23 +6948,20 @@ ConstraintSystem::simplifyKeyPathConstraint(
69376948
}
69386949

69396950
// tuple elements do not change the capability of the key path
6940-
if (choices[i].getKind() == OverloadChoiceKind::TupleIndex) {
6951+
if (choice.getKind() == OverloadChoiceKind::TupleIndex) {
69416952
continue;
69426953
}
69436954

69446955
// Discarded unsupported non-decl member lookups.
6945-
if (!choices[i].isDecl()) {
6956+
if (!choice.isDecl()) {
69466957
return SolutionKind::Error;
69476958
}
69486959

6949-
auto storage = dyn_cast<AbstractStorageDecl>(choices[i].getDecl());
6950-
6951-
auto *componentLoc = getConstraintLocator(
6952-
locator.withPathElement(LocatorPathElt::KeyPathComponent(i)));
6960+
auto storage = dyn_cast<AbstractStorageDecl>(choice.getDecl());
69536961

69546962
if (auto *fix = AllowInvalidRefInKeyPath::forRef(
6955-
*this, choices[i].getDecl(), componentLoc)) {
6956-
if (!hasFixFor(componentLoc, FixKind::AllowTypeOrInstanceMember))
6963+
*this, choice.getDecl(), calleeLoc)) {
6964+
if (!hasFixFor(calleeLoc, FixKind::AllowTypeOrInstanceMember))
69576965
if (!shouldAttemptFixes() || recordFix(fix))
69586966
return SolutionKind::Error;
69596967

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,12 +410,51 @@ func testIUOUnwrap(_ x: SR_11893) {
410410
// CHECK: keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicig : $@convention(method) (Int, SR_11893_Base) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicipACTK : $@convention(thin) (@in_guaranteed SR_11893_Base, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int)
411411
x[5]
412412

413-
// FIXME(SR-11896): We should not vend a WritableKeyPath for the "outer" key path here.
414413
// CHECK: [[INNER_KP:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; stored_property #SR_11893_Base.i : $Optional<Int>; optional_force : $Int)
415-
// CHECK: keypath $WritableKeyPath<SR_11893, ()>, (root $SR_11893; gettable_property $(), id @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_11893) -> (), getter @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_11893, UnsafeRawPointer) -> @out (), indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_KP]])
414+
// CHECK: keypath $KeyPath<SR_11893, ()>, (root $SR_11893; gettable_property $(), id @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_11893) -> (), getter @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_11893, UnsafeRawPointer) -> @out (), indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_KP]])
416415
_ = \SR_11893.i
417416

418417
// CHECK: [[INNER_SUB_KP:%[0-9]+]] = keypath $KeyPath<SR_11893_Base, Int>, (root $SR_11893_Base; gettable_property $Optional<Int>, id @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicig : $@convention(method) (Int, SR_11893_Base) -> Optional<Int>, getter @$s29keypath_dynamic_member_lookup13SR_11893_BaseVySiSgSicipACTK : $@convention(thin) (@in_guaranteed SR_11893_Base, UnsafeRawPointer) -> @out Optional<Int>, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int; optional_force : $Int)
419418
// CHECK: keypath $KeyPath<SR_11893, ()>, (root $SR_11893; gettable_property $(), id @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcig : $@convention(method) (@guaranteed KeyPath<SR_11893_Base, Int>, SR_11893) -> (), getter @$s29keypath_dynamic_member_lookup8SR_11893V0B6Memberys7KeyPathCyAA0E11_11893_BaseVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_11893, UnsafeRawPointer) -> @out (), indices [%$0 : $KeyPath<SR_11893_Base, Int> : $KeyPath<SR_11893_Base, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup13SR_11893_BaseVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_SUB_KP]])
420419
_ = \SR_11893.[5]
421420
}
421+
422+
// SR-11896: Make sure the outer key path reflects the mutability of the 'dynamicMember:' subscript.
423+
struct SR_11896_Base {
424+
var mutable: Int
425+
let immutable: Int
426+
}
427+
428+
@dynamicMemberLookup
429+
struct SR_11896_Mutable {
430+
subscript(dynamicMember kp: KeyPath<SR_11896_Base, Int>) -> Int {
431+
get { 5 } set {}
432+
}
433+
}
434+
435+
@dynamicMemberLookup
436+
struct SR_11896_Immutable {
437+
subscript(dynamicMember kp: KeyPath<SR_11896_Base, Int>) -> Int {
438+
get { 5 }
439+
}
440+
}
441+
442+
443+
// CHECK-LABEL: sil hidden @$s29keypath_dynamic_member_lookup21testKeyPathMutabilityyyF : $@convention(thin) () -> ()
444+
func testKeyPathMutability() {
445+
// CHECK: keypath $KeyPath<SR_11896_Base, Int>, (root $SR_11896_Base; stored_property #SR_11896_Base.mutable : $Int)
446+
// CHECK: keypath $WritableKeyPath<SR_11896_Mutable, Int>, (root $SR_11896_Mutable; settable_property $Int
447+
_ = \SR_11896_Mutable.mutable
448+
449+
// CHECK: keypath $KeyPath<SR_11896_Base, Int>, (root $SR_11896_Base; stored_property #SR_11896_Base.immutable : $Int)
450+
// CHECK: keypath $WritableKeyPath<SR_11896_Mutable, Int>, (root $SR_11896_Mutable; settable_property $Int
451+
_ = \SR_11896_Mutable.immutable
452+
453+
// CHECK: keypath $KeyPath<SR_11896_Base, Int>, (root $SR_11896_Base; stored_property #SR_11896_Base.mutable : $Int)
454+
// CHECK: keypath $KeyPath<SR_11896_Immutable, Int>, (root $SR_11896_Immutable; gettable_property $Int
455+
_ = \SR_11896_Immutable.mutable
456+
457+
// CHECK: keypath $KeyPath<SR_11896_Base, Int>, (root $SR_11896_Base; stored_property #SR_11896_Base.immutable : $Int)
458+
// CHECK: keypath $KeyPath<SR_11896_Immutable, Int>, (root $SR_11896_Immutable; gettable_property $Int
459+
_ = \SR_11896_Immutable.immutable
460+
}

0 commit comments

Comments
 (0)