Skip to content

Commit 3e01160

Browse files
committed
[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
1 parent ed25559 commit 3e01160

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ void ConstraintSystem::inferTransitiveSupertypeBindings(
3030
llvm::SmallVector<Constraint *, 4> subtypeOf;
3131
// First, let's collect all of the `subtype` constraints associated
3232
// with this type variable.
33-
llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf),
34-
[&](const Constraint *constraint) -> bool {
35-
if (constraint->getKind() != ConstraintKind::Subtype)
36-
return false;
37-
38-
auto rhs = simplifyType(constraint->getSecondType());
39-
return rhs->getAs<TypeVariableType>() == typeVar;
40-
});
33+
llvm::copy_if(
34+
bindings.Sources, std::back_inserter(subtypeOf),
35+
[&](const Constraint *constraint) -> bool {
36+
if (constraint->getKind() != ConstraintKind::Subtype &&
37+
constraint->getKind() != ConstraintKind::ArgumentConversion &&
38+
constraint->getKind() != ConstraintKind::OperatorArgumentConversion)
39+
return false;
40+
41+
auto rhs = simplifyType(constraint->getSecondType());
42+
return rhs->getAs<TypeVariableType>() == typeVar;
43+
});
4144

4245
if (subtypeOf.empty())
4346
return;
@@ -618,7 +621,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
618621
continue;
619622

620623
literalBindings.push_back(
621-
{defaultType, AllowedBindingKind::Subtypes, constraint});
624+
{defaultType, AllowedBindingKind::Exact, constraint});
622625
continue;
623626
}
624627

@@ -644,7 +647,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
644647
if (!matched) {
645648
exactTypes.insert(defaultType->getCanonicalType());
646649
literalBindings.push_back(
647-
{defaultType, AllowedBindingKind::Subtypes, constraint});
650+
{defaultType, AllowedBindingKind::Exact, constraint});
648651
}
649652

650653
break;

test/Constraints/default_literals.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,14 @@ extension Int {
4242

4343

4444
var (div, mod) = (9 / 4, 9 % 4)
45+
46+
// rdar://problem/56212087 - solver fails to infer correct type for a generic parameter (Any vs. String)
47+
func test_transitive_inference_of_default_literal_types() {
48+
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
49+
fatalError()
50+
}
51+
52+
func bar(_: Any?) {}
53+
54+
bar(foo("", "")) // Ok
55+
}

0 commit comments

Comments
 (0)