@@ -401,6 +401,29 @@ diagnoseInvalidDynamicConstructorReferences(ConstraintSystem &cs,
401
401
return true ;
402
402
}
403
403
404
+ // / Form a type checked expression for the index of a @dynamicMemberLookup
405
+ // / subscript index expression. This will have tuple type of (dynamicMember:T).
406
+ static Expr *getDMLIndexExpr (StringRef name, Type ty, SourceLoc loc,
407
+ DeclContext *dc, ConstraintSystem &cs) {
408
+ auto &ctx = cs.TC .Context ;
409
+
410
+ // Build and type check the string literal index value to the specific
411
+ // string type expected by the subscript.
412
+ Expr *nameExpr = new (ctx)
413
+ StringLiteralExpr (name, loc, /* implicit*/ true );
414
+
415
+
416
+ // Build a tuple so that argument has a label.
417
+ Expr *tuple = TupleExpr::create (ctx, loc, nameExpr, ctx.Id_dynamicMember , loc,
418
+ loc, /* hasTrailingClosure*/ false ,
419
+ /* implicit*/ true );
420
+ (void )cs.TC .typeCheckExpression (tuple, dc, TypeLoc::withoutLoc (ty),
421
+ CTP_CallArgument);
422
+ cs.cacheExprTypes (tuple);
423
+ return tuple;
424
+ }
425
+
426
+
404
427
namespace {
405
428
406
429
// / \brief Rewrites an expression by applying the solution of a constraint
@@ -1370,13 +1393,15 @@ namespace {
1370
1393
ArrayRef<Identifier> argLabels,
1371
1394
bool hasTrailingClosure,
1372
1395
ConstraintLocatorBuilder locator, bool isImplicit,
1373
- AccessSemantics semantics) {
1396
+ AccessSemantics semantics,
1397
+ Optional<SelectedOverload> selected = None) {
1374
1398
1375
1399
// Determine the declaration selected for this subscript operation.
1376
- auto selected = getOverloadChoiceIfAvailable (
1377
- cs.getConstraintLocator (
1378
- locator.withPathElement (
1379
- ConstraintLocator::SubscriptMember)));
1400
+ if (!selected)
1401
+ selected = getOverloadChoiceIfAvailable (
1402
+ cs.getConstraintLocator (
1403
+ locator.withPathElement (
1404
+ ConstraintLocator::SubscriptMember)));
1380
1405
1381
1406
// Handles situation where there was a solution available but it didn't
1382
1407
// have a proper overload selected from subscript call, might be because
@@ -1418,10 +1443,16 @@ namespace {
1418
1443
}
1419
1444
}
1420
1445
1421
- if (selected->choice .isDecl ())
1446
+ if (selected->choice .isDecl ()) {
1447
+ auto locatorKind = ConstraintLocator::SubscriptMember;
1448
+ if (selected->choice .getKind () ==
1449
+ OverloadChoiceKind::DynamicMemberLookup)
1450
+ locatorKind = ConstraintLocator::Member;
1451
+
1422
1452
newSubscript = forceUnwrapIfExpected (
1423
1453
newSubscript, selected->choice .getDecl (),
1424
- locator.withPathElement (ConstraintLocator::SubscriptMember));
1454
+ locator.withPathElement (locatorKind));
1455
+ }
1425
1456
1426
1457
return newSubscript;
1427
1458
}
@@ -1528,30 +1559,45 @@ namespace {
1528
1559
// Check whether the base is 'super'.
1529
1560
bool isSuper = base->isSuperExpr ();
1530
1561
1531
- // Figure out the index and result types.
1532
- auto subscriptTy = simplifyType (selected.openedType );
1533
- auto subscriptFnTy = subscriptTy->castTo <AnyFunctionType>();
1534
- auto resultTy = subscriptFnTy->getResult ();
1535
-
1562
+ // Use the correct kind of locator depending on how this subscript came
1563
+ // to be.
1564
+ auto locatorKind = ConstraintLocator::SubscriptMember;
1565
+ if (choice.getKind () == OverloadChoiceKind::DynamicMemberLookup)
1566
+ locatorKind = ConstraintLocator::Member;
1567
+
1536
1568
// If we opened up an existential when performing the subscript, open
1537
1569
// the base accordingly.
1538
1570
auto knownOpened = solution.OpenedExistentialTypes .find (
1539
1571
getConstraintSystem ().getConstraintLocator (
1540
- locator.withPathElement (
1541
- ConstraintLocator::SubscriptMember)));
1572
+ locator.withPathElement (locatorKind)));
1542
1573
if (knownOpened != solution.OpenedExistentialTypes .end ()) {
1543
1574
base = openExistentialReference (base, knownOpened->second , subscript);
1544
1575
baseTy = knownOpened->second ;
1545
1576
}
1577
+
1578
+ // Figure out the index and result types.
1579
+ Type resultTy;
1580
+ if (choice.getKind () != OverloadChoiceKind::DynamicMemberLookup) {
1581
+ auto subscriptTy = simplifyType (selected.openedType );
1582
+ auto *subscriptFnTy = subscriptTy->castTo <FunctionType>();
1583
+ resultTy = subscriptFnTy->getResult ();
1584
+
1585
+ // Coerce the index argument.
1586
+ index = coerceCallArguments (index, subscriptFnTy, nullptr ,
1587
+ argLabels, hasTrailingClosure,
1588
+ locator.withPathElement (
1589
+ ConstraintLocator::SubscriptIndex));
1590
+ if (!index)
1591
+ return nullptr ;
1546
1592
1547
- // Coerce the index argument.
1548
- index = coerceCallArguments (index, subscriptFnTy, nullptr ,
1549
- argLabels, hasTrailingClosure,
1550
- locator. withPathElement (
1551
- ConstraintLocator::SubscriptIndex));
1552
- if (!index)
1553
- return nullptr ;
1554
-
1593
+ } else {
1594
+ // If this is a @dynamicMemberLookup, then the type of the selection is
1595
+ // actually the property/result type. That's fine though, and we
1596
+ // already have the index type adjusted to the correct type expected by
1597
+ // the subscript.
1598
+ resultTy = simplifyType (selected. openedType );
1599
+ }
1600
+
1555
1601
auto getType = [&](const Expr *E) -> Type {
1556
1602
return cs.getType (E);
1557
1603
};
@@ -1562,7 +1608,7 @@ namespace {
1562
1608
SmallVector<Substitution, 4 > substitutions;
1563
1609
solution.computeSubstitutions (
1564
1610
subscript->getInnermostDeclContext ()->getGenericSignatureOfContext (),
1565
- locator.withPathElement (ConstraintLocator::SubscriptMember ),
1611
+ locator.withPathElement (locatorKind ),
1566
1612
substitutions);
1567
1613
ConcreteDeclRef subscriptRef (tc.Context , subscript, substitutions);
1568
1614
@@ -2737,23 +2783,54 @@ namespace {
2737
2783
// before taking a single element.
2738
2784
auto baseTy = cs.getType (base);
2739
2785
if (!toType->hasLValueType () && baseTy->hasLValueType ())
2740
- base = coerceToType (base, baseTy->getRValueType (), cs.getConstraintLocator (base));
2786
+ base = coerceToType (base, baseTy->getRValueType (),
2787
+ cs.getConstraintLocator (base));
2741
2788
2742
2789
return cs.cacheType (new (cs.getASTContext ())
2743
2790
TupleElementExpr (base, dotLoc,
2744
2791
selected.choice .getTupleIndex (),
2745
2792
nameLoc.getBaseNameLoc (), toType));
2746
2793
}
2747
2794
2748
- case OverloadChoiceKind::BaseType: {
2795
+ case OverloadChoiceKind::BaseType:
2749
2796
return base;
2750
- }
2751
2797
2752
2798
case OverloadChoiceKind::KeyPathApplication:
2753
2799
llvm_unreachable (" should only happen in a subscript" );
2754
- }
2755
-
2756
- llvm_unreachable (" Unhandled OverloadChoiceKind in switch." );
2800
+
2801
+ case OverloadChoiceKind::DynamicMemberLookup: {
2802
+ // Application of a DynamicMemberLookup result turns a member access of
2803
+ // x.foo into x[dynamicMember: "foo"].
2804
+ auto &ctx = cs.getASTContext ();
2805
+ auto loc = nameLoc.getStartLoc ();
2806
+
2807
+ // Figure out the expected type of the string. We know the
2808
+ // openedFullType will be "xType -> indexType -> resultType". Dig out
2809
+ // its index type.
2810
+ auto declTy = solution.simplifyType (selected.openedFullType );
2811
+ auto subscriptTy = declTy->castTo <FunctionType>()->getResult ();
2812
+ auto refFnType = subscriptTy->castTo <FunctionType>();
2813
+ assert (refFnType->getParams ().size () == 1 &&
2814
+ " subscript always has one arg" );
2815
+ auto stringType = refFnType->getParams ()[0 ].getPlainType ();
2816
+ auto tupleTy = TupleType::get (TupleTypeElt (stringType,
2817
+ ctx.Id_dynamicMember ), ctx);
2818
+
2819
+ // Build and type check the string literal index value to the specific
2820
+ // string type expected by the subscript.
2821
+ auto fieldName = selected.choice .getName ().getBaseIdentifier ().str ();
2822
+ auto index = getDMLIndexExpr (fieldName, tupleTy, loc, dc, cs);
2823
+
2824
+ // Build and return a subscript that uses this string as the index.
2825
+ return buildSubscript (base, index, ctx.Id_dynamicMember ,
2826
+ /* trailingClosure*/ false ,
2827
+ cs.getConstraintLocator (expr),
2828
+ /* isImplicit*/ false ,
2829
+ AccessSemantics::Ordinary, selected);
2830
+ }
2831
+ }
2832
+
2833
+ llvm_unreachable (" Unhandled OverloadChoiceKind in switch." );
2757
2834
}
2758
2835
2759
2836
public:
@@ -4154,7 +4231,7 @@ namespace {
4154
4231
Type leafTy = keyPathTy->getGenericArgs ()[1 ];
4155
4232
4156
4233
for (unsigned i : indices (E->getComponents ())) {
4157
- auto &origComponent = E->getComponents ()[i];
4234
+ auto &origComponent = E->getMutableComponents ()[i];
4158
4235
4159
4236
// If there were unresolved types, we may end up with a null base for
4160
4237
// following components.
@@ -4181,17 +4258,36 @@ namespace {
4181
4258
return objectTy;
4182
4259
};
4183
4260
4184
- KeyPathExpr::Component component ;
4185
- switch ( auto kind = origComponent. getKind ()) {
4186
- case KeyPathExpr::Component::Kind::UnresolvedProperty: {
4187
- auto locator = cs.getConstraintLocator (E,
4261
+ auto kind = origComponent. getKind () ;
4262
+ Optional<SelectedOverload> foundDecl;
4263
+
4264
+ auto locator = cs.getConstraintLocator (E,
4188
4265
ConstraintLocator::PathElement::getKeyPathComponent (i));
4189
- auto foundDecl = getOverloadChoiceIfAvailable (locator);
4266
+
4267
+ // If this is an unresolved link, make sure we resolved it.
4268
+ if (kind == KeyPathExpr::Component::Kind::UnresolvedProperty ||
4269
+ kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
4270
+ foundDecl = getOverloadChoiceIfAvailable (locator);
4190
4271
// Leave the component unresolved if the overload was not resolved.
4272
+ if (foundDecl) {
4273
+ // If this was a @dynamicMemberLookup property, then we actually
4274
+ // form a subscript reference, so switch the kind.
4275
+ if (foundDecl->choice .getKind ()
4276
+ == OverloadChoiceKind::DynamicMemberLookup) {
4277
+ kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
4278
+ }
4279
+ }
4280
+ }
4281
+
4282
+ KeyPathExpr::Component component;
4283
+ switch (kind) {
4284
+ case KeyPathExpr::Component::Kind::UnresolvedProperty: {
4285
+ // If we couldn't resolve the component, leave it alone.
4191
4286
if (!foundDecl) {
4192
4287
component = origComponent;
4193
4288
break ;
4194
4289
}
4290
+
4195
4291
auto property = foundDecl->choice .getDecl ();
4196
4292
4197
4293
// Key paths can only refer to properties currently.
@@ -4231,6 +4327,7 @@ namespace {
4231
4327
resolvedTy = simplifyType (resolvedTy);
4232
4328
4233
4329
auto ref = ConcreteDeclRef (cs.getASTContext (), property, subs);
4330
+
4234
4331
component = KeyPathExpr::Component::forProperty (ref,
4235
4332
resolvedTy,
4236
4333
origComponent.getLoc ());
@@ -4248,14 +4345,12 @@ namespace {
4248
4345
break ;
4249
4346
}
4250
4347
case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
4251
- auto locator = cs.getConstraintLocator (E,
4252
- ConstraintLocator::PathElement::getKeyPathComponent (i));
4253
- auto foundDecl = getOverloadChoiceIfAvailable (locator);
4254
4348
// Leave the component unresolved if the overload was not resolved.
4255
4349
if (!foundDecl) {
4256
4350
component = origComponent;
4257
4351
break ;
4258
4352
}
4353
+
4259
4354
auto subscript = cast<SubscriptDecl>(foundDecl->choice .getDecl ());
4260
4355
if (subscript->isGetterMutating ()) {
4261
4356
cs.TC .diagnose (origComponent.getLoc (),
@@ -4267,18 +4362,38 @@ namespace {
4267
4362
4268
4363
auto dc = subscript->getInnermostDeclContext ();
4269
4364
SmallVector<Substitution, 4 > subs;
4270
- SubstitutionMap subMap;
4271
4365
auto indexType = subscript->getIndicesInterfaceType ();
4272
4366
4273
4367
if (auto sig = dc->getGenericSignatureOfContext ()) {
4274
4368
// Compute substitutions to refer to the member.
4275
4369
solution.computeSubstitutions (sig, locator, subs);
4276
- subMap = sig->getSubstitutionMap (subs);
4277
- indexType = indexType.subst (subMap);
4370
+ indexType = indexType.subst (sig->getSubstitutionMap (subs));
4371
+ }
4372
+
4373
+ // If this is a @dynamicMemberLookup reference to resolve a property
4374
+ // through the subscript(dynamicMember:) member, restore the
4375
+ // openedType and origComponent to its full reference as if the user
4376
+ // wrote out the subscript manually.
4377
+ if (foundDecl->choice .getKind ()
4378
+ == OverloadChoiceKind::DynamicMemberLookup) {
4379
+ foundDecl->openedType = foundDecl->openedFullType
4380
+ ->castTo <AnyFunctionType>()->getResult ();
4381
+
4382
+ auto &ctx = cs.TC .Context ;
4383
+ auto loc = origComponent.getLoc ();
4384
+ auto fieldName =
4385
+ foundDecl->choice .getName ().getBaseIdentifier ().str ();
4386
+ auto index = getDMLIndexExpr (fieldName, indexType, loc, dc, cs);
4387
+
4388
+ origComponent = KeyPathExpr::Component::
4389
+ forUnresolvedSubscript (ctx, loc, index, {}, loc, loc,
4390
+ /* trailingClosure*/ nullptr );
4391
+ cs.setType (origComponent.getIndexExpr (), index->getType ());
4278
4392
}
4279
4393
4280
4394
auto resolvedTy = foundDecl->openedType ->castTo <AnyFunctionType>()
4281
4395
->getResult ();
4396
+
4282
4397
resolvedTy = simplifyType (resolvedTy);
4283
4398
4284
4399
auto ref = ConcreteDeclRef (cs.getASTContext (), subscript, subs);
@@ -6406,7 +6521,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
6406
6521
// coercion.
6407
6522
if (auto fromLValue = fromType->getAs <LValueType>()) {
6408
6523
if (auto *toIO = toType->getAs <InOutType>()) {
6409
- // In an 'inout' operator like "++i ", the operand is converted from
6524
+ // In an 'inout' operator like "i += 1 ", the operand is converted from
6410
6525
// an implicit lvalue to an inout argument.
6411
6526
assert (toIO->getObjectType ()->isEqual (fromLValue->getObjectType ()));
6412
6527
cs.propagateLValueAccessKind (expr, AccessKind::ReadWrite);
@@ -8042,7 +8157,8 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
8042
8157
}
8043
8158
8044
8159
Expr *
8045
- Solution::convertBooleanTypeToBuiltinI1 (Expr *expr, ConstraintLocator *locator) const {
8160
+ Solution::convertBooleanTypeToBuiltinI1 (Expr *expr,
8161
+ ConstraintLocator *locator) const {
8046
8162
auto &cs = getConstraintSystem ();
8047
8163
8048
8164
// Load lvalues here.
0 commit comments