@@ -3973,6 +3973,19 @@ bool swift::hasDynamicMemberLookupAttribute(Type type) {
3973
3973
return ::hasDynamicMemberLookupAttribute (type, DynamicMemberLookupCache);
3974
3974
}
3975
3975
3976
+ static bool isForKeyPathSubscript (ConstraintSystem &cs,
3977
+ ConstraintLocator *locator) {
3978
+ if (!locator || !locator->getAnchor ())
3979
+ return false ;
3980
+
3981
+ if (auto *SE = dyn_cast<SubscriptExpr>(locator->getAnchor ())) {
3982
+ auto *indexExpr = dyn_cast<TupleExpr>(SE->getIndex ());
3983
+ return indexExpr && indexExpr->getNumElements () == 1 &&
3984
+ indexExpr->getElementName (0 ) == cs.getASTContext ().Id_keyPath ;
3985
+ }
3986
+ return false ;
3987
+ }
3988
+
3976
3989
// / Given a ValueMember, UnresolvedValueMember, or TypeMember constraint,
3977
3990
// / perform a lookup into the specified base type to find a candidate list.
3978
3991
// / The list returned includes the viable candidates as well as the unviable
@@ -4004,14 +4017,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
4004
4017
MemberLookupResult result;
4005
4018
result.OverallResult = MemberLookupResult::HasResults;
4006
4019
4007
- // If we're looking for a subscript, consider key path operations.
4008
- //
4009
- // TODO: This logic needs to be refactored to make sure that implicit
4010
- // keypath result is only introduced when it makes sense e.g. if there
4011
- // is a single argument with `keypath:` label or `\.` syntax is used.
4012
- if (memberName.isSimpleName () &&
4013
- memberName.getBaseName ().getKind () == DeclBaseName::Kind::Subscript &&
4014
- !(memberLocator && memberLocator->isForKeyPathDynamicMemberLookup ())) {
4020
+ if (isForKeyPathSubscript (*this , memberLocator)) {
4015
4021
if (baseTy->isAnyObject ()) {
4016
4022
result.addUnviable (
4017
4023
OverloadChoice (baseTy, OverloadChoiceKind::KeyPathApplication),
@@ -4756,17 +4762,21 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
4756
4762
performMemberLookup (kind, member, baseTy, functionRefKind, locator,
4757
4763
/* includeInaccessibleMembers*/ shouldAttemptFixes ());
4758
4764
4759
- switch (result.OverallResult ) {
4760
- case MemberLookupResult::Unsolved:
4765
+ auto formUnsolved = [&] {
4761
4766
// If requested, generate a constraint.
4762
4767
if (flags.contains (TMF_GenerateConstraints)) {
4763
- addUnsolvedConstraint (
4764
- Constraint::createMemberOrOuterDisjunction ( *this , kind, baseTy, memberTy, member, useDC,
4765
- functionRefKind, outerAlternatives, locator));
4768
+ addUnsolvedConstraint (Constraint::createMemberOrOuterDisjunction (
4769
+ *this , kind, baseTy, memberTy, member, useDC, functionRefKind ,
4770
+ outerAlternatives, locator));
4766
4771
return SolutionKind::Solved;
4767
4772
}
4768
4773
4769
4774
return SolutionKind::Unsolved;
4775
+ };
4776
+
4777
+ switch (result.OverallResult ) {
4778
+ case MemberLookupResult::Unsolved:
4779
+ return formUnsolved ();
4770
4780
4771
4781
case MemberLookupResult::ErrorAlreadyDiagnosed:
4772
4782
return SolutionKind::Error;
@@ -4779,6 +4789,18 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
4779
4789
SmallVector<Constraint *, 4 > candidates;
4780
4790
// If we found viable candidates, then we're done!
4781
4791
if (!result.ViableCandidates .empty ()) {
4792
+ // If only possible choice to refer to member is via keypath
4793
+ // dynamic member dispatch, let's delay solving this constraint
4794
+ // until constraint generation phase is complete, because
4795
+ // subscript dispatch relies on presence of function application.
4796
+ if (result.ViableCandidates .size () == 1 ) {
4797
+ auto &choice = result.ViableCandidates .front ();
4798
+ if (!solverState && choice.isKeyPathDynamicMemberLookup () &&
4799
+ member.getBaseName ().isSubscript ()) {
4800
+ return formUnsolved ();
4801
+ }
4802
+ }
4803
+
4782
4804
generateConstraints (
4783
4805
candidates, memberTy, result.ViableCandidates , useDC, locator,
4784
4806
result.getFavoredIndex (), /* requiresFix=*/ false ,
@@ -5855,7 +5877,11 @@ Type ConstraintSystem::simplifyAppliedOverloads(
5855
5877
}
5856
5878
5857
5879
// FIXME: Could also rewrite fnType to include this result type.
5858
- addConstraint (ConstraintKind::Bind, argFnType->getResult (),
5880
+ // Introduction of `Bind` constraint here could result in the disconnect
5881
+ // in the constraint system with unintended consequences because e.g.
5882
+ // in case of key path application it could disconnect one of the
5883
+ // components like subscript from the rest of the context.
5884
+ addConstraint (ConstraintKind::Equal, argFnType->getResult (),
5859
5885
commonResultType, locator);
5860
5886
}
5861
5887
0 commit comments