Skip to content

Commit 4b25dc5

Browse files
committed
[CS] Do member lookup last when binding dynamic member overload
Otherwise if the member lookup gets simplified immediately and we have a recursive dynamic member lookup we will crash since we wouldn't have introduced the corresponding applicable function constraint. rdar://164321858
1 parent 22d1825 commit 4b25dc5

File tree

2 files changed

+66
-27
lines changed

2 files changed

+66
-27
lines changed

lib/Sema/TypeOfReference.cpp

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,38 +2446,12 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
24462446
// don't which at the moment, so let's allow its type to be l-value.
24472447
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue |
24482448
TVO_CanBindToNoEscape);
2449-
// Attempt to lookup a member with a give name in the root type and
2450-
// assign result to the leaf type of the keypath.
2451-
bool isSubscriptRef = locator->isSubscriptMemberRef();
2452-
DeclNameRef memberName = isSubscriptRef
2453-
? DeclNameRef::createSubscript()
2454-
// FIXME: Should propagate name-as-written through.
2455-
: DeclNameRef(choice.getName());
2456-
2457-
// Check the current depth of applied dynamic member lookups, if we've
2458-
// exceeded the limit then record a fix and set a hole for the member.
2459-
unsigned lookupDepth = [&]() {
2460-
auto path = keyPathLoc->getPath();
2461-
auto iter = path.begin();
2462-
(void)keyPathLoc->findFirst<LocatorPathElt::KeyPathDynamicMember>(iter);
2463-
return path.end() - iter;
2464-
}();
2465-
if (lookupDepth > ctx.TypeCheckerOpts.DynamicMemberLookupDepthLimit) {
2466-
(void)recordFix(TooManyDynamicMemberLookups::create(
2467-
*this, DeclNameRef(choice.getName()), locator));
2468-
recordTypeVariablesAsHoles(memberTy);
2469-
} else {
2470-
addValueMemberConstraint(
2471-
LValueType::get(rootTy), memberName, memberTy, useDC,
2472-
isSubscriptRef ? FunctionRefInfo::doubleBaseNameApply()
2473-
: FunctionRefInfo::unappliedBaseName(),
2474-
/*outerAlternatives=*/{}, keyPathLoc);
2475-
}
24762449

24772450
// In case of subscript things are more complicated comparing to "dot"
24782451
// syntax, because we have to get "applicable function" constraint
24792452
// associated with index expression and re-bind it to match "member type"
24802453
// looked up by dynamically.
2454+
bool isSubscriptRef = locator->isSubscriptMemberRef();
24812455
if (isSubscriptRef) {
24822456
// Make sure that regular subscript declarations (if any) are
24832457
// preferred over key path dynamic member lookup.
@@ -2554,6 +2528,35 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
25542528
// fact that this a property access in the source.
25552529
addDynamicMemberSubscriptConstraints(/*argTy*/ paramTy, boundType);
25562530
}
2531+
2532+
// Attempt to lookup a member with a give name in the root type and
2533+
// assign result to the leaf type of the keypath. Note we need to do this
2534+
// after handling the applicable function constraint in the subscript case
2535+
// to ensure it's available for recursive cases.
2536+
DeclNameRef memberName = isSubscriptRef
2537+
? DeclNameRef::createSubscript()
2538+
// FIXME: Should propagate name-as-written through.
2539+
: DeclNameRef(choice.getName());
2540+
2541+
// Check the current depth of applied dynamic member lookups, if we've
2542+
// exceeded the limit then record a fix and set a hole for the member.
2543+
unsigned lookupDepth = [&]() {
2544+
auto path = keyPathLoc->getPath();
2545+
auto iter = path.begin();
2546+
(void)keyPathLoc->findFirst<LocatorPathElt::KeyPathDynamicMember>(iter);
2547+
return path.end() - iter;
2548+
}();
2549+
if (lookupDepth > ctx.TypeCheckerOpts.DynamicMemberLookupDepthLimit) {
2550+
(void)recordFix(TooManyDynamicMemberLookups::create(
2551+
*this, DeclNameRef(choice.getName()), locator));
2552+
recordTypeVariablesAsHoles(memberTy);
2553+
} else {
2554+
addValueMemberConstraint(
2555+
LValueType::get(rootTy), memberName, memberTy, useDC,
2556+
isSubscriptRef ? FunctionRefInfo::doubleBaseNameApply()
2557+
: FunctionRefInfo::unappliedBaseName(),
2558+
/*outerAlternatives=*/{}, keyPathLoc);
2559+
}
25572560
return;
25582561
}
25592562
}

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,39 @@ class TestDynamicSelf {
616616
fatalError()
617617
}
618618
}
619+
620+
@dynamicMemberLookup
621+
protocol P1 {}
622+
623+
extension P1 {
624+
subscript<T>(dynamicMember dynamicMemberLookup: KeyPath<TestOverloaded.S2, T>) -> T {
625+
fatalError()
626+
}
627+
}
628+
629+
struct TestOverloaded {
630+
struct S1: P1 {
631+
subscript(x: String) -> Int {
632+
fatalError()
633+
}
634+
func f(_ x: String) -> Int {
635+
return self[x]
636+
}
637+
}
638+
struct S2: P1 {}
639+
}
640+
641+
@dynamicMemberLookup
642+
struct SingleLens<T> {
643+
var value: T
644+
init(_ value: T) {
645+
self.value = value
646+
}
647+
subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U {
648+
value[keyPath: keyPath]
649+
}
650+
}
651+
652+
func testRecursiveSingleSubscript(_ x: SingleLens<SingleLens<SingleLens<SingleLens<[Int]>>>>) {
653+
_ = x[0]
654+
}

0 commit comments

Comments
 (0)