@@ -1555,31 +1555,80 @@ namespace {
1555
1555
// based diagnostics could hold the reference to original AST.
1556
1556
Expr *componentExpr = nullptr ;
1557
1557
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
+
1558
1596
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 );
1562
1603
1563
1604
component = buildKeyPathPropertyComponent (overload, UDE->getLoc (),
1564
1605
componentLoc);
1565
1606
} 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
+ }
1573
1620
1574
- Expr *trailingClosure = nullptr ;
1575
- if (SE->hasTrailingClosure ())
1576
- trailingClosure = arguments.back ();
1621
+ Expr *trailingClosure = nullptr ;
1622
+ if (SE->hasTrailingClosure ())
1623
+ trailingClosure = arguments.back ();
1577
1624
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
+ }
1583
1632
1584
1633
component = buildKeyPathSubscriptComponent (
1585
1634
overload, SE->getLoc (), SE->getIndex (), SE->getArgumentLabels (),
@@ -4300,16 +4349,22 @@ namespace {
4300
4349
ConstraintLocator::SubscriptMember);
4301
4350
}
4302
4351
4352
+ bool isDynamicMember = false ;
4303
4353
// If this is an unresolved link, make sure we resolved it.
4304
4354
if (kind == KeyPathExpr::Component::Kind::UnresolvedProperty ||
4305
4355
kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
4306
4356
foundDecl = solution.getOverloadChoiceIfAvailable (locator);
4307
4357
// Leave the component unresolved if the overload was not resolved.
4308
4358
if (foundDecl) {
4359
+ isDynamicMember =
4360
+ foundDecl->choice .getKind () ==
4361
+ OverloadChoiceKind::DynamicMemberLookup ||
4362
+ foundDecl->choice .getKind () ==
4363
+ OverloadChoiceKind::KeyPathDynamicMemberLookup;
4364
+
4309
4365
// If this was a @dynamicMemberLookup property, then we actually
4310
4366
// form a subscript reference, so switch the kind.
4311
- if (foundDecl->choice .getKind () ==
4312
- OverloadChoiceKind::DynamicMemberLookup) {
4367
+ if (isDynamicMember) {
4313
4368
kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
4314
4369
}
4315
4370
}
@@ -4347,8 +4402,7 @@ namespace {
4347
4402
}
4348
4403
4349
4404
ArrayRef<Identifier> subscriptLabels;
4350
- if (foundDecl->choice .getKind () !=
4351
- OverloadChoiceKind::DynamicMemberLookup)
4405
+ if (!isDynamicMember)
4352
4406
subscriptLabels = origComponent.getSubscriptLabels ();
4353
4407
4354
4408
component = buildKeyPathSubscriptComponent (
@@ -4535,18 +4589,25 @@ namespace {
4535
4589
// openedType and origComponent to its full reference as if the user
4536
4590
// wrote out the subscript manually.
4537
4591
if (overload.choice .getKind () ==
4538
- OverloadChoiceKind::DynamicMemberLookup) {
4592
+ OverloadChoiceKind::DynamicMemberLookup ||
4593
+ overload.choice .getKind () ==
4594
+ OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4539
4595
overload.openedType =
4540
4596
overload.openedFullType ->castTo <AnyFunctionType>()->getResult ();
4541
4597
4542
- auto &ctx = cs.TC .Context ;
4543
- auto fieldName = overload.choice .getName ().getBaseIdentifier ().str ();
4598
+ labels = cs.getASTContext ().Id_dynamicMember ;
4544
4599
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
+ }
4550
4611
}
4551
4612
4552
4613
auto subscriptType =
0 commit comments