@@ -1257,9 +1257,12 @@ namespace {
12571257 if (selected->choice .isDecl ()) {
12581258 auto locatorKind = ConstraintLocator::SubscriptMember;
12591259 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 ()))
12631266 locatorKind = ConstraintLocator::Member;
12641267
12651268 newSubscript =
@@ -1373,10 +1376,15 @@ namespace {
13731376
13741377 // Use the correct locator kind based on the subscript kind.
13751378 auto locatorKind = ConstraintLocator::SubscriptMember;
1376- if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup ||
1377- choice.getKind () == OverloadChoiceKind::KeyPathDynamicMemberLookup)
1379+ if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup)
13781380 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+
13801388 // If we opened up an existential when performing the subscript, open
13811389 // the base accordingly.
13821390 auto knownOpened = solution.OpenedExistentialTypes .find (
@@ -1527,31 +1535,43 @@ namespace {
15271535 SourceLoc dotLoc,
15281536 ConstraintLocator *memberLoc) {
15291537 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 ;
15341538
1535- simplifyExprType (UDE) ;
1536- UDE-> setType (cs. getType (UDE) );
1539+ KeyPathExpr::Component component ;
1540+ auto *componentExpr = memberLoc-> getAnchor ( );
15371541
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));
15411544
15421545 // Now, let's create a KeyPath expression itself.
15431546 auto *keyPath = new (ctx) KeyPathExpr (/* backslashLoc=*/ dotLoc,
15441547 /* parsedRoot=*/ nullptr ,
1545- /* parsedPath=*/ UDE ,
1548+ /* parsedPath=*/ componentExpr ,
15461549 /* isImplicit=*/ true );
15471550
1548- auto *propertyLoc = cs.getConstraintLocator (
1551+ auto *componentLoc = cs.getConstraintLocator (
15491552 memberLoc,
15501553 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});
15551575 keyPath->setType (keyPathTy);
15561576 cs.cacheType (keyPath);
15571577 return keyPath;
@@ -2627,8 +2647,7 @@ namespace {
26272647 AccessSemantics::Ordinary);
26282648 }
26292649
2630- auto choiceKind = selected.choice .getKind ();
2631- switch (choiceKind) {
2650+ switch (selected.choice .getKind ()) {
26322651 case OverloadChoiceKind::DeclViaBridge: {
26332652 base = cs.coerceToRValue (base);
26342653
@@ -2702,56 +2721,65 @@ namespace {
27022721
27032722 case OverloadChoiceKind::DynamicMemberLookup:
27042723 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+ }
27312728
2732- assert (argExpr);
2729+ llvm_unreachable (" Unhandled OverloadChoiceKind in switch." );
2730+ }
27332731
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 ( );
27422740
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);
27502761 }
27512762
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);
27532781 }
2754-
2782+
27552783 public:
27562784 Expr *visitUnresolvedDotExpr (UnresolvedDotExpr *expr) {
27572785 return applyMemberRefExpr (expr, expr->getBase (), expr->getDotLoc (),
@@ -2811,12 +2839,21 @@ namespace {
28112839 }
28122840
28132841 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);
28202857 }
28212858
28222859 // / "Finish" an array expression by filling in the semantic expression.
0 commit comments