mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user