@@ -323,27 +323,18 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
323
323
// / Form a type checked expression for the index of a @dynamicMemberLookup
324
324
// / subscript index parameter.
325
325
// / The index expression will have a tuple type of `(dynamicMember: T)`.
326
- static Expr *buildDynamicMemberLookupIndexExpr (StringRef name, Type ty ,
327
- SourceLoc loc, DeclContext *dc,
326
+ static Expr *buildDynamicMemberLookupIndexExpr (StringRef name, SourceLoc loc ,
327
+ DeclContext *dc,
328
328
ConstraintSystem &cs) {
329
329
auto &ctx = cs.TC .Context ;
330
-
331
330
// Build and type check the string literal index value to the specific
332
331
// string type expected by the subscript.
333
332
Expr *nameExpr = new (ctx) StringLiteralExpr (name, loc, /* implicit*/ true );
334
333
(void )cs.TC .typeCheckExpression (nameExpr, dc);
335
334
cs.cacheExprTypes (nameExpr);
336
-
337
- // Build a tuple so that the argument has a label.
338
- Expr *tuple = TupleExpr::create (ctx, loc, nameExpr, ctx.Id_dynamicMember ,
339
- loc, loc, /* hasTrailingClosure*/ false ,
340
- /* implicit*/ true );
341
- cs.setType (tuple, ty);
342
- tuple->setType (ty);
343
- return tuple;
335
+ return nameExpr;
344
336
}
345
337
346
-
347
338
namespace {
348
339
349
340
// / Rewrites an expression by applying the solution of a constraint
@@ -1380,7 +1371,8 @@ namespace {
1380
1371
1381
1372
// Use the correct locator kind based on the subscript kind.
1382
1373
auto locatorKind = ConstraintLocator::SubscriptMember;
1383
- if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup)
1374
+ if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup ||
1375
+ choice.getKind () == OverloadChoiceKind::KeyPathDynamicMemberLookup)
1384
1376
locatorKind = ConstraintLocator::Member;
1385
1377
1386
1378
// If we opened up an existential when performing the subscript, open
@@ -1395,7 +1387,8 @@ namespace {
1395
1387
1396
1388
// Figure out the index and result types.
1397
1389
Type resultTy;
1398
- if (choice.getKind () != OverloadChoiceKind::DynamicMemberLookup) {
1390
+ if (choice.getKind () != OverloadChoiceKind::DynamicMemberLookup &&
1391
+ choice.getKind () != OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1399
1392
auto subscriptTy = simplifyType (selected.openedType );
1400
1393
auto *subscriptFnTy = subscriptTy->castTo <FunctionType>();
1401
1394
resultTy = subscriptFnTy->getResult ();
@@ -1415,7 +1408,7 @@ namespace {
1415
1408
// the subscript.
1416
1409
resultTy = simplifyType (selected.openedType );
1417
1410
}
1418
-
1411
+
1419
1412
auto getType = [&](const Expr *E) -> Type {
1420
1413
return cs.getType (E);
1421
1414
};
@@ -1522,6 +1515,20 @@ namespace {
1522
1515
return ctorRef;
1523
1516
}
1524
1517
1518
+ Expr *buildKeyPathDynamicMemberIndexExpr (ConstraintLocator *memberLoc) {
1519
+ auto arg = solution.DynamicMemberArguments .find (memberLoc);
1520
+ assert (arg != solution.DynamicMemberArguments .end () &&
1521
+ " cannot find argument for keypath dynamic member lookup" );
1522
+
1523
+ auto *keyPath = arg->getSecond ();
1524
+ keyPath->forEachChildExpr ([&](Expr *childExpr) -> Expr * {
1525
+ simplifyExprType (childExpr);
1526
+ return childExpr;
1527
+ });
1528
+
1529
+ return visitKeyPathExpr (keyPath);
1530
+ }
1531
+
1525
1532
// / Bridge the given value (which is an error type) to NSError.
1526
1533
Expr *bridgeErrorToObjectiveC (Expr *value) {
1527
1534
auto &tc = cs.getTypeChecker ();
@@ -2592,7 +2599,8 @@ namespace {
2592
2599
AccessSemantics::Ordinary);
2593
2600
}
2594
2601
2595
- switch (selected.choice .getKind ()) {
2602
+ auto choiceKind = selected.choice .getKind ();
2603
+ switch (choiceKind) {
2596
2604
case OverloadChoiceKind::DeclViaBridge: {
2597
2605
base = cs.coerceToRValue (base);
2598
2606
@@ -2663,30 +2671,45 @@ namespace {
2663
2671
2664
2672
case OverloadChoiceKind::KeyPathApplication:
2665
2673
llvm_unreachable (" should only happen in a subscript" );
2666
-
2667
- case OverloadChoiceKind::DynamicMemberLookup: {
2668
- // Application of a DynamicMemberLookup result turns a member access of
2669
- // x.foo into x[dynamicMember: "foo"].
2674
+
2675
+ case OverloadChoiceKind::DynamicMemberLookup:
2676
+ case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2677
+ // Application of a DynamicMemberLookup result turns
2678
+ // a member access of `x.foo` into x[dynamicMember: "foo"], or
2679
+ // x[dynamicMember: KeyPath<T, U>]
2670
2680
auto &ctx = cs.getASTContext ();
2671
2681
auto loc = nameLoc.getStartLoc ();
2672
-
2673
- // Figure out the expected type of the string. We know the
2682
+
2683
+ // Figure out the expected type of the lookup parameter. We know the
2674
2684
// openedFullType will be "xType -> indexType -> resultType". Dig out
2675
2685
// its index type.
2676
2686
auto declTy = solution.simplifyType (selected.openedFullType );
2677
2687
auto subscriptTy = declTy->castTo <FunctionType>()->getResult ();
2678
2688
auto refFnType = subscriptTy->castTo <FunctionType>();
2679
2689
assert (refFnType->getParams ().size () == 1 &&
2680
2690
" subscript always has one arg" );
2681
- auto stringType = refFnType->getParams ()[0 ].getPlainType ();
2682
- auto tupleTy = TupleType::get (TupleTypeElt (stringType,
2683
- ctx.Id_dynamicMember ), ctx);
2691
+ auto paramTy = refFnType->getParams ()[0 ].getPlainType ();
2692
+
2693
+ Expr *argExpr = nullptr ;
2694
+ if (choiceKind == OverloadChoiceKind::DynamicMemberLookup) {
2695
+ // Build and type check the string literal index value to the specific
2696
+ // string type expected by the subscript.
2697
+ auto fieldName = selected.choice .getName ().getBaseIdentifier ().str ();
2698
+ argExpr = buildDynamicMemberLookupIndexExpr (fieldName, loc, dc, cs);
2699
+ } else {
2700
+ argExpr = buildKeyPathDynamicMemberIndexExpr (memberLocator);
2701
+ }
2702
+
2703
+ assert (argExpr);
2684
2704
2685
- // Build and type check the string literal index value to the specific
2686
- // string type expected by the subscript.
2687
- auto fieldName = selected.choice .getName ().getBaseIdentifier ().str ();
2688
- auto index =
2689
- buildDynamicMemberLookupIndexExpr (fieldName, tupleTy, loc, dc, cs);
2705
+ // Build a tuple so that the argument has a label.
2706
+ auto tupleTy =
2707
+ TupleType::get (TupleTypeElt (paramTy, ctx.Id_dynamicMember ), ctx);
2708
+ Expr *index = TupleExpr::create (ctx, loc, argExpr, ctx.Id_dynamicMember ,
2709
+ loc, loc, /* hasTrailingClosure*/ false ,
2710
+ /* implicit*/ true );
2711
+ index->setType (tupleTy);
2712
+ cs.cacheType (index);
2690
2713
2691
2714
// Build and return a subscript that uses this string as the index.
2692
2715
return buildSubscript (base, index, ctx.Id_dynamicMember ,
@@ -2695,10 +2718,6 @@ namespace {
2695
2718
/* isImplicit*/ false ,
2696
2719
AccessSemantics::Ordinary, selected);
2697
2720
}
2698
-
2699
- case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2700
- break ;
2701
- }
2702
2721
}
2703
2722
2704
2723
llvm_unreachable (" Unhandled OverloadChoiceKind in switch." );
@@ -4109,6 +4128,10 @@ namespace {
4109
4128
KeyPathSubscriptComponents;
4110
4129
public:
4111
4130
Expr *visitKeyPathExpr (KeyPathExpr *E) {
4131
+ return visitKeyPathExpr (E, cs.getConstraintLocator (E));
4132
+ }
4133
+
4134
+ Expr *visitKeyPathExpr (KeyPathExpr *E, ConstraintLocator *baseLocator) {
4112
4135
if (E->isObjC ()) {
4113
4136
cs.setType (E, cs.getType (E->getObjCStringLiteralExpr ()));
4114
4137
return E;
@@ -4181,9 +4204,9 @@ namespace {
4181
4204
auto kind = origComponent.getKind ();
4182
4205
Optional<SelectedOverload> foundDecl;
4183
4206
4184
- auto locator =
4185
- cs. getConstraintLocator (E ,
4186
- ConstraintLocator::PathElement::getKeyPathComponent (i));
4207
+ auto locator = cs. getConstraintLocator (
4208
+ baseLocator ,
4209
+ ConstraintLocator::PathElement::getKeyPathComponent (i));
4187
4210
if (kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
4188
4211
locator =
4189
4212
cs.getConstraintLocator (locator,
@@ -4199,9 +4222,7 @@ namespace {
4199
4222
// If this was a @dynamicMemberLookup property, then we actually
4200
4223
// form a subscript reference, so switch the kind.
4201
4224
if (foundDecl->choice .getKind () ==
4202
- OverloadChoiceKind::DynamicMemberLookup ||
4203
- foundDecl->choice .getKind () ==
4204
- OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4225
+ OverloadChoiceKind::DynamicMemberLookup) {
4205
4226
kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
4206
4227
}
4207
4228
}
0 commit comments