Typecheck Mapping/Listing members lazily (#628)

This changes how the language performs typechecks for mappings and
listings.

Currently, Pkl will shallow-force any Mapping and Listing to check it
the type parameter (e.g. Listing<Person> means each element is checked
to be an instance of Person).

This changes the language to check each member's type when the member
is accessed.

This also adjust test runner to handle thrown errors from within tests.

With the change to make mapping/listing typechecks lazy, we can now
correctly handle thrown errors from within a single test case.

This adjusts the test runner to consider any thrown errors as a failure
for that specific test case.
This commit is contained in:
Daniel Chao
2024-09-06 15:05:23 -07:00
committed by GitHub
parent 7001a42149
commit 7868d9d9c8
86 changed files with 3342 additions and 385 deletions
@@ -20,9 +20,9 @@ examples {
["listing"] {
new Listing { 1; 2; 3 } as Listing<Int>
module.catch(() -> new Listing { 1; 2; 3 } as Listing<String>)
module.catch(() -> (new Listing { 1; 2; 3 } as Listing<String>)[0])
}
["mapping"] {
module.catch(() -> new Listing { 1; 2; 3 } as Mapping<Int, String>)
new Mapping { ["Pigeon"] = 42; ["Barn Owl"] = 21 } as Mapping<String, Int>
@@ -49,9 +49,9 @@ examples {
["function type"] {
(((x) -> x) as (Int) -> Int).apply(42)
(((x) -> x) as (String) -> String).apply(42)
module.catch(() -> ((x, y) -> x) as (Int) -> Int)
module.catch(() -> ((x, _) -> x) as (Int) -> Int)
}
["string literal type"] {
"Pigeon" as "Pigeon"|"Barn Owl"
module.catch(() -> "Pigeon" as "Piggy"|"Barn Owl")
@@ -0,0 +1,34 @@
amends "../snippetTest.pkl"
examples {
["set of listing"] {
local s1 = Set(
new Listing { 1; 2; 3 }
) as Set<Listing<Int>>
local s2 = Set(
new Listing { "one"; "two"; "three" }
) as Set<Listing<Int>>
s1.first[0]
module.catchOrNull(() -> s2.first) == null
module.catch(() -> s2.first[0])
}
["listing"] {
local l = new Listing { 1; 2; 3 } as Listing<String>
module.catchOrNull(() -> l) == null
module.catch(() -> l[0])
}
["mapping"] {
local m1 = new Mapping {
["hi"] = 1
["bye"] = 2
} as Mapping<String, String>
module.catchOrNull(() -> m1) == null
module.catch(() -> m1["hi"])
module.catch(() -> m1["bye"])
local m2 = new Mapping {
["hi"] = 1
["bye"] = 2
} as Mapping<Int, Int>
module.catch(() -> m2)
}
}
@@ -0,0 +1,3 @@
res = new Listing<String> {
1
}
@@ -0,0 +1,5 @@
one = 1
res = new Listing<String> {
one
}
@@ -0,0 +1,3 @@
res: Listing<String(!isEmpty)> = new Listing<String> {
""
}
@@ -0,0 +1,3 @@
res: Listing<String(!isEmpty)> = new Listing<String(endsWith("ga"))> {
"hola"
}
@@ -0,0 +1,4 @@
local l = new Listing { 1; 2; 3 } as Listing<String>
res = l[0]
@@ -0,0 +1,3 @@
res = new Mapping<String, String> {
["foo"] = 1
}
@@ -0,0 +1,3 @@
res: Mapping<String, String> = new {
["foo"] = 1
}
@@ -0,0 +1,4 @@
// ConstantEntriesLiteralNode
res: Mapping<String, String> = new {
[1] = "foo"
}
@@ -0,0 +1,6 @@
num = 1
// EntriesLiteralNode
res: Mapping<String, String> = new {
[num] = "foo"
}
@@ -0,0 +1,7 @@
// GeneratorObjectLiteralNode
res: Mapping<String, String> = new {
when (false) {
["foo"] = "foo"
}
[1] = "foo"
}
@@ -0,0 +1,11 @@
a = new Listing { "hi" }
b = (a) {
"hihih"
}
bar = new Mapping {
[b] = "foo"
}
res: Mapping<Listing<String(length == 5)>, String> = bar
@@ -0,0 +1,3 @@
res = new Mapping<Listing<String(length == 5)>, String> {
[new Listing { "hi" }] = "hi"
}
@@ -0,0 +1,3 @@
res: Mapping<String, String> = new {
...Map("foo", 1)
}
@@ -0,0 +1,32 @@
amends "../snippetTest.pkl"
examples {
["listings are lazy"] {
// backed by ConstantEntriesLiteralNode
local listing = new Listing<String> {
"foo"
throw("uh oh")
}
listing[0]
module.catch(() -> listing[1])
}
["listings are lazy with generator entries"] {
local listing = new Listing<String> {
when (false) {
"uh oh"
}
"foo"
throw("uh oh")
}
listing[0]
}
["nested listings are also lazy"] {
local listing = new Listing<Listing<String>> {
new {
"bar"
throw("uh oh")
}
}
listing[0][0]
}
}
@@ -0,0 +1,168 @@
amends "../snippetTest.pkl"
facts {
["equals"] {
local l1 = new Listing<String(length.isOdd)> {}
local l2: Listing<String(this == capitalize())> = l1
l1 == l2
}
}
examples {
["type check: new with explicit parent"] {
local l = new Listing<String> {
1
}
module.catch(() -> l[0])
}
["type check: local new with inferred parent"] {
local l: Listing<String> = new {
1
}
module.catch(() -> l[0])
}
["type check: local paramaterized property type, unparamaterized new with explicit parent"] {
local m: Listing<String> = new Listing {
1
}
module.catch(() -> m[0])
}
["type check: local unparameterized property type, paramaterized new with explicit parent"] {
local m: Listing = new Listing<String> {
1
}
module.catch(() -> m[0])
}
["amending listings does not require type checks on amending object members"] {
local m: Listing<String> = new {
"hi"
}
// ElementsLiteralNode
(m) {
1
}
// ElementsEntriesLiteralNode
(m) {
[0] = 1
2
}
// GeneratorObjectLiteralNode
(m) {
when (false) {
"hi"
}
1
}
}
["type check: constraints on both property type node and explicit parent type node are checked"] {
local l: Listing<String(length.isOdd)> = new Listing<String(this == capitalize())> {
"Ba"
"bar"
}
module.catch(() -> l[0])
module.catch(() -> l[1])
}
["type check: nested listings: constraints on both parent type node and child type node are checked"] {
local res12: Listing<Listing<String(length.isOdd)>> =
new Listing<Listing<String(this == capitalize())>> {
new {
"Ba"
"bar"
}
}
module.catch(() -> res12[0][0])
module.catch(() -> res12[0][1])
}
["type check: propagate from List"] {
local l: List<Listing<String(length.isOdd)>> = List(
new Listing<String(this == capitalize())> {
"Ba"
"bar"
}
)
module.catch(() -> l[0][0])
module.catch(() -> l[0][1])
}
["type check: propagate function types"] {
local l = new Listing<String(this == capitalize())> {
"Ba" // fails `length.isOdd`
"bar" // fails `this == capitalize()`
}
local l2 = new Listing {
"Ba" // fails `length.isOdd`
"bar" // fails `this == capitalize()`
}
// type check String(length.isOdd) should be propagated to the listing via a paramater type
// annotation
local function func1(listing: Listing<String(length.isOdd)>) = listing
// type check String(length.isOdd) should be propagated to the listing via a return type
// annotation
local function func2(listing): Listing<String(length.isOdd)> = listing
// type check String(length.isOdd) and String(this == capitalize()) should be propagated to the
// listing via both parameter type and return type annotations
local function func3(listing: Listing<String(length.isOdd)>): Listing<String(this == capitalize())> = listing
module.catch(() -> func1(l)[0])
module.catch(() -> func1(l)[1])
module.catch(() -> func2(l)[0])
module.catch(() -> func2(l)[1])
module.catch(() -> func3(l2)[0])
module.catch(() -> func3(l2)[1])
}
["type check: union type"] {
local l: Listing<String(length.isOdd)>|Listing<String(length == 4)> =
new Listing<String(this == capitalize())> {
"Ba" // fails length.isOdd and length == 4
"bar" // fails this == capitalize()
"Bazz" // passes this == capitalize() and length == 4
"Qux" // passes this == capitalize() and length.isOdd
}
module.catch(() -> l)
}
["type check: nullable type"] {
local l: Listing<String(length.isOdd)>? =
new Listing<String(this == capitalize())> {
"Ba" // fails length.isOdd
"bar" // fails this == capitalize()
}
module.catch(() -> l!![0])
module.catch(() -> l!![1])
}
["type check: propagate lambda type"] {
local func1 = (it: Listing<String(length.isOdd)>) -> it
local l = new Listing<String(this == capitalize())> {
"Ba" // fails `length.isOdd`
"bar" // fails `this == capitalize()`
}
module.catch(() -> func1.apply(l)[0])
module.catch(() -> func1.apply(l)[1])
}
["intermediary objects are not checked"] {
local l = new Listing<String> {
// okay, because this node never gets evaluated
50
}
(l) {
[0] = "Hello"
}
}
}
@@ -0,0 +1,46 @@
amends "../snippetTest.pkl"
local class TheClass {
local isLongString = (it) -> it.length > 10
prop: Listing<String(isLongString)>
}
local class TheClass2 {
hidden requiredLength: Int
prop: Listing<String(length > requiredLength)>
}
examples {
["name resolution in type constraint"] {
// should be able to resolve `isLongString` when checking this member
module.catch(() -> new TheClass {
prop {
"too short"
}
}.prop[0])
new TheClass {
prop {
"this is long enough"
}
}
}
["resolves the receiver"] {
local base: TheClass2 = new {
requiredLength = 5
}
(base) {
prop {
"long enough"
}
}
module.catch(() -> (base) {
requiredLength = 10
prop {
"too short"
}
}.prop[0])
}
}
@@ -0,0 +1,10 @@
// ensure that these members are only evaluated once (trace should only be emitted once)
listing = new Listing { trace(1) }
listing2: Listing<Int> = listing
listing3 = new Listing {
new Listing { trace(2) }
}
listing4: Listing<Listing<Int>> = listing3
@@ -1,41 +1,367 @@
import "pkl:test"
hidden x1: Listing<String> = new {
local x1: Listing<String> = new {
"pigeon"
42
"barn owl"
}
hidden x2: Listing<String(length > 3)> = new {
local x2: Listing<String(length > 3)> = new {
"pigeon"
"bob"
}
hidden x3: Listing<String>(!isEmpty)
res1 = x1[0]
res2 = test.catchOrNull(() -> x1[1])
res3 = x2[0]
res4 = test.catchOrNull(() -> x2[1])
res1 = test.catch(() -> x1)
res2 = test.catch(() -> x2)
res3 = test.catch(() -> x3)
hidden x4: Listing = new {
local x4: Listing = new {
throw("element unnecessarily evaluated")
}
hidden x5: Listing<Any> = new {
local x5: Listing<Any> = new {
throw("element unnecessarily evaluated")
}
hidden x6: Listing<unknown> = new {
local x6: Listing<unknown> = new {
throw("element unnecessarily evaluated")
}
hidden x7 = new Listing {
local x7 = new Listing {
throw("element unnecessarily evaluated")
42
throw("element unnecessarily evaluated")
}
res4 = x4.length == 1
res5 = x5.length == 1
res6 = x6.length == 1
res7 = x7[1] == 42
local x8 = new Listing<String> {
throw("element unneccessarily evaluated")
}
res5 = x4.length == 1
res6 = x5.length == 1
res7 = x6.length == 1
res8 = x7[1] == 42
res9 = x8.length == 1
local x9 = new Listing {
"foo"
1
}
local x10 = x9 as Listing<String>
res10 = x9 is Listing<String>
res11 = x10[0]
res12 = test.catch(() -> x10[1])
local x11: Listing<String(!isEmpty)> = new Listing<String> {
""
}
res13 = test.catch(() -> x11[0])
local x12: Listing<String> = new Listing<String(!isEmpty)> {
""
}
res14 = test.catch(() -> x12[0])
local l = new Listing { "foo"; 1 }
local x13: (Listing<String>|Listing<Int>) = l
local x14: Listing<String>|Listing<Int>? = l
local x15: Listing<String>|(Listing<Int>|Int) = l
local x16: Listing<String>|Int = l
res15 = test.catch(() -> x13)
res16 = test.catch(() -> x14)
res17 = test.catch(() -> x15)
// just accessing x16 doesn't throw because only one Listing in the union type
res18 = x16.length
// noinspection TypeMismatch
res19 = test.catch(() -> x16[1])
local x17: Listing<Listing<String>> = new {
new {
5
}
}
res20 = x17.length
res21 = x17[0].length
res22 = test.catch(() -> x17[0][0])
local x18 = new Listing { 1; 2; 3 } as Listing<String>
res23 = x18.length
res24 = test.catch(() -> x18[0])
local x19 = new Listing<String> {
when (true) {
15
}
}
res25 = x19.length
res26 = test.catch(() -> x19[0])
local x20 = new Listing<String> {
...List(1, 2, 3)
}
res27 = x20.length
res28 = test.catch(() -> x20[0])
local x21 = new Listing<String> {
for (elem in List(1, 2, 3)) {
elem
}
}
res29 = x21.length
res30 = test.catch(() -> x21[0])
local x22: Listing<String> = new {
"hi"
}
// typechecks not required when amending
// ElementsLiteralNode
res31 = (x22) {
"hi"
}
// ElementsEntriesLiteralNode
res32 = (x22) {
[0] = 1
2
}
// GeneratorObjectLiteralNode
res33 = (x22) {
when (false) {
"hi"
}
1
}
// GeneratorSpreadNode
res34 = (x22) {
...List(1, 2, 3)
}
local x23: Listing<Listing<String(length.isOdd)>> =
new Listing<Listing<String(this == capitalize())>> {
new {
"Ba"
"bar"
}
}
res35 = test.catch(() -> x23[0][0])
res36 = test.catch(() -> x23[0][1])
// check listings from inside a list
local x24: List<Listing<String(length.isOdd)>> = List(
new Listing<String(this == capitalize())> {
"Ba"
"bar"
}
)
res37 = test.catch(() -> x24[0][0])
res38 = test.catch(() -> x24[0][1])
local x25: List<String|Listing<Int>> = List(
"hello",
new Listing {
"foo"
},
"goodbye"
)
res39 = x25[0]
// retain lazy typecheck of listing.
res40 = x25[1].length
res41 = test.catch(() -> x25[1][0])
res42 = x25[2]
// check listings from inside a set
local x26: Set<Listing<String(length.isOdd)>> = Set(
new Listing<String(this == capitalize())> {
"Ba"
"bar"
}
)
res43 = test.catch(() -> x26[0][0])
local x27: Set<String|Listing<Int>> = Set(
"hello",
new Listing {
"foo"
},
"goodbye"
)
// sets are eagerly checked (need to compute hash code, therefore need to deep force)
res45 = test.catch(() -> x27)
local x28: List<Listing<Int>>|List<Listing<String>> = List(
new Listing { "hello" }
)
res46 = x28[0][0]
local x29: List<Listing<Int>>|List<Listing<String>> = List(
new Listing { 1; "hello" }
)
res47 = test.catch(() -> x29)
// check listings from inside a map
local x30: Map<String, Listing<String(length.isOdd)>> = Map(
"hello",
new Listing<String(this == capitalize())> {
"Ba"
"bar"
}
)
res48 = x30["hello"].length
res49 = test.catch(() -> x30["hello"][0])
res50 = test.catch(() -> x30["hello"][1])
local x31: Map<String, Int|Listing<String>> = Map(
"hello", 1,
"thelisting", new Listing {
1
2
},
"goodbye", 2
)
res51 = x31.length
res52 = x31["hello"]
res53 = x31["goodbye"]
res54 = x31["thelisting"].length
res55 = test.catch(() -> x31["thelisting"][0])
res56 = test.catch(() -> x31["thelisting"][1])
local x32: Map<Listing<String>, Int> = Map(
new Listing { 1; 2 },
1
)
res57 = test.catch(() -> x32)
local x33: Map<String, Listing<Int>|Int> = Map(
"first", 1,
"second", new Listing { "hi" }
)
res58 = x33.length
res59 = x33["first"]
res60 = x33["second"].length
res61 = test.catch(() -> x33["second"][0])
local x34: Pair<Listing<String>, Listing<String>> = Pair(
new Listing { 1 },
new Listing { 2 }
)
res62 = x34.first.length
res63 = x34.second.length
res64 = test.catch(() -> x34.first[0])
res65 = test.catch(() -> x34.second[0])
local x35: Pair<Int, Listing<String>> = Pair(
5,
new Listing { 1 }
)
res66 = x35.first
res67 = x35.second.length
res68 = test.catch(() -> x35.second[0])
local x36: Collection<Int|Listing<String>> = List(
1,
new Listing { "hello"; 1 }
)
res69 = x36.length
res70 = x36.first
res71 = x36[1].length
res73 = x36[1][0]
res74 = test.catch(() -> x36[1][1])
local x37: Collection<Int|Listing<String>> = Set(
1,
new Listing {
"hello"
1
}
)
res75 = test.catch(() -> x37)
local x38: Collection<Listing<String>>|Collection<Listing<Int>> =
List(new Listing {
1
"hi"
})
res76 = test.catch(() -> x38)
local class Person {
prop1 = 1
prop2 = 2
prop3 = "hi"
}
local x39: Listing<Int> = new Person {}.toMap().values.toListing()
res77 = x39.length
res78 = x39[0]
res79 = x39[1]
res80 = test.catch(() -> x39[2])
local x40: Listing<Int> = new {
...List(1, 2, "hello")
}
res81 = x40.length
res82 = x40[0]
res83 = x40[1]
res84 = test.catch(() -> x40[2])
// returns a new listing
function myFunction(elem: Listing<Int>) = elem
local x41 = myFunction(new Listing { "hello" })
res85 = x41.length
res86 = test.catch(() -> x41[0])
function myFunction2(elem): Listing<Int> = elem
local x42 = myFunction(new Listing { "hello" })
res87 = x42.length
res88 = test.catch(() -> x42[0])
local x43 = (it: Listing<Int>) -> it
local x44 = x43.apply(new Listing { "hello" })
res89 = x44.length
res90 = test.catch(() -> x44[0])
function myFunction3(elem: Listing<Int>): Listing<Int> = elem
local x45 = myFunction3(new Listing { "hello" })
res91 = x45.length
res92 = test.catch(() -> x45[0])
@@ -15,9 +15,9 @@ hidden x2: Listing<String(length > 3)> = new {
hidden x3: Listing<String>(!isEmpty)
res1 = test.catch(() -> x1)
res2 = test.catch(() -> x2)
res3 = test.catch(() -> x3)
res1 = test.catch(() -> x1.toList())
res2 = test.catch(() -> x2.toList())
res3 = test.catch(() -> x3.toList())
hidden x4: Listing = new {
when (true) {
@@ -27,12 +27,16 @@ local x6: Mapping<String, String(!isEmpty)> = new {
["pigeon"] = ""
}
res1 = test.catch(() -> x1)
res2 = test.catch(() -> x2)
res3 = test.catch(() -> x3)
res4 = test.catch(() -> x4)
res5 = test.catch(() -> x5)
res6 = test.catch(() -> x6)
res1 = x1.length
res2 = test.catch(() -> x1["barn owl"])
res3 = x2.length
res4 = x2["fred"]
res5 = test.catch(() -> x2["barney"])
res6 = test.catch(() -> x3)
res7 = test.catch(() -> x4)
res8 = test.catch(() -> x5)
res9 = x6.length
res10 = test.catch(() -> x6["pigeon"])
hidden x7: Mapping = new {
["first"] = throw("value unnecessarily evaluated")
@@ -52,7 +56,312 @@ hidden x10 = new Mapping {
["third"] = throw("value unnecessarily evaluated")
}
res7 = !x7.isEmpty
res8 = !x8.isEmpty
res9 = !x9.isEmpty
res10 = x10["second"] == 42
res11 = x7.length
res12 = x8.length
res13 = x9.length
res14 = x10.length
res15 = x10["second"]
local x11: Mapping<String, String(!isEmpty)> = new Mapping<String, String> {
["foo"] = ""
}
res16 = x11.length
res17 = test.catch(() -> x11["foo"])
local x12: Mapping<String, String> = new Mapping<String, String(!isEmpty)> {
["foo"] = ""
}
res18 = x12.length
res19 = test.catch(() -> x12["foo"])
local m = new Mapping {
["one"] = 1
["two"] = "two"
}
local x13: Mapping<String, String>|Mapping<String, Int> = m
local x14: Mapping<String, String>|Mapping<String, Int>? = m
local x15: Mapping<String, String>|(Mapping<String, Int>|Int) = m
local x16: Mapping<String, String>|Int = m
res20 = test.catch(() -> x13)
res21 = test.catch(() -> x14)
res22 = test.catch(() -> x15)
res23 = x16.length
res24 = test.catch(() -> x16["one"])
local x17: Mapping<String, Mapping<String, String>> = new {
["foo"] {
["bar"] = 1
}
}
res25 = x17.length
res26 = x17["foo"].length
res27 = test.catch(() -> x17["foo"]["bar"])
local x18 = new Mapping { ["foo"] = 1 } as Mapping<String, String>
res28 = x18.length
res29 = test.catch(() -> x18["foo"])
local x19 = new Mapping<String, String> {
when (true) {
["foo"] = 1
}
}
res30 = x19.length
res31 = test.catch(() -> x19["foo"])
local x20 = new Mapping<String, String> {
...Map("foo", 1)
}
res32 = x20.length
res33 = test.catch(() -> x20["foo"])
local x21 = new Mapping<String, String> {
for (k, v in Map("foo", 1)) {
[k] = v
}
}
res34 = x21.length
res35 = test.catch(() -> x21["foo"])
local x22: Mapping<String, String> = new {
["hi"] = "hi"
}
// typechecks not required when amending
// ElementsEntriesLiteralNode
res36 = (x22) {
["hi2"] = 1
}
// GeneratorObjectLiteralNode
res37 = (x22) {
when (true) {
["hi2"] = 1
}
}
// GeneratorSpreadNode
res38 = (x22) {
...Map("hi2", 1)
}
local x23: Mapping<String, Mapping<String, String(length.isOdd)>> = new Mapping<String, Mapping<String, String(this == capitalize())>> {
["foo"] {
["first"] = "Ba"
["second"] = "bar"
}
}
res39 = test.catch(() -> x23["foo"]["first"])
res40 = test.catch(() -> x23[""])
// check mappings from inside a list
local x24: List<Mapping<String, String(length.isOdd)>> = List(
new Mapping<String, String(this == capitalize())> {
["first"] = "Ba"
["second"] = "bar"
}
)
res41 = test.catch(() -> x24[0]["first"])
res42 = test.catch(() -> x24[0]["second"])
local x25: List<String|Mapping<String, Int>> = List(
"hello",
new Mapping {
["foo"] = "foo"
},
"goodbye"
)
res43 = x25[0]
// retain lazy typecheck of mapping.
res44 = x25[1].length
res45 = test.catch(() -> x25[1]["foo"])
res46 = x25[2]
// check mappings from inside a set
local x26: Set<Mapping<String, String(length.isOdd)>> = Set(
new Mapping<String, String(this == capitalize())> {
["first"] = "Ba"
["second"] = "bar"
}
)
// sets are eagerly checked (need to compute hash code, therefore need to deep force)
res47 = test.catch(() -> x26)
local x28: List<Mapping<String, Int>>|List<Mapping<String, String>> = List(
new Mapping { ["foo"] = 1 }
)
res48 = x28[0]["foo"]
local x29: List<Mapping<String, Int>>|List<Mapping<String, String>> = List(
new Mapping {
["foo"] = 1
["bar"] = "hi"
}
)
res49 = test.catch(() -> x29)
// check mappings from inside a map
local x30: Map<String, Mapping<String, String(length.isOdd)>> = Map(
"hello",
new Mapping<String, String(this == capitalize())> {
["first"] = "Ba"
["second"] = "bar"
}
)
res50 = x30["hello"].length
res51 = test.catch(() -> x30["hello"]["first"])
res52 = test.catch(() -> x30["hello"]["second"])
local x31: Map<String, Int|Mapping<String, String>> = Map(
"hello", 1,
"themapping", new Mapping {
["one"] = 1
["two"] = 2
},
"goodbye", 2
)
res53 = x31.length
res54 = x31["hello"]
res55 = x31["goodbye"]
res56 = x31["themapping"].length
res57 = test.catch(() -> x31["themapping"]["one"])
res58 = test.catch(() -> x31["themapping"]["two"])
local x32: Map<Mapping<String, String>, Int> = Map(
new Mapping { ["one"] = 1 },
1
)
res59 = test.catch(() -> x32)
local x33: Map<String, Mapping<String, Int>|Int> = Map(
"first", 1,
"second", new Mapping { ["hi"] = "hi" }
)
res60 = x33.length
res61 = x33["first"]
res62 = x33["second"].length
res63 = test.catch(() -> x33["second"]["hi"])
local x34: Pair<Mapping<String, String>, Mapping<String, String>> = Pair(
new Mapping { ["one"] = 1 },
new Mapping { ["one"] = 1 }
)
res64 = x34.first.length
res65 = x34.second.length
res66 = test.catch(() -> x34.first["one"])
res67 = test.catch(() -> x34.second["one"])
local x35: Pair<Int, Mapping<String, String>> = Pair(
5,
new Mapping { ["one"] = 1 }
)
res68 = x35.first
res69 = x35.second.length
res70 = test.catch(() -> x35.second["one"])
local x36: Collection<Int|Mapping<String, String>> = List(
1,
new Mapping {
["one"] = "hello"
["two"] = 1
}
)
res71 = x36.length
res72 = x36.first
res73 = x36[1].length
res74 = x36[1]["one"]
res75 = test.catch(() -> x36[1]["two"])
local x37: Collection<Int|Mapping<String, String>> = Set(
1,
new Mapping {
["one"] = "hello"
["two"] = 1
}
)
res77 = test.catch(() -> x37)
local x38: Collection<Mapping<String, String>>|Collection<Mapping<String, Int>> =
List(new Mapping {
["one"] = "hello"
["two"] = 1
})
res78 = test.catch(() -> x38)
local class Person {
prop1 = 1
prop2 = 2
prop3 = "hi"
}
local x39: Mapping<String, Int> = new Person {}
.toMap()
.toMapping()
res79 = x39.length
res80 = x39["prop1"]
res81 = x39["prop2"]
res82 = test.catch(() -> x39["prop3"])
local x40: Mapping<String, Int> = new {
...Map("one", 1, "two", 2, "three", "hello")
}
res83 = x40.length
res84 = x40["one"]
res85 = x40["two"]
res86 = test.catch(() -> x40["three"])
// returns a new mapping
function myFunction(elem: Mapping<String, Int>) = elem
local x41 = myFunction(new Mapping { ["hello"] = "hello" })
res87 = x41.length
res88 = test.catch(() -> x41["hello"])
function myFunction2(elem): Mapping<String, Int> = elem
local x42 = myFunction(new Mapping { ["hello"] = "hello" })
res89 = x42.length
res90 = test.catch(() -> x42["hello"])
local x43 = (it: Mapping<String, Int>) -> it
local x44 = x43.apply(new Mapping { ["hello"] = "hello" })
res91 = x44.length
res92 = test.catch(() -> x44["hello"])
function myFunction3(elem: Mapping<String, Int>): Mapping<String, Int> = elem
local x45 = myFunction3(new Mapping { ["hello"] = "hello" })
res93 = x45.length
res94 = test.catch(() -> x45["hello"])
@@ -33,12 +33,12 @@ local x6: Mapping<String, String(!isEmpty)> = new {
["pigeon"] = ""
}
res1 = test.catch(() -> x1)
res2 = test.catch(() -> x2)
res1 = test.catch(() -> x1["barn owl"])
res2 = test.catch(() -> x2["barney"])
res3 = test.catch(() -> x3)
res4 = test.catch(() -> x4)
res5 = test.catch(() -> x5)
res6 = test.catch(() -> x6)
res6 = test.catch(() -> x6["pigeon"])
hidden x7: Mapping = new {
when (true) {
@@ -0,0 +1,17 @@
examples {
["set of listing"] {
1
false
"Expected value of type `Int`, but got type `String`. Value: \"one\""
}
["listing"] {
true
"Expected value of type `String`, but got type `Int`. Value: 1"
}
["mapping"] {
true
"Expected value of type `String`, but got type `Int`. Value: 1"
"Expected value of type `String`, but got type `Int`. Value: 2"
"Expected value of type `Int`, but got type `String`. Value: \"hi\""
}
}
@@ -5,10 +5,6 @@ x | ["\(idx)_2"] = o // at this point, `o` should be out of scope
^
at forGeneratorWrongVariableName#res[#2] (file:///$snippetsDir/input/errors/forGeneratorWrongVariableName.pkl)
x | res: Mapping<String, Int> = new {
^^^^^
at forGeneratorWrongVariableName#res (file:///$snippetsDir/input/errors/forGeneratorWrongVariableName.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res = new Listing<String> {
^^^^^^
at listingTypeCheckError1#res (file:///$snippetsDir/input/errors/listingTypeCheckError1.pkl)
x | 1
^
at listingTypeCheckError1#res[#1] (file:///$snippetsDir/input/errors/listingTypeCheckError1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res = new Listing<String> {
^^^^^^
at listingTypeCheckError2#res (file:///$snippetsDir/input/errors/listingTypeCheckError2.pkl)
x | one
^^^
at listingTypeCheckError2#res[#1] (file:///$snippetsDir/input/errors/listingTypeCheckError2.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Type constraint `!isEmpty` violated.
Value: ""
x | res: Listing<String(!isEmpty)> = new Listing<String> {
^^^^^^^^
at listingTypeCheckError3#res (file:///$snippetsDir/input/errors/listingTypeCheckError3.pkl)
x | ""
^^
at listingTypeCheckError3#res[#1] (file:///$snippetsDir/input/errors/listingTypeCheckError3.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Type constraint `endsWith("ga")` violated.
Value: "hola"
x | res: Listing<String(!isEmpty)> = new Listing<String(endsWith("ga"))> {
^^^^^^^^^^^^^^
at listingTypeCheckError4#res (file:///$snippetsDir/input/errors/listingTypeCheckError4.pkl)
x | "hola"
^^^^^^
at listingTypeCheckError4#res[#1] (file:///$snippetsDir/input/errors/listingTypeCheckError4.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,19 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | local l = new Listing { 1; 2; 3 } as Listing<String>
^^^^^^
at listingTypeCheckError5#l (file:///$snippetsDir/input/errors/listingTypeCheckError5.pkl)
x | local l = new Listing { 1; 2; 3 } as Listing<String>
^
at listingTypeCheckError5#l[#1] (file:///$snippetsDir/input/errors/listingTypeCheckError5.pkl)
x | res = l[0]
^^^^
at listingTypeCheckError5#res (file:///$snippetsDir/input/errors/listingTypeCheckError5.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res = new Mapping<String, String> {
^^^^^^
at mappingTypeCheckError1#res (file:///$snippetsDir/input/errors/mappingTypeCheckError1.pkl)
x | ["foo"] = 1
^
at mappingTypeCheckError1#res["foo"] (file:///$snippetsDir/input/errors/mappingTypeCheckError1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res: Mapping<String, String> = new {
^^^^^^
at mappingTypeCheckError2#res (file:///$snippetsDir/input/errors/mappingTypeCheckError2.pkl)
x | ["foo"] = 1
^
at mappingTypeCheckError2#res["foo"] (file:///$snippetsDir/input/errors/mappingTypeCheckError2.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,19 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res: Mapping<String, String> = new {
^^^^^^
at mappingTypeCheckError3#res (file:///$snippetsDir/input/errors/mappingTypeCheckError3.pkl)
x | [1] = "foo"
^
at mappingTypeCheckError3#res[1] (file:///$snippetsDir/input/errors/mappingTypeCheckError3.pkl)
x | res: Mapping<String, String> = new {
^^^^^
at mappingTypeCheckError3#res (file:///$snippetsDir/input/errors/mappingTypeCheckError3.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,19 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res: Mapping<String, String> = new {
^^^^^^
at mappingTypeCheckError4#res (file:///$snippetsDir/input/errors/mappingTypeCheckError4.pkl)
x | [num] = "foo"
^^^
at mappingTypeCheckError4#res[#1] (file:///$snippetsDir/input/errors/mappingTypeCheckError4.pkl)
x | res: Mapping<String, String> = new {
^^^^^
at mappingTypeCheckError4#res (file:///$snippetsDir/input/errors/mappingTypeCheckError4.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,19 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res: Mapping<String, String> = new {
^^^^^^
at mappingTypeCheckError5#res (file:///$snippetsDir/input/errors/mappingTypeCheckError5.pkl)
x | [1] = "foo"
^
at mappingTypeCheckError5#res[1] (file:///$snippetsDir/input/errors/mappingTypeCheckError5.pkl)
x | res: Mapping<String, String> = new {
^^^^^
at mappingTypeCheckError5#res (file:///$snippetsDir/input/errors/mappingTypeCheckError5.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,19 @@
–– Pkl Error ––
Type constraint `length == 5` violated.
Value: "hi"
xx | res: Mapping<Listing<String(length == 5)>, String> = bar
^^^^^^^^^^^
at mappingTypeCheckError6#res (file:///$snippetsDir/input/errors/mappingTypeCheckError6.pkl)
x | [b] = "foo"
^
at mappingTypeCheckError6#bar[#1] (file:///$snippetsDir/input/errors/mappingTypeCheckError6.pkl)
xx | res: Mapping<Listing<String(length == 5)>, String> = bar
^^^
at mappingTypeCheckError6#res (file:///$snippetsDir/input/errors/mappingTypeCheckError6.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,15 @@
–– Pkl Error ––
Type constraint `length == 5` violated.
Value: "hi"
x | res = new Mapping<Listing<String(length == 5)>, String> {
^^^^^^^^^^^
at mappingTypeCheckError7#res (file:///$snippetsDir/input/errors/mappingTypeCheckError7.pkl)
x | [new Listing { "hi" }] = "hi"
^^^^^^^^^^^^^^^^^^^^
at mappingTypeCheckError7#res[#1] (file:///$snippetsDir/input/errors/mappingTypeCheckError7.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,11 @@
–– Pkl Error ––
Expected value of type `String`, but got type `Int`.
Value: 1
x | res: Mapping<String, String> = new {
^^^^^^
at mappingTypeCheckError8#res (file:///$snippetsDir/input/errors/mappingTypeCheckError8.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
@@ -0,0 +1,12 @@
examples {
["listings are lazy"] {
"foo"
"uh oh"
}
["listings are lazy with generator entries"] {
"foo"
}
["nested listings are also lazy"] {
"bar"
}
}
@@ -0,0 +1,69 @@
facts {
["equals"] {
true
}
}
examples {
["type check: new with explicit parent"] {
"Expected value of type `String`, but got type `Int`. Value: 1"
}
["type check: local new with inferred parent"] {
"Expected value of type `String`, but got type `Int`. Value: 1"
}
["type check: local paramaterized property type, unparamaterized new with explicit parent"] {
"Expected value of type `String`, but got type `Int`. Value: 1"
}
["type check: local unparameterized property type, paramaterized new with explicit parent"] {
"Expected value of type `String`, but got type `Int`. Value: 1"
}
["amending listings does not require type checks on amending object members"] {
new {
"hi"
1
}
new {
1
2
}
new {
"hi"
1
}
}
["type check: constraints on both property type node and explicit parent type node are checked"] {
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
}
["type check: nested listings: constraints on both parent type node and child type node are checked"] {
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
}
["type check: propagate from List"] {
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
}
["type check: propagate function types"] {
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
}
["type check: union type"] {
"Expected value of type `Listing<String(length.isOdd)>|Listing<String(length == 4)>`, but got a different `Listing`. Value: new Listing { \"Ba\"; ?; ?; ? }"
}
["type check: nullable type"] {
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
}
["type check: propagate lambda type"] {
"Type constraint `length.isOdd` violated. Value: \"Ba\""
"Type constraint `this == capitalize()` violated. Value: \"bar\""
}
["intermediary objects are not checked"] {
new {
"Hello"
}
}
}
@@ -0,0 +1,18 @@
examples {
["name resolution in type constraint"] {
"Type constraint `isLongString` violated. Value: \"too short\""
new {
prop {
"this is long enough"
}
}
}
["resolves the receiver"] {
new {
prop {
"long enough"
}
}
"Type constraint `length > requiredLength` violated. Value: \"too short\""
}
}
@@ -0,0 +1,18 @@
listing {
1
}
listing2 {
1
}
listing3 {
new {
2
}
}
listing4 {
new {
2
}
}
pkl: TRACE: 1 = 1 (file:///$snippetsDir/input/listings/listing7.pkl)
pkl: TRACE: 2 = 2 (file:///$snippetsDir/input/listings/listing7.pkl)
@@ -1,7 +1,104 @@
res1 = "Expected value of type `String`, but got type `Int`. Value: 42"
res2 = "Type constraint `length > 3` violated. Value: \"bob\""
res3 = "Type constraint `!isEmpty` violated. Value: new Listing {}"
res4 = true
res1 = "pigeon"
res2 = "Expected value of type `String`, but got type `Int`. Value: 42"
res3 = "pigeon"
res4 = "Type constraint `length > 3` violated. Value: \"bob\""
res5 = true
res6 = true
res7 = true
res8 = true
res9 = true
res10 = false
res11 = "foo"
res12 = "Expected value of type `String`, but got type `Int`. Value: 1"
res13 = "Type constraint `!isEmpty` violated. Value: \"\""
res14 = "Type constraint `!isEmpty` violated. Value: \"\""
res15 = "Expected value of type `Listing<String>|Listing<Int>`, but got a different `Listing`. Value: new Listing { \"foo\"; 1 }"
res16 = "Expected value of type `Listing<String>|Listing<Int>?`, but got a different `Listing`. Value: new Listing { \"foo\"; 1 }"
res17 = "Expected value of type `Listing<String>|(Listing<Int>|Int)`, but got a different `Listing`. Value: new Listing { \"foo\"; 1 }"
res18 = 2
res19 = "Expected value of type `String`, but got type `Int`. Value: 1"
res20 = 1
res21 = 1
res22 = "Expected value of type `String`, but got type `Int`. Value: 5"
res23 = 3
res24 = "Expected value of type `String`, but got type `Int`. Value: 1"
res25 = 1
res26 = "Expected value of type `String`, but got type `Int`. Value: 15"
res27 = 3
res28 = "Expected value of type `String`, but got type `Int`. Value: 1"
res29 = 3
res30 = "Expected value of type `String`, but got type `Int`. Value: 1"
res31 {
"hi"
"hi"
}
res32 {
1
2
}
res33 {
"hi"
1
}
res34 {
"hi"
1
2
3
}
res35 = "Type constraint `length.isOdd` violated. Value: \"Ba\""
res36 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res37 = "Type constraint `length.isOdd` violated. Value: \"Ba\""
res38 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res39 = "hello"
res40 = 1
res41 = "Expected value of type `Int`, but got type `String`. Value: \"foo\""
res42 = "goodbye"
res43 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res45 = "Expected value of type `String|Listing<Int>`, but got a different `Listing`. Value: new Listing { \"foo\" }"
res46 = "hello"
res47 = "Expected value of type `List<Listing<Int>>|List<Listing<String>>`, but got a different `List`. Value: List(new Listing { 1; \"hello\" })"
res48 = 2
res49 = "Type constraint `length.isOdd` violated. Value: \"Ba\""
res50 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res51 = 3
res52 = 1
res53 = 2
res54 = 2
res55 = "Expected value of type `String`, but got type `Int`. Value: 1"
res56 = "Expected value of type `String`, but got type `Int`. Value: 2"
res57 = "Expected value of type `String`, but got type `Int`. Value: 1"
res58 = 2
res59 = 1
res60 = 1
res61 = "Expected value of type `Int`, but got type `String`. Value: \"hi\""
res62 = 1
res63 = 1
res64 = "Expected value of type `String`, but got type `Int`. Value: 1"
res65 = "Expected value of type `String`, but got type `Int`. Value: 2"
res66 = 5
res67 = 1
res68 = "Expected value of type `String`, but got type `Int`. Value: 1"
res69 = 2
res70 = 1
res71 = 2
res73 = "hello"
res74 = "Expected value of type `String`, but got type `Int`. Value: 1"
res75 = "Expected value of type `Int|Listing<String>`, but got a different `Listing`. Value: new Listing { \"hello\"; 1 }"
res76 = "Expected value of type `Collection<Listing<String>>|Collection<Listing<Int>>`, but got a different `List`. Value: List(new Listing { 1; \"hi\" })"
res77 = 3
res78 = 1
res79 = 2
res80 = "Expected value of type `Int`, but got type `String`. Value: \"hi\""
res81 = 3
res82 = 1
res83 = 2
res84 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res85 = 1
res86 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res87 = 1
res88 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res89 = 1
res90 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res91 = 1
res92 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
@@ -1,10 +1,102 @@
res1 = "Expected value of type `List`, but got type `Int`. Value: 42"
res1 = 2
res2 = "Expected value of type `List`, but got type `Int`. Value: 42"
res3 = "Expected value of type `List`, but got type `Int`. Value: 42"
res4 = "Expected value of type `List`, but got type `Int`. Value: 42"
res5 = "Type constraint `!isEmpty` violated. Value: \"\""
res6 = "Type constraint `!isEmpty` violated. Value: \"\""
res7 = true
res8 = true
res9 = true
res10 = true
res3 = 2
res4 = List(1, 2, 3)
res5 = "Expected value of type `List`, but got type `Int`. Value: 42"
res6 = "Expected value of type `List`, but got type `Int`. Value: 42"
res7 = "Expected value of type `List`, but got type `Int`. Value: 42"
res8 = "Type constraint `!isEmpty` violated. Value: \"\""
res9 = 1
res10 = "Type constraint `!isEmpty` violated. Value: \"\""
res11 = 1
res12 = 1
res13 = 1
res14 = 3
res15 = 42
res16 = 1
res17 = "Type constraint `!isEmpty` violated. Value: \"\""
res18 = 1
res19 = "Type constraint `!isEmpty` violated. Value: \"\""
res20 = "Expected value of type `Mapping<String, String>|Mapping<String, Int>`, but got a different `Mapping`. Value: new Mapping { [\"one\"] = 1; [\"two\"] = \"two\" }"
res21 = "Expected value of type `Mapping<String, String>|Mapping<String, Int>?`, but got a different `Mapping`. Value: new Mapping { [\"one\"] = 1; [\"two\"] = \"two\" }"
res22 = "Expected value of type `Mapping<String, String>|(Mapping<String, Int>|Int)`, but got a different `Mapping`. Value: new Mapping { [\"one\"] = 1; [\"two\"] = \"two\" }"
res23 = 2
res24 = "Expected value of type `String`, but got type `Int`. Value: 1"
res25 = 1
res26 = 1
res27 = "Expected value of type `String`, but got type `Int`. Value: 1"
res28 = 1
res29 = "Expected value of type `String`, but got type `Int`. Value: 1"
res30 = 1
res31 = "Expected value of type `String`, but got type `Int`. Value: 1"
res32 = 1
res33 = "Expected value of type `String`, but got type `Int`. Value: 1"
res34 = 1
res35 = "Expected value of type `String`, but got type `Int`. Value: 1"
res36 {
["hi"] = "hi"
["hi2"] = 1
}
res37 {
["hi"] = "hi"
["hi2"] = 1
}
res38 {
["hi"] = "hi"
["hi2"] = 1
}
res39 = "Type constraint `length.isOdd` violated. Value: \"Ba\""
res40 = "Cannot find key `\"\"`."
res41 = "Type constraint `length.isOdd` violated. Value: \"Ba\""
res42 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res43 = "hello"
res44 = 1
res45 = "Expected value of type `Int`, but got type `String`. Value: \"foo\""
res46 = "goodbye"
res47 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res48 = 1
res49 = "Expected value of type `List<Mapping<String, Int>>|List<Mapping<String, String>>`, but got a different `List`. Value: List(new Mapping { [\"foo\"] = 1; [\"bar\"] = \"hi\" })"
res50 = 2
res51 = "Type constraint `length.isOdd` violated. Value: \"Ba\""
res52 = "Type constraint `this == capitalize()` violated. Value: \"bar\""
res53 = 3
res54 = 1
res55 = 2
res56 = 2
res57 = "Expected value of type `String`, but got type `Int`. Value: 1"
res58 = "Expected value of type `String`, but got type `Int`. Value: 2"
res59 = "Expected value of type `String`, but got type `Int`. Value: 1"
res60 = 2
res61 = 1
res62 = 1
res63 = "Expected value of type `Int`, but got type `String`. Value: \"hi\""
res64 = 1
res65 = 1
res66 = "Expected value of type `String`, but got type `Int`. Value: 1"
res67 = "Expected value of type `String`, but got type `Int`. Value: 1"
res68 = 5
res69 = 1
res70 = "Expected value of type `String`, but got type `Int`. Value: 1"
res71 = 2
res72 = 1
res73 = 2
res74 = "hello"
res75 = "Expected value of type `String`, but got type `Int`. Value: 1"
res77 = "Expected value of type `Int|Mapping<String, String>`, but got a different `Mapping`. Value: new Mapping { [\"one\"] = \"hello\"; [\"two\"] = 1 }"
res78 = "Expected value of type `Collection<Mapping<String, String>>|Collection<Mapping<String, Int>>`, but got a different `List`. Value: List(new Mapping { [\"one\"] = \"hello\"; [\"two\"] = 1 })"
res79 = 3
res80 = 1
res81 = 2
res82 = "Expected value of type `Int`, but got type `String`. Value: \"hi\""
res83 = 3
res84 = 1
res85 = 2
res86 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res87 = 1
res88 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res89 = 1
res90 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res91 = 1
res92 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
res93 = 1
res94 = "Expected value of type `Int`, but got type `String`. Value: \"hello\""
@@ -10,6 +10,6 @@ at pkl.Project#dependencies (pkl:Project)
Type constraint `isValidLoadDependency` violated.
Value: new ModuleClass { package = null; tests {}; dependencies {}; evaluatorSetti...
x | dependencies {
^^^^^^^^^^^^^^
at PklProject#dependencies (file:///$snippetsDir/input/projects/badProjectDeps4/PklProject)
x | ["badLocalProject"] = import("../badLocalProject/PklProject")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at PklProject#dependencies["badLocalProject"] (file:///$snippetsDir/input/projects/badProjectDeps4/PklProject)
@@ -114,13 +114,13 @@ class EvaluateTestsTest {
)
assertThat(results.totalTests()).isEqualTo(1)
assertThat(results.totalFailures()).isEqualTo(0)
assertThat(results.totalFailures()).isEqualTo(1)
assertThat(results.failed()).isTrue
val res = results.results[0]
assertThat(res.name).isEqualTo("text")
assertThat(res.failures).isEmpty()
assertThat(res.errors.size).isEqualTo(1)
assertThat(res.name).isEqualTo("should fail")
assertThat(res.failures).hasSize(1)
assertThat(res.errors).hasSize(1)
val error = res.errors[0]
assertThat(error.message).isEqualTo("got an error")
@@ -134,10 +134,6 @@ class EvaluateTestsTest {
^^^^^^^^^^^^^^^^^^^^^
at text#facts["should fail"][#2] (repl:text)
3 | facts {
^^^^^^^
at text#facts (repl:text)
"""
.trimIndent()
)