Skip to content

Commit 2cdd785

Browse files
committed
[ConstraintSystem] Look through l-value while checking whether dynamic key path is recursive
Fix a crash in dynamic member lookup attempting to recursively lookup a member on the same base type. The problem is related to `isSelfRecursiveKeyPathDynamicMemberLookup` which failed to look through l-value wrapping base type on each side of the comparison, that's important because it's possible to have l-value mismatch due to the fact that implicit call always gets l-value base type but actual subscript which triggered dynamic lookup might be r-value. Resolves: [SR-11743](https://bugs.swift.org/browse/SR-11743) Resolves: rdar://problem/57091169
1 parent 853c0f5 commit 2cdd785

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5546,7 +5546,15 @@ static bool isSelfRecursiveKeyPathDynamicMemberLookup(
55465546
return baseDecl == keyPathRootDecl;
55475547
}
55485548

5549-
if (baseTy->isEqual(keyPathRootTy))
5549+
// Previous base type could be r-value because that could be
5550+
// a base type of subscript "as written" for which we attempt
5551+
// a dynamic member lookup.
5552+
auto baseTy1 = baseTy->getRValueType();
5553+
// Root type of key path is always wrapped in an l-value
5554+
// before lookup is performed, so we need to unwrap that.
5555+
auto baseTy2 = keyPathRootTy->getRValueType();
5556+
5557+
if (baseTy1->isEqual(baseTy2))
55505558
return true;
55515559
}
55525560

@@ -5848,6 +5856,10 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
58485856
using KPDynamicMemberElt = LocatorPathElt::KeyPathDynamicMember;
58495857
if (auto kpElt = memberLocator->getLastElementAs<KPDynamicMemberElt>()) {
58505858
auto *keyPath = kpElt->getKeyPathDecl();
5859+
if (isSelfRecursiveKeyPathDynamicMemberLookup(*this, baseTy,
5860+
memberLocator))
5861+
return;
5862+
58515863
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
58525864
// If this is an attempt to access read-only member via
58535865
// writable key path, let's fail this choice early.

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,3 +483,16 @@ func testDynamicMemberWithDefault(_ x: SR_11933) {
483483
// CHECK: [[OUTER_KP:%[0-9]+]] = keypath $KeyPath<SR_11933, Int>, (root $SR_11933; gettable_property $Int, id @$s29keypath_dynamic_member_lookup8SR_11933V0B6MemberSis7KeyPathCyAA21HasDefaultedSubscriptVSiG_tcig : $@convention(method) (@guaranteed KeyPath<HasDefaultedSubscript, Int>, SR_11933) -> Int, getter @$s29keypath_dynamic_member_lookup8SR_11933V0B6MemberSis7KeyPathCyAA21HasDefaultedSubscriptVSiG_tcipACTK : $@convention(thin) (@in_guaranteed SR_11933, UnsafeRawPointer) -> @out Int, indices [%$0 : $KeyPath<HasDefaultedSubscript, Int> : $KeyPath<HasDefaultedSubscript, Int>], indices_equals @$ss7KeyPathCy29keypath_dynamic_member_lookup21HasDefaultedSubscriptVSiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$ss7KeyPathCy29keypath_dynamic_member_lookup21HasDefaultedSubscriptVSiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[INNER_KP]])
484484
_ = \SR_11933.[]
485485
}
486+
487+
@dynamicMemberLookup
488+
protocol SR_11743 {
489+
subscript(dynamicMember member: KeyPath<Self, Any>) -> Any { get }
490+
}
491+
492+
extension SR_11743 {
493+
subscript(dynamicMember member: KeyPath<Self, Any>) -> Any {
494+
self[keyPath: member] // Ok
495+
// CHECK: function_ref @swift_getAtKeyPath
496+
// CHECK-NEXT: apply %{{.*}}<Self, Any>({{.*}})
497+
}
498+
}

0 commit comments

Comments
 (0)