Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 30 additions & 27 deletions lib/Sema/TypeOfReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2439,38 +2439,12 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
// don't which at the moment, so let's allow its type to be l-value.
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue |
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"
// syntax, because we have to get "applicable function" constraint
// associated with index expression and re-bind it to match "member type"
// looked up by dynamically.
bool isSubscriptRef = locator->isSubscriptMemberRef();
if (isSubscriptRef) {
// Make sure that regular subscript declarations (if any) are
// preferred over key path dynamic member lookup.
Expand Down Expand Up @@ -2547,6 +2521,35 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
// fact that this a property access in the source.
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;
}
}
Expand Down
36 changes: 36 additions & 0 deletions test/Constraints/keypath_dynamic_member_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -616,3 +616,39 @@ class TestDynamicSelf {
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]
}