@@ -96,7 +96,7 @@ bool BindingSet::isDelayed() const {
96
96
97
97
// Delay key path literal type binding until there is at least
98
98
// one contextual binding (or default is promoted into a binding).
99
- if (TypeVar->getImpl ().isKeyPathType () && Bindings .empty ())
99
+ if (TypeVar->getImpl ().isKeyPathType () && !Defaults .empty ())
100
100
return true ;
101
101
102
102
if (isHole ()) {
@@ -178,7 +178,7 @@ bool BindingSet::isPotentiallyIncomplete() const {
178
178
// contextual type or key path is resolved enough to infer
179
179
// capability and promote default into a binding.
180
180
if (TypeVar->getImpl ().isKeyPathType ())
181
- return Bindings .empty ();
181
+ return !Defaults .empty ();
182
182
183
183
// If current type variable is associated with a code completion token
184
184
// it's possible that it doesn't have enough contextual information
@@ -531,6 +531,24 @@ void BindingSet::inferTransitiveBindings(
531
531
}
532
532
}
533
533
534
+ static BoundGenericType *getKeyPathType (ASTContext &ctx,
535
+ KeyPathCapability capability,
536
+ Type rootType, Type valueType) {
537
+ switch (capability) {
538
+ case KeyPathCapability::ReadOnly:
539
+ return BoundGenericType::get (ctx.getKeyPathDecl (), /* parent=*/ Type (),
540
+ {rootType, valueType});
541
+
542
+ case KeyPathCapability::Writable:
543
+ return BoundGenericType::get (ctx.getWritableKeyPathDecl (),
544
+ /* parent=*/ Type (), {rootType, valueType});
545
+
546
+ case KeyPathCapability::ReferenceWritable:
547
+ return BoundGenericType::get (ctx.getReferenceWritableKeyPathDecl (),
548
+ /* parent=*/ Type (), {rootType, valueType});
549
+ }
550
+ }
551
+
534
552
void BindingSet::finalize (
535
553
llvm::SmallDenseMap<TypeVariableType *, BindingSet> &inferredBindings) {
536
554
inferTransitiveBindings (inferredBindings);
@@ -573,6 +591,90 @@ void BindingSet::finalize(
573
591
}
574
592
}
575
593
594
+ if (TypeVar->getImpl ().isKeyPathType ()) {
595
+ auto &ctx = CS.getASTContext ();
596
+
597
+ auto *keyPathLoc = TypeVar->getImpl ().getLocator ();
598
+ auto *keyPath = castToExpr<KeyPathExpr>(keyPathLoc->getAnchor ());
599
+
600
+ bool isValid;
601
+ llvm::Optional<KeyPathCapability> capability;
602
+
603
+ std::tie (isValid, capability) = CS.inferKeyPathLiteralCapability (TypeVar);
604
+
605
+ if (!isValid) {
606
+ // If key path is invalid we have to drop all the contextual
607
+ // bindings, none of the could be used unless capability is
608
+ // known.
609
+ Bindings.clear ();
610
+
611
+ // If one of the references in a key path is invalid let's add
612
+ // a placeholder binding in diagnostic mode to indicate that
613
+ // the key path cannot be properly resolved.
614
+ if (CS.shouldAttemptFixes ()) {
615
+ auto rootTy = CS.getKeyPathRootType (keyPath);
616
+ // If key path is structurally correct and has a resolved root
617
+ // type, let's promote the fallback type into a binding because
618
+ // root would have been inferred from explicit type already and
619
+ // it's benefitial for diagnostics to assign a non-placeholder
620
+ // type to key path literal to propagate root/value to the context.
621
+ if (!keyPath->hasSingleInvalidComponent () &&
622
+ (keyPath->getParsedRoot () ||
623
+ !CS.getFixedType (rootTy)->isTypeVariableOrMember ())) {
624
+ auto fallback = llvm::find_if (Defaults, [](const auto &entry) {
625
+ return entry.second ->getKind () == ConstraintKind::FallbackType;
626
+ });
627
+ assert (fallback != Defaults.end ());
628
+ addBinding (
629
+ {fallback->first , AllowedBindingKind::Exact, fallback->second });
630
+ } else {
631
+ addBinding (PotentialBinding::forHole (
632
+ TypeVar, CS.getConstraintLocator (
633
+ keyPath, ConstraintLocator::FallbackType)));
634
+ }
635
+ }
636
+
637
+ // No need for fallback if key path is invalid.
638
+ Defaults.clear ();
639
+ return ;
640
+ }
641
+
642
+ // If the key path is sufficiently resolved we can add inferred binding
643
+ // to the set.
644
+ if (capability) {
645
+ SmallSetVector<PotentialBinding, 4 > updatedBindings;
646
+ for (const auto &binding : Bindings) {
647
+ auto bindingTy = binding.BindingType ->lookThroughAllOptionalTypes ();
648
+
649
+ assert (isKnownKeyPathType (bindingTy) ||
650
+ bindingTy->is <FunctionType>());
651
+
652
+ // Functions don't have capability so we can simply add them.
653
+ if (bindingTy->is <FunctionType>())
654
+ updatedBindings.insert (binding);
655
+ }
656
+
657
+ // Note that the binding is formed using root & value
658
+ // type variables produced during constraint generation
659
+ // because at this point root is already known (otherwise
660
+ // inference wouldn't been able to determine key path's
661
+ // capability) and we always want to infer value from
662
+ // the key path and match it to a contextual type to produce
663
+ // better diagnostics.
664
+ auto keyPathTy =
665
+ getKeyPathType (ctx, *capability, CS.getKeyPathRootType (keyPath),
666
+ CS.getKeyPathValueType (keyPath));
667
+
668
+ updatedBindings.insert (
669
+ {keyPathTy, AllowedBindingKind::Exact, keyPathLoc});
670
+
671
+ Bindings = std::move (updatedBindings);
672
+ Defaults.clear ();
673
+ }
674
+
675
+ return ;
676
+ }
677
+
576
678
if (CS.shouldAttemptFixes () &&
577
679
locator->isLastElement <LocatorPathElt::UnresolvedMemberChainResult>()) {
578
680
// Let's see whether this chain is valid, if it isn't then to avoid
@@ -927,60 +1029,6 @@ void PotentialBindings::addDefault(Constraint *constraint) {
927
1029
928
1030
void BindingSet::addDefault (Constraint *constraint) {
929
1031
auto defaultTy = constraint->getSecondType ();
930
-
931
- if (TypeVar->getImpl ().isKeyPathType () && Bindings.empty ()) {
932
- if (constraint->getKind () == ConstraintKind::FallbackType) {
933
- auto &ctx = CS.getASTContext ();
934
-
935
- bool isValid;
936
- llvm::Optional<KeyPathCapability> capability;
937
-
938
- std::tie (isValid, capability) = CS.inferKeyPathLiteralCapability (TypeVar);
939
-
940
- if (!isValid) {
941
- // If one of the references in a key path is invalid let's add
942
- // a placeholder binding in diagnostic mode to indicate that
943
- // the key path cannot be properly resolved.
944
- if (CS.shouldAttemptFixes ()) {
945
- addBinding ({PlaceholderType::get (ctx, TypeVar),
946
- AllowedBindingKind::Exact, constraint});
947
- }
948
-
949
- // During normal solving the set has to stay empty.
950
- return ;
951
- }
952
-
953
- if (capability) {
954
- auto *keyPathType = defaultTy->castTo <BoundGenericType>();
955
-
956
- auto root = keyPathType->getGenericArgs ()[0 ];
957
- auto value = keyPathType->getGenericArgs ()[1 ];
958
-
959
- switch (*capability) {
960
- case KeyPathCapability::ReadOnly:
961
- break ;
962
-
963
- case KeyPathCapability::Writable:
964
- keyPathType = BoundGenericType::get (ctx.getWritableKeyPathDecl (),
965
- /* parent=*/ Type (), {root, value});
966
- break ;
967
-
968
- case KeyPathCapability::ReferenceWritable:
969
- keyPathType =
970
- BoundGenericType::get (ctx.getReferenceWritableKeyPathDecl (),
971
- /* parent=*/ Type (), {root, value});
972
- break ;
973
- }
974
-
975
- addBinding ({keyPathType, AllowedBindingKind::Exact, constraint});
976
- }
977
-
978
- // If key path is not yet sufficiently resolved, don't add any
979
- // bindings.
980
- return ;
981
- }
982
- }
983
-
984
1032
Defaults.insert ({defaultTy->getCanonicalType (), constraint});
985
1033
}
986
1034
0 commit comments