Skip to content

Commit 6e5ba7a

Browse files
authored
Merge pull request #86012 from hamishknight/dyn-apply-6.3
[6.3] [CS] Do member lookup last when binding dynamic member overload
2 parents 9c9e5df + 6ca9de3 commit 6e5ba7a

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

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

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)