Skip to content

Commit 8dc2251

Browse files
committed
[CSBindings] NFC: Add a unit test for closure result inference
Make sure that `Void` doesn't get attempted twice if it was inferred directly or transitively.
1 parent 942ff69 commit 8dc2251

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5369,6 +5369,9 @@ class TypeVariableBinding {
53695369
TypeVariableBinding(TypeVariableType *typeVar, PotentialBinding &binding)
53705370
: TypeVar(typeVar), Binding(binding) {}
53715371

5372+
TypeVariableType *getTypeVariable() const { return TypeVar; }
5373+
Type getType() const { return Binding.BindingType; }
5374+
53725375
bool isDefaultable() const { return Binding.isDefaultableBinding(); }
53735376

53745377
bool hasDefaultedProtocol() const {

unittests/Sema/BindingInferenceTests.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,62 @@ TEST_F(SemaTest, TestTransitiveProtocolInferenceThroughEquivalenceChains) {
336336
verifyProtocolInferenceResults(*bindings.TransitiveProtocols,
337337
{protocolTy0, protocolTy1});
338338
}
339+
340+
TEST_F(SemaTest, TestNoDoubleVoidClosureResultInference) {
341+
ConstraintSystemOptions options;
342+
ConstraintSystem cs(DC, options);
343+
344+
auto verifyInference = [&](TypeVariableType *typeVar, unsigned numExpected) {
345+
auto bindings = cs.getBindingsFor(typeVar);
346+
TypeVarBindingProducer producer(bindings);
347+
348+
llvm::SmallPtrSet<Type, 2> inferredTypes;
349+
350+
while (auto binding = producer()) {
351+
ASSERT_TRUE(binding.hasValue());
352+
ASSERT_EQ(binding->getTypeVariable(), typeVar);
353+
ASSERT_TRUE(inferredTypes.insert(binding->getType()).second);
354+
}
355+
356+
ASSERT_EQ(inferredTypes.size(), numExpected);
357+
};
358+
359+
auto *closureResultLoc =
360+
cs.getConstraintLocator({}, ConstraintLocator::ClosureResult);
361+
362+
auto *closureResult = cs.createTypeVariable(closureResultLoc, /*options=*/0);
363+
364+
cs.addConstraint(ConstraintKind::Subtype, getStdlibType("Int"), closureResult,
365+
closureResultLoc);
366+
cs.addConstraint(ConstraintKind::Subtype, closureResult, getStdlibType("Void"),
367+
closureResultLoc);
368+
369+
verifyInference(closureResult, 2);
370+
371+
auto closureResultWithTransitiveVoid = cs.createTypeVariable(closureResultLoc,
372+
/*options=*/0);
373+
374+
auto contextualVar = cs.createTypeVariable({}, /*options=*/0);
375+
376+
cs.addConstraint(ConstraintKind::Subtype, getStdlibType("Void"),
377+
contextualVar, cs.getConstraintLocator({}));
378+
379+
cs.addConstraint(ConstraintKind::Subtype, contextualVar,
380+
closureResultWithTransitiveVoid, closureResultLoc);
381+
382+
cs.addConstraint(ConstraintKind::Subtype, getStdlibType("Int"),
383+
closureResultWithTransitiveVoid, closureResultLoc);
384+
385+
verifyInference(closureResultWithTransitiveVoid, 2);
386+
387+
auto closureResultWithoutVoid =
388+
cs.createTypeVariable(closureResultLoc, /*options=*/0);
389+
390+
// Supertype triggers `Void` inference
391+
cs.addConstraint(ConstraintKind::Subtype, getStdlibType("Int"),
392+
closureResultWithoutVoid, closureResultLoc);
393+
cs.addConstraint(ConstraintKind::Subtype, closureResultWithoutVoid,
394+
getStdlibType("String"), closureResultLoc);
395+
396+
verifyInference(closureResultWithoutVoid, 3);
397+
}

0 commit comments

Comments
 (0)