@@ -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
}
@@ -4296,12 +4289,7 @@ namespace {
4296
4289
E->setMethod (method);
4297
4290
return E;
4298
4291
}
4299
-
4300
- private:
4301
- // Key path components we need to
4302
- SmallVector<std::pair<KeyPathExpr *, unsigned >, 4 >
4303
- KeyPathSubscriptComponents;
4304
- public:
4292
+
4305
4293
Expr *visitKeyPathExpr (KeyPathExpr *E) {
4306
4294
if (E->isObjC ()) {
4307
4295
cs.setType (E, cs.getType (E->getObjCStringLiteralExpr ()));
@@ -4443,10 +4431,6 @@ namespace {
4443
4431
*foundDecl, origComponent.getLoc (), origComponent.getIndexExpr (),
4444
4432
subscriptLabels, locator);
4445
4433
4446
- // Save a reference to the component so we can do a post-pass to check
4447
- // the Hashable conformance of the indexes.
4448
- KeyPathSubscriptComponents.push_back ({E, resolvedComponents.size ()});
4449
-
4450
4434
baseTy = component.getComponentType ();
4451
4435
resolvedComponents.push_back (component);
4452
4436
@@ -4622,10 +4606,13 @@ namespace {
4622
4606
// through the subscript(dynamicMember:) member, restore the
4623
4607
// openedType and origComponent to its full reference as if the user
4624
4608
// wrote out the subscript manually.
4625
- if (overload.choice .getKind () ==
4609
+ bool forDynamicLookup =
4610
+ overload.choice .getKind () ==
4626
4611
OverloadChoiceKind::DynamicMemberLookup ||
4627
4612
overload.choice .getKind () ==
4628
- OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4613
+ OverloadChoiceKind::KeyPathDynamicMemberLookup;
4614
+
4615
+ if (forDynamicLookup) {
4629
4616
overload.openedType =
4630
4617
overload.openedFullType ->castTo <AnyFunctionType>()->getResult ();
4631
4618
@@ -4654,8 +4641,48 @@ namespace {
4654
4641
/* applyExpr*/ nullptr , labels,
4655
4642
/* hasTrailingClosure*/ false , locator);
4656
4643
4657
- return KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr (
4644
+ auto component = KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr (
4658
4645
ref, newIndexExpr, labels, resolvedTy, componentLoc, {});
4646
+
4647
+ // We need to be able to hash the captured index values in order for
4648
+ // KeyPath itself to be hashable, so check that all of the subscript
4649
+ // index components are hashable and collect their conformances here.
4650
+ SmallVector<ProtocolConformanceRef, 4 > conformances;
4651
+
4652
+ auto hashable =
4653
+ cs.getASTContext ().getProtocol (KnownProtocolKind::Hashable);
4654
+
4655
+ auto equatable =
4656
+ cs.getASTContext ().getProtocol (KnownProtocolKind::Equatable);
4657
+
4658
+ auto &TC = cs.getTypeChecker ();
4659
+ auto fnType = overload.openedType ->castTo <FunctionType>();
4660
+ for (const auto ¶m : fnType->getParams ()) {
4661
+ auto indexType = simplifyType (param.getPlainType ());
4662
+ // Index type conformance to Hashable protocol has been
4663
+ // verified by the solver, we just need to get it again
4664
+ // with all of the generic parameters resolved.
4665
+ auto hashableConformance =
4666
+ TC.conformsToProtocol (indexType, hashable, cs.DC ,
4667
+ (ConformanceCheckFlags::Used |
4668
+ ConformanceCheckFlags::InExpression));
4669
+ assert (hashableConformance.hasValue ());
4670
+
4671
+ // FIXME: Hashable implies Equatable, but we need to make sure the
4672
+ // Equatable conformance is forced into existence during type
4673
+ // checking so that it's available for SILGen.
4674
+ auto eqConformance =
4675
+ TC.conformsToProtocol (indexType, equatable, cs.DC ,
4676
+ (ConformanceCheckFlags::Used |
4677
+ ConformanceCheckFlags::InExpression));
4678
+ assert (eqConformance.hasValue ());
4679
+ (void )eqConformance;
4680
+
4681
+ conformances.push_back (*hashableConformance);
4682
+ }
4683
+
4684
+ component.setSubscriptIndexHashableConformances (conformances);
4685
+ return component;
4659
4686
}
4660
4687
4661
4688
Expr *visitKeyPathDotExpr (KeyPathDotExpr *E) {
@@ -4724,61 +4751,6 @@ namespace {
4724
4751
.fixItInsertAfter (cast->getEndLoc (), " )" );
4725
4752
}
4726
4753
4727
- // Look at key path subscript components to verify that they're hashable.
4728
- for (auto componentRef : KeyPathSubscriptComponents) {
4729
- auto &component = componentRef.first
4730
- ->getMutableComponents ()[componentRef.second ];
4731
- // We need to be able to hash the captured index values in order for
4732
- // KeyPath itself to be hashable, so check that all of the subscript
4733
- // index components are hashable and collect their conformances here.
4734
- SmallVector<ProtocolConformanceRef, 2 > hashables;
4735
- bool allIndexesHashable = true ;
4736
- ArrayRef<TupleTypeElt> indexTypes;
4737
- TupleTypeElt singleIndexTypeBuf;
4738
- if (auto tup = cs.getType (component.getIndexExpr ())
4739
- ->getAs <TupleType>()) {
4740
- indexTypes = tup->getElements ();
4741
- } else {
4742
- singleIndexTypeBuf = cs.getType (component.getIndexExpr ());
4743
- indexTypes = singleIndexTypeBuf;
4744
- }
4745
-
4746
- auto hashable =
4747
- cs.getASTContext ().getProtocol (KnownProtocolKind::Hashable);
4748
- auto equatable =
4749
- cs.getASTContext ().getProtocol (KnownProtocolKind::Equatable);
4750
- for (auto indexType : indexTypes) {
4751
- auto conformance =
4752
- cs.TC .conformsToProtocol (indexType.getType (), hashable,
4753
- cs.DC ,
4754
- (ConformanceCheckFlags::Used|
4755
- ConformanceCheckFlags::InExpression));
4756
- if (!conformance) {
4757
- cs.TC .diagnose (component.getIndexExpr ()->getLoc (),
4758
- diag::expr_keypath_subscript_index_not_hashable,
4759
- indexType.getType ());
4760
- allIndexesHashable = false ;
4761
- continue ;
4762
- }
4763
- hashables.push_back (*conformance);
4764
-
4765
- // FIXME: Hashable implies Equatable, but we need to make sure the
4766
- // Equatable conformance is forced into existence during type checking
4767
- // so that it's available for SILGen.
4768
- auto eqConformance =
4769
- cs.TC .conformsToProtocol (indexType.getType (), equatable,
4770
- cs.DC ,
4771
- (ConformanceCheckFlags::Used|
4772
- ConformanceCheckFlags::InExpression));
4773
- assert (eqConformance.hasValue ());
4774
- (void )eqConformance;
4775
- }
4776
-
4777
- if (allIndexesHashable) {
4778
- component.setSubscriptIndexHashableConformances (hashables);
4779
- }
4780
- }
4781
-
4782
4754
// Set the final types on the expression.
4783
4755
cs.setExprTypes (result);
4784
4756
}
0 commit comments