diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index f8d82147e149..d3073ba76683 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -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(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. @@ -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(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; } } diff --git a/test/Constraints/keypath_dynamic_member_lookup.swift b/test/Constraints/keypath_dynamic_member_lookup.swift index f92d80b316c3..0143463187d5 100644 --- a/test/Constraints/keypath_dynamic_member_lookup.swift +++ b/test/Constraints/keypath_dynamic_member_lookup.swift @@ -616,3 +616,39 @@ class TestDynamicSelf { fatalError() } } + +@dynamicMemberLookup +protocol P1 {} + +extension P1 { + subscript(dynamicMember dynamicMemberLookup: KeyPath) -> 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 { + var value: T + init(_ value: T) { + self.value = value + } + subscript(dynamicMember keyPath: KeyPath) -> U { + value[keyPath: keyPath] + } +} + +func testRecursiveSingleSubscript(_ x: SingleLens>>>) { + _ = x[0] +}