|
13 | 13 | #include "SemaFixture.h"
|
14 | 14 | #include "swift/AST/Expr.h"
|
15 | 15 | #include "swift/Sema/ConstraintSystem.h"
|
| 16 | +#include "llvm/ADT/DenseMap.h" |
16 | 17 | #include "llvm/ADT/SmallPtrSet.h"
|
17 | 18 |
|
18 | 19 | using namespace swift;
|
@@ -49,6 +50,97 @@ TEST_F(SemaTest, TestIntLiteralBindingInference) {
|
49 | 50 | ASSERT_TRUE(literal.getDefaultType()->isEqual(intTy));
|
50 | 51 | ASSERT_FALSE(literal.isCovered());
|
51 | 52 | }
|
| 53 | + |
| 54 | + // Make sure that coverage by direct bindings works as expected. |
| 55 | + |
| 56 | + // First, let's attempt a binding which would match default type |
| 57 | + // of the literal. |
| 58 | + |
| 59 | + cs.addConstraint(ConstraintKind::Conversion, literalTy, intTy, |
| 60 | + cs.getConstraintLocator(intLiteral)); |
| 61 | + |
| 62 | + { |
| 63 | + auto bindings = cs.inferBindingsFor(literalTy); |
| 64 | + |
| 65 | + ASSERT_EQ(bindings.Bindings.size(), (unsigned)1); |
| 66 | + ASSERT_EQ(bindings.Literals.size(), (unsigned)1); |
| 67 | + |
| 68 | + ASSERT_TRUE(bindings.Bindings[0].BindingType->isEqual(intTy)); |
| 69 | + |
| 70 | + const auto &literal = bindings.Literals.front().second; |
| 71 | + ASSERT_TRUE(literal.isCovered()); |
| 72 | + ASSERT_TRUE(literal.isDirectRequirement()); |
| 73 | + ASSERT_TRUE(literal.getDefaultType()->isEqual(intTy)); |
| 74 | + } |
| 75 | + |
| 76 | + // Now let's use non-default type that conforms to |
| 77 | + // `ExpressibleByIntegerLiteral` protocol. |
| 78 | + |
| 79 | + auto *floatLiteralTy = |
| 80 | + cs.createTypeVariable(cs.getConstraintLocator(intLiteral), |
| 81 | + /*options=*/0); |
| 82 | + |
| 83 | + auto floatTy = getStdlibType("Float"); |
| 84 | + |
| 85 | + // $T_float <conforms to> ExpressibleByIntegerLiteral |
| 86 | + cs.addConstraint( |
| 87 | + ConstraintKind::LiteralConformsTo, floatLiteralTy, |
| 88 | + Context.getProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral) |
| 89 | + ->getDeclaredInterfaceType(), |
| 90 | + cs.getConstraintLocator(intLiteral)); |
| 91 | + |
| 92 | + // Float <covertible> $T_float |
| 93 | + cs.addConstraint(ConstraintKind::Conversion, floatTy, floatLiteralTy, |
| 94 | + cs.getConstraintLocator(intLiteral)); |
| 95 | + |
| 96 | + { |
| 97 | + auto bindings = cs.inferBindingsFor(floatLiteralTy); |
| 98 | + |
| 99 | + ASSERT_EQ(bindings.Bindings.size(), (unsigned)1); |
| 100 | + ASSERT_EQ(bindings.Literals.size(), (unsigned)1); |
| 101 | + |
| 102 | + ASSERT_TRUE(bindings.Bindings[0].BindingType->isEqual(floatTy)); |
| 103 | + |
| 104 | + const auto &literal = bindings.Literals.front().second; |
| 105 | + ASSERT_TRUE(literal.isCovered()); |
| 106 | + ASSERT_TRUE(literal.isDirectRequirement()); |
| 107 | + ASSERT_FALSE(literal.getDefaultType()->isEqual(floatTy)); |
| 108 | + } |
| 109 | + |
| 110 | + // Let's test transitive literal requirement coverage, |
| 111 | + // literal requirements are prepagated up the subtype chain. |
| 112 | + |
| 113 | + auto *otherTy = cs.createTypeVariable(cs.getConstraintLocator({}), |
| 114 | + /*options=*/0); |
| 115 | + |
| 116 | + cs.addConstraint(ConstraintKind::Subtype, floatLiteralTy, otherTy, |
| 117 | + cs.getConstraintLocator({})); |
| 118 | + |
| 119 | + { |
| 120 | + auto bindings = cs.inferBindingsFor(otherTy, /*finalize=*/false); |
| 121 | + |
| 122 | + // Make sure that there are no direct bindings or protocol requirements. |
| 123 | + |
| 124 | + ASSERT_EQ(bindings.Bindings.size(), (unsigned)0); |
| 125 | + ASSERT_EQ(bindings.Literals.size(), (unsigned)0); |
| 126 | + |
| 127 | + llvm::SmallDenseMap<TypeVariableType *, ConstraintSystem::PotentialBindings> |
| 128 | + env; |
| 129 | + env.insert({floatLiteralTy, cs.inferBindingsFor(floatLiteralTy)}); |
| 130 | + |
| 131 | + bindings.finalize(cs, env); |
| 132 | + |
| 133 | + // Inferred a single transitive binding through `$T_float`. |
| 134 | + ASSERT_EQ(bindings.Bindings.size(), (unsigned)1); |
| 135 | + // Inferred literal requirement through `$T_float` as well. |
| 136 | + ASSERT_EQ(bindings.Literals.size(), (unsigned)1); |
| 137 | + |
| 138 | + const auto &literal = bindings.Literals.front().second; |
| 139 | + |
| 140 | + ASSERT_TRUE(literal.isCovered()); |
| 141 | + ASSERT_FALSE(literal.isDirectRequirement()); |
| 142 | + ASSERT_FALSE(literal.getDefaultType()->isEqual(floatTy)); |
| 143 | + } |
52 | 144 | }
|
53 | 145 |
|
54 | 146 | // Given a set of inferred protocol requirements, make sure that
|
|
0 commit comments