Skip to content

Commit a1b9cf3

Browse files
authored
Merge pull request #86362 from hamishknight/dyn-fix-6.3
[6.3] [CS] Narrow the cases where we add dynamic member after applicable fn
2 parents af9842f + fcc0f76 commit a1b9cf3

File tree

2 files changed

+81
-30
lines changed

2 files changed

+81
-30
lines changed

lib/Sema/TypeOfReference.cpp

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,11 +2440,62 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
24402440
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue |
24412441
TVO_CanBindToNoEscape);
24422442

2443+
bool isSubscriptRef = locator->isSubscriptMemberRef();
2444+
auto addMemberConstraint = [&]() {
2445+
// Attempt to lookup a member with a give name in the root type and
2446+
// assign result to the leaf type of the keypath.
2447+
DeclNameRef memberName =
2448+
isSubscriptRef ? DeclNameRef::createSubscript()
2449+
// FIXME: Should propagate name-as-written through.
2450+
: DeclNameRef(choice.getName());
2451+
2452+
// Check the current depth of applied dynamic member lookups, if we've
2453+
// exceeded the limit then record a fix and set a hole for the member.
2454+
unsigned lookupDepth = [&]() {
2455+
auto path = keyPathLoc->getPath();
2456+
auto iter = path.begin();
2457+
(void)keyPathLoc->findFirst<LocatorPathElt::KeyPathDynamicMember>(iter);
2458+
return path.end() - iter;
2459+
}();
2460+
if (lookupDepth > ctx.TypeCheckerOpts.DynamicMemberLookupDepthLimit) {
2461+
(void)recordFix(TooManyDynamicMemberLookups::create(
2462+
*this, DeclNameRef(choice.getName()), locator));
2463+
recordTypeVariablesAsHoles(memberTy);
2464+
} else {
2465+
addValueMemberConstraint(
2466+
LValueType::get(rootTy), memberName, memberTy, useDC,
2467+
isSubscriptRef ? FunctionRefInfo::doubleBaseNameApply()
2468+
: FunctionRefInfo::unappliedBaseName(),
2469+
/*outerAlternatives=*/{}, keyPathLoc);
2470+
}
2471+
};
2472+
2473+
// If we're doing a subscript lookup and have a dynamic member base we need
2474+
// to add the applicable function first since solving the member constraint
2475+
// requires the constraint to be available for recursive cases since it may
2476+
// retire it. We can't yet do this in the general case since the simplifying
2477+
// of the applicable fn in CSGen is currently load-bearing for existential
2478+
// opening.
2479+
// FIXME: Once existential opening is no longer sensitive to solving
2480+
// order, we ought to be able to just always record the applicable fn as
2481+
// an unsolved constraint before the member.
2482+
auto delayMemberConstraint =
2483+
isSubscriptRef && simplifyType(rootTy)
2484+
->getRValueType()
2485+
->getMetatypeInstanceType()
2486+
->eraseDynamicSelfType()
2487+
->hasDynamicMemberLookupAttribute();
2488+
if (!delayMemberConstraint)
2489+
addMemberConstraint();
2490+
SWIFT_DEFER {
2491+
if (delayMemberConstraint)
2492+
addMemberConstraint();
2493+
};
2494+
24432495
// In case of subscript things are more complicated comparing to "dot"
24442496
// syntax, because we have to get "applicable function" constraint
24452497
// associated with index expression and re-bind it to match "member type"
24462498
// looked up by dynamically.
2447-
bool isSubscriptRef = locator->isSubscriptMemberRef();
24482499
if (isSubscriptRef) {
24492500
// Make sure that regular subscript declarations (if any) are
24502501
// preferred over key path dynamic member lookup.
@@ -2521,35 +2572,6 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
25212572
// fact that this a property access in the source.
25222573
addDynamicMemberSubscriptConstraints(/*argTy*/ paramTy, boundType);
25232574
}
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-
}
25532575
return;
25542576
}
25552577
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P {}
4+
func takesP(_ x: some P) {}
5+
6+
struct Value {
7+
let prop: any P
8+
}
9+
10+
@dynamicMemberLookup
11+
struct ValueWithDynamicMember {
12+
let prop: any P
13+
14+
subscript<U>(dynamicMember keyPath: KeyPath<Int, U>) -> U {
15+
fatalError()
16+
}
17+
}
18+
19+
@dynamicMemberLookup
20+
struct Lens<T> {
21+
subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U {
22+
fatalError()
23+
}
24+
}
25+
26+
func test(_ a: Lens<Value>, _ b: Lens<ValueWithDynamicMember>) {
27+
takesP(a.prop)
28+
takesP(b.prop)
29+
}

0 commit comments

Comments
 (0)