@@ -3702,6 +3702,96 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
3702
3702
auto baseTy = rootTy;
3703
3703
SmallVector<SILValue, 4 > operands;
3704
3704
3705
+ auto lowerSubscriptIndices =
3706
+ [this , &operands, &needsGenericContext, baseTy, E]
3707
+ (const KeyPathExpr::Component &component) ->
3708
+ SmallVector<KeyPathPatternComponent::Index, 4 > {
3709
+ // Capturing an index value dependent on the generic context means we
3710
+ // need the generic context captured in the key path.
3711
+ needsGenericContext |=
3712
+ component.getIndexExpr ()->getType ()->hasArchetype ()
3713
+ | baseTy->hasTypeParameter ();
3714
+
3715
+ // Evaluate the index arguments.
3716
+ SmallVector<RValue, 2 > indexValues;
3717
+ auto indexResult = visit (component.getIndexExpr (), SGFContext ());
3718
+ if (isa<TupleType>(indexResult.getType ())) {
3719
+ std::move (indexResult).extractElements (indexValues);
3720
+ } else {
3721
+ indexValues.push_back (std::move (indexResult));
3722
+ }
3723
+
3724
+ SmallVector<KeyPathPatternComponent::Index, 4 > indexPatterns;
3725
+ for (unsigned i : indices (indexValues)) {
3726
+ auto hashable = component.getSubscriptIndexHashableConformances ()[i];
3727
+ assert (hashable.isAbstract () ||
3728
+ hashable.getConcrete ()->getType ()->isEqual (indexValues[i].getType ()));
3729
+ auto &value = indexValues[i];
3730
+
3731
+ auto indexTy = value.getType ()->mapTypeOutOfContext ()->getCanonicalType ();
3732
+ auto indexLoweredTy = SGF.getLoweredType (value.getType ());
3733
+ indexLoweredTy = SILType::getPrimitiveType (
3734
+ indexLoweredTy.getSwiftRValueType ()->mapTypeOutOfContext ()
3735
+ ->getCanonicalType (),
3736
+ indexLoweredTy.getCategory ());
3737
+ indexPatterns.push_back ({(unsigned )operands.size (),
3738
+ indexTy, indexLoweredTy,
3739
+ hashable});
3740
+ operands.push_back (
3741
+ std::move (indexValues[i]).forwardAsSingleValue (SGF, E));
3742
+ }
3743
+ return indexPatterns;
3744
+ };
3745
+
3746
+ // / Returns true if a key path component for the given property or
3747
+ // / subscript should be externally referenced.
3748
+ auto shouldUseExternalKeyPathComponent =
3749
+ [&](AbstractStorageDecl *storage) -> bool {
3750
+ return SGF.getASTContext ().LangOpts .EnableKeyPathResilience
3751
+ && storage->getModuleContext () != SGF.SGM .SwiftModule ;
3752
+ };
3753
+
3754
+ // / Build an external key path component referencing a property or subscript
3755
+ // / from another module.
3756
+ auto makeExternalKeyPathComponent =
3757
+ [&](const KeyPathExpr::Component &component,
3758
+ CanType ty) -> KeyPathPatternComponent {
3759
+ SmallVector<KeyPathPatternComponent::Index, 4 > indices;
3760
+ SubstitutionList subs = component.getDeclRef ().getSubstitutions ();
3761
+
3762
+ // Map the substitutions out of context.
3763
+ if (!subs.empty ()) {
3764
+ // If any of the substitutions involve local archetypes, then the
3765
+ // key path pattern needs to capture the generic context, and we need
3766
+ // to map the pattern substitutions out of this context.
3767
+ if (std::any_of (subs.begin (), subs.end (),
3768
+ [](const Substitution &s) -> bool {
3769
+ return s.getReplacement ()->hasArchetype ();
3770
+ })) {
3771
+ needsGenericContext = true ;
3772
+ auto sig = component.getDeclRef ().getDecl ()
3773
+ ->getInnermostDeclContext ()
3774
+ ->getGenericSignatureOfContext ();
3775
+ auto subMap = sig
3776
+ ->getSubstitutionMap (component.getDeclRef ().getSubstitutions ());
3777
+ subMap = subMap.mapReplacementTypesOutOfContext ();
3778
+ SmallVector<Substitution, 4 > subsBuf;
3779
+
3780
+ sig->getSubstitutions (subMap, subsBuf);
3781
+
3782
+ subs = SGF.getASTContext ().AllocateCopy (subsBuf);
3783
+ }
3784
+ }
3785
+
3786
+ if (component.getKind () == KeyPathExpr::Component::Kind::Subscript)
3787
+ indices = lowerSubscriptIndices (component);
3788
+ return KeyPathPatternComponent::forExternal (
3789
+ cast<AbstractStorageDecl>(component.getDeclRef ().getDecl ()),
3790
+ subs,
3791
+ SGF.getASTContext ().AllocateCopy (indices),
3792
+ ty);
3793
+ };
3794
+
3705
3795
for (auto &component : E->getComponents ()) {
3706
3796
switch (auto kind = component.getKind ()) {
3707
3797
case KeyPathExpr::Component::Kind::Property: {
@@ -3711,6 +3801,12 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
3711
3801
->getReferenceStorageReferent ()
3712
3802
->getCanonicalType ();
3713
3803
3804
+ if (shouldUseExternalKeyPathComponent (decl)) {
3805
+ loweredComponents.push_back (makeExternalKeyPathComponent (component,
3806
+ baseTy));
3807
+ continue ;
3808
+ }
3809
+
3714
3810
switch (auto strategy = decl->getAccessStrategy (AccessSemantics::Ordinary,
3715
3811
AccessKind::ReadWrite)) {
3716
3812
case AccessStrategy::Storage: {
@@ -3805,44 +3901,16 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
3805
3901
->substGenericArgs (component.getDeclRef ().getSubstitutions ());
3806
3902
auto baseSubscriptInterfaceTy = cast<AnyFunctionType>(
3807
3903
baseSubscriptTy->mapTypeOutOfContext ()->getCanonicalType ());
3808
-
3809
3904
baseTy = baseSubscriptInterfaceTy.getResult ();
3810
-
3811
- // Capturing an index value dependent on the generic context means we
3812
- // need the generic context captured in the key path.
3813
- needsGenericContext |=
3814
- component.getIndexExpr ()->getType ()->hasArchetype ()
3815
- | baseTy->hasTypeParameter ();
3816
-
3817
- // Evaluate the index arguments.
3818
- SmallVector<RValue, 2 > indexValues;
3819
- auto indexResult = visit (component.getIndexExpr (), SGFContext ());
3820
- if (isa<TupleType>(indexResult.getType ())) {
3821
- std::move (indexResult).extractElements (indexValues);
3822
- } else {
3823
- indexValues.push_back (std::move (indexResult));
3905
+
3906
+ if (shouldUseExternalKeyPathComponent (decl)) {
3907
+ loweredComponents.push_back (makeExternalKeyPathComponent (component,
3908
+ baseTy));
3909
+ continue ;
3824
3910
}
3825
-
3826
- SmallVector<KeyPathPatternComponent::Index, 4 > indexPatterns;
3911
+
3912
+ auto indexPatterns = lowerSubscriptIndices (component) ;
3827
3913
SILFunction *indexEquals = nullptr , *indexHash = nullptr ;
3828
- for (unsigned i : indices (indexValues)) {
3829
- auto hashable = component.getSubscriptIndexHashableConformances ()[i];
3830
- assert (hashable.isAbstract () ||
3831
- hashable.getConcrete ()->getType ()->isEqual (indexValues[i].getType ()));
3832
- auto &value = indexValues[i];
3833
-
3834
- auto indexTy = value.getType ()->mapTypeOutOfContext ()->getCanonicalType ();
3835
- auto indexLoweredTy = SGF.getLoweredType (value.getType ());
3836
- indexLoweredTy = SILType::getPrimitiveType (
3837
- indexLoweredTy.getSwiftRValueType ()->mapTypeOutOfContext ()
3838
- ->getCanonicalType (),
3839
- indexLoweredTy.getCategory ());
3840
- indexPatterns.push_back ({(unsigned )operands.size (),
3841
- indexTy, indexLoweredTy,
3842
- hashable});
3843
- operands.push_back (
3844
- std::move (indexValues[i]).forwardAsSingleValue (SGF, E));
3845
- }
3846
3914
getOrCreateKeyPathEqualsAndHash (SGF, SILLocation (E),
3847
3915
needsGenericContext ? SGF.F .getGenericEnvironment () : nullptr ,
3848
3916
indexPatterns,
0 commit comments