[ConstraintSystem] Make it possible to infer subtype bindings through argument conversions

Enable solver to transitively infer bindings through argument conversion
constraints. That helps to infer bindings for (generic) parameters
from their arguments e.g.

```swift
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
  fatalError()
}

func bar(_: Any?) {}

func test() {
  bar(foo("", ""))
}
```

In this case `T` can currently only be inferred as `Any?`
(based on parameter type of `bar`) although a complete
set of bindings for that type variable includes `String`
as well, which comes from use of `T` in argument position.

Resolves: rdar://problem/56212087
This commit is contained in:
Pavel Yaskevich
2020-02-21 17:29:19 -08:00
parent ed255596a6
commit 3e01160a2f
2 changed files with 23 additions and 9 deletions

View File

@@ -30,14 +30,17 @@ void ConstraintSystem::inferTransitiveSupertypeBindings(
llvm::SmallVector<Constraint *, 4> subtypeOf;
// First, let's collect all of the `subtype` constraints associated
// with this type variable.
llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf),
[&](const Constraint *constraint) -> bool {
if (constraint->getKind() != ConstraintKind::Subtype)
return false;
llvm::copy_if(
bindings.Sources, std::back_inserter(subtypeOf),
[&](const Constraint *constraint) -> bool {
if (constraint->getKind() != ConstraintKind::Subtype &&
constraint->getKind() != ConstraintKind::ArgumentConversion &&
constraint->getKind() != ConstraintKind::OperatorArgumentConversion)
return false;
auto rhs = simplifyType(constraint->getSecondType());
return rhs->getAs<TypeVariableType>() == typeVar;
});
auto rhs = simplifyType(constraint->getSecondType());
return rhs->getAs<TypeVariableType>() == typeVar;
});
if (subtypeOf.empty())
return;
@@ -618,7 +621,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
continue;
literalBindings.push_back(
{defaultType, AllowedBindingKind::Subtypes, constraint});
{defaultType, AllowedBindingKind::Exact, constraint});
continue;
}
@@ -644,7 +647,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
if (!matched) {
exactTypes.insert(defaultType->getCanonicalType());
literalBindings.push_back(
{defaultType, AllowedBindingKind::Subtypes, constraint});
{defaultType, AllowedBindingKind::Exact, constraint});
}
break;

View File

@@ -42,3 +42,14 @@ extension Int {
var (div, mod) = (9 / 4, 9 % 4)
// rdar://problem/56212087 - solver fails to infer correct type for a generic parameter (Any vs. String)
func test_transitive_inference_of_default_literal_types() {
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
fatalError()
}
func bar(_: Any?) {}
bar(foo("", "")) // Ok
}