mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -2446,38 +2446,12 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
|
|||||||
// don't which at the moment, so let's allow its type to be l-value.
|
// don't which at the moment, so let's allow its type to be l-value.
|
||||||
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue |
|
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue |
|
||||||
TVO_CanBindToNoEscape);
|
TVO_CanBindToNoEscape);
|
||||||
// Attempt to lookup a member with a give name in the root type and
|
|
||||||
// assign result to the leaf type of the keypath.
|
|
||||||
bool isSubscriptRef = locator->isSubscriptMemberRef();
|
|
||||||
DeclNameRef memberName = isSubscriptRef
|
|
||||||
? DeclNameRef::createSubscript()
|
|
||||||
// FIXME: Should propagate name-as-written through.
|
|
||||||
: DeclNameRef(choice.getName());
|
|
||||||
|
|
||||||
// Check the current depth of applied dynamic member lookups, if we've
|
|
||||||
// exceeded the limit then record a fix and set a hole for the member.
|
|
||||||
unsigned lookupDepth = [&]() {
|
|
||||||
auto path = keyPathLoc->getPath();
|
|
||||||
auto iter = path.begin();
|
|
||||||
(void)keyPathLoc->findFirst<LocatorPathElt::KeyPathDynamicMember>(iter);
|
|
||||||
return path.end() - iter;
|
|
||||||
}();
|
|
||||||
if (lookupDepth > ctx.TypeCheckerOpts.DynamicMemberLookupDepthLimit) {
|
|
||||||
(void)recordFix(TooManyDynamicMemberLookups::create(
|
|
||||||
*this, DeclNameRef(choice.getName()), locator));
|
|
||||||
recordTypeVariablesAsHoles(memberTy);
|
|
||||||
} else {
|
|
||||||
addValueMemberConstraint(
|
|
||||||
LValueType::get(rootTy), memberName, memberTy, useDC,
|
|
||||||
isSubscriptRef ? FunctionRefInfo::doubleBaseNameApply()
|
|
||||||
: FunctionRefInfo::unappliedBaseName(),
|
|
||||||
/*outerAlternatives=*/{}, keyPathLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case of subscript things are more complicated comparing to "dot"
|
// In case of subscript things are more complicated comparing to "dot"
|
||||||
// syntax, because we have to get "applicable function" constraint
|
// syntax, because we have to get "applicable function" constraint
|
||||||
// associated with index expression and re-bind it to match "member type"
|
// associated with index expression and re-bind it to match "member type"
|
||||||
// looked up by dynamically.
|
// looked up by dynamically.
|
||||||
|
bool isSubscriptRef = locator->isSubscriptMemberRef();
|
||||||
if (isSubscriptRef) {
|
if (isSubscriptRef) {
|
||||||
// Make sure that regular subscript declarations (if any) are
|
// Make sure that regular subscript declarations (if any) are
|
||||||
// preferred over key path dynamic member lookup.
|
// preferred over key path dynamic member lookup.
|
||||||
@@ -2554,6 +2528,35 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
|
|||||||
// fact that this a property access in the source.
|
// fact that this a property access in the source.
|
||||||
addDynamicMemberSubscriptConstraints(/*argTy*/ paramTy, boundType);
|
addDynamicMemberSubscriptConstraints(/*argTy*/ paramTy, boundType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempt to lookup a member with a give name in the root type and
|
||||||
|
// assign result to the leaf type of the keypath. Note we need to do this
|
||||||
|
// after handling the applicable function constraint in the subscript case
|
||||||
|
// to ensure it's available for recursive cases.
|
||||||
|
DeclNameRef memberName = isSubscriptRef
|
||||||
|
? DeclNameRef::createSubscript()
|
||||||
|
// FIXME: Should propagate name-as-written through.
|
||||||
|
: DeclNameRef(choice.getName());
|
||||||
|
|
||||||
|
// Check the current depth of applied dynamic member lookups, if we've
|
||||||
|
// exceeded the limit then record a fix and set a hole for the member.
|
||||||
|
unsigned lookupDepth = [&]() {
|
||||||
|
auto path = keyPathLoc->getPath();
|
||||||
|
auto iter = path.begin();
|
||||||
|
(void)keyPathLoc->findFirst<LocatorPathElt::KeyPathDynamicMember>(iter);
|
||||||
|
return path.end() - iter;
|
||||||
|
}();
|
||||||
|
if (lookupDepth > ctx.TypeCheckerOpts.DynamicMemberLookupDepthLimit) {
|
||||||
|
(void)recordFix(TooManyDynamicMemberLookups::create(
|
||||||
|
*this, DeclNameRef(choice.getName()), locator));
|
||||||
|
recordTypeVariablesAsHoles(memberTy);
|
||||||
|
} else {
|
||||||
|
addValueMemberConstraint(
|
||||||
|
LValueType::get(rootTy), memberName, memberTy, useDC,
|
||||||
|
isSubscriptRef ? FunctionRefInfo::doubleBaseNameApply()
|
||||||
|
: FunctionRefInfo::unappliedBaseName(),
|
||||||
|
/*outerAlternatives=*/{}, keyPathLoc);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -616,3 +616,39 @@ class TestDynamicSelf {
|
|||||||
fatalError()
|
fatalError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@dynamicMemberLookup
|
||||||
|
protocol P1 {}
|
||||||
|
|
||||||
|
extension P1 {
|
||||||
|
subscript<T>(dynamicMember dynamicMemberLookup: KeyPath<TestOverloaded.S2, T>) -> T {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestOverloaded {
|
||||||
|
struct S1: P1 {
|
||||||
|
subscript(x: String) -> Int {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
func f(_ x: String) -> Int {
|
||||||
|
return self[x]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct S2: P1 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@dynamicMemberLookup
|
||||||
|
struct SingleLens<T> {
|
||||||
|
var value: T
|
||||||
|
init(_ value: T) {
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U {
|
||||||
|
value[keyPath: keyPath]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRecursiveSingleSubscript(_ x: SingleLens<SingleLens<SingleLens<SingleLens<[Int]>>>>) {
|
||||||
|
_ = x[0]
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user