@@ -1561,15 +1561,6 @@ namespace {
1561
1561
LocatorPathElt::getKeyPathDynamicMember (keyPathTy->getAnyNominal ()));
1562
1562
auto overload = solution.getOverloadChoice (componentLoc);
1563
1563
1564
- auto buildSubscriptComponent = [&](SourceLoc loc, Expr *indexExpr,
1565
- ArrayRef<Identifier> labels) {
1566
- // Save a reference to the component so we can do a post-pass to check
1567
- // the Hashable conformance of the indexes.
1568
- KeyPathSubscriptComponents.push_back ({keyPath, 0 });
1569
- return buildKeyPathSubscriptComponent (overload, loc, indexExpr, labels,
1570
- componentLoc);
1571
- };
1572
-
1573
1564
auto getKeyPathComponentIndex =
1574
1565
[](ConstraintLocator *locator) -> unsigned {
1575
1566
for (const auto &elt : locator->getPath ()) {
@@ -1583,9 +1574,10 @@ namespace {
1583
1574
// calls necessary to resolve a member reference.
1584
1575
if (overload.choice .getKind () ==
1585
1576
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1586
- keyPath->resolveComponents (
1587
- ctx, buildSubscriptComponent (dotLoc, /* indexExpr=*/ nullptr ,
1588
- ctx.Id_dynamicMember ));
1577
+ keyPath->resolveComponents (ctx,
1578
+ buildKeyPathSubscriptComponent (
1579
+ overload, dotLoc, /* indexExpr=*/ nullptr ,
1580
+ ctx.Id_dynamicMember , componentLoc));
1589
1581
return keyPath;
1590
1582
}
1591
1583
@@ -1663,8 +1655,9 @@ namespace {
1663
1655
/* implicit=*/ true , SE->getAccessSemantics ());
1664
1656
}
1665
1657
1666
- component = buildSubscriptComponent (SE->getLoc (), SE->getIndex (),
1667
- SE->getArgumentLabels ());
1658
+ component = buildKeyPathSubscriptComponent (
1659
+ overload, SE->getLoc (), SE->getIndex (), SE->getArgumentLabels (),
1660
+ componentLoc);
1668
1661
} else {
1669
1662
return nullptr ;
1670
1663
}
@@ -4298,12 +4291,7 @@ namespace {
4298
4291
E->setMethod (method);
4299
4292
return E;
4300
4293
}
4301
-
4302
- private:
4303
- // Key path components we need to
4304
- SmallVector<std::pair<KeyPathExpr *, unsigned >, 4 >
4305
- KeyPathSubscriptComponents;
4306
- public:
4294
+
4307
4295
Expr *visitKeyPathExpr (KeyPathExpr *E) {
4308
4296
if (E->isObjC ()) {
4309
4297
cs.setType (E, cs.getType (E->getObjCStringLiteralExpr ()));
@@ -4445,10 +4433,6 @@ namespace {
4445
4433
*foundDecl, origComponent.getLoc (), origComponent.getIndexExpr (),
4446
4434
subscriptLabels, locator);
4447
4435
4448
- // Save a reference to the component so we can do a post-pass to check
4449
- // the Hashable conformance of the indexes.
4450
- KeyPathSubscriptComponents.push_back ({E, resolvedComponents.size ()});
4451
-
4452
4436
baseTy = component.getComponentType ();
4453
4437
resolvedComponents.push_back (component);
4454
4438
@@ -4624,10 +4608,13 @@ namespace {
4624
4608
// through the subscript(dynamicMember:) member, restore the
4625
4609
// openedType and origComponent to its full reference as if the user
4626
4610
// wrote out the subscript manually.
4627
- if (overload.choice .getKind () ==
4611
+ bool forDynamicLookup =
4612
+ overload.choice .getKind () ==
4628
4613
OverloadChoiceKind::DynamicMemberLookup ||
4629
4614
overload.choice .getKind () ==
4630
- OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4615
+ OverloadChoiceKind::KeyPathDynamicMemberLookup;
4616
+
4617
+ if (forDynamicLookup) {
4631
4618
overload.openedType =
4632
4619
overload.openedFullType ->castTo <AnyFunctionType>()->getResult ();
4633
4620
@@ -4656,8 +4643,48 @@ namespace {
4656
4643
/* applyExpr*/ nullptr , labels,
4657
4644
/* hasTrailingClosure*/ false , locator);
4658
4645
4659
- return KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr (
4646
+ auto component = KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr (
4660
4647
ref, newIndexExpr, labels, resolvedTy, componentLoc, {});
4648
+
4649
+ // We need to be able to hash the captured index values in order for
4650
+ // KeyPath itself to be hashable, so check that all of the subscript
4651
+ // index components are hashable and collect their conformances here.
4652
+ SmallVector<ProtocolConformanceRef, 4 > conformances;
4653
+
4654
+ auto hashable =
4655
+ cs.getASTContext ().getProtocol (KnownProtocolKind::Hashable);
4656
+
4657
+ auto equatable =
4658
+ cs.getASTContext ().getProtocol (KnownProtocolKind::Equatable);
4659
+
4660
+ auto &TC = cs.getTypeChecker ();
4661
+ auto fnType = overload.openedType ->castTo <FunctionType>();
4662
+ for (const auto ¶m : fnType->getParams ()) {
4663
+ auto indexType = simplifyType (param.getPlainType ());
4664
+ // index conformance to the Hashable protocol has been verified
4665
+ // by the solver, we just need to get it again with all of the
4666
+ // generic parameters resolved.
4667
+ auto hashableConformance =
4668
+ TC.conformsToProtocol (indexType, hashable, cs.DC ,
4669
+ (ConformanceCheckFlags::Used |
4670
+ ConformanceCheckFlags::InExpression));
4671
+ assert (hashableConformance.hasValue ());
4672
+
4673
+ // FIXME: Hashable implies Equatable, but we need to make sure the
4674
+ // Equatable conformance is forced into existence during type
4675
+ // checking so that it's available for SILGen.
4676
+ auto eqConformance =
4677
+ TC.conformsToProtocol (simplifyType (indexType), equatable, cs.DC ,
4678
+ (ConformanceCheckFlags::Used |
4679
+ ConformanceCheckFlags::InExpression));
4680
+ assert (eqConformance.hasValue ());
4681
+ (void )eqConformance;
4682
+
4683
+ conformances.push_back (*hashableConformance);
4684
+ }
4685
+
4686
+ component.setSubscriptIndexHashableConformances (conformances);
4687
+ return component;
4661
4688
}
4662
4689
4663
4690
Expr *visitKeyPathDotExpr (KeyPathDotExpr *E) {
@@ -4726,61 +4753,6 @@ namespace {
4726
4753
.fixItInsertAfter (cast->getEndLoc (), " )" );
4727
4754
}
4728
4755
4729
- // Look at key path subscript components to verify that they're hashable.
4730
- for (auto componentRef : KeyPathSubscriptComponents) {
4731
- auto &component = componentRef.first
4732
- ->getMutableComponents ()[componentRef.second ];
4733
- // We need to be able to hash the captured index values in order for
4734
- // KeyPath itself to be hashable, so check that all of the subscript
4735
- // index components are hashable and collect their conformances here.
4736
- SmallVector<ProtocolConformanceRef, 2 > hashables;
4737
- bool allIndexesHashable = true ;
4738
- ArrayRef<TupleTypeElt> indexTypes;
4739
- TupleTypeElt singleIndexTypeBuf;
4740
- if (auto tup = cs.getType (component.getIndexExpr ())
4741
- ->getAs <TupleType>()) {
4742
- indexTypes = tup->getElements ();
4743
- } else {
4744
- singleIndexTypeBuf = cs.getType (component.getIndexExpr ());
4745
- indexTypes = singleIndexTypeBuf;
4746
- }
4747
-
4748
- auto hashable =
4749
- cs.getASTContext ().getProtocol (KnownProtocolKind::Hashable);
4750
- auto equatable =
4751
- cs.getASTContext ().getProtocol (KnownProtocolKind::Equatable);
4752
- for (auto indexType : indexTypes) {
4753
- auto conformance =
4754
- cs.TC .conformsToProtocol (indexType.getType (), hashable,
4755
- cs.DC ,
4756
- (ConformanceCheckFlags::Used|
4757
- ConformanceCheckFlags::InExpression));
4758
- if (!conformance) {
4759
- cs.TC .diagnose (component.getIndexExpr ()->getLoc (),
4760
- diag::expr_keypath_subscript_index_not_hashable,
4761
- indexType.getType ());
4762
- allIndexesHashable = false ;
4763
- continue ;
4764
- }
4765
- hashables.push_back (*conformance);
4766
-
4767
- // FIXME: Hashable implies Equatable, but we need to make sure the
4768
- // Equatable conformance is forced into existence during type checking
4769
- // so that it's available for SILGen.
4770
- auto eqConformance =
4771
- cs.TC .conformsToProtocol (indexType.getType (), equatable,
4772
- cs.DC ,
4773
- (ConformanceCheckFlags::Used|
4774
- ConformanceCheckFlags::InExpression));
4775
- assert (eqConformance.hasValue ());
4776
- (void )eqConformance;
4777
- }
4778
-
4779
- if (allIndexesHashable) {
4780
- component.setSubscriptIndexHashableConformances (hashables);
4781
- }
4782
- }
4783
-
4784
4756
// Set the final types on the expression.
4785
4757
cs.setExprTypes (result);
4786
4758
}
0 commit comments