@@ -460,9 +460,21 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(
460
460
}
461
461
462
462
auto anchor = locator->getAnchor ();
463
+ auto path = locator->getPath ();
464
+ {
465
+ // If we have an implicit x[dynamicMember:] subscript call, the callee
466
+ // is given by the original member locator it is based on, which we can get
467
+ // by stripping away the implicit member element and everything after it.
468
+ auto iter = path.rbegin ();
469
+ using ImplicitSubscriptElt = LocatorPathElt::ImplicitDynamicMemberSubscript;
470
+ if (locator->findLast <ImplicitSubscriptElt>(iter)) {
471
+ auto newPath = path.drop_back (iter - path.rbegin () + 1 );
472
+ return getConstraintLocator (anchor, newPath);
473
+ }
474
+ }
475
+
463
476
assert (bool (anchor) && " Expected an anchor!" );
464
477
465
- auto path = locator->getPath ();
466
478
{
467
479
// If we have a locator for a member found through key path dynamic member
468
480
// lookup, then we need to chop off the elements after the
@@ -2664,6 +2676,7 @@ void ConstraintSystem::bindOverloadType(
2664
2676
ConstraintLocator *locator, DeclContext *useDC,
2665
2677
llvm::function_ref<void (unsigned int , Type, ConstraintLocator *)>
2666
2678
verifyThatArgumentIsHashable) {
2679
+ auto &ctx = getASTContext ();
2667
2680
auto choice = overload.choice ;
2668
2681
auto openedType = overload.openedType ;
2669
2682
@@ -2677,6 +2690,37 @@ void ConstraintSystem::bindOverloadType(
2677
2690
addConstraint (ConstraintKind::Bind, boundType, ty, locator);
2678
2691
}
2679
2692
};
2693
+ auto addDynamicMemberSubscriptConstraints = [&](Type argTy, Type resultTy) {
2694
+ // DynamicMemberLookup results are always a (dynamicMember: T1) -> T2
2695
+ // subscript.
2696
+ auto *fnTy = openedType->castTo <FunctionType>();
2697
+ assert (fnTy->getParams ().size () == 1 &&
2698
+ " subscript always has one argument" );
2699
+
2700
+ auto *callLoc = getConstraintLocator (
2701
+ locator, LocatorPathElt::ImplicitDynamicMemberSubscript ());
2702
+
2703
+ // Associate an argument list for the implicit x[dynamicMember:] subscript
2704
+ // if we haven't already.
2705
+ auto *&argList = ArgumentLists[getArgumentInfoLocator (callLoc)];
2706
+ if (!argList) {
2707
+ argList = ArgumentList::createImplicit (
2708
+ ctx, {Argument (SourceLoc (), ctx.Id_dynamicMember , /* expr*/ nullptr )},
2709
+ AllocationArena::ConstraintSolver);
2710
+ }
2711
+
2712
+ auto *callerTy = FunctionType::get (
2713
+ {FunctionType::Param (argTy, ctx.Id_dynamicMember )}, resultTy);
2714
+
2715
+ ConstraintLocatorBuilder builder (callLoc);
2716
+ addConstraint (ConstraintKind::ApplicableFunction, callerTy, fnTy,
2717
+ builder.withPathElement (ConstraintLocator::ApplyFunction));
2718
+
2719
+ if (isExpr<KeyPathExpr>(locator->getAnchor ())) {
2720
+ auto paramTy = fnTy->getParams ()[0 ].getParameterType ();
2721
+ verifyThatArgumentIsHashable (/* idx*/ 0 , paramTy, locator);
2722
+ }
2723
+ };
2680
2724
switch (choice.getKind ()) {
2681
2725
case OverloadChoiceKind::Decl:
2682
2726
case OverloadChoiceKind::DeclViaBridge:
@@ -2696,25 +2740,20 @@ void ConstraintSystem::bindOverloadType(
2696
2740
// makes the index default to String if otherwise unconstrained.
2697
2741
assert (refFnType->getParams ().size () == 1 &&
2698
2742
" subscript always has one arg" );
2699
- auto argType = refFnType->getParams ()[0 ].getPlainType ();
2700
2743
2701
2744
auto stringLiteral =
2702
2745
TypeChecker::getProtocol (getASTContext (), choice.getDecl ()->getLoc (),
2703
2746
KnownProtocolKind::ExpressibleByStringLiteral);
2704
2747
if (!stringLiteral)
2705
2748
return ;
2706
2749
2707
- addConstraint (ConstraintKind::LiteralConformsTo, argType,
2750
+ // Form constraints for a x[dynamicMember:] subscript with a string literal
2751
+ // argument, where the overload type is bound to the result to model the
2752
+ // fact that this a property access in the source.
2753
+ auto argTy = createTypeVariable (locator, /* options*/ 0 );
2754
+ addConstraint (ConstraintKind::LiteralConformsTo, argTy,
2708
2755
stringLiteral->getDeclaredInterfaceType (), locator);
2709
-
2710
- // If this is used inside of the keypath expression, we need to make
2711
- // sure that argument is Hashable.
2712
- if (isExpr<KeyPathExpr>(locator->getAnchor ()))
2713
- verifyThatArgumentIsHashable (0 , argType, locator);
2714
-
2715
- // The resolved decl is for subscript(dynamicMember:), however the original
2716
- // member constraint was for a property. Therefore we need to bind to the
2717
- // result type.
2756
+ addDynamicMemberSubscriptConstraints (argTy, refFnType->getResult ());
2718
2757
bindTypeOrIUO (refFnType->getResult ());
2719
2758
return ;
2720
2759
}
@@ -2764,9 +2803,9 @@ void ConstraintSystem::bindOverloadType(
2764
2803
// preferred over key path dynamic member lookup.
2765
2804
increaseScore (SK_KeyPathSubscript);
2766
2805
2767
- auto dynamicResultTy = boundType->castTo <TypeVariableType>();
2806
+ auto boundTypeVar = boundType->castTo <TypeVariableType>();
2768
2807
auto constraints = getConstraintGraph ().gatherConstraints (
2769
- dynamicResultTy , ConstraintGraph::GatheringKind::EquivalenceClass,
2808
+ boundTypeVar , ConstraintGraph::GatheringKind::EquivalenceClass,
2770
2809
[](Constraint *constraint) {
2771
2810
return constraint->getKind () == ConstraintKind::ApplicableFunction;
2772
2811
});
@@ -2790,20 +2829,11 @@ void ConstraintSystem::bindOverloadType(
2790
2829
// - Original result type `$T_R` is going to represent result of
2791
2830
// the `[dynamicMember: \.[0]]` invocation.
2792
2831
2793
- // Result of the `WritableKeyPath` is going to be l-value type,
2794
- // let's adjust l-valueness of the result type to accommodate that.
2795
- //
2796
- // This is required because we are binding result of the subscript
2797
- // to its "member type" which becomes dynamic result type. We could
2798
- // form additional `applicable fn` constraint here and bind it to a
2799
- // function type, but it would create inconsistency with how properties
2800
- // are handled, which means more special handling in CSApply.
2801
- if (keyPathTy->isWritableKeyPath () ||
2802
- keyPathTy->isReferenceWritableKeyPath ())
2803
- dynamicResultTy->getImpl ().setCanBindToLValue (getSavedBindings (),
2804
- /* enabled=*/ true );
2805
-
2806
- auto fnType = applicableFn->getFirstType ()->castTo <FunctionType>();
2832
+ // The function type of the original call-site. We'll want to create a
2833
+ // new applicable fn constraint using its parameter along with a fresh
2834
+ // type variable for the result of the inner subscript.
2835
+ auto originalCallerTy =
2836
+ applicableFn->getFirstType ()->castTo <FunctionType>();
2807
2837
2808
2838
auto subscriptResultTy = createTypeVariable (
2809
2839
getConstraintLocator (locator->getAnchor (),
@@ -2812,35 +2842,41 @@ void ConstraintSystem::bindOverloadType(
2812
2842
2813
2843
// FIXME: Verify ExtInfo state is correct, not working by accident.
2814
2844
FunctionType::ExtInfo info;
2815
- auto adjustedFnTy =
2816
- FunctionType::get (fnType-> getParams (), subscriptResultTy, info);
2845
+ auto adjustedFnTy = FunctionType::get (originalCallerTy-> getParams (),
2846
+ subscriptResultTy, info);
2817
2847
2848
+ // Add a constraint for the inner application that uses the args of the
2849
+ // original call-site, and a fresh type var result equal to the leaf type.
2818
2850
ConstraintLocatorBuilder kpLocBuilder (keyPathLoc);
2819
2851
addConstraint (
2820
2852
ConstraintKind::ApplicableFunction, adjustedFnTy, memberTy,
2821
2853
kpLocBuilder.withPathElement (ConstraintLocator::ApplyFunction));
2822
2854
2823
- addConstraint (ConstraintKind::Bind, dynamicResultTy, fnType-> getResult () ,
2824
- keyPathLoc);
2855
+ addConstraint (ConstraintKind::FunctionResult, boundType ,
2856
+ originalCallerTy-> getResult (), keyPathLoc);
2825
2857
2826
2858
addConstraint (ConstraintKind::Equal, subscriptResultTy, leafTy,
2827
2859
keyPathLoc);
2860
+
2861
+ addDynamicMemberSubscriptConstraints (/* argTy*/ keyPathTy,
2862
+ fnType->getResult ());
2863
+
2864
+ // Bind the overload type to the opened type as usual to match the fact
2865
+ // that this is a subscript in the source.
2866
+ bindTypeOrIUO (fnType);
2828
2867
} else {
2829
2868
// Since member type is going to be bound to "leaf" generic parameter
2830
2869
// of the keypath, it has to be an r-value always, so let's add a new
2831
2870
// constraint to represent that conversion instead of loading member
2832
2871
// type into "leaf" directly.
2833
2872
addConstraint (ConstraintKind::Equal, memberTy, leafTy, keyPathLoc);
2834
- }
2873
+ addDynamicMemberSubscriptConstraints (/* argTy*/ keyPathTy,
2874
+ fnType->getResult ());
2835
2875
2836
- if (isExpr<KeyPathExpr>(locator->getAnchor ()))
2837
- verifyThatArgumentIsHashable (0 , keyPathTy, locator);
2838
-
2839
- // The resolved decl is for subscript(dynamicMember:), however the
2840
- // original member constraint was either for a property, or we've
2841
- // re-purposed the overload type variable to represent the result type of
2842
- // the subscript. In both cases, we need to bind to the result type.
2843
- bindTypeOrIUO (fnType->getResult ());
2876
+ // Bind the overload type to the result to model the fact that this a
2877
+ // property access in the source.
2878
+ bindTypeOrIUO (fnType->getResult ());
2879
+ }
2844
2880
return ;
2845
2881
}
2846
2882
}
@@ -4534,7 +4570,8 @@ void constraints::simplifyLocator(ASTNode &anchor,
4534
4570
continue ;
4535
4571
}
4536
4572
4537
- case ConstraintLocator::KeyPathDynamicMember: {
4573
+ case ConstraintLocator::KeyPathDynamicMember:
4574
+ case ConstraintLocator::ImplicitDynamicMemberSubscript: {
4538
4575
// Key path dynamic member lookup should be completely transparent.
4539
4576
path = path.slice (1 );
4540
4577
continue ;
@@ -4716,6 +4753,13 @@ ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
4716
4753
if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor))
4717
4754
return getConstraintLocator (UME);
4718
4755
4756
+ // All implicit x[dynamicMember:] subscript calls can share the same argument
4757
+ // list.
4758
+ if (locator->findLast <LocatorPathElt::ImplicitDynamicMemberSubscript>()) {
4759
+ return getConstraintLocator (
4760
+ ASTNode (), LocatorPathElt::ImplicitDynamicMemberSubscript ());
4761
+ }
4762
+
4719
4763
auto path = locator->getPath ();
4720
4764
{
4721
4765
// If this is for a dynamic member reference, the argument info is for the
0 commit comments