@@ -1257,9 +1257,12 @@ namespace {
1257
1257
if (selected->choice .isDecl ()) {
1258
1258
auto locatorKind = ConstraintLocator::SubscriptMember;
1259
1259
if (selected->choice .getKind () ==
1260
- OverloadChoiceKind::DynamicMemberLookup ||
1261
- selected->choice .getKind () ==
1262
- OverloadChoiceKind::KeyPathDynamicMemberLookup)
1260
+ OverloadChoiceKind::DynamicMemberLookup)
1261
+ locatorKind = ConstraintLocator::Member;
1262
+
1263
+ if (selected->choice .getKind () ==
1264
+ OverloadChoiceKind::KeyPathDynamicMemberLookup &&
1265
+ !isa<SubscriptExpr>(locator.getAnchor ()))
1263
1266
locatorKind = ConstraintLocator::Member;
1264
1267
1265
1268
newSubscript =
@@ -1373,10 +1376,15 @@ namespace {
1373
1376
1374
1377
// Use the correct locator kind based on the subscript kind.
1375
1378
auto locatorKind = ConstraintLocator::SubscriptMember;
1376
- if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup ||
1377
- choice.getKind () == OverloadChoiceKind::KeyPathDynamicMemberLookup)
1379
+ if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup)
1378
1380
locatorKind = ConstraintLocator::Member;
1379
-
1381
+
1382
+ if (choice.getKind () == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1383
+ locatorKind = isa<SubscriptExpr>(locator.getAnchor ())
1384
+ ? ConstraintLocator::SubscriptMember
1385
+ : ConstraintLocator::Member;
1386
+ }
1387
+
1380
1388
// If we opened up an existential when performing the subscript, open
1381
1389
// the base accordingly.
1382
1390
auto knownOpened = solution.OpenedExistentialTypes .find (
@@ -1527,31 +1535,43 @@ namespace {
1527
1535
SourceLoc dotLoc,
1528
1536
ConstraintLocator *memberLoc) {
1529
1537
auto &ctx = cs.getASTContext ();
1530
- // Only properties are supported at the moment.
1531
- auto *UDE = dyn_cast<UnresolvedDotExpr>(memberLoc->getAnchor ());
1532
- if (!UDE)
1533
- return nullptr ;
1534
1538
1535
- simplifyExprType (UDE) ;
1536
- UDE-> setType (cs. getType (UDE) );
1539
+ KeyPathExpr::Component component ;
1540
+ auto *componentExpr = memberLoc-> getAnchor ( );
1537
1541
1538
- // Let's re-use existinng expression but switch its base
1539
- // to keypath special dot expression.
1540
- UDE->setBase (new (ctx) KeyPathDotExpr (dotLoc));
1542
+ simplifyExprType (componentExpr);
1543
+ componentExpr->setType (cs.getType (componentExpr));
1541
1544
1542
1545
// Now, let's create a KeyPath expression itself.
1543
1546
auto *keyPath = new (ctx) KeyPathExpr (/* backslashLoc=*/ dotLoc,
1544
1547
/* parsedRoot=*/ nullptr ,
1545
- /* parsedPath=*/ UDE ,
1548
+ /* parsedPath=*/ componentExpr ,
1546
1549
/* isImplicit=*/ true );
1547
1550
1548
- auto *propertyLoc = cs.getConstraintLocator (
1551
+ auto *componentLoc = cs.getConstraintLocator (
1549
1552
memberLoc,
1550
1553
LocatorPathElt::getKeyPathDynamicMember (keyPathTy->getAnyNominal ()));
1551
- auto overload = solution.getOverloadChoice (propertyLoc);
1552
- keyPath->resolveComponents (
1553
- ctx, {buildKeyPathPropertyComponent (overload, UDE->getLoc (),
1554
- propertyLoc)});
1554
+ auto overload = solution.getOverloadChoice (componentLoc);
1555
+
1556
+ // Let's re-use existing expression, but switch its base
1557
+ // to keypath special "dot" expression.
1558
+ if (auto *UDE = dyn_cast<UnresolvedDotExpr>(componentExpr)) {
1559
+ UDE->setBase (new (ctx) KeyPathDotExpr (dotLoc));
1560
+ component = buildKeyPathPropertyComponent (overload, UDE->getLoc (),
1561
+ componentLoc);
1562
+ } else if (auto *SE = dyn_cast<SubscriptExpr>(componentExpr)) {
1563
+ SE->setBase (new (ctx) KeyPathDotExpr (dotLoc));
1564
+ component = buildKeyPathSubscriptComponent (
1565
+ overload, SE->getLoc (), SE->getIndex (), SE->getArgumentLabels (),
1566
+ componentLoc);
1567
+ // Save a reference to the component so we can do a post-pass to check
1568
+ // the Hashable conformance of the indexes.
1569
+ KeyPathSubscriptComponents.push_back ({keyPath, 0 });
1570
+ } else {
1571
+ return nullptr ;
1572
+ }
1573
+
1574
+ keyPath->resolveComponents (ctx, {component});
1555
1575
keyPath->setType (keyPathTy);
1556
1576
cs.cacheType (keyPath);
1557
1577
return keyPath;
@@ -2627,8 +2647,7 @@ namespace {
2627
2647
AccessSemantics::Ordinary);
2628
2648
}
2629
2649
2630
- auto choiceKind = selected.choice .getKind ();
2631
- switch (choiceKind) {
2650
+ switch (selected.choice .getKind ()) {
2632
2651
case OverloadChoiceKind::DeclViaBridge: {
2633
2652
base = cs.coerceToRValue (base);
2634
2653
@@ -2702,56 +2721,65 @@ namespace {
2702
2721
2703
2722
case OverloadChoiceKind::DynamicMemberLookup:
2704
2723
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2705
- // Application of a DynamicMemberLookup result turns
2706
- // a member access of `x.foo` into x[dynamicMember: "foo"], or
2707
- // x[dynamicMember: KeyPath<T, U>]
2708
- auto &ctx = cs.getASTContext ();
2709
- auto loc = nameLoc.getStartLoc ();
2710
-
2711
- // Figure out the expected type of the lookup parameter. We know the
2712
- // openedFullType will be "xType -> indexType -> resultType". Dig out
2713
- // its index type.
2714
- auto declTy = solution.simplifyType (selected.openedFullType );
2715
- auto subscriptTy = declTy->castTo <FunctionType>()->getResult ();
2716
- auto refFnType = subscriptTy->castTo <FunctionType>();
2717
- assert (refFnType->getParams ().size () == 1 &&
2718
- " subscript always has one arg" );
2719
- auto paramTy = refFnType->getParams ()[0 ].getPlainType ();
2720
-
2721
- Expr *argExpr = nullptr ;
2722
- if (choiceKind == OverloadChoiceKind::DynamicMemberLookup) {
2723
- // Build and type check the string literal index value to the specific
2724
- // string type expected by the subscript.
2725
- auto fieldName = selected.choice .getName ().getBaseIdentifier ().str ();
2726
- argExpr = buildDynamicMemberLookupIndexExpr (fieldName, loc, dc, cs);
2727
- } else {
2728
- argExpr = buildKeyPathDynamicMemberIndexExpr (
2729
- paramTy->castTo <BoundGenericType>(), dotLoc, memberLocator);
2730
- }
2724
+ return buildDynamicMemberLookupRef (
2725
+ expr, base, dotLoc, nameLoc.getStartLoc (), selected, memberLocator);
2726
+ }
2727
+ }
2731
2728
2732
- assert (argExpr);
2729
+ llvm_unreachable (" Unhandled OverloadChoiceKind in switch." );
2730
+ }
2733
2731
2734
- // Build a tuple so that the argument has a label.
2735
- auto tupleTy =
2736
- TupleType::get ( TupleTypeElt (paramTy, ctx. Id_dynamicMember ), ctx);
2737
- Expr *index = TupleExpr::create (ctx, loc, argExpr, ctx. Id_dynamicMember ,
2738
- loc, loc, /* hasTrailingClosure */ false ,
2739
- /* implicit */ true );
2740
- index-> setType (tupleTy);
2741
- cs.cacheType (index );
2732
+ Expr * buildDynamicMemberLookupRef (Expr *expr, Expr *base, SourceLoc dotLoc,
2733
+ SourceLoc nameLoc,
2734
+ const SelectedOverload &overload,
2735
+ ConstraintLocator *memberLocator) {
2736
+ // Application of a DynamicMemberLookup result turns
2737
+ // a member access of `x.foo` into x[dynamicMember: "foo"], or
2738
+ // x[dynamicMember: KeyPath<T, U>]
2739
+ auto &ctx = cs.getASTContext ( );
2742
2740
2743
- // Build and return a subscript that uses this string as the index.
2744
- return buildSubscript (base, index, ctx.Id_dynamicMember ,
2745
- /* trailingClosure*/ false ,
2746
- cs.getConstraintLocator (expr),
2747
- /* isImplicit*/ false ,
2748
- AccessSemantics::Ordinary, selected);
2749
- }
2741
+ // Figure out the expected type of the lookup parameter. We know the
2742
+ // openedFullType will be "xType -> indexType -> resultType". Dig out
2743
+ // its index type.
2744
+ auto declTy = solution.simplifyType (overload.openedFullType );
2745
+ auto subscriptTy = declTy->castTo <FunctionType>()->getResult ();
2746
+ auto refFnType = subscriptTy->castTo <FunctionType>();
2747
+ assert (refFnType->getParams ().size () == 1 &&
2748
+ " subscript always has one arg" );
2749
+ auto paramTy = refFnType->getParams ()[0 ].getPlainType ();
2750
+
2751
+ Expr *argExpr = nullptr ;
2752
+ if (overload.choice .getKind () ==
2753
+ OverloadChoiceKind::DynamicMemberLookup) {
2754
+ // Build and type check the string literal index value to the specific
2755
+ // string type expected by the subscript.
2756
+ auto fieldName = overload.choice .getName ().getBaseIdentifier ().str ();
2757
+ argExpr = buildDynamicMemberLookupIndexExpr (fieldName, nameLoc, dc, cs);
2758
+ } else {
2759
+ argExpr = buildKeyPathDynamicMemberIndexExpr (
2760
+ paramTy->castTo <BoundGenericType>(), dotLoc, memberLocator);
2750
2761
}
2751
2762
2752
- llvm_unreachable (" Unhandled OverloadChoiceKind in switch." );
2763
+ assert (argExpr);
2764
+
2765
+ // Build a tuple so that the argument has a label.
2766
+ auto tupleTy =
2767
+ TupleType::get (TupleTypeElt (paramTy, ctx.Id_dynamicMember ), ctx);
2768
+
2769
+ auto loc = nameLoc;
2770
+ Expr *index = TupleExpr::create (ctx, loc, argExpr, ctx.Id_dynamicMember ,
2771
+ loc, loc, /* hasTrailingClosure*/ false ,
2772
+ /* implicit*/ true );
2773
+ index->setType (tupleTy);
2774
+ cs.cacheType (index);
2775
+
2776
+ // Build and return a subscript that uses this string as the index.
2777
+ return buildSubscript (
2778
+ base, index, ctx.Id_dynamicMember ,
2779
+ /* trailingClosure*/ false , cs.getConstraintLocator (expr),
2780
+ /* isImplicit*/ false , AccessSemantics::Ordinary, overload);
2753
2781
}
2754
-
2782
+
2755
2783
public:
2756
2784
Expr *visitUnresolvedDotExpr (UnresolvedDotExpr *expr) {
2757
2785
return applyMemberRefExpr (expr, expr->getBase (), expr->getDotLoc (),
@@ -2811,12 +2839,21 @@ namespace {
2811
2839
}
2812
2840
2813
2841
Expr *visitSubscriptExpr (SubscriptExpr *expr) {
2814
- return buildSubscript (expr->getBase (), expr->getIndex (),
2815
- expr->getArgumentLabels (),
2816
- expr->hasTrailingClosure (),
2817
- cs.getConstraintLocator (expr),
2818
- expr->isImplicit (),
2819
- expr->getAccessSemantics ());
2842
+ auto *memberLocator =
2843
+ cs.getConstraintLocator (expr, ConstraintLocator::SubscriptMember);
2844
+ auto overload = solution.getOverloadChoiceIfAvailable (memberLocator);
2845
+
2846
+ if (overload && overload->choice .getKind () ==
2847
+ OverloadChoiceKind::KeyPathDynamicMemberLookup) {
2848
+ return buildDynamicMemberLookupRef (
2849
+ expr, expr->getBase (), expr->getIndex ()->getStartLoc (), SourceLoc (),
2850
+ *overload, memberLocator);
2851
+ }
2852
+
2853
+ return buildSubscript (
2854
+ expr->getBase (), expr->getIndex (), expr->getArgumentLabels (),
2855
+ expr->hasTrailingClosure (), cs.getConstraintLocator (expr),
2856
+ expr->isImplicit (), expr->getAccessSemantics (), overload);
2820
2857
}
2821
2858
2822
2859
// / "Finish" an array expression by filling in the semantic expression.
0 commit comments