@@ -1555,31 +1555,80 @@ namespace {
15551555 // based diagnostics could hold the reference to original AST.
15561556 Expr *componentExpr = nullptr ;
15571557 auto *dotExpr = new (ctx) KeyPathDotExpr (dotLoc);
1558+
1559+ // Determines whether this index is built to be used for
1560+ // one of the existing keypath components e.g. `\Lens<[Int]>.count`
1561+ // instead of a regular expression e.g. `lens[0]`.
1562+ bool forKeyPathComponent = false ;
1563+ // Looks like keypath dynamic member lookup was used inside
1564+ // of a keypath expression e.g. `\Lens<[Int]>.count` where
1565+ // `count` is referenced using dynamic lookup.
1566+ if (auto *KPE = dyn_cast<KeyPathExpr>(anchor)) {
1567+ auto path = memberLoc->getPath ();
1568+ if (memberLoc->isSubscriptMemberRef ())
1569+ path = path.drop_back ();
1570+
1571+ auto &componentIdx = path.back ();
1572+ assert (componentIdx.getKind () == ConstraintLocator::KeyPathComponent);
1573+ auto &origComponent = KPE->getComponents ()[componentIdx.getValue ()];
1574+
1575+ using ComponentKind = KeyPathExpr::Component::Kind;
1576+ if (origComponent.getKind () == ComponentKind::UnresolvedProperty) {
1577+ anchor = new (ctx) UnresolvedDotExpr (
1578+ dotExpr, dotLoc, origComponent.getUnresolvedDeclName (),
1579+ DeclNameLoc (origComponent.getLoc ()),
1580+ /* Implicit=*/ true );
1581+ } else if (origComponent.getKind () ==
1582+ ComponentKind::UnresolvedSubscript) {
1583+ anchor = SubscriptExpr::create (
1584+ ctx, dotExpr, origComponent.getIndexExpr (), ConcreteDeclRef (),
1585+ /* implicit=*/ true , AccessSemantics::Ordinary,
1586+ [&](const Expr *expr) { return simplifyType (cs.getType (expr)); });
1587+ } else {
1588+ return nullptr ;
1589+ }
1590+
1591+ anchor->setType (simplifyType (overload.openedType ));
1592+ cs.cacheType (anchor);
1593+ forKeyPathComponent = true ;
1594+ }
1595+
15581596 if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
1559- componentExpr = new (ctx) UnresolvedDotExpr (
1560- dotExpr, dotLoc, UDE->getName (), UDE->getNameLoc (),
1561- /* Implicit=*/ true );
1597+ componentExpr =
1598+ forKeyPathComponent
1599+ ? UDE
1600+ : new (ctx) UnresolvedDotExpr (dotExpr, dotLoc, UDE->getName (),
1601+ UDE->getNameLoc (),
1602+ /* Implicit=*/ true );
15621603
15631604 component = buildKeyPathPropertyComponent (overload, UDE->getLoc (),
15641605 componentLoc);
15651606 } else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
1566- SmallVector<Expr *, 4 > arguments;
1567- if (auto *TE = dyn_cast<TupleExpr>(SE->getIndex ())) {
1568- auto args = TE->getElements ();
1569- arguments.append (args.begin (), args.end ());
1570- } else {
1571- arguments.push_back (SE->getIndex ()->getSemanticsProvidingExpr ());
1572- }
1607+ componentExpr = SE;
1608+ // If this is not for a keypath component, we have to copy
1609+ // original subscript expression because expression based
1610+ // diagnostics might have a reference to it, so it couldn't
1611+ // be modified.
1612+ if (!forKeyPathComponent) {
1613+ SmallVector<Expr *, 4 > arguments;
1614+ if (auto *TE = dyn_cast<TupleExpr>(SE->getIndex ())) {
1615+ auto args = TE->getElements ();
1616+ arguments.append (args.begin (), args.end ());
1617+ } else {
1618+ arguments.push_back (SE->getIndex ()->getSemanticsProvidingExpr ());
1619+ }
15731620
1574- Expr *trailingClosure = nullptr ;
1575- if (SE->hasTrailingClosure ())
1576- trailingClosure = arguments.back ();
1621+ Expr *trailingClosure = nullptr ;
1622+ if (SE->hasTrailingClosure ())
1623+ trailingClosure = arguments.back ();
15771624
1578- componentExpr = SubscriptExpr::create (
1579- ctx, dotExpr, SE->getStartLoc (), arguments, SE->getArgumentLabels (),
1580- SE->getArgumentLabelLocs (), SE->getEndLoc (), trailingClosure,
1581- SE->hasDecl () ? SE->getDecl () : ConcreteDeclRef (),
1582- /* implicit=*/ true , SE->getAccessSemantics ());
1625+ componentExpr = SubscriptExpr::create (
1626+ ctx, dotExpr, SE->getStartLoc (), arguments,
1627+ SE->getArgumentLabels (), SE->getArgumentLabelLocs (),
1628+ SE->getEndLoc (), trailingClosure,
1629+ SE->hasDecl () ? SE->getDecl () : ConcreteDeclRef (),
1630+ /* implicit=*/ true , SE->getAccessSemantics ());
1631+ }
15831632
15841633 component = buildKeyPathSubscriptComponent (
15851634 overload, SE->getLoc (), SE->getIndex (), SE->getArgumentLabels (),
@@ -4300,16 +4349,22 @@ namespace {
43004349 ConstraintLocator::SubscriptMember);
43014350 }
43024351
4352+ bool isDynamicMember = false ;
43034353 // If this is an unresolved link, make sure we resolved it.
43044354 if (kind == KeyPathExpr::Component::Kind::UnresolvedProperty ||
43054355 kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
43064356 foundDecl = solution.getOverloadChoiceIfAvailable (locator);
43074357 // Leave the component unresolved if the overload was not resolved.
43084358 if (foundDecl) {
4359+ isDynamicMember =
4360+ foundDecl->choice .getKind () ==
4361+ OverloadChoiceKind::DynamicMemberLookup ||
4362+ foundDecl->choice .getKind () ==
4363+ OverloadChoiceKind::KeyPathDynamicMemberLookup;
4364+
43094365 // If this was a @dynamicMemberLookup property, then we actually
43104366 // form a subscript reference, so switch the kind.
4311- if (foundDecl->choice .getKind () ==
4312- OverloadChoiceKind::DynamicMemberLookup) {
4367+ if (isDynamicMember) {
43134368 kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
43144369 }
43154370 }
@@ -4347,8 +4402,7 @@ namespace {
43474402 }
43484403
43494404 ArrayRef<Identifier> subscriptLabels;
4350- if (foundDecl->choice .getKind () !=
4351- OverloadChoiceKind::DynamicMemberLookup)
4405+ if (!isDynamicMember)
43524406 subscriptLabels = origComponent.getSubscriptLabels ();
43534407
43544408 component = buildKeyPathSubscriptComponent (
@@ -4535,18 +4589,25 @@ namespace {
45354589 // openedType and origComponent to its full reference as if the user
45364590 // wrote out the subscript manually.
45374591 if (overload.choice .getKind () ==
4538- OverloadChoiceKind::DynamicMemberLookup) {
4592+ OverloadChoiceKind::DynamicMemberLookup ||
4593+ overload.choice .getKind () ==
4594+ OverloadChoiceKind::KeyPathDynamicMemberLookup) {
45394595 overload.openedType =
45404596 overload.openedFullType ->castTo <AnyFunctionType>()->getResult ();
45414597
4542- auto &ctx = cs.TC .Context ;
4543- auto fieldName = overload.choice .getName ().getBaseIdentifier ().str ();
4598+ labels = cs.getASTContext ().Id_dynamicMember ;
45444599
4545- labels = ctx.Id_dynamicMember ;
4546- indexExpr = new (ctx) StringLiteralExpr (fieldName, componentLoc,
4547- /* implicit*/ true );
4548- (void )cs.TC .typeCheckExpression (indexExpr, dc);
4549- cs.cacheExprTypes (indexExpr);
4600+ if (overload.choice .getKind () ==
4601+ OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4602+ auto fnType = overload.openedType ->castTo <FunctionType>();
4603+ auto keyPathTy = simplifyType (fnType->getParams ()[0 ].getPlainType ());
4604+ indexExpr = buildKeyPathDynamicMemberIndexExpr (
4605+ keyPathTy->castTo <BoundGenericType>(), componentLoc, locator);
4606+ } else {
4607+ auto fieldName = overload.choice .getName ().getBaseIdentifier ().str ();
4608+ indexExpr = buildDynamicMemberLookupIndexExpr (fieldName, componentLoc,
4609+ dc, cs);
4610+ }
45504611 }
45514612
45524613 auto subscriptType =
0 commit comments