@@ -1545,12 +1545,44 @@ namespace {
1545
1545
/* parsedRoot=*/ nullptr ,
1546
1546
/* parsedPath=*/ anchor,
1547
1547
/* isImplicit=*/ true );
1548
+ // Type of the keypath expression we are forming is known
1549
+ // in advance, so let's set it right away.
1550
+ keyPath->setType (keyPathTy);
1551
+ cs.cacheType (keyPath);
1548
1552
1549
1553
auto *componentLoc = cs.getConstraintLocator (
1550
1554
memberLoc,
1551
1555
LocatorPathElt::getKeyPathDynamicMember (keyPathTy->getAnyNominal ()));
1552
1556
auto overload = solution.getOverloadChoice (componentLoc);
1553
1557
1558
+ auto buildSubscriptComponent = [&](SourceLoc loc, Expr *indexExpr,
1559
+ ArrayRef<Identifier> labels) {
1560
+ // Save a reference to the component so we can do a post-pass to check
1561
+ // the Hashable conformance of the indexes.
1562
+ KeyPathSubscriptComponents.push_back ({keyPath, 0 });
1563
+ return buildKeyPathSubscriptComponent (overload, loc, indexExpr, labels,
1564
+ componentLoc);
1565
+ };
1566
+
1567
+ auto getKeyPathComponentIndex =
1568
+ [](ConstraintLocator *locator) -> unsigned {
1569
+ for (const auto &elt : locator->getPath ()) {
1570
+ if (elt.getKind () == ConstraintLocator::KeyPathComponent)
1571
+ return elt.getValue ();
1572
+ }
1573
+ llvm_unreachable (" no keypath component node" );
1574
+ };
1575
+
1576
+ // Looks like there is a chain of implicit `subscript(dynamicMember:)`
1577
+ // calls necessary to resolve a member reference.
1578
+ if (overload.choice .getKind () ==
1579
+ OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1580
+ keyPath->resolveComponents (
1581
+ ctx, buildSubscriptComponent (dotLoc, /* indexExpr=*/ nullptr ,
1582
+ ctx.Id_dynamicMember ));
1583
+ return keyPath;
1584
+ }
1585
+
1554
1586
// We can't reuse existing expression because type-check
1555
1587
// based diagnostics could hold the reference to original AST.
1556
1588
Expr *componentExpr = nullptr ;
@@ -1564,13 +1596,8 @@ namespace {
1564
1596
// of a keypath expression e.g. `\Lens<[Int]>.count` where
1565
1597
// `count` is referenced using dynamic lookup.
1566
1598
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 ()];
1599
+ auto componentIdx = getKeyPathComponentIndex (memberLoc);
1600
+ auto &origComponent = KPE->getComponents ()[componentIdx];
1574
1601
1575
1602
using ComponentKind = KeyPathExpr::Component::Kind;
1576
1603
if (origComponent.getKind () == ComponentKind::UnresolvedProperty) {
@@ -1630,12 +1657,8 @@ namespace {
1630
1657
/* implicit=*/ true , SE->getAccessSemantics ());
1631
1658
}
1632
1659
1633
- component = buildKeyPathSubscriptComponent (
1634
- overload, SE->getLoc (), SE->getIndex (), SE->getArgumentLabels (),
1635
- componentLoc);
1636
- // Save a reference to the component so we can do a post-pass to check
1637
- // the Hashable conformance of the indexes.
1638
- KeyPathSubscriptComponents.push_back ({keyPath, 0 });
1660
+ component = buildSubscriptComponent (SE->getLoc (), SE->getIndex (),
1661
+ SE->getArgumentLabels ());
1639
1662
} else {
1640
1663
return nullptr ;
1641
1664
}
@@ -1646,8 +1669,6 @@ namespace {
1646
1669
1647
1670
keyPath->setParsedPath (componentExpr);
1648
1671
keyPath->resolveComponents (ctx, {component});
1649
- keyPath->setType (keyPathTy);
1650
- cs.cacheType (keyPath);
1651
1672
return keyPath;
1652
1673
}
1653
1674
@@ -2815,12 +2836,7 @@ namespace {
2815
2836
// Figure out the expected type of the lookup parameter. We know the
2816
2837
// openedFullType will be "xType -> indexType -> resultType". Dig out
2817
2838
// its index type.
2818
- auto declTy = solution.simplifyType (overload.openedFullType );
2819
- auto subscriptTy = declTy->castTo <FunctionType>()->getResult ();
2820
- auto refFnType = subscriptTy->castTo <FunctionType>();
2821
- assert (refFnType->getParams ().size () == 1 &&
2822
- " subscript always has one arg" );
2823
- auto paramTy = refFnType->getParams ()[0 ].getPlainType ();
2839
+ auto paramTy = getTypeOfDynamicMemberIndex (overload);
2824
2840
2825
2841
Expr *argExpr = nullptr ;
2826
2842
if (overload.choice .getKind () ==
@@ -2855,6 +2871,20 @@ namespace {
2855
2871
/* isImplicit*/ false , AccessSemantics::Ordinary, overload);
2856
2872
}
2857
2873
2874
+ Type getTypeOfDynamicMemberIndex (const SelectedOverload &overload) {
2875
+ assert (overload.choice .getKind () ==
2876
+ OverloadChoiceKind::DynamicMemberLookup ||
2877
+ overload.choice .getKind () ==
2878
+ OverloadChoiceKind::KeyPathDynamicMemberLookup);
2879
+
2880
+ auto declTy = solution.simplifyType (overload.openedFullType );
2881
+ auto subscriptTy = declTy->castTo <FunctionType>()->getResult ();
2882
+ auto refFnType = subscriptTy->castTo <FunctionType>();
2883
+ assert (refFnType->getParams ().size () == 1 &&
2884
+ " subscript always has one arg" );
2885
+ return refFnType->getParams ()[0 ].getPlainType ();
2886
+ }
2887
+
2858
2888
public:
2859
2889
Expr *visitUnresolvedDotExpr (UnresolvedDotExpr *expr) {
2860
2890
return applyMemberRefExpr (expr, expr->getBase (), expr->getDotLoc (),
@@ -4599,10 +4629,9 @@ namespace {
4599
4629
4600
4630
if (overload.choice .getKind () ==
4601
4631
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4602
- auto fnType = overload.openedType ->castTo <FunctionType>();
4603
- auto keyPathTy = simplifyType (fnType->getParams ()[0 ].getPlainType ());
4632
+ auto indexType = getTypeOfDynamicMemberIndex (overload);
4604
4633
indexExpr = buildKeyPathDynamicMemberIndexExpr (
4605
- keyPathTy ->castTo <BoundGenericType>(), componentLoc, locator);
4634
+ indexType ->castTo <BoundGenericType>(), componentLoc, locator);
4606
4635
} else {
4607
4636
auto fieldName = overload.choice .getName ().getBaseIdentifier ().str ();
4608
4637
indexExpr = buildDynamicMemberLookupIndexExpr (fieldName, componentLoc,
0 commit comments