Skip to content

Commit 153bd9d

Browse files
committed
[CSBindings] Add inferred key path type bindings only if there is no other choice
If key path literal type is converted to a function type, it's always the best course of action to use such a binding and forego adding a KeyPath type binding based on capability because it would never match. This applies to invalid key pathes as well because we'd want to propagate as much contextual information from the key path literal into the context as possible.
1 parent 7877c07 commit 153bd9d

File tree

1 file changed

+43
-49
lines changed

1 file changed

+43
-49
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -602,17 +602,45 @@ void BindingSet::finalize(
602602

603603
std::tie(isValid, capability) = CS.inferKeyPathLiteralCapability(TypeVar);
604604

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);
605+
// Key path literal is not yet sufficiently resolved.
606+
if (isValid && !capability)
607+
return;
608+
609+
// If the key path is sufficiently resolved we can add inferred binding
610+
// to the set.
611+
SmallSetVector<PotentialBinding, 4> updatedBindings;
612+
for (const auto &binding : Bindings) {
613+
auto bindingTy = binding.BindingType->lookThroughAllOptionalTypes();
614+
615+
assert(isKnownKeyPathType(bindingTy) || bindingTy->is<FunctionType>());
616+
617+
// Functions don't have capability so we can simply add them.
618+
if (bindingTy->is<FunctionType>())
619+
updatedBindings.insert(binding);
620+
}
621+
622+
// Note that even though key path literal maybe be invalid it's
623+
// still the best course of action to use contextual function type
624+
// bindings because they allow to propagate type information from
625+
// the key path into the context, so key path bindings are addded
626+
// only if there is absolutely no other choice.
627+
if (updatedBindings.empty()) {
628+
auto rootTy = CS.getKeyPathRootType(keyPath);
629+
630+
// A valid key path literal.
631+
if (capability) {
632+
// Note that the binding is formed using root & value
633+
// type variables produced during constraint generation
634+
// because at this point root is already known (otherwise
635+
// inference wouldn't been able to determine key path's
636+
// capability) and we always want to infer value from
637+
// the key path and match it to a contextual type to produce
638+
// better diagnostics.
639+
auto keyPathTy = getKeyPathType(ctx, *capability, rootTy,
640+
CS.getKeyPathValueType(keyPath));
641+
updatedBindings.insert(
642+
{keyPathTy, AllowedBindingKind::Exact, keyPathLoc});
643+
} else if (CS.shouldAttemptFixes()) {
616644
// If key path is structurally correct and has a resolved root
617645
// type, let's promote the fallback type into a binding because
618646
// root would have been inferred from explicit type already and
@@ -625,52 +653,18 @@ void BindingSet::finalize(
625653
return entry.second->getKind() == ConstraintKind::FallbackType;
626654
});
627655
assert(fallback != Defaults.end());
628-
addBinding(
656+
updatedBindings.insert(
629657
{fallback->first, AllowedBindingKind::Exact, fallback->second});
630658
} else {
631-
addBinding(PotentialBinding::forHole(
659+
updatedBindings.insert(PotentialBinding::forHole(
632660
TypeVar, CS.getConstraintLocator(
633661
keyPath, ConstraintLocator::FallbackType)));
634662
}
635663
}
636-
637-
// No need for fallback if key path is invalid.
638-
Defaults.clear();
639-
return;
640664
}
641665

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-
}
666+
Bindings = std::move(updatedBindings);
667+
Defaults.clear();
674668

675669
return;
676670
}

0 commit comments

Comments
 (0)