Skip to content

Commit 56f390d

Browse files
committed
[CSBindings] Delay default binding production until inference is exhausted
Previously, default bindings (from Defaultable and FallbackType constraints) where added to the set right after the first attempt, but that is incorrect because binding producer should exhaust the chain of superclasses and other "inferred" bindings first or risk producing subpar solutions.
1 parent d0a3082 commit 56f390d

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2052,7 +2052,7 @@ bool TypeVarBindingProducer::computeNext() {
20522052
}
20532053
}
20542054

2055-
if (NumTries == 0) {
2055+
if (newBindings.empty()) {
20562056
// Add defaultable constraints (if any).
20572057
for (auto *constraint : DelayedDefaults) {
20582058
if (constraint->getKind() == ConstraintKind::FallbackType) {
@@ -2065,6 +2065,9 @@ bool TypeVarBindingProducer::computeNext() {
20652065

20662066
addNewBinding(getDefaultBinding(constraint));
20672067
}
2068+
2069+
// Drop all of the default since we have converted them into bindings.
2070+
DelayedDefaults.clear();
20682071
}
20692072

20702073
if (newBindings.empty())

unittests/Sema/BindingInferenceTests.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,43 @@ TEST_F(SemaTest, TestNoDoubleVoidClosureResultInference) {
395395

396396
verifyInference(closureResultWithoutVoid, 3);
397397
}
398+
399+
TEST_F(SemaTest, TestSupertypeInferenceWithDefaults) {
400+
ConstraintSystemOptions options;
401+
ConstraintSystem cs(DC, options);
402+
403+
auto *genericArg = cs.createTypeVariable(
404+
cs.getConstraintLocator({}, ConstraintLocator::GenericArgument),
405+
/*options=*/0);
406+
407+
// KeyPath<String, Int> i.e. \.utf8.count or something similar
408+
auto keyPath =
409+
BoundGenericType::get(Context.getKeyPathDecl(), /*parent=*/Type(),
410+
{getStdlibType("String"), getStdlibType("Int")});
411+
412+
cs.addConstraint(ConstraintKind::Conversion, keyPath, genericArg,
413+
cs.getConstraintLocator({}));
414+
415+
cs.addConstraint(ConstraintKind::Defaultable, genericArg, Context.TheAnyType,
416+
cs.getConstraintLocator({}));
417+
418+
auto bindings = cs.getBindingsFor(genericArg);
419+
TypeVarBindingProducer producer(bindings);
420+
421+
llvm::SmallVector<Type, 4> inferredTypes;
422+
while (auto binding = producer()) {
423+
ASSERT_TRUE(binding.has_value());
424+
inferredTypes.push_back(binding->getType());
425+
}
426+
427+
// The inference should produce 4 types: KeyPath<String, Int>,
428+
// PartialKeyPath<String>, AnyKeyPath and Any - in that order.
429+
430+
ASSERT_EQ(inferredTypes.size(), 4);
431+
ASSERT_TRUE(inferredTypes[0]->isEqual(keyPath));
432+
ASSERT_TRUE(inferredTypes[1]->isEqual(
433+
BoundGenericType::get(Context.getPartialKeyPathDecl(),
434+
/*parent=*/Type(), {getStdlibType("String")})));
435+
ASSERT_TRUE(inferredTypes[2]->isEqual(getStdlibType("AnyKeyPath")));
436+
ASSERT_TRUE(inferredTypes[3]->isEqual(Context.TheAnyType));
437+
}

0 commit comments

Comments
 (0)