[CSBindings] Prevent BindingSet::isViable from dropping viable bindings (v2)

The original attempt to do this was reverted by https://github.com/swiftlang/swift/pull/77653

The problem is that the fix was too broad, I narrowed it down to
non-exact uses of stdlib collections that support upcasts.
This commit is contained in:
Pavel Yaskevich
2024-11-22 17:25:45 -08:00
parent 87cd5f8733
commit b7e7493076

View File

@@ -31,6 +31,12 @@ using namespace swift;
using namespace constraints;
using namespace inference;
/// Check whether there exists a type that could be implicitly converted
/// to a given type i.e. is the given type is Double or Optional<..> this
/// function is going to return true because CGFloat could be converted
/// to a Double and non-optional value could be injected into an optional.
static bool hasConversions(Type);
static std::optional<Type> checkTypeOfBinding(TypeVariableType *typeVar,
Type type);
@@ -1209,7 +1215,31 @@ bool BindingSet::isViable(PotentialBinding &binding, bool isTransitive) {
if (!existingNTD || NTD != existingNTD)
continue;
// FIXME: What is going on here needs to be thoroughly re-evaluated.
// What is going on in this method needs to be thoroughly re-evaluated!
//
// This logic aims to skip dropping bindings if
// collection type has conversions i.e. in situations like:
//
// [$T1] conv $T2
// $T2 conv [(Int, String)]
// $T2.Element equal $T5.Element
//
// `$T1` could be bound to `(i: Int, v: String)` after
// `$T2` is bound to `[(Int, String)]` which is is a problem
// because it means that `$T2` was attempted to early
// before the solver had a chance to discover all viable
// bindings.
//
// Let's say existing binding is `[(Int, String)]` and
// relation is "exact", in this case there is no point
// tracking `[$T1]` because upcasts are only allowed for
// subtype and other conversions.
if (existing->Kind != AllowedBindingKind::Exact) {
if (existingType->isKnownStdlibCollectionType() &&
hasConversions(existingType)) {
continue;
}
}
// If new type has a type variable it shouldn't
// be considered viable.