diff --git a/cue/testdata/basicrewrite/000_errors.txtar b/cue/testdata/basicrewrite/000_errors.txtar --- a/cue/testdata/basicrewrite/000_errors.txtar +++ b/cue/testdata/basicrewrite/000_errors.txtar @@ -13,17 +13,6 @@ ./in.cue:1:10 [user] explicit error (_|_ literal) in source: ./in.cue:2:11 --- out/compile -- ---- in.cue -{ - a: (_|_(explicit error (_|_ literal) in source) & _|_(explicit error (_|_ literal) in source)) - b: (null & _|_(explicit error (_|_ literal) in source)) - c: (〈0;b〉.a == _|_(explicit error (_|_ literal) in source)) - d: (_|_(explicit error (_|_ literal) in source) != 〈0;b〉.a) - e: (_|_(explicit error (_|_ literal) in source) == _|_(explicit error (_|_ literal) in source)) - f: (({} & false) == _|_(explicit error (_|_ literal) in source)) - g: (_|_(explicit error (_|_ literal) in source) != ({} & false)) -} -- out/eval/stats -- Leaks: 0 Freed: 10 diff --git a/cue/testdata/basicrewrite/001_regexp.txtar b/cue/testdata/basicrewrite/001_regexp.txtar --- a/cue/testdata/basicrewrite/001_regexp.txtar +++ b/cue/testdata/basicrewrite/001_regexp.txtar @@ -37,29 +37,6 @@ [eval] e3: conflicting values !="a" and <5 (mismatched types string and number): ./in.cue:24:5 ./in.cue:24:13 --- out/compile -- ---- in.cue -{ - c1: ("a" =~ "a") - c2: ("foo" =~ "[a-z]{3}") - c3: ("foo" =~ "[a-z]{4}") - c4: ("foo" !~ "[a-z]{4}") - b1: =~"a" - b1: "a" - b2: =~"[a-z]{3}" - b2: "foo" - b3: =~"[a-z]{4}" - b3: "foo" - b4: !~"[a-z]{4}" - b4: "foo" - s1: (!="b" & =~"c") - s2: (=~"c" & !="b") - s3: (!="b" & =~"[a-z]") - s4: (=~"[a-z]" & !="b") - e1: ("foo" =~ 1) - e2: ("foo" !~ true) - e3: (!="a" & <5) -} -- out/eval/stats -- Leaks: 0 Freed: 16 diff --git a/cue/testdata/basicrewrite/002_arithmetic.txtar b/cue/testdata/basicrewrite/002_arithmetic.txtar --- a/cue/testdata/basicrewrite/002_arithmetic.txtar +++ b/cue/testdata/basicrewrite/002_arithmetic.txtar @@ -61,30 +61,3 @@ Unifications: 24 Conjuncts: 26 Disjuncts: 24 --- out/compile -- ---- in.cue -{ - i1: (1 & int) - i2: (2 & int) - sum: (-1 + +2) - div1: ((2.0 / 3) * 6) - div2: ((2 / 3) * 6) - div3: (1.00 / 1.00) - divZero: (1.0 / 0) - div00: (0 / 0) - b: (1 != 4) - add: (〈0;div1〉 + 1.0) - idiv00: div(0, 0) - imod00: mod(0, 0) - iquo00: quo(0, 0) - irem00: rem(0, 0) - v1: (1000000000000 / 2.0) - v2: (2.0 == 2) - v3: (2.0 / 3.0) - v5: div(〈0;i1〉, 〈0;i2〉) - e0: (2 + "a") - e5: div(1.0, 2) - e6: rem(2, 2.0) - e7: quo(2, 2.0) - e8: mod(1.0, 1) -} diff --git a/cue/testdata/basicrewrite/003_integer-specific_arithmetic.txtar b/cue/testdata/basicrewrite/003_integer-specific_arithmetic.txtar --- a/cue/testdata/basicrewrite/003_integer-specific_arithmetic.txtar +++ b/cue/testdata/basicrewrite/003_integer-specific_arithmetic.txtar @@ -43,34 +43,6 @@ ./in.cue:26:10 [eval] me2: cannot use 1.0 (type float) as int in argument 2 to mod: ./in.cue:27:13 --- out/compile -- ---- in.cue -{ - q1: quo(5, 2) - q2: quo(5, -2) - q3: quo(-5, 2) - q4: quo(-5, -2) - qe1: quo(2.0, 1) - qe2: quo(2, 1.0) - r1: rem(5, 2) - r2: rem(5, -2) - r3: rem(-5, 2) - r4: rem(-5, -2) - re1: rem(2.0, 1) - re2: rem(2, 1.0) - d1: div(5, 2) - d2: div(5, -2) - d3: div(-5, 2) - d4: div(-5, -2) - de1: div(2.0, 1) - de2: div(2, 1.0) - m1: mod(5, 2) - m2: mod(5, -2) - m3: mod(-5, 2) - m4: mod(-5, -2) - me1: mod(2.0, 1) - me2: mod(2, 1.0) -} -- out/eval/stats -- Leaks: 0 Freed: 25 diff --git a/cue/testdata/basicrewrite/004_booleans.txtar b/cue/testdata/basicrewrite/004_booleans.txtar --- a/cue/testdata/basicrewrite/004_booleans.txtar +++ b/cue/testdata/basicrewrite/004_booleans.txtar @@ -9,16 +9,6 @@ [eval] e: conflicting values false and true: ./in.cue:5:4 ./in.cue:6:4 --- out/compile -- ---- in.cue -{ - t: true - t: !false - f: false - f: !〈0;t〉 - e: true - e: !true -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/basicrewrite/005_boolean_arithmetic.txtar b/cue/testdata/basicrewrite/005_boolean_arithmetic.txtar --- a/cue/testdata/basicrewrite/005_boolean_arithmetic.txtar +++ b/cue/testdata/basicrewrite/005_boolean_arithmetic.txtar @@ -9,16 +9,6 @@ [eval] f: conflicting values false and true: ./in.cue:6:4 ./in.cue:6:11 --- out/compile -- ---- in.cue -{ - a: (true && true) - b: (true || false) - c: (false == true) - d: (false != true) - e: (true & true) - f: (true & false) -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/basicrewrite/006_basic_type.txtar b/cue/testdata/basicrewrite/006_basic_type.txtar --- a/cue/testdata/basicrewrite/006_basic_type.txtar +++ b/cue/testdata/basicrewrite/006_basic_type.txtar @@ -11,18 +11,6 @@ [eval] d: conflicting values int and float (mismatched types int and float): ./in.cue:5:4 ./in.cue:5:10 --- out/compile -- ---- in.cue -{ - a: (1 & int) - b: (number & 1) - c: 1.0 - c: float - d: (int & float) - e: ("4" & string) - f: true - f: bool -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/basicrewrite/007_strings_and_bytes.txtar b/cue/testdata/basicrewrite/007_strings_and_bytes.txtar --- a/cue/testdata/basicrewrite/007_strings_and_bytes.txtar +++ b/cue/testdata/basicrewrite/007_strings_and_bytes.txtar @@ -17,18 +17,6 @@ [eval] e1: invalid operands 'b' and "c" to '+' (type bytes and string): ./in.cue:11:5 ./in.cue:11:11 --- out/compile -- ---- in.cue -{ - s0: ("foo" + "bar") - s1: (3 * "abc") - s2: ("abc" * 2) - b0: ('foo' + 'bar') - b1: (3 * 'abc') - b2: ('abc' * 2) - e0: ("a" + '') - e1: ('b' + "c") -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/basicrewrite/008_escaping.txtar b/cue/testdata/basicrewrite/008_escaping.txtar --- a/cue/testdata/basicrewrite/008_escaping.txtar +++ b/cue/testdata/basicrewrite/008_escaping.txtar @@ -3,12 +3,6 @@ b: a @test(eq, "foo\nbar") // TODO: mimic http://exploringjs.com/es6/ch_template-literals.html#sec_introduction-template-literals --- out/compile -- ---- in.cue -{ - a: "foo\nbar" - b: 〈0;a〉 -} -- out/eval/stats -- Leaks: 0 Freed: 3 diff --git a/cue/testdata/basicrewrite/009_reference.txtar b/cue/testdata/basicrewrite/009_reference.txtar --- a/cue/testdata/basicrewrite/009_reference.txtar +++ b/cue/testdata/basicrewrite/009_reference.txtar @@ -17,24 +17,6 @@ v: e.v } } --- out/compile -- ---- in.cue -{ - a: 〈0;b〉 - b: 2 - d: { - d: 3 - e: 〈0;d〉 - } - e: { - e: { - v: 1 - } - f: { - v: 〈1;e〉.v - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/basicrewrite/010_lists.txtar b/cue/testdata/basicrewrite/010_lists.txtar --- a/cue/testdata/basicrewrite/010_lists.txtar +++ b/cue/testdata/basicrewrite/010_lists.txtar @@ -24,56 +24,6 @@ [eval] e5.3: invalid value 8 (out of bound <=5): ./in.cue:10:39 ./in.cue:10:18 --- out/compile -- ---- in.cue -{ - list: [ - 1, - 2, - 3, - ] - index: [ - 1, - 2, - 3, - ][1] - unify: ([ - 1, - 2, - 3, - ] & [ - _, - 2, - 3, - ]) - e: ([] & 4) - e2: [ - 3, - ]["d"] - e3: [ - 3, - ][-1] - e4: ([ - 1, - 2, - ...(>=4 & <=5), - ] & [ - 1, - 2, - 4, - 8, - ]) - e5: ([ - 1, - 2, - 4, - 8, - ] & [ - 1, - 2, - ...(>=4 & <=5), - ]) -} -- out/eval/stats -- Leaks: 4 Freed: 23 diff --git a/cue/testdata/basicrewrite/012_selecting.txtar b/cue/testdata/basicrewrite/012_selecting.txtar --- a/cue/testdata/basicrewrite/012_selecting.txtar +++ b/cue/testdata/basicrewrite/012_selecting.txtar @@ -18,37 +18,6 @@ -- todo.txt -- Some error messages could use improvement. Address after query extension is implemented. --- out/compile -- ---- in.cue -{ - obj: { - a: 1 - b: 2 - } - index: { - a: 1 - b: 2 - }["b"] - mulidx: { - a: 1 - b: { - a: 1 - b: 3 - } - }["b"]["b"] - e: { - a: 1 - }[4] - f: { - a: 1 - }.b - g: { - a: 1 - }["b"] - h: [ - 3, - ].b -} -- out/eval/stats -- Leaks: 9 Freed: 10 diff --git a/cue/testdata/basicrewrite/013_obj_unify.txtar b/cue/testdata/basicrewrite/013_obj_unify.txtar --- a/cue/testdata/basicrewrite/013_obj_unify.txtar +++ b/cue/testdata/basicrewrite/013_obj_unify.txtar @@ -12,48 +12,6 @@ [eval] e: conflicting values 1 and {a:3} (mismatched types int and struct): ./in.cue:8:4 ./in.cue:9:4 --- out/compile -- ---- in.cue -{ - o1: ({ - a: 1 - } & { - b: 2 - }) - o2: ({ - a: 1 - b: 2 - } & { - b: 2 - }) - o3: ({ - a: 1 - } & { - a: 1 - b: 2 - }) - o4: ({ - a: 1 - } & { - b: 2 - }) - o4: ({ - a: 1 - b: 2 - } & { - b: 2 - }) - o4: ({ - a: 1 - } & { - a: 1 - b: 2 - }) - e: 1 - e: { - a: 3 - } -} -- out/eval/stats -- Leaks: 0 Freed: 15 diff --git a/cue/testdata/basicrewrite/014_disjunctions.txtar b/cue/testdata/basicrewrite/014_disjunctions.txtar --- a/cue/testdata/basicrewrite/014_disjunctions.txtar +++ b/cue/testdata/basicrewrite/014_disjunctions.txtar @@ -39,26 +39,3 @@ Unifications: 18 Conjuncts: 150 Disjuncts: 135 --- out/compile -- ---- in.cue -{ - o1: (1|2|3) - o2: ((1|2|3) & 1) - o3: (2 & (1|*2|3)) - o4: ((1|*2|3) & (1|2|*3)) - o5: ((1|*2|3) & (3|*2|1)) - o6: ((1|2|3) & (3|1|2)) - o7: ((1|2|3) & (2|3)) - o8: ((1|2|3) & (3|2)) - o9: ((2|3) & (1|2|3)) - o10: ((3|2) & (1|*2|3)) - m1: ((1|(*2|3)) & (>=2 & <=3)) - m2: ((1|(*2|3)) & (2|3)) - m3: ((*1|*(*2|3)) & (2|3)) - m4: ((2|3) & (*2|3)) - m5: ((*2|3) & (2|3)) - i1: ([ - 1, - 2, - ][3]|"c") -} diff --git a/cue/testdata/basicrewrite/015_types.txtar b/cue/testdata/basicrewrite/015_types.txtar --- a/cue/testdata/basicrewrite/015_types.txtar +++ b/cue/testdata/basicrewrite/015_types.txtar @@ -21,19 +21,6 @@ ./in.cue:8:5 [eval] m: invalid operation -false (- bool): ./in.cue:9:5 --- out/compile -- ---- in.cue -{ - i: int - j: (int & 3) - s: string - t: ("s" & string) - e: (int & string) - e2: (1 & string) - b: !int - p: +true - m: -false -} -- out/eval/stats -- Leaks: 0 Freed: 10 diff --git a/cue/testdata/basicrewrite/016_comparison.txtar b/cue/testdata/basicrewrite/016_comparison.txtar --- a/cue/testdata/basicrewrite/016_comparison.txtar +++ b/cue/testdata/basicrewrite/016_comparison.txtar @@ -230,602 +230,6 @@ -- out/diff-v2-v3.txt -- lists.eIncompat: v3 reports "incomplete" (list element type is abstract) while v2 reports "eval" (permanent type mismatch [int] vs [string]). Verdict: worsening -- v3 does not yet promote the type mismatch to a permanent eval error. --- out/compile -- ---- in.cue -{ - numbers: { - tLss: (1 < 2) - tLeq: (1 <= 1.0) - tLeq: (2.0 <= 3) - tEql: (1 == 1.0) - tNeq: (1.0 == 1) - tGeq: (2.0 >= 2) - tGtr: !(2 > 3) - tExpr: (("a" + "b") == "ab") - } -} ---- lists.cue -{ - lists: { - t1: ([] == []) - t2: ([ - 1, - 2, - 3, - ] == [ - 1, - 2, - 3, - ]) - t3: ([ - 1, - "foo", - true, - ] == [ - 1, - "foo", - true, - ]) - t4: ([ - [ - 1, - 2, - ], - [ - 3, - 4, - ], - ] == [ - [ - 1, - 2, - ], - [ - 3, - 4, - ], - ]) - t5: (([ - 1, - ...int, - ] & [ - 1, - 2, - 3, - ]) == [ - 1, - 2, - 3, - ]) - t6: ([ - 1, - ] == ([ - ...1, - ] & [ - _, - ])) - t7: ([ - { - a: 1 - }, - ] == ([ - ...{ - a: 1 - }, - ] & [ - _, - ])) - t8: ([ - { - a: 1 - }, - ] != [ - ...{ - a: 1 - }, - ]) - t9: ([ - ...int, - ] == [ - ...string, - ]) - f1: ([ - 1, - 2, - 3, - ] == [ - 1, - 2, - 4, - ]) - f2: ([ - 1, - 2, - 3, - ] == [ - 1, - 2, - ]) - f3: ([ - 1, - 2, - 3, - ] == [ - 1, - 3, - 2, - ]) - f4: ([] == [ - 1, - ]) - f5: ([ - 1, - 2, - ] == [ - 1, - "2", - ]) - f6: ([ - (*1|2|3), - ] == [ - (*2|3|4), - ]) - eIncompat: ([ - int, - ] == [ - string, - ]) - eErrPassthrough: ([ - (1 / 0), - ] == [ - 1, - ]) - _e3l: {} - eErrPassthrough: ([ - 〈1;_e3l〉.b, - ] == [ - 1, - ]) - eErrPassthrough: ([ - 1, - 2, - ] == [ - 1, - (int & string), - ]) - tNeq1: ([ - 1, - 2, - ] != [ - 1, - 3, - ]) - fNeq2: ([ - 1, - 2, - ] != [ - 1, - 2, - ]) - } -} ---- structs.cue -{ - structs: { - eq: { - t1: ({} == {}) - t2: ({ - a: 1 - b: "foo" - } == { - a: 1 - b: "foo" - }) - t3: ({ - a: 1 - b: 2 - } == { - b: 2 - a: 1 - }) - t4: ({ - a: { - x: 1 - y: 2 - } - } == { - a: { - x: 1 - y: 2 - } - }) - t5: (({ - a: 1 - b: 2 - c: 3 - } & { - d: 4 - }) == { - a: 1 - b: 2 - c: 3 - d: 4 - }) - t6: ({ - { - { - { - a: 1 - } - } - } - } == { - { - a: 1 - } - }) - t7: ({ - [string]: int - } == { - [string]: string - }) - _t8l: (*1|2|3) - t8: ({ - a: 〈1;_t8l〉 - } == { - a: (3|*1) - }) - f1: ({ - a: 1 - b: "foo" - } == { - a: 2 - b: "foo" - }) - f2: ({ - a: 1 - b: "foo" - } == { - a: 1 - c: "foo" - }) - f3: ({ - a: { - x: 1 - } - } == { - a: { - x: 2 - } - }) - f4: ({ - a: 1 - b: 2 - } == { - a: 1 - }) - f5: ({} == { - a: 1 - }) - f6: ({ - a: 1 - } == 1) - f7: ({ - a: 1 - b?: 2 - } == { - a: 1 - b: 2 - }) - f8: ({ - { - { - { - a: 1 - } - } - } - } == { - { - a: 1 - b: 2 - } - }) - _f9r: (*2|3|4) - f9: ({ - a: (*1|2|3) - } == { - a: 〈1;_f9r〉 - }) - tNe1: ({ - a: 1 - } != { - a: 2 - }) - fNe1: ({ - a: 2 - } != { - a: 2 - }) - } - } - ignore: { - t0: ({ - _hidden: 1 - } == { - _hidden: 2 - }) - t1: ({ - _hidden: 1 - } == {}) - t1: ({} == { - _hidden: 1 - }) - t2: ({ - #def: 1 - } == { - #def: 2 - }) - t3: ({ - #def: 1 - } == {}) - t4: ({} == { - #def: 1 - }) - t5: ({ - _#hiddenDef: 1 - } == { - _#hiddenDef: 2 - }) - t6: ({ - _#hiddenDef: 1 - } == {}) - t7: ({} == { - _#hiddenDef: 1 - }) - f0: ({ - _hidden: 1 - } != { - _hidden: 2 - }) - f1: ({ - _hidden: 1 - } != {}) - f1: ({} != { - _hidden: 1 - }) - f2: ({ - #def: 1 - } != { - #def: 2 - }) - f3: ({ - #def: 1 - } != {}) - f4: ({} != { - #def: 1 - }) - f5: ({ - _#hiddenDef: 1 - } != { - _#hiddenDef: 2 - }) - f6: ({ - _#hiddenDef: 1 - } != {}) - f7: ({} != { - _#hiddenDef: 1 - }) - } - embeddedScalars: { - _one: 1 - _two: 2 - t1: (1 == { - 1 - }) - t2: ([ - 1, - ] == [ - { - 1 - }, - ]) - t3: ({ - a: 1 - } == { - a: { - 1 - } - }) - t4: ([ - 〈1;_one〉, - ] == [ - { - 〈2;_one〉 - }, - ]) - f1: (〈0;_one〉 == [ - { - 〈2;_two〉 - }, - ]) - f2: ({ - a: 〈1;_two〉 - } == { - a: { - 〈2;_one〉 - } - }) - f3: (〈0;_one〉 == { - 〈1;_two〉 - }) - f4: ([ - 〈1;_two〉, - ] == [ - { - 〈2;_one〉 - }, - ]) - } - incomplete: { - _int: int - _string: string - iErr1: ({ - a!: 〈1;_int〉 - } == { - a!: 〈1;_int〉 - }) - iErr2: ({ - a!: 〈1;_int〉 - } == { - a!: 1 - }) - eErr3: ({ - a: 〈1;_int〉 - } == { - a: 〈1;_string〉 - }) - eErr4: ({ - a: (1 / 0) - } == { - a: 1 - }) - eErr5: ({ - a: 1 - } == { - a: (〈1;_int〉 & 〈1;_string〉) - }) - iErr6: ({ - a!: 1 - } == { - a: 1 - }) - eErr7: ({ - a: 1 - } == { - a!: 2 - }) - tNe1: ({ - a: 1 - } != { - a: 2 - }) - fNe1: ({ - a: 2 - } != { - a: 2 - }) - } -} ---- typediff.cue -{ - diffTypes: { - fScalar1: (2 == "s") - fScalar2: ("s" == 2) - fScalar3: (true == 2) - fStruct1: ({ - a: 1 - } == "s") - fList1: (5 == [ - 5, - ]) - fList2: ("ab" == [ - "a", - "b", - ]) - fList3: (true == [ - true, - ]) - fList4: ({ - a: 1 - } == [ - { - a: 1 - }, - ]) - fList5: ([ - 1, - 2, - ] == 3) - fList6: ([ - 1, - 2, - ] == "ab") - fList7: ([ - true, - ] == false) - fList8: ([ - 1, - 2, - ] == { - a: 1 - }) - fList9: ([ - 1, - 2, - ] == null) - tNeList1: ([ - 1, - 2, - ] != 3) - tNeList2: ([ - 1, - 2, - ] != "ab") - _int: int - _string: string - iRecursive1: ([ - 〈1;_int〉, - ] == [ - 〈1;_int〉, - ]) - eRecursive2: ([ - 〈1;_int〉, - ] == [ - 〈1;_string〉, - ]) - fRecursive3: ([ - 1, - 2, - ] == [ - 1, - "2", - ]) - tRecursive4: ([ - ...int, - ] == [ - ...string, - ]) - fRecursive5: ([ - 1, - "a", - ] == [ - 1, - 2, - ]) - eNe1: ([ - 1, - 2, - ] != [ - 〈1;_int〉, - ]) - iNe2: ([ - 〈1;_int〉, - ] != [ - 1, - ]) - iNe3: ({ - a: 1 - } != { - a: 〈1;_int〉 - }) - iNe4: ({ - a: 〈1;_int〉 - } != { - a: 1 - }) - } -} -- out/eval/stats -- Leaks: 0 Freed: 547 diff --git a/cue/testdata/basicrewrite/017_null.txtar b/cue/testdata/basicrewrite/017_null.txtar --- a/cue/testdata/basicrewrite/017_null.txtar +++ b/cue/testdata/basicrewrite/017_null.txtar @@ -11,17 +11,6 @@ -- out/errors.txt -- [eval] call: cannot call non-function null (type null): ./in.cue:9:7 --- out/compile -- ---- in.cue -{ - eql: (null == null) - neq: (null != null) - unf: (null & null) - eq1: (null == 1) - eq2: (1 == null) - ne1: ("s" != null) - call: null() -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/basicrewrite/018_self-reference_cycles.txtar b/cue/testdata/basicrewrite/018_self-reference_cycles.txtar --- a/cue/testdata/basicrewrite/018_self-reference_cycles.txtar +++ b/cue/testdata/basicrewrite/018_self-reference_cycles.txtar @@ -196,74 +196,3 @@ Disjuncts: 10 NumCloseIDs: 10 --- out/compile -- ---- disjunction.cue -{ - oneway: { - t1: { - a: (*1|int) - a: (〈0;b〉 + 1) - b: <〈0;a〉 - } - t2: (〈0;t1〉 & { - a: 3 - }) - } - issue3669: { - #Schema: { - two: (1 + 〈0;one〉) - one: (〈0;two〉 - 1) - } - out: (〈0;#Schema〉 & { - two: (0|*2) - }) - } -} ---- in.cue -{ - a: (〈0;b〉 - 100) - b: (〈0;a〉 + 100) - c: [ - 〈1;c〉[1], - 〈1;c〉[0], - ] - d: (〈0;e〉 - 1) - e: (1 + 〈0;d〉) - e: (*2|0) -} ---- issue3737.cue -{ - issue3737: { - reduced1: { - #A: { - a: (〈0;b〉 * 12) - b: (〈0;a〉 / 12) - } - x: 〈0;#A〉 - x: { - b: 1000.0 - } - y: (〈0;#A〉|*〈0;x〉) - y: { - b: (〈1;x〉.b * 0.7) - } - } - } - issue3737: { - reduced2: { - x: (〈0;#TimeSpan〉 & { - start: 〈1;y〉.start - end: 1000.0 - }) - y: (〈0;#TimeSpan〉 & { - duration: 100.0 - end: 〈1;x〉.end - }) - #TimeSpan: { - start: (〈0;end〉 - 〈0;duration〉) - duration: (〈0;end〉 - 〈0;start〉) - end: (〈0;start〉 + 〈0;duration〉) - } - } - } -} diff --git a/cue/testdata/basicrewrite/019_resolved_self-reference_cycles.txtar b/cue/testdata/basicrewrite/019_resolved_self-reference_cycles.txtar --- a/cue/testdata/basicrewrite/019_resolved_self-reference_cycles.txtar +++ b/cue/testdata/basicrewrite/019_resolved_self-reference_cycles.txtar @@ -51,81 +51,3 @@ Unifications: 62 Conjuncts: 105 Disjuncts: 70 --- out/compile -- ---- in.cue -{ - math: { - a: (〈0;b〉 - 100) - b: (〈0;a〉 + 100) - b: 200 - } - a: 100 - list: { - t0: { - c: [ - 〈1;c〉[0], - ] - } - } - list: { - t1: { - p1: { - c: [ - 〈1;c〉[1], - 〈4;a〉, - ] - } - } - } - list: { - t1: { - p2: { - c: [ - 〈4;a〉, - 〈1;c〉[0], - ] - } - } - } - nodes: { - t1: { - p1: { - s1: (〈0;s1〉 & { - a: 1 - }) - } - } - } - nodes: { - t1: { - p2: { - s1: ({ - a: 1 - } & 〈0;s1〉) - } - } - } - nodes: { - t2: { - s1: (〈0;s2〉 & { - a: 1 - }) - s2: (〈0;s1〉 & { - b: 2 - }) - } - } - nodes: { - t3: { - s1: (〈0;s2〉 & { - a: 1 - }) - s2: (〈0;s3〉 & { - b: 2 - }) - s3: (〈0;s1〉 & { - c: 3 - }) - } - } -} diff --git a/cue/testdata/basicrewrite/020_resolved_self-reference_cycles__Issue_19.txtar b/cue/testdata/basicrewrite/020_resolved_self-reference_cycles__Issue_19.txtar --- a/cue/testdata/basicrewrite/020_resolved_self-reference_cycles__Issue_19.txtar +++ b/cue/testdata/basicrewrite/020_resolved_self-reference_cycles__Issue_19.txtar @@ -10,17 +10,6 @@ z3: 8 // TODO: extensive tests with disjunctions. --- out/compile -- ---- in.cue -{ - x: (〈0;y〉 + 100) - y: (〈0;x〉 - 100) - x: 200 - z1: (〈0;z2〉 + 1) - z2: (〈0;z3〉 + 2) - z3: (〈0;z1〉 - 3) - z3: 8 -} -- out/eval/stats -- Leaks: 0 Freed: 6 diff --git a/cue/testdata/benchmarks/chain.txtar b/cue/testdata/benchmarks/chain.txtar --- a/cue/testdata/benchmarks/chain.txtar +++ b/cue/testdata/benchmarks/chain.txtar @@ -1000,1010 +1000,6 @@ f998: f997 f999: f998 f1000: f999 @test(eq, string) --- out/compile -- ---- in.cue -{ - f1: string - f2: 〈0;f1〉 - f3: 〈0;f2〉 - f4: 〈0;f3〉 - f5: 〈0;f4〉 - f6: 〈0;f5〉 - f7: 〈0;f6〉 - f8: 〈0;f7〉 - f9: 〈0;f8〉 - f10: 〈0;f9〉 - f11: 〈0;f10〉 - f12: 〈0;f11〉 - f13: 〈0;f12〉 - f14: 〈0;f13〉 - f15: 〈0;f14〉 - f16: 〈0;f15〉 - f17: 〈0;f16〉 - f18: 〈0;f17〉 - f19: 〈0;f18〉 - f20: 〈0;f19〉 - f21: 〈0;f20〉 - f22: 〈0;f21〉 - f23: 〈0;f22〉 - f24: 〈0;f23〉 - f25: 〈0;f24〉 - f26: 〈0;f25〉 - f27: 〈0;f26〉 - f28: 〈0;f27〉 - f29: 〈0;f28〉 - f30: 〈0;f29〉 - f31: 〈0;f30〉 - f32: 〈0;f31〉 - f33: 〈0;f32〉 - f34: 〈0;f33〉 - f35: 〈0;f34〉 - f36: 〈0;f35〉 - f37: 〈0;f36〉 - f38: 〈0;f37〉 - f39: 〈0;f38〉 - f40: 〈0;f39〉 - f41: 〈0;f40〉 - f42: 〈0;f41〉 - f43: 〈0;f42〉 - f44: 〈0;f43〉 - f45: 〈0;f44〉 - f46: 〈0;f45〉 - f47: 〈0;f46〉 - f48: 〈0;f47〉 - f49: 〈0;f48〉 - f50: 〈0;f49〉 - f51: 〈0;f50〉 - f52: 〈0;f51〉 - f53: 〈0;f52〉 - f54: 〈0;f53〉 - f55: 〈0;f54〉 - f56: 〈0;f55〉 - f57: 〈0;f56〉 - f58: 〈0;f57〉 - f59: 〈0;f58〉 - f60: 〈0;f59〉 - f61: 〈0;f60〉 - f62: 〈0;f61〉 - f63: 〈0;f62〉 - f64: 〈0;f63〉 - f65: 〈0;f64〉 - f66: 〈0;f65〉 - f67: 〈0;f66〉 - f68: 〈0;f67〉 - f69: 〈0;f68〉 - f70: 〈0;f69〉 - f71: 〈0;f70〉 - f72: 〈0;f71〉 - f73: 〈0;f72〉 - f74: 〈0;f73〉 - f75: 〈0;f74〉 - f76: 〈0;f75〉 - f77: 〈0;f76〉 - f78: 〈0;f77〉 - f79: 〈0;f78〉 - f80: 〈0;f79〉 - f81: 〈0;f80〉 - f82: 〈0;f81〉 - f83: 〈0;f82〉 - f84: 〈0;f83〉 - f85: 〈0;f84〉 - f86: 〈0;f85〉 - f87: 〈0;f86〉 - f88: 〈0;f87〉 - f89: 〈0;f88〉 - f90: 〈0;f89〉 - f91: 〈0;f90〉 - f92: 〈0;f91〉 - f93: 〈0;f92〉 - f94: 〈0;f93〉 - f95: 〈0;f94〉 - f96: 〈0;f95〉 - f97: 〈0;f96〉 - f98: 〈0;f97〉 - f99: 〈0;f98〉 - f100: 〈0;f99〉 - f101: 〈0;f100〉 - f102: 〈0;f101〉 - f103: 〈0;f102〉 - f104: 〈0;f103〉 - f105: 〈0;f104〉 - f106: 〈0;f105〉 - f107: 〈0;f106〉 - f108: 〈0;f107〉 - f109: 〈0;f108〉 - f110: 〈0;f109〉 - f111: 〈0;f110〉 - f112: 〈0;f111〉 - f113: 〈0;f112〉 - f114: 〈0;f113〉 - f115: 〈0;f114〉 - f116: 〈0;f115〉 - f117: 〈0;f116〉 - f118: 〈0;f117〉 - f119: 〈0;f118〉 - f120: 〈0;f119〉 - f121: 〈0;f120〉 - f122: 〈0;f121〉 - f123: 〈0;f122〉 - f124: 〈0;f123〉 - f125: 〈0;f124〉 - f126: 〈0;f125〉 - f127: 〈0;f126〉 - f128: 〈0;f127〉 - f129: 〈0;f128〉 - f130: 〈0;f129〉 - f131: 〈0;f130〉 - f132: 〈0;f131〉 - f133: 〈0;f132〉 - f134: 〈0;f133〉 - f135: 〈0;f134〉 - f136: 〈0;f135〉 - f137: 〈0;f136〉 - f138: 〈0;f137〉 - f139: 〈0;f138〉 - f140: 〈0;f139〉 - f141: 〈0;f140〉 - f142: 〈0;f141〉 - f143: 〈0;f142〉 - f144: 〈0;f143〉 - f145: 〈0;f144〉 - f146: 〈0;f145〉 - f147: 〈0;f146〉 - f148: 〈0;f147〉 - f149: 〈0;f148〉 - f150: 〈0;f149〉 - f151: 〈0;f150〉 - f152: 〈0;f151〉 - f153: 〈0;f152〉 - f154: 〈0;f153〉 - f155: 〈0;f154〉 - f156: 〈0;f155〉 - f157: 〈0;f156〉 - f158: 〈0;f157〉 - f159: 〈0;f158〉 - f160: 〈0;f159〉 - f161: 〈0;f160〉 - f162: 〈0;f161〉 - f163: 〈0;f162〉 - f164: 〈0;f163〉 - f165: 〈0;f164〉 - f166: 〈0;f165〉 - f167: 〈0;f166〉 - f168: 〈0;f167〉 - f169: 〈0;f168〉 - f170: 〈0;f169〉 - f171: 〈0;f170〉 - f172: 〈0;f171〉 - f173: 〈0;f172〉 - f174: 〈0;f173〉 - f175: 〈0;f174〉 - f176: 〈0;f175〉 - f177: 〈0;f176〉 - f178: 〈0;f177〉 - f179: 〈0;f178〉 - f180: 〈0;f179〉 - f181: 〈0;f180〉 - f182: 〈0;f181〉 - f183: 〈0;f182〉 - f184: 〈0;f183〉 - f185: 〈0;f184〉 - f186: 〈0;f185〉 - f187: 〈0;f186〉 - f188: 〈0;f187〉 - f189: 〈0;f188〉 - f190: 〈0;f189〉 - f191: 〈0;f190〉 - f192: 〈0;f191〉 - f193: 〈0;f192〉 - f194: 〈0;f193〉 - f195: 〈0;f194〉 - f196: 〈0;f195〉 - f197: 〈0;f196〉 - f198: 〈0;f197〉 - f199: 〈0;f198〉 - f200: 〈0;f199〉 - f201: 〈0;f200〉 - f202: 〈0;f201〉 - f203: 〈0;f202〉 - f204: 〈0;f203〉 - f205: 〈0;f204〉 - f206: 〈0;f205〉 - f207: 〈0;f206〉 - f208: 〈0;f207〉 - f209: 〈0;f208〉 - f210: 〈0;f209〉 - f211: 〈0;f210〉 - f212: 〈0;f211〉 - f213: 〈0;f212〉 - f214: 〈0;f213〉 - f215: 〈0;f214〉 - f216: 〈0;f215〉 - f217: 〈0;f216〉 - f218: 〈0;f217〉 - f219: 〈0;f218〉 - f220: 〈0;f219〉 - f221: 〈0;f220〉 - f222: 〈0;f221〉 - f223: 〈0;f222〉 - f224: 〈0;f223〉 - f225: 〈0;f224〉 - f226: 〈0;f225〉 - f227: 〈0;f226〉 - f228: 〈0;f227〉 - f229: 〈0;f228〉 - f230: 〈0;f229〉 - f231: 〈0;f230〉 - f232: 〈0;f231〉 - f233: 〈0;f232〉 - f234: 〈0;f233〉 - f235: 〈0;f234〉 - f236: 〈0;f235〉 - f237: 〈0;f236〉 - f238: 〈0;f237〉 - f239: 〈0;f238〉 - f240: 〈0;f239〉 - f241: 〈0;f240〉 - f242: 〈0;f241〉 - f243: 〈0;f242〉 - f244: 〈0;f243〉 - f245: 〈0;f244〉 - f246: 〈0;f245〉 - f247: 〈0;f246〉 - f248: 〈0;f247〉 - f249: 〈0;f248〉 - f250: 〈0;f249〉 - f251: 〈0;f250〉 - f252: 〈0;f251〉 - f253: 〈0;f252〉 - f254: 〈0;f253〉 - f255: 〈0;f254〉 - f256: 〈0;f255〉 - f257: 〈0;f256〉 - f258: 〈0;f257〉 - f259: 〈0;f258〉 - f260: 〈0;f259〉 - f261: 〈0;f260〉 - f262: 〈0;f261〉 - f263: 〈0;f262〉 - f264: 〈0;f263〉 - f265: 〈0;f264〉 - f266: 〈0;f265〉 - f267: 〈0;f266〉 - f268: 〈0;f267〉 - f269: 〈0;f268〉 - f270: 〈0;f269〉 - f271: 〈0;f270〉 - f272: 〈0;f271〉 - f273: 〈0;f272〉 - f274: 〈0;f273〉 - f275: 〈0;f274〉 - f276: 〈0;f275〉 - f277: 〈0;f276〉 - f278: 〈0;f277〉 - f279: 〈0;f278〉 - f280: 〈0;f279〉 - f281: 〈0;f280〉 - f282: 〈0;f281〉 - f283: 〈0;f282〉 - f284: 〈0;f283〉 - f285: 〈0;f284〉 - f286: 〈0;f285〉 - f287: 〈0;f286〉 - f288: 〈0;f287〉 - f289: 〈0;f288〉 - f290: 〈0;f289〉 - f291: 〈0;f290〉 - f292: 〈0;f291〉 - f293: 〈0;f292〉 - f294: 〈0;f293〉 - f295: 〈0;f294〉 - f296: 〈0;f295〉 - f297: 〈0;f296〉 - f298: 〈0;f297〉 - f299: 〈0;f298〉 - f300: 〈0;f299〉 - f301: 〈0;f300〉 - f302: 〈0;f301〉 - f303: 〈0;f302〉 - f304: 〈0;f303〉 - f305: 〈0;f304〉 - f306: 〈0;f305〉 - f307: 〈0;f306〉 - f308: 〈0;f307〉 - f309: 〈0;f308〉 - f310: 〈0;f309〉 - f311: 〈0;f310〉 - f312: 〈0;f311〉 - f313: 〈0;f312〉 - f314: 〈0;f313〉 - f315: 〈0;f314〉 - f316: 〈0;f315〉 - f317: 〈0;f316〉 - f318: 〈0;f317〉 - f319: 〈0;f318〉 - f320: 〈0;f319〉 - f321: 〈0;f320〉 - f322: 〈0;f321〉 - f323: 〈0;f322〉 - f324: 〈0;f323〉 - f325: 〈0;f324〉 - f326: 〈0;f325〉 - f327: 〈0;f326〉 - f328: 〈0;f327〉 - f329: 〈0;f328〉 - f330: 〈0;f329〉 - f331: 〈0;f330〉 - f332: 〈0;f331〉 - f333: 〈0;f332〉 - f334: 〈0;f333〉 - f335: 〈0;f334〉 - f336: 〈0;f335〉 - f337: 〈0;f336〉 - f338: 〈0;f337〉 - f339: 〈0;f338〉 - f340: 〈0;f339〉 - f341: 〈0;f340〉 - f342: 〈0;f341〉 - f343: 〈0;f342〉 - f344: 〈0;f343〉 - f345: 〈0;f344〉 - f346: 〈0;f345〉 - f347: 〈0;f346〉 - f348: 〈0;f347〉 - f349: 〈0;f348〉 - f350: 〈0;f349〉 - f351: 〈0;f350〉 - f352: 〈0;f351〉 - f353: 〈0;f352〉 - f354: 〈0;f353〉 - f355: 〈0;f354〉 - f356: 〈0;f355〉 - f357: 〈0;f356〉 - f358: 〈0;f357〉 - f359: 〈0;f358〉 - f360: 〈0;f359〉 - f361: 〈0;f360〉 - f362: 〈0;f361〉 - f363: 〈0;f362〉 - f364: 〈0;f363〉 - f365: 〈0;f364〉 - f366: 〈0;f365〉 - f367: 〈0;f366〉 - f368: 〈0;f367〉 - f369: 〈0;f368〉 - f370: 〈0;f369〉 - f371: 〈0;f370〉 - f372: 〈0;f371〉 - f373: 〈0;f372〉 - f374: 〈0;f373〉 - f375: 〈0;f374〉 - f376: 〈0;f375〉 - f377: 〈0;f376〉 - f378: 〈0;f377〉 - f379: 〈0;f378〉 - f380: 〈0;f379〉 - f381: 〈0;f380〉 - f382: 〈0;f381〉 - f383: 〈0;f382〉 - f384: 〈0;f383〉 - f385: 〈0;f384〉 - f386: 〈0;f385〉 - f387: 〈0;f386〉 - f388: 〈0;f387〉 - f389: 〈0;f388〉 - f390: 〈0;f389〉 - f391: 〈0;f390〉 - f392: 〈0;f391〉 - f393: 〈0;f392〉 - f394: 〈0;f393〉 - f395: 〈0;f394〉 - f396: 〈0;f395〉 - f397: 〈0;f396〉 - f398: 〈0;f397〉 - f399: 〈0;f398〉 - f400: 〈0;f399〉 - f401: 〈0;f400〉 - f402: 〈0;f401〉 - f403: 〈0;f402〉 - f404: 〈0;f403〉 - f405: 〈0;f404〉 - f406: 〈0;f405〉 - f407: 〈0;f406〉 - f408: 〈0;f407〉 - f409: 〈0;f408〉 - f410: 〈0;f409〉 - f411: 〈0;f410〉 - f412: 〈0;f411〉 - f413: 〈0;f412〉 - f414: 〈0;f413〉 - f415: 〈0;f414〉 - f416: 〈0;f415〉 - f417: 〈0;f416〉 - f418: 〈0;f417〉 - f419: 〈0;f418〉 - f420: 〈0;f419〉 - f421: 〈0;f420〉 - f422: 〈0;f421〉 - f423: 〈0;f422〉 - f424: 〈0;f423〉 - f425: 〈0;f424〉 - f426: 〈0;f425〉 - f427: 〈0;f426〉 - f428: 〈0;f427〉 - f429: 〈0;f428〉 - f430: 〈0;f429〉 - f431: 〈0;f430〉 - f432: 〈0;f431〉 - f433: 〈0;f432〉 - f434: 〈0;f433〉 - f435: 〈0;f434〉 - f436: 〈0;f435〉 - f437: 〈0;f436〉 - f438: 〈0;f437〉 - f439: 〈0;f438〉 - f440: 〈0;f439〉 - f441: 〈0;f440〉 - f442: 〈0;f441〉 - f443: 〈0;f442〉 - f444: 〈0;f443〉 - f445: 〈0;f444〉 - f446: 〈0;f445〉 - f447: 〈0;f446〉 - f448: 〈0;f447〉 - f449: 〈0;f448〉 - f450: 〈0;f449〉 - f451: 〈0;f450〉 - f452: 〈0;f451〉 - f453: 〈0;f452〉 - f454: 〈0;f453〉 - f455: 〈0;f454〉 - f456: 〈0;f455〉 - f457: 〈0;f456〉 - f458: 〈0;f457〉 - f459: 〈0;f458〉 - f460: 〈0;f459〉 - f461: 〈0;f460〉 - f462: 〈0;f461〉 - f463: 〈0;f462〉 - f464: 〈0;f463〉 - f465: 〈0;f464〉 - f466: 〈0;f465〉 - f467: 〈0;f466〉 - f468: 〈0;f467〉 - f469: 〈0;f468〉 - f470: 〈0;f469〉 - f471: 〈0;f470〉 - f472: 〈0;f471〉 - f473: 〈0;f472〉 - f474: 〈0;f473〉 - f475: 〈0;f474〉 - f476: 〈0;f475〉 - f477: 〈0;f476〉 - f478: 〈0;f477〉 - f479: 〈0;f478〉 - f480: 〈0;f479〉 - f481: 〈0;f480〉 - f482: 〈0;f481〉 - f483: 〈0;f482〉 - f484: 〈0;f483〉 - f485: 〈0;f484〉 - f486: 〈0;f485〉 - f487: 〈0;f486〉 - f488: 〈0;f487〉 - f489: 〈0;f488〉 - f490: 〈0;f489〉 - f491: 〈0;f490〉 - f492: 〈0;f491〉 - f493: 〈0;f492〉 - f494: 〈0;f493〉 - f495: 〈0;f494〉 - f496: 〈0;f495〉 - f497: 〈0;f496〉 - f498: 〈0;f497〉 - f499: 〈0;f498〉 - f500: 〈0;f499〉 - f501: 〈0;f500〉 - f502: 〈0;f501〉 - f503: 〈0;f502〉 - f504: 〈0;f503〉 - f505: 〈0;f504〉 - f506: 〈0;f505〉 - f507: 〈0;f506〉 - f508: 〈0;f507〉 - f509: 〈0;f508〉 - f510: 〈0;f509〉 - f511: 〈0;f510〉 - f512: 〈0;f511〉 - f513: 〈0;f512〉 - f514: 〈0;f513〉 - f515: 〈0;f514〉 - f516: 〈0;f515〉 - f517: 〈0;f516〉 - f518: 〈0;f517〉 - f519: 〈0;f518〉 - f520: 〈0;f519〉 - f521: 〈0;f520〉 - f522: 〈0;f521〉 - f523: 〈0;f522〉 - f524: 〈0;f523〉 - f525: 〈0;f524〉 - f526: 〈0;f525〉 - f527: 〈0;f526〉 - f528: 〈0;f527〉 - f529: 〈0;f528〉 - f530: 〈0;f529〉 - f531: 〈0;f530〉 - f532: 〈0;f531〉 - f533: 〈0;f532〉 - f534: 〈0;f533〉 - f535: 〈0;f534〉 - f536: 〈0;f535〉 - f537: 〈0;f536〉 - f538: 〈0;f537〉 - f539: 〈0;f538〉 - f540: 〈0;f539〉 - f541: 〈0;f540〉 - f542: 〈0;f541〉 - f543: 〈0;f542〉 - f544: 〈0;f543〉 - f545: 〈0;f544〉 - f546: 〈0;f545〉 - f547: 〈0;f546〉 - f548: 〈0;f547〉 - f549: 〈0;f548〉 - f550: 〈0;f549〉 - f551: 〈0;f550〉 - f552: 〈0;f551〉 - f553: 〈0;f552〉 - f554: 〈0;f553〉 - f555: 〈0;f554〉 - f556: 〈0;f555〉 - f557: 〈0;f556〉 - f558: 〈0;f557〉 - f559: 〈0;f558〉 - f560: 〈0;f559〉 - f561: 〈0;f560〉 - f562: 〈0;f561〉 - f563: 〈0;f562〉 - f564: 〈0;f563〉 - f565: 〈0;f564〉 - f566: 〈0;f565〉 - f567: 〈0;f566〉 - f568: 〈0;f567〉 - f569: 〈0;f568〉 - f570: 〈0;f569〉 - f571: 〈0;f570〉 - f572: 〈0;f571〉 - f573: 〈0;f572〉 - f574: 〈0;f573〉 - f575: 〈0;f574〉 - f576: 〈0;f575〉 - f577: 〈0;f576〉 - f578: 〈0;f577〉 - f579: 〈0;f578〉 - f580: 〈0;f579〉 - f581: 〈0;f580〉 - f582: 〈0;f581〉 - f583: 〈0;f582〉 - f584: 〈0;f583〉 - f585: 〈0;f584〉 - f586: 〈0;f585〉 - f587: 〈0;f586〉 - f588: 〈0;f587〉 - f589: 〈0;f588〉 - f590: 〈0;f589〉 - f591: 〈0;f590〉 - f592: 〈0;f591〉 - f593: 〈0;f592〉 - f594: 〈0;f593〉 - f595: 〈0;f594〉 - f596: 〈0;f595〉 - f597: 〈0;f596〉 - f598: 〈0;f597〉 - f599: 〈0;f598〉 - f600: 〈0;f599〉 - f601: 〈0;f600〉 - f602: 〈0;f601〉 - f603: 〈0;f602〉 - f604: 〈0;f603〉 - f605: 〈0;f604〉 - f606: 〈0;f605〉 - f607: 〈0;f606〉 - f608: 〈0;f607〉 - f609: 〈0;f608〉 - f610: 〈0;f609〉 - f611: 〈0;f610〉 - f612: 〈0;f611〉 - f613: 〈0;f612〉 - f614: 〈0;f613〉 - f615: 〈0;f614〉 - f616: 〈0;f615〉 - f617: 〈0;f616〉 - f618: 〈0;f617〉 - f619: 〈0;f618〉 - f620: 〈0;f619〉 - f621: 〈0;f620〉 - f622: 〈0;f621〉 - f623: 〈0;f622〉 - f624: 〈0;f623〉 - f625: 〈0;f624〉 - f626: 〈0;f625〉 - f627: 〈0;f626〉 - f628: 〈0;f627〉 - f629: 〈0;f628〉 - f630: 〈0;f629〉 - f631: 〈0;f630〉 - f632: 〈0;f631〉 - f633: 〈0;f632〉 - f634: 〈0;f633〉 - f635: 〈0;f634〉 - f636: 〈0;f635〉 - f637: 〈0;f636〉 - f638: 〈0;f637〉 - f639: 〈0;f638〉 - f640: 〈0;f639〉 - f641: 〈0;f640〉 - f642: 〈0;f641〉 - f643: 〈0;f642〉 - f644: 〈0;f643〉 - f645: 〈0;f644〉 - f646: 〈0;f645〉 - f647: 〈0;f646〉 - f648: 〈0;f647〉 - f649: 〈0;f648〉 - f650: 〈0;f649〉 - f651: 〈0;f650〉 - f652: 〈0;f651〉 - f653: 〈0;f652〉 - f654: 〈0;f653〉 - f655: 〈0;f654〉 - f656: 〈0;f655〉 - f657: 〈0;f656〉 - f658: 〈0;f657〉 - f659: 〈0;f658〉 - f660: 〈0;f659〉 - f661: 〈0;f660〉 - f662: 〈0;f661〉 - f663: 〈0;f662〉 - f664: 〈0;f663〉 - f665: 〈0;f664〉 - f666: 〈0;f665〉 - f667: 〈0;f666〉 - f668: 〈0;f667〉 - f669: 〈0;f668〉 - f670: 〈0;f669〉 - f671: 〈0;f670〉 - f672: 〈0;f671〉 - f673: 〈0;f672〉 - f674: 〈0;f673〉 - f675: 〈0;f674〉 - f676: 〈0;f675〉 - f677: 〈0;f676〉 - f678: 〈0;f677〉 - f679: 〈0;f678〉 - f680: 〈0;f679〉 - f681: 〈0;f680〉 - f682: 〈0;f681〉 - f683: 〈0;f682〉 - f684: 〈0;f683〉 - f685: 〈0;f684〉 - f686: 〈0;f685〉 - f687: 〈0;f686〉 - f688: 〈0;f687〉 - f689: 〈0;f688〉 - f690: 〈0;f689〉 - f691: 〈0;f690〉 - f692: 〈0;f691〉 - f693: 〈0;f692〉 - f694: 〈0;f693〉 - f695: 〈0;f694〉 - f696: 〈0;f695〉 - f697: 〈0;f696〉 - f698: 〈0;f697〉 - f699: 〈0;f698〉 - f700: 〈0;f699〉 - f701: 〈0;f700〉 - f702: 〈0;f701〉 - f703: 〈0;f702〉 - f704: 〈0;f703〉 - f705: 〈0;f704〉 - f706: 〈0;f705〉 - f707: 〈0;f706〉 - f708: 〈0;f707〉 - f709: 〈0;f708〉 - f710: 〈0;f709〉 - f711: 〈0;f710〉 - f712: 〈0;f711〉 - f713: 〈0;f712〉 - f714: 〈0;f713〉 - f715: 〈0;f714〉 - f716: 〈0;f715〉 - f717: 〈0;f716〉 - f718: 〈0;f717〉 - f719: 〈0;f718〉 - f720: 〈0;f719〉 - f721: 〈0;f720〉 - f722: 〈0;f721〉 - f723: 〈0;f722〉 - f724: 〈0;f723〉 - f725: 〈0;f724〉 - f726: 〈0;f725〉 - f727: 〈0;f726〉 - f728: 〈0;f727〉 - f729: 〈0;f728〉 - f730: 〈0;f729〉 - f731: 〈0;f730〉 - f732: 〈0;f731〉 - f733: 〈0;f732〉 - f734: 〈0;f733〉 - f735: 〈0;f734〉 - f736: 〈0;f735〉 - f737: 〈0;f736〉 - f738: 〈0;f737〉 - f739: 〈0;f738〉 - f740: 〈0;f739〉 - f741: 〈0;f740〉 - f742: 〈0;f741〉 - f743: 〈0;f742〉 - f744: 〈0;f743〉 - f745: 〈0;f744〉 - f746: 〈0;f745〉 - f747: 〈0;f746〉 - f748: 〈0;f747〉 - f749: 〈0;f748〉 - f750: 〈0;f749〉 - f751: 〈0;f750〉 - f752: 〈0;f751〉 - f753: 〈0;f752〉 - f754: 〈0;f753〉 - f755: 〈0;f754〉 - f756: 〈0;f755〉 - f757: 〈0;f756〉 - f758: 〈0;f757〉 - f759: 〈0;f758〉 - f760: 〈0;f759〉 - f761: 〈0;f760〉 - f762: 〈0;f761〉 - f763: 〈0;f762〉 - f764: 〈0;f763〉 - f765: 〈0;f764〉 - f766: 〈0;f765〉 - f767: 〈0;f766〉 - f768: 〈0;f767〉 - f769: 〈0;f768〉 - f770: 〈0;f769〉 - f771: 〈0;f770〉 - f772: 〈0;f771〉 - f773: 〈0;f772〉 - f774: 〈0;f773〉 - f775: 〈0;f774〉 - f776: 〈0;f775〉 - f777: 〈0;f776〉 - f778: 〈0;f777〉 - f779: 〈0;f778〉 - f780: 〈0;f779〉 - f781: 〈0;f780〉 - f782: 〈0;f781〉 - f783: 〈0;f782〉 - f784: 〈0;f783〉 - f785: 〈0;f784〉 - f786: 〈0;f785〉 - f787: 〈0;f786〉 - f788: 〈0;f787〉 - f789: 〈0;f788〉 - f790: 〈0;f789〉 - f791: 〈0;f790〉 - f792: 〈0;f791〉 - f793: 〈0;f792〉 - f794: 〈0;f793〉 - f795: 〈0;f794〉 - f796: 〈0;f795〉 - f797: 〈0;f796〉 - f798: 〈0;f797〉 - f799: 〈0;f798〉 - f800: 〈0;f799〉 - f801: 〈0;f800〉 - f802: 〈0;f801〉 - f803: 〈0;f802〉 - f804: 〈0;f803〉 - f805: 〈0;f804〉 - f806: 〈0;f805〉 - f807: 〈0;f806〉 - f808: 〈0;f807〉 - f809: 〈0;f808〉 - f810: 〈0;f809〉 - f811: 〈0;f810〉 - f812: 〈0;f811〉 - f813: 〈0;f812〉 - f814: 〈0;f813〉 - f815: 〈0;f814〉 - f816: 〈0;f815〉 - f817: 〈0;f816〉 - f818: 〈0;f817〉 - f819: 〈0;f818〉 - f820: 〈0;f819〉 - f821: 〈0;f820〉 - f822: 〈0;f821〉 - f823: 〈0;f822〉 - f824: 〈0;f823〉 - f825: 〈0;f824〉 - f826: 〈0;f825〉 - f827: 〈0;f826〉 - f828: 〈0;f827〉 - f829: 〈0;f828〉 - f830: 〈0;f829〉 - f831: 〈0;f830〉 - f832: 〈0;f831〉 - f833: 〈0;f832〉 - f834: 〈0;f833〉 - f835: 〈0;f834〉 - f836: 〈0;f835〉 - f837: 〈0;f836〉 - f838: 〈0;f837〉 - f839: 〈0;f838〉 - f840: 〈0;f839〉 - f841: 〈0;f840〉 - f842: 〈0;f841〉 - f843: 〈0;f842〉 - f844: 〈0;f843〉 - f845: 〈0;f844〉 - f846: 〈0;f845〉 - f847: 〈0;f846〉 - f848: 〈0;f847〉 - f849: 〈0;f848〉 - f850: 〈0;f849〉 - f851: 〈0;f850〉 - f852: 〈0;f851〉 - f853: 〈0;f852〉 - f854: 〈0;f853〉 - f855: 〈0;f854〉 - f856: 〈0;f855〉 - f857: 〈0;f856〉 - f858: 〈0;f857〉 - f859: 〈0;f858〉 - f860: 〈0;f859〉 - f861: 〈0;f860〉 - f862: 〈0;f861〉 - f863: 〈0;f862〉 - f864: 〈0;f863〉 - f865: 〈0;f864〉 - f866: 〈0;f865〉 - f867: 〈0;f866〉 - f868: 〈0;f867〉 - f869: 〈0;f868〉 - f870: 〈0;f869〉 - f871: 〈0;f870〉 - f872: 〈0;f871〉 - f873: 〈0;f872〉 - f874: 〈0;f873〉 - f875: 〈0;f874〉 - f876: 〈0;f875〉 - f877: 〈0;f876〉 - f878: 〈0;f877〉 - f879: 〈0;f878〉 - f880: 〈0;f879〉 - f881: 〈0;f880〉 - f882: 〈0;f881〉 - f883: 〈0;f882〉 - f884: 〈0;f883〉 - f885: 〈0;f884〉 - f886: 〈0;f885〉 - f887: 〈0;f886〉 - f888: 〈0;f887〉 - f889: 〈0;f888〉 - f890: 〈0;f889〉 - f891: 〈0;f890〉 - f892: 〈0;f891〉 - f893: 〈0;f892〉 - f894: 〈0;f893〉 - f895: 〈0;f894〉 - f896: 〈0;f895〉 - f897: 〈0;f896〉 - f898: 〈0;f897〉 - f899: 〈0;f898〉 - f900: 〈0;f899〉 - f901: 〈0;f900〉 - f902: 〈0;f901〉 - f903: 〈0;f902〉 - f904: 〈0;f903〉 - f905: 〈0;f904〉 - f906: 〈0;f905〉 - f907: 〈0;f906〉 - f908: 〈0;f907〉 - f909: 〈0;f908〉 - f910: 〈0;f909〉 - f911: 〈0;f910〉 - f912: 〈0;f911〉 - f913: 〈0;f912〉 - f914: 〈0;f913〉 - f915: 〈0;f914〉 - f916: 〈0;f915〉 - f917: 〈0;f916〉 - f918: 〈0;f917〉 - f919: 〈0;f918〉 - f920: 〈0;f919〉 - f921: 〈0;f920〉 - f922: 〈0;f921〉 - f923: 〈0;f922〉 - f924: 〈0;f923〉 - f925: 〈0;f924〉 - f926: 〈0;f925〉 - f927: 〈0;f926〉 - f928: 〈0;f927〉 - f929: 〈0;f928〉 - f930: 〈0;f929〉 - f931: 〈0;f930〉 - f932: 〈0;f931〉 - f933: 〈0;f932〉 - f934: 〈0;f933〉 - f935: 〈0;f934〉 - f936: 〈0;f935〉 - f937: 〈0;f936〉 - f938: 〈0;f937〉 - f939: 〈0;f938〉 - f940: 〈0;f939〉 - f941: 〈0;f940〉 - f942: 〈0;f941〉 - f943: 〈0;f942〉 - f944: 〈0;f943〉 - f945: 〈0;f944〉 - f946: 〈0;f945〉 - f947: 〈0;f946〉 - f948: 〈0;f947〉 - f949: 〈0;f948〉 - f950: 〈0;f949〉 - f951: 〈0;f950〉 - f952: 〈0;f951〉 - f953: 〈0;f952〉 - f954: 〈0;f953〉 - f955: 〈0;f954〉 - f956: 〈0;f955〉 - f957: 〈0;f956〉 - f958: 〈0;f957〉 - f959: 〈0;f958〉 - f960: 〈0;f959〉 - f961: 〈0;f960〉 - f962: 〈0;f961〉 - f963: 〈0;f962〉 - f964: 〈0;f963〉 - f965: 〈0;f964〉 - f966: 〈0;f965〉 - f967: 〈0;f966〉 - f968: 〈0;f967〉 - f969: 〈0;f968〉 - f970: 〈0;f969〉 - f971: 〈0;f970〉 - f972: 〈0;f971〉 - f973: 〈0;f972〉 - f974: 〈0;f973〉 - f975: 〈0;f974〉 - f976: 〈0;f975〉 - f977: 〈0;f976〉 - f978: 〈0;f977〉 - f979: 〈0;f978〉 - f980: 〈0;f979〉 - f981: 〈0;f980〉 - f982: 〈0;f981〉 - f983: 〈0;f982〉 - f984: 〈0;f983〉 - f985: 〈0;f984〉 - f986: 〈0;f985〉 - f987: 〈0;f986〉 - f988: 〈0;f987〉 - f989: 〈0;f988〉 - f990: 〈0;f989〉 - f991: 〈0;f990〉 - f992: 〈0;f991〉 - f993: 〈0;f992〉 - f994: 〈0;f993〉 - f995: 〈0;f994〉 - f996: 〈0;f995〉 - f997: 〈0;f996〉 - f998: 〈0;f997〉 - f999: 〈0;f998〉 - f1000: 〈0;f999〉 -} -- out/eval/stats -- Leaks: 0 Freed: 1001 diff --git a/cue/testdata/benchmarks/cycle.txtar b/cue/testdata/benchmarks/cycle.txtar --- a/cue/testdata/benchmarks/cycle.txtar +++ b/cue/testdata/benchmarks/cycle.txtar @@ -20,29 +20,6 @@ -- out/todo.txt -- v2 expanded S and C into independent copies; v3 uses structure sharing (S: ~(sameValues.SmustBeF.F), C: ~(sameValues.CmustBeA.A)). --- out/compile -- ---- in.cue -{ - sameValues: { - SmustBeF: { - T: (string|〈0;F〉) - F: { - x: 〈1;T〉 - } - S: 〈0;F〉 - } - } - sameValues: { - CmustBeA: { - A: { - x: [ - (string|〈2;A〉), - ] - } - C: 〈0;A〉 - } - } -} -- out/eval/stats -- Leaks: 2 Freed: 15 diff --git a/cue/testdata/benchmarks/cycleshare.txtar b/cue/testdata/benchmarks/cycleshare.txtar --- a/cue/testdata/benchmarks/cycleshare.txtar +++ b/cue/testdata/benchmarks/cycleshare.txtar @@ -201,80 +201,3 @@ root_2: ~(root) root_3: ~(root) } --- out/compile -- ---- in.cue -{ - #D1: ({ - a: 〈1;#D2〉 - }|{ - b: 〈1;#D2〉 - }|{ - c: 〈1;#D2〉 - }) - #D2: ({ - a: 〈1;#D3〉 - }|{ - b: 〈1;#D3〉 - }|{ - c: 〈1;#D3〉 - }) - #D3: { - one: ({ - a: int - }|{ - b: int - }|{ - c: int - }) - two: ({ - a: string - }|{ - b: string - }|{ - c: string - }) - three: ({ - a: bool - }|{ - b: bool - }|{ - c: bool - }) - } - root: { - y: (〈1;#D1〉|[ - 〈2;#D1〉, - ]|{ - x: 〈2;#D1〉 - }) - } - root: { - x: { - empty: {} - } - } - root: { - "0": { - data: 〈2;let root_0#1〉.x.empty - } - } - root: { - "1": { - data: 〈2;let root_1#2〉.x.empty - } - } - root: { - "2": { - data: 〈2;root_2〉.x.empty - } - } - root: { - "3": { - data: 〈2;root_3〉.x.empty - } - } - let root_0#1 = 〈0;root〉 - let root_1#2 = 〈0;root〉 - root_2: 〈0;root〉 - root_3: 〈0;root〉 -} diff --git a/cue/testdata/benchmarks/decimal.txtar b/cue/testdata/benchmarks/decimal.txtar --- a/cue/testdata/benchmarks/decimal.txtar +++ b/cue/testdata/benchmarks/decimal.txtar @@ -24,21 +24,6 @@ 5.0, 0.3333333333333333333333333333333333 ]) --- out/compile -- ---- in.cue -{ - out: [ - (123.45 + 987.65), - (123.45 - 987.65), - (123.45 * 987.65), - (123.45 / 987.65), - (2 + 3), - (7 - 1), - (5 * 10), - (20 / 4), - (1 / 3), - ] -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/benchmarks/deduparc.txtar b/cue/testdata/benchmarks/deduparc.txtar --- a/cue/testdata/benchmarks/deduparc.txtar +++ b/cue/testdata/benchmarks/deduparc.txtar @@ -36,30 +36,3 @@ Disjuncts: 4 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - #Value: ({ - type: "float" - }|{ - type: "string" - }) - foo: { - type: "string" - } - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 - foo: 〈0;#Value〉 -} diff --git a/cue/testdata/benchmarks/dedupelem.txtar b/cue/testdata/benchmarks/dedupelem.txtar --- a/cue/testdata/benchmarks/dedupelem.txtar +++ b/cue/testdata/benchmarks/dedupelem.txtar @@ -33,84 +33,3 @@ Disjuncts: 3 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - #Value: ({ - type: "int" - }|{ - type: "float" - }|{ - type: "string" - }) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "string" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "string" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "string" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) - foo: ([ - { - type: "float" - }, - ] & [ - ...〈1;#Value〉, - ]) -} diff --git a/cue/testdata/benchmarks/disjunctelim.txtar b/cue/testdata/benchmarks/disjunctelim.txtar --- a/cue/testdata/benchmarks/disjunctelim.txtar +++ b/cue/testdata/benchmarks/disjunctelim.txtar @@ -63,129 +63,3 @@ Notifications: 1 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - pat: ({ - [string]: 1 - }|{ - a: 2 - }) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - list: ([ - 1, - ]|[ - 2, - ]|[ - 3, - ]|[ - 4, - ]) - issue3610: { - 〈0;#a〉 - #a: (<"a"|>"b"|string) - #a: (<"a"|>"b"|string) - #a: (<"a"|>"b"|string) - #a: (<"a"|>"b"|string) - #a: (<"a"|>"b"|string) - #a: (<"a"|>"b"|string) - } -} diff --git a/cue/testdata/benchmarks/disjunction.txtar b/cue/testdata/benchmarks/disjunction.txtar --- a/cue/testdata/benchmarks/disjunction.txtar +++ b/cue/testdata/benchmarks/disjunction.txtar @@ -27,116 +27,6 @@ a0: {} @test(eq, {a0: {f: *1 | int}}) } --- out/compile -- ---- in.cue -{ - x: { - a0: {} - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - [_]: { - f: (*1|int) - } - } - x: { - a0: {} - } -} -- out/eval/stats -- Leaks: 0 Freed: 82 diff --git a/cue/testdata/benchmarks/inlinedisjunction.txtar b/cue/testdata/benchmarks/inlinedisjunction.txtar --- a/cue/testdata/benchmarks/inlinedisjunction.txtar +++ b/cue/testdata/benchmarks/inlinedisjunction.txtar @@ -34,43 +34,3 @@ ConjunctInfos: 99 MaxConjunctInfos: 12 MaxReqSets: 12 --- out/compile -- ---- in.cue -{ - #def: { - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - c: string - }) - ({}|{ - a: string - }) - } - x: 〈0;#def〉 - x: { - c: "foo" - } -} diff --git a/cue/testdata/benchmarks/issue1684.txtar b/cue/testdata/benchmarks/issue1684.txtar --- a/cue/testdata/benchmarks/issue1684.txtar +++ b/cue/testdata/benchmarks/issue1684.txtar @@ -75,115 +75,3 @@ in some cases eliminate earlier than with a flat structure. So this may not be attainable with the current implementation. TODO(perf): investigate nonetheless. --- out/compile -- ---- in.cue -{ - #Secret: { - $secret: { - id: string - } - } - #secrets: (〈0;#Secret〉|{ - [string]: 〈1;#secrets〉 - }) - out: (〈0;#secrets〉 & { - FOO: { - $secret: { - id: "100" - } - } - ONE: { - TWO: { - THREE: { - $secret: { - id: "123" - } - } - } - } - }) - #Secret: { - $secret: { - _id: string - } - } - #secrets: (〈0;#Secret〉|{ - [string]: 〈1;#secrets〉 - }) - out: (〈0;#secrets〉 & { - FOO: { - $secret: { - _id: "100" - } - } - ONE: { - TWO: { - THREE: { - $secret: { - _id: "123" - } - } - } - } - }) -} ---- perf.cue -{ - nestedCross: { - closed: { - #D: ({ - id: string - }|{ - [string]: 〈1;#D〉 - }) - #D: ({ - id: string - }|{ - [string]: 〈1;#D〉 - }) - #D: ({ - id: string - }|{ - [string]: 〈1;#D〉 - }) - } - } - nestedCross: { - open: { - D: ({ - id: string - }|{ - [string]: 〈1;D〉 - }) - D: ({ - id: string - }|{ - [string]: 〈1;D〉 - }) - D: ({ - id: string - }|{ - [string]: 〈1;D〉 - }) - } - } - nestedClosed: { - passing: { - D: ({ - id: {} - }|{ - [string]: 〈1;D〉 - }) - D: ({ - id: {} - }|{ - [string]: 〈1;D〉 - }) - D: ({ - id: {} - }|{ - [string]: 〈1;D〉 - }) - } - } -} diff --git a/cue/testdata/benchmarks/issue2176.txtar b/cue/testdata/benchmarks/issue2176.txtar --- a/cue/testdata/benchmarks/issue2176.txtar +++ b/cue/testdata/benchmarks/issue2176.txtar @@ -81,53 +81,5 @@ ConjunctInfos: 919 MaxConjunctInfos: 28 MaxReqSets: 26 --- out/compile -- ---- in.cue -{ - #Datastream: { - message: string - message: 〈import;strings〉.MinRunes(4) - marker: { - length: int - position: { - let characters#1 = 〈import;strings〉.Split(〈2;message〉, "") - let unique_combinations#2multi = { - for i, _ in 〈1;let characters#1〉 if (〈0;i〉 >= (〈3;length〉 - 1)) { - let combination#3multi = 〈import;list〉.Slice(〈3;let characters#1〉, ((〈1;i〉 - 〈4;length〉) + 1), (〈1;i〉 + 1)) - if 〈import;list〉.UniqueItems(〈import;list〉.Slice(〈3;let characters#1〉, ((〈1;i〉 - 〈4;length〉) + 1), (〈1;i〉 + 1))) { - "\((〈2;i〉 + 1))": 〈1;let combination#3〉 - } - } - } - [ - for i, _ in 〈1;let unique_combinations#2〉 { - 〈1;i〉 - }, - ][0] - } - } - } - input_short: "mjqjpqmgbljsphdztnvjfqwrcgsmlb" - input_long: "qfmfhmhjmjggwbbvdvwvlvrrtsrsccwsslvlffjrrtprprjjvmmclmmghhddpvddclctcqtccgbgdbgdgsdgghqhtqtvvptvppwrwprpvrrrhpphththvhhrnnhnlnslnlhnhnhgnhnpnqqsmsgsllprlprrlzzqzffmzztctbtnbtthlttqvqcqmcmpcpbbczzbqbgghcghchhvwvllfrfnnbssfzsszpsplpglpprnpnfnbnhbnbtbzzvbvpbbhjjlzzbtbvbppczppbwppqwwnwlwccglgvgrgmmdwmwrmrppnfnhhhhqthqthqqrhrshhhqbhqqjgjvjllzvzbzhbbpttjsszvzqqtzzmbmddpldpdcdnccrmcrmmpwprplrrqssvddmpdmmwfwwlrljrrdsssmhsspnpffjggqllnzlnlhnnmddfrfpfbbvssjsrrznngcghgchcmhmrrrtzztjzzhchssslsmlmvvpwpqpjqjdddmsdmmtgtmgtglttfbbgrrcprrqffmmjnjttcmczzgbzggthhsttpggrmmgwwnpnqnqvnqvqppmlpmlpmpjpljljmmtpptfppfrppfdpfdppddmdttgzgzzdbzdzhzhnnsqssvmvbbpjjzwwvnwvvzmvzmzpmpttvrvccqddpgdppgmmthmthtggsfsbbvfbvfvhfvhvvpwpddqrqgqhghnnfmfbbwrbrgbgbvgbbdttffrddqbqpqzzmttlhhsqhsqhsqhhlplttpnpsstpthhpfhpfplprrgfrgffjppghgppghgdggjmmcgmccjvvsrvsrrwgrgmrrngrgttvbtbltthrthrttmfffjpfpssncnrngrrltrltlggjgcgllrzzllhwwjwrwgrgsrgrhrphrhhqwqsqmqlmqlmqmqrmrnnwnhwnhwhzwzjwwgbghhsjspszsznzfztfzfpzzlczztctsstctqtfqfqcfqqjrjccttmqqfpfdfnfwnffqbfbblpbpfpcfcwfccblbwwmqwqrrgprpccngnhghpppwmpplcppfrfjjgmmbzbhbcbzzgdgsdsvvqllzlppnfnlnlslsljlppcscqqfjjjwzwppfgfjjsvvsggjbjljpjpzjzrzjrzzfnfpnfpnfpnfnsnggmpggdllpmmrhhdqqppttgqqcsqsjsbjsjrsrqrbqqmbmcbmcbmbfmfvfqqdbdppmrprnrggmjjhnhbhdhbbfcbbcjjdhhwjwmjmssjswscswcwzccbgbqqmqgmmsdsjsbsdbsddvttjpppcqpcqcgqqslqsssczszrzvvrtvvjppswwhnnwlwtwhhwwzfwwpfpddlvvnvnnvlnntjtqjqjzzjttvvbqbhqbhbbbwnwhnwnppdbpdpvddrqdqjjlvlqqdfdhdjhdjdcjcrcjjggfmfvvfllvfvgglzllmhmzmdddfwddqjjqjfqfcfrrstrssptsstllrflfwwgswslwlbwbwjjvhvfvhfhffhsslwsllbnbblccbwwjqwqqdllrdrnrnffcbbqqpnqqdmdndtntvvrjvvsvmvgvnnmjlwgnjcwljgwnrwpqlztwrpmpgqtwlhrcwsrrhqhjhznrtpqfdnzbfqrzwslptdbdcnqvcllpjsfdvmzqwvzbpnmfcfcjnbmhtwhttjgtnczwctpdthhwmzvzrrgsnmbflgmszgsbvghbzgcmcmszgsbfmlmpbdspqlftmqrcjtmvgcrzznlfwjcbmddplsqrfflqnqfsldwhnncczdmfrrrsbjjqsdzrsgbdbwjbslfcqglsqfddhdsrcdrgqfqthgmfjvnfdfgdncfzpvqcpscnpmfgvqbfwszwzgmqvmcrdrwplfshdgqrchmccpqfznbmfvlhdpctlqgjslrwhjfjlmqfblgjrdlnzdtwlpwhnrhrcrpfwqpmjlgrdbgpbljntmbqlblqqqpgrnjtmjqvjpzvsqdpgtchmmwbhtmgcjqdplrtptqcvdjjpqdzsrcjhcwvdcghlwrdhtdfctmqfcjcqhcvvbzgsvlggcrdgqbtznwwmnbgsfrjprqgcmlswftlwpqqqvshdprldrsghmhrqvmqmvglbvzpvtrjbhcvhqmvdtcvsllznqzjmhpnlbhmlzthbwwhhvdtcdfdcdzhnbsrnqqjvzzsvfjhbsdlsbdlqjnlpnhfcjtdppzmphghltztzcdvzwbftbvwhvgmrllqfzrpbltptdtjjqtfwjfmczzgdvclqbsbftgtlhnhrrvbpvdltstdnhqvpvtjhmghptvsfnlspslmfsftzdrwljrgblgmcbmlszmhnlfdtmsrnjqwrfmsnfgpcqgzmlwppffrmbvhnlstfpgzw" - input: (*〈0;input_short〉|〈0;input_long〉) - datastream: (〈0;#Datastream〉 & { - message: 〈1;input〉 - }) - output: { - [string]: string - } - output: { - "1": (〈1;datastream〉 & { - marker: { - length: 4 - } - }).marker.position - "2": (〈1;datastream〉 & { - marker: { - length: 14 - } - }).marker.position - } -} -- out/todo.txt -- let unique_combinations: not marked as multi in v3. Seems benign, but should be fixed. diff --git a/cue/testdata/benchmarks/issue3307.txtar b/cue/testdata/benchmarks/issue3307.txtar --- a/cue/testdata/benchmarks/issue3307.txtar +++ b/cue/testdata/benchmarks/issue3307.txtar @@ -41,31 +41,3 @@ Disjuncts: 0 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - if 〈0;_request〉.enabled { - r1: { - k1: 0 - k2: 0 - k3: 0 - k4: 0 - k5: 0 - k6: 0 - k7: 0 - k8: 0 - k9: 0 - k10: 0 - k11: 0 - k12: 0 - k13: 0 - k14: 0 - k15: 0 - k16: 0 - k17: 0 - } - } - _request: { - enabled: _ - } -} diff --git a/cue/testdata/benchmarks/issue3334.txtar b/cue/testdata/benchmarks/issue3334.txtar --- a/cue/testdata/benchmarks/issue3334.txtar +++ b/cue/testdata/benchmarks/issue3334.txtar @@ -265,71 +265,3 @@ Disjuncts: 310 NumCloseIDs: 21 --- out/compile -- ---- in.cue -{ - x?: (null|〈0;Schema〉) - x: { - properties: { - disableSelfServiceScrape: {} - dnsConfig: { - properties: { - nameservers: {} - } - } - podDisruptionBudget: { - properties: { - maxUnavailable: {} - minAvailable: { - anyOf: [ - {}, - {}, - ] - } - labels: {} - } - } - } - } - Schema: { - title?: string - $ref?: (null|string) - enum?: [ - ..., - ] - required?: [ - ...string, - ] - items?: (null|_) - anyOf?: [ - ...〈2;Schema〉, - ] - allOf?: [ - ...〈2;Schema〉, - ] - oneOf?: [ - ...〈2;Schema〉, - ] - not?: (null|〈1;Schema〉) - properties?: { - [string]: 〈2;Schema〉 - } - additionalProperties?: (null|_) - patternProperties?: { - [string]: 〈2;Schema〉 - } - dependencies?: { - [string]: _ - } - additionalItems?: (null|_) - definitions?: { - [string]: _ - } - externalDocs?: (null|{ - description?: string - url?: string - }) - example?: (null|_) - nullable?: bool - } -} diff --git a/cue/testdata/benchmarks/issue3514.txtar b/cue/testdata/benchmarks/issue3514.txtar --- a/cue/testdata/benchmarks/issue3514.txtar +++ b/cue/testdata/benchmarks/issue3514.txtar @@ -54,53 +54,3 @@ Notifications: 2 NumCloseIDs: 2876 --- out/compile -- ---- in.cue -{ - (〈0;_schema〉 & 〈0;_data〉) - _data: { - updates: [ - { - schedule: { - interval: "daily" - } - }, - ] - } - _schema: { - (matchIf((null|bool|number|string|[ - ..., - ]|{ - "enable-beta-ecosystems"!: true - }), _, (null|bool|number|string|[ - ..., - ]|{ - updates?: (null|bool|number|string|[ - ...(null|bool|number|string|[ - ..., - ]|{ - ... - }), - ]|{ - ... - }) - ... - })) & { - updates!: [ - ...〈2;#update〉, - ] - }) - #update: { - schedule!: { - timezone?: 〈2;#timezone〉 - ... - } - ... - } - #timezone: or([ - for _, i in 〈import;list〉.Range(0, 571, 1) { - "\(〈1;i〉)" - }, - ]) - } -} diff --git a/cue/testdata/benchmarks/issue3517.txtar b/cue/testdata/benchmarks/issue3517.txtar --- a/cue/testdata/benchmarks/issue3517.txtar +++ b/cue/testdata/benchmarks/issue3517.txtar @@ -201,69 +201,6 @@ Disjuncts: 0 NumCloseIDs: 13 --- out/compile -- ---- main.cue -{ - #TimeSpan: { - start: float - duration: float - end: float - start: (〈0;end〉 - 〈0;duration〉) - duration: (〈0;end〉 - 〈0;start〉) - end: (〈0;start〉 + 〈0;duration〉) - start: <=〈0;end〉 - } - #Task: { - action: string - timeSpan: 〈1;#TimeSpan〉 - } - #TaskSet: { - action: string - #tasks: { - [string]: 〈2;#Task〉 - } - tasks: [ - for _, v in 〈1;#tasks〉 { - 〈1;v〉 - }, - ] - tasks: [ - ...〈2;#Task〉, - ] - timeSpan?: 〈1;#TimeSpan〉 - } - #T1: (〈0;#Task〉 & { - action: "Task 1" - timeSpan: (〈1;#TimeSpan〉 & { - duration: 4.2 - }) - }) - #T2: (〈0;#Task〉 & { - action: "Task 2" - timeSpan: (〈1;#TimeSpan〉 & { - duration: 120.0 - }) - }) - ts: 〈0;#TaskSet〉 - ts: { - action: "Task 1 and Task 2" - #tasks: { - t1: (〈2;#T1〉 & { - timeSpan: { - end: 〈4〉.#tasks.t2.timeSpan.start - } - }) - t2: (〈2;#T2〉 & { - timeSpan: { - end: 119 - } - }) - } - timeSpan: { - start: 〈2〉.#tasks.t1.timeSpan.start - } - } -} -- out/evalalpha -- Errors: ts.#tasks.t2.timeSpan.end: conflicting values 119 and float (mismatched types int and float): diff --git a/cue/testdata/benchmarks/issue3633.txtar b/cue/testdata/benchmarks/issue3633.txtar --- a/cue/testdata/benchmarks/issue3633.txtar +++ b/cue/testdata/benchmarks/issue3633.txtar @@ -123,147 +123,3 @@ Disjuncts: 1625 NumCloseIDs: 50 --- out/compile -- ---- in.cue -{ - reduced: { - #Schema: { - a?: (null|bool|string|int|〈1;#Schema〉) - b?: (null|bool|string|int|〈1;#Schema〉) - c?: (null|bool|string|int|〈1;#Schema〉) - d?: (null|bool|string|int|〈1;#Schema〉) - e?: (null|bool|string|int|〈1;#Schema〉) - f?: (null|bool|string|int|〈1;#Schema〉) - } - out: (〈0;#Schema〉 & { - 〈1;#Schema〉 - }) - } - full: { - #Schema: { - required?: [ - ...string, - ] - properties?: { - [string]: (null|bool|string|[ - ...int, - ]|〈2;#Schema〉) - } - foo00?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo01?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo02?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo03?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo04?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo05?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo06?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo07?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo08?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo09?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo10?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo11?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo12?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo13?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo14?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo15?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo16?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo17?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo18?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - foo19?: (null|bool|string|[ - ...int, - ]|{ - string: &(int, >=-2147483648, <=2147483647) - }) - } - out: ([ - ...〈1;#Schema〉, - ] & [ - { - 〈2;#Schema〉 - properties: { - foo: { - required: [ - "bar", - "baz", - ] - } - } - }, - ]) - } -} diff --git a/cue/testdata/benchmarks/issue572.txtar b/cue/testdata/benchmarks/issue572.txtar --- a/cue/testdata/benchmarks/issue572.txtar +++ b/cue/testdata/benchmarks/issue572.txtar @@ -32,17 +32,3 @@ Disjuncts: 0 NumCloseIDs: 4499 --- out/compile -- ---- in.cue -{ - _entries(:p): [ - for _, i in 〈import;list〉.Range(1, 1500, 1) { - 〈1;i〉 - }, - ] - unified: { - for _, entry in 〈1;_entries(:p)〉 { - "\(〈1;entry〉)": true - } - } -} diff --git a/cue/testdata/benchmarks/listdedup.txtar b/cue/testdata/benchmarks/listdedup.txtar --- a/cue/testdata/benchmarks/listdedup.txtar +++ b/cue/testdata/benchmarks/listdedup.txtar @@ -142,40 +142,3 @@ MaxConjunctInfos: 6 MaxReqSets: 9 MaxRedirect: 2 --- out/compile -- ---- in.cue -{ - A: 〈0;#Task〉 - B: { - #steps: (〈1;#Script〉 & { - mount: [ - 〈3;A〉, - ] - }) - } - C: { - #steps: (〈1;#Script〉 & { - mount: [ - 〈3;B〉, - ] - }) - } - #Script: { - mount: [ - ...〈2;#Task〉, - ] - } - #Task: { - 〈1;#ref〉 - 〈1;#ref〉 - (_|{}) - (_|{}) - #steps: 〈1;#Script〉 - ... - } - #ref: ({ - a: 1 - }|{ - b: 2 - }) -} diff --git a/cue/testdata/benchmarks/listdisj.txtar b/cue/testdata/benchmarks/listdisj.txtar --- a/cue/testdata/benchmarks/listdisj.txtar +++ b/cue/testdata/benchmarks/listdisj.txtar @@ -19,32 +19,6 @@ #X: z #X: v #X: #T --- out/compile -- ---- in.cue -{ - #T: ([ - "a", - 〈1;#T〉, - ]|[ - "b", - 〈1;#T〉, - ]|[ - "c", - 〈1;#T〉, - ]|[ - "d", - ...〈1;#T〉, - ]) - x: 〈0;#T〉 - y: 〈0;#T〉 - z: 〈0;#T〉 - v: 〈0;#T〉 - #X: 〈0;x〉 - #X: 〈0;y〉 - #X: 〈0;z〉 - #X: 〈0;v〉 - #X: 〈0;#T〉 -} -- out/eval/stats -- Leaks: 2 Freed: 16 diff --git a/cue/testdata/benchmarks/mergeddisjunction.txtar b/cue/testdata/benchmarks/mergeddisjunction.txtar --- a/cue/testdata/benchmarks/mergeddisjunction.txtar +++ b/cue/testdata/benchmarks/mergeddisjunction.txtar @@ -45,59 +45,3 @@ ConjunctInfos: 194 MaxConjunctInfos: 32 MaxReqSets: 2 --- out/compile -- ---- in.cue -{ - list: [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - ] - a: { - [string]: { - text: (*"default"|string) - } - } - a: { - for _, i in 〈1;list〉 { - "\(〈1;i〉)": { - text: string - } - } - } - b: { - for _, x in 〈1;a〉 { - "\(〈1;x〉.text)": { - text: 〈2;x〉.text - } - } - } -} diff --git a/cue/testdata/benchmarks/share.txtar b/cue/testdata/benchmarks/share.txtar --- a/cue/testdata/benchmarks/share.txtar +++ b/cue/testdata/benchmarks/share.txtar @@ -5,47 +5,6 @@ h: [i, i, i, i, i, i, i] @test(shareID=H) @test(shareID=I, at=0) @test(shareID=I, at=3) @test(shareID=I, at=6) i: [j, j, j, j, j, j, j] @test(shareID=I) j: 1 --- out/compile -- ---- in.cue -{ - f: [ - 〈1;g〉, - 〈1;g〉, - 〈1;g〉, - 〈1;g〉, - 〈1;g〉, - 〈1;g〉, - 〈1;g〉, - ] - g: [ - 〈1;h〉, - 〈1;h〉, - 〈1;h〉, - 〈1;h〉, - 〈1;h〉, - 〈1;h〉, - 〈1;h〉, - ] - h: [ - 〈1;i〉, - 〈1;i〉, - 〈1;i〉, - 〈1;i〉, - 〈1;i〉, - 〈1;i〉, - 〈1;i〉, - ] - i: [ - 〈1;j〉, - 〈1;j〉, - 〈1;j〉, - 〈1;j〉, - 〈1;j〉, - 〈1;j〉, - 〈1;j〉, - ] - j: 1 -} -- out/eval/stats -- Leaks: 0 Freed: 34 diff --git a/cue/testdata/benchmarks/sharefg.txtar b/cue/testdata/benchmarks/sharefg.txtar --- a/cue/testdata/benchmarks/sharefg.txtar +++ b/cue/testdata/benchmarks/sharefg.txtar @@ -189,270 +189,6 @@ Disjuncts: 0 NumCloseIDs: 238 --- out/compile -- ---- in.cue -{ - binexpr: { - f1: { - out: { - x: 2 - } - } - f2: { - out: { - x: (〈2;f1〉.out.x + 1) - } - } - f3: { - out: { - x: (〈2;f2〉.out.x + 1) - } - } - f4: { - out: { - x: (〈2;f3〉.out.x + 1) - } - } - f5: { - out: { - x: (〈2;f4〉.out.x + 1) - } - } - f6: { - out: { - x: (〈2;f5〉.out.x + 1) - } - } - f7: { - out: { - x: (〈2;f6〉.out.x + 1) - } - } - f8: { - out: { - x: (〈2;f7〉.out.x + 1) - } - } - } - parenthesized: { - f1: { - out: { - x: 2 - } - } - f2: { - out: { - x: (〈2;f1〉.out.x + 1) - } - } - f3: { - out: { - x: (〈2;f2〉.out.x + 1) - } - } - f4: { - out: { - x: (〈2;f3〉.out.x + 1) - } - } - f5: { - out: { - x: (〈2;f4〉.out.x + 1) - } - } - f6: { - out: { - x: (〈2;f5〉.out.x + 1) - } - } - f7: { - out: { - x: (〈2;f6〉.out.x + 1) - } - } - f8: { - out: { - x: (〈2;f7〉.out.x + 1) - } - } - } - embedded: { - f1: { - out: { - x: 2 - } - } - f2: { - out: { - x: ({ - 〈3;f1〉.out - }.x + 1) - } - } - f3: { - out: { - x: ({ - 〈3;f2〉.out - }.x + 1) - } - } - f4: { - out: { - x: ({ - 〈3;f3〉.out - }.x + 1) - } - } - f5: { - out: { - x: ({ - 〈3;f4〉.out - }.x + 1) - } - } - f6: { - out: { - x: ({ - 〈3;f5〉.out - }.x + 1) - } - } - f7: { - out: { - x: ({ - 〈3;f6〉.out - }.x + 1) - } - } - f8: { - out: { - x: ({ - 〈3;f7〉.out - }.x + 1) - } - } - } - embeddedWithEmpty: { - f1: { - out: { - x: 2 - } - } - f2: { - out: { - x: ({ - (〈3;f1〉.out & {}) - }.x + 1) - } - } - f3: { - out: { - x: ({ - (〈3;f2〉.out & {}) - }.x + 1) - } - } - f4: { - out: { - x: ({ - (〈3;f3〉.out & {}) - }.x + 1) - } - } - f5: { - out: { - x: ({ - (〈3;f4〉.out & {}) - }.x + 1) - } - } - f6: { - out: { - x: ({ - (〈3;f5〉.out & {}) - }.x + 1) - } - } - f7: { - out: { - x: ({ - (〈3;f6〉.out & {}) - }.x + 1) - } - } - f8: { - out: { - x: ({ - (〈3;f7〉.out & {}) - }.x + 1) - } - } - } - weave: { - f: { - out: (〈0;in〉 + 1) - in: (〈1〉.ref.out + 1) - ref: (_ & {}) - } - f8: (〈0;f〉 & { - ref: 〈1;f7〉 - }) - f7: (〈0;f〉 & { - ref: 〈1;f6〉 - }) - f6: (〈0;f〉 & { - ref: 〈1;f5〉 - }) - f5: (〈0;f〉 & { - ref: 〈1;f4〉 - }) - f4: (〈0;f〉 & { - ref: 〈1;f3〉 - }) - f3: (〈0;f〉 & { - ref: 〈1;f2〉 - }) - f2: (〈0;f〉 & { - ref: 〈1;f1〉 - }) - f1: { - out: 2 - } - } - weaveExtraField: { - f: { - out: (〈0;in〉 + 1) - in: (〈1〉.ref.out + 1) - ref: { - y: 4 - } - } - f8: (〈0;f〉 & { - ref: 〈1;f7〉 - }) - f7: (〈0;f〉 & { - ref: 〈1;f6〉 - }) - f6: (〈0;f〉 & { - ref: 〈1;f5〉 - }) - f5: (〈0;f〉 & { - ref: 〈1;f4〉 - }) - f4: (〈0;f〉 & { - ref: 〈1;f3〉 - }) - f3: (〈0;f〉 & { - ref: 〈1;f2〉 - }) - f2: (〈0;f〉 & { - ref: 〈1;f1〉 - }) - f1: { - out: 2 - } - } -} -- out/todo.txt -- weave.f.out: v2 reports [cycle] error, v3 reports [incomplete] "undefined field: out". weaveExtraField.f.out: same v2/v3 difference as weave.f.out. diff --git a/cue/testdata/benchmarks/sort.txtar b/cue/testdata/benchmarks/sort.txtar --- a/cue/testdata/benchmarks/sort.txtar +++ b/cue/testdata/benchmarks/sort.txtar @@ -16,68 +16,6 @@ v2 expanded _b and _c elements into independent copies of the sublists; v3 uses structure sharing (_b elements: ~(_a), _c elements: ~(_b)). NOTE: this sharing is tested explicitly in share.txtar. --- out/compile -- ---- in.cue -{ - _a: [ - { - name: 1 - }, - { - name: 3 - }, - { - name: 4 - }, - { - name: 5 - }, - { - name: 6 - }, - { - name: 7 - }, - { - name: 8 - }, - { - name: 9 - }, - { - name: 0 - }, - ] - _b: [ - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - 〈1;_a〉, - ] - _c: [ - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - 〈1;_b〉, - ] - out: 〈import;list〉.Sort(〈import;list〉.FlattenN(〈0;_c〉, 4), { - x: _ - y: _ - less: (〈0;x〉.name < 〈0;y〉.name) - }) -} -- out/eval/stats -- Leaks: 0 Freed: 947 diff --git a/cue/testdata/benchmarks/typocheck.txtar b/cue/testdata/benchmarks/typocheck.txtar --- a/cue/testdata/benchmarks/typocheck.txtar +++ b/cue/testdata/benchmarks/typocheck.txtar @@ -43,34 +43,3 @@ ConjunctInfos: 905 MaxConjunctInfos: 103 MaxReqSets: 104 --- out/compile -- ---- in.cue -{ - out: (〈0;#Output〉 & { - #input: 〈1;_input〉 - }) - _input: { - for _, n in 〈import;list〉.Range(1, 100, 1) { - "A\(〈1;n〉)": { - "B\(〈2;n〉)": { - name: "name\(〈3;n〉)" - } - } - } - } - #Embed: { - [string]: string - } - #Output: { - 〈1;#Embed〉 - #input: _ - for _, lvlA in 〈0;#input〉 { - for nameB, lvlB in 〈1;lvlA〉 { - 〈1;nameB〉: 〈1;lvlB〉.name - } - } - } - _checkB1: 〈0;out〉.B1 - _checkB50: 〈0;out〉.B50 - _checkB99: 〈0;out〉.B99 -} diff --git a/cue/testdata/builtins/056_issue314.txtar b/cue/testdata/builtins/056_issue314.txtar --- a/cue/testdata/builtins/056_issue314.txtar +++ b/cue/testdata/builtins/056_issue314.txtar @@ -60,29 +60,3 @@ -- out/diff-v2-v3.txt -- positions: v3 reports different position for some errors Verdict: worsening -- v3 reports different error positions. --- out/compile -- ---- in.cue -{ - x: { - s: "myname" - 〈1;#T〉 - } - #T: { - s: string - out: 〈import;"text/template"〉.Execute("{{.s}}", { - s: 〈1;s〉 - }) - } - #V: { - s: string - out: 〈import;"encoding/json"〉.Marshal({ - s: 〈1;s〉 - }) - } - #U: { - s: string - out: 〈import;"encoding/yaml"〉.Marshal({ - s: 〈1;s〉 - }) - } -} diff --git a/cue/testdata/builtins/all.txtar b/cue/testdata/builtins/all.txtar --- a/cue/testdata/builtins/all.txtar +++ b/cue/testdata/builtins/all.txtar @@ -57,41 +57,3 @@ ./in.cue:10:17 [incomplete] okIncompleteChild.x.a: undefined field: c: ./in.cue:18:16 --- out/compile -- ---- in.cue -{ - fatalArg: { - x: len(("eee" + 'eee')) - } - fatalChild: { - #b: {} - x: and([ - { - a: 〈2;#b〉.c - }, - ]) - } - okIncompleteChild: { - b: {} - x: and([ - { - a: 〈2;b〉.c - }, - { - b: 1 - }, - ]) - } -} ---- issue3412.cue -{ - andInPattern: { - out: { - [and(〈1;#constraints〉)]: _ - someKey: {} - } - #constraints: [ - =~"^.*$", - ] - } -} diff --git a/cue/testdata/builtins/and.txtar b/cue/testdata/builtins/and.txtar --- a/cue/testdata/builtins/and.txtar +++ b/cue/testdata/builtins/and.txtar @@ -48,37 +48,3 @@ ./in.cue:11:28 [incomplete] issue3719._filledLater: undefined field: foo: ./in.cue:11:28 --- out/compile -- ---- in.cue -{ - merge: and([ - 1, - 1, - ]) - embed: and([ - { - 2 - #x: 1 - }, - { - 2 - #x: 2 - }, - ]) - issue3719: { - #openStruct: { - ... - } - _filledLater: 〈0;#openStruct〉.foo - withoutAnd: { - for k, v in 〈1;_filledLater〉.bar { - 〈1;k〉: 〈1;v〉 - } - } - withAnd: and([ - for k, v in 〈1;_filledLater〉.bar { - 〈1;k〉: 〈1;v〉 - }, - ]) - } -} diff --git a/cue/testdata/builtins/args.txtar b/cue/testdata/builtins/args.txtar --- a/cue/testdata/builtins/args.txtar +++ b/cue/testdata/builtins/args.txtar @@ -33,24 +33,3 @@ Unifications: 10 Conjuncts: 16 Disjuncts: 4 --- out/compile -- ---- in.cue -{ - issue3584: { - reduced: { - t1: { - ref: 〈0;out〉 - trigger: (*1|2) - out: 〈import;strings〉.SliceRunes("ABC", 0, 〈0;trigger〉) - } - } - } - issue3584: { - reduced: { - t2: { - x: 〈import;math〉.Abs(〈0;y〉) - y: (*6|5) - } - } - } -} diff --git a/cue/testdata/builtins/closeall.txtar b/cue/testdata/builtins/closeall.txtar --- a/cue/testdata/builtins/closeall.txtar +++ b/cue/testdata/builtins/closeall.txtar @@ -63,48 +63,3 @@ ./in.cue:44:7 [eval] h.err: error in call to __closeAll: __closeAll may only be used when explicitopen is enabled: ./old.cue:3:7 --- out/compile -- ---- in.cue -{ - a: __closeAll({ - field1: 1 - nested: { - field2: "hello" - } - }) - b: { - err: (〈1;a〉 & { - extra: "not allowed" - }) - } - c: { - err: (〈1;a〉 & { - field1: 1 - nested: { - field2: "hello" - extra: "not allowed" - } - }) - } - d: { - err: __closeAll("not a struct") - } - e: __closeAll({}) - f: { - err: (〈1;e〉 & { - extra: "not allowed" - }) - } - #A: { - a: int - } - g: { - err: __closeAll(〈1;#A〉) - } -} ---- old.cue -{ - h: { - err: __closeAll({}) - } -} diff --git a/cue/testdata/builtins/closed.txtar b/cue/testdata/builtins/closed.txtar --- a/cue/testdata/builtins/closed.txtar +++ b/cue/testdata/builtins/closed.txtar @@ -206,246 +206,3 @@ Reordering Let differs. Verdict: cosmetic -- Field reordering; let binding differences. No semantic change. --- out/compile -- ---- embed.cue -{ - nestedEmbedded: { - base: { - close({ - foo?: close({ - foo?: _ - }) - }) - foo: { - allowed: 5 - } - } - } - nestedEmbedded: { - t1: { - { - close({ - foo?: close({ - foo?: _ - }) - }) - } - foo: { - allowed: 5 - } - } - } - nestedEmbedded: { - t2: { - { - { - close({ - foo?: close({ - foo?: _ - }) - }) - } - } - foo: { - allowed: 5 - } - } - } - unified: { - base: { - x: close({ - foo?: close({ - foo?: _ - }) - }) - x: { - foo: { - disallowed: 5 - } - } - } - } - unified: { - t1: { - x: { - close({ - foo?: close({ - foo?: _ - }) - }) - } - x: { - foo: { - disallowed: 5 - } - } - } - } - unified: { - t2: { - x: { - { - close({ - foo?: close({ - foo?: _ - }) - }) - } - } - x: { - foo: { - disallowed: 5 - } - } - } - } - nestedWithSelfReference: { - t1: { - _schema: close({ - foo?: 〈1;_schema〉 - }) - x: { - 〈1;_schema〉 - } - x: { - foo: { - disallowed: 5 - } - } - } - } - nestedWithSelfReference: { - t2: { - _schema: close({ - foo?: 〈1;_schema〉 - }) - x: { - { - 〈2;_schema〉 - } - } - x: { - foo: { - disallowed: 5 - } - } - } - } -} ---- in.cue -{ - a: close({ - a: { - b: int - } - }) - b: (〈0;a〉 & { - x: int - }) - c: (〈0;a〉 & { - a: { - c: int - } - }) - inDisjunctions: { - x: { - [string]: 〈1;#Def〉 - } - #Def: { - [string]: { - a: { - b: true - } - let X#1 = 〈0;a〉 - (close({ - uint: { - a: { - b: 〈3;let X#1〉.b - } - } - })|close({ - string: { - a: { - b: true - } - } - })) - } - } - x: { - socket: { - string: {} - } - } - x: { - syslog: 〈1;x〉.socket - } - x: { - syslog: { - xxx: {} - } - } - } - issue642: { - test: close(({ - a: _ - b: { - x: _ - } - } & { - [string]: { - y: _ - } - })) - test: { - a: { - x: _ - } - } - test: { - b: { - x: _ - } - } - } - withSubfields: { - test: close({ - a: _ - b: { - x: _ - } - [string]: { - y: _ - } - }) - test: { - a: { - x: _ - } - } - test: { - b: { - x: _ - } - } - } - issue3572: { - t1: (close({ - ... - }) & { - a: 5 - }) - e: close({ - ... - }) - t2: (〈0;e〉 & { - a: 5 - }) - } - issue3580: { - x: close({ - a: _ - b: 〈1;x〉.a - }) - } -} diff --git a/cue/testdata/builtins/default.txtar b/cue/testdata/builtins/default.txtar --- a/cue/testdata/builtins/default.txtar +++ b/cue/testdata/builtins/default.txtar @@ -7,28 +7,6 @@ Mod: mod(*5 | string, 2) @test(eq, 1) Quo: quo(*5 | string, 2) @test(eq, 2) Rem: rem(*5 | string, 2) @test(eq, 1) --- out/compile -- ---- in.cue -{ - Len: len((*[ - 1, - 2, - 3, - ]|0)) - Close: close((*{}|0)) - And: and((*[ - 1, - 1, - ]|int)) - Or: or((*[ - 1, - 1, - ]|int)) - Div: div((*5|string), 2) - Mod: mod((*5|string), 2) - Quo: quo((*5|string), 2) - Rem: rem((*5|string), 2) -} -- out/eval/stats -- Leaks: 1 Freed: 42 diff --git a/cue/testdata/builtins/error.txtar b/cue/testdata/builtins/error.txtar --- a/cue/testdata/builtins/error.txtar +++ b/cue/testdata/builtins/error.txtar @@ -170,69 +170,3 @@ ./self.cue:6:12 ./self.cue:7:5 ./self.cue:8:5 --- out/compile -- ---- in.cue -{ - selection: { - dropError: (1|error("drop me")) - useCustomError: ((1 & 2)|error("use me")) - twoCustomErrors: ((1 & 2)|error("error one")|error("error two")) - x: int - dropIncomplete: ((〈0;x〉 + 1)|error("user msg: x + 1 failed")) - } - interpolation: { - a: { - b: int - } - world: "world" - substituteAll: (〈0;a〉.notExist|error("hello \(〈0;world〉)")) - substituteFail: ((〈0;a〉.b + 1)|〈0;a〉.notExist|error("reference failed: \(〈0;a〉.b) | \(〈0;a〉.notExist)")) - errorNoInterpolation: ("a"|"b"|error("custom")) - errorNoInterpolation: "c" - errorStructInterpolation: ("a"|"b"|error("custom: \({ - x: 1 - })")) - errorStructInterpolation: "c" - errorBottomInterpolation: ("a"|"b"|error("custom: \((1 & 2))")) - errorBottomInterpolation: "c" - } - indirect: { - x: error - y: 〈0;x〉("msg") - } -} ---- incomplete.cue -{ - minFields: (〈import;struct〉.MinFields(2)|error("should remain incomplete")) - maxFields: { - a: 1 - } - multi: (〈import;struct〉.MinFields(2)|error("should remain incomplete")|error("second")) - multi: { - a: 1 - } -} ---- issues.cue -{ - issue4001: { - a: "b" - a: (int|error(("error: " + "a='\(〈0;a〉)'"))) - } - issue3983: { - x: (int|error("I wanted an integer")) - x: (>10|error("I wanted more than 10")) - x: (<20|error("I wanted less than 20")) - x: 3 - } - issue3984: { - v: ("a"|error("must be a")) - v: "b" - } -} ---- self.cue -{ - errorSelf: { - v: ("x"|"y"|error("bad: \(〈1〉)")) - v: "z" - } -} diff --git a/cue/testdata/builtins/export.txtar b/cue/testdata/builtins/export.txtar --- a/cue/testdata/builtins/export.txtar +++ b/cue/testdata/builtins/export.txtar @@ -37,36 +37,3 @@ Disjuncts: 0 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - issue3972: { - output: { - out0: "static" - } - input: { - inputStatic: "static" - } - if false { - input: { - inputNever: "never" - } - } - derived: { - derivedStatic: "static" - } - if false { - derived: { - derivedNever: 〈2;input〉.inputNever - } - } - _out1: [ - for svc, _ in 〈1;derived〉 { - 〈1;svc〉 - }, - ] - output: { - out1: 〈import;"encoding/yaml"〉.Marshal(〈1;_out1〉) - } - } -} diff --git a/cue/testdata/builtins/incomplete.txtar b/cue/testdata/builtins/incomplete.txtar --- a/cue/testdata/builtins/incomplete.txtar +++ b/cue/testdata/builtins/incomplete.txtar @@ -185,102 +185,3 @@ [incomplete] multipleErrors.#T.out: error in call to text/template.Execute: cannot convert non-concrete value string: ./in.cue:106:8 ./in.cue:103:4 --- out/compile -- ---- in.cue -{ - list1: { - Out1: 〈import;list〉.FlattenN(〈0;Top〉, 1) - Out2: ([ - ..., - ] & 〈import;list〉.FlattenN(〈0;Top〉, 1)) - Out3: (〈import;list〉.FlattenN(〈0;Top〉, 1) & [ - ..., - ]) - Top: [ - [ - for _, F in 〈2;_Sub〉 { - 〈1;F〉 - }, - ], - ] - _Sub: 〈0;a〉.b - a: {} - } - list2: { - Out1: 〈import;list〉.FlattenN(〈0;_Top〉, 1) - Out2: ([ - ..., - ] & 〈import;list〉.FlattenN(〈0;_Top〉, 1)) - Out3: (〈import;list〉.FlattenN(〈0;_Top〉, 1) & [ - ..., - ]) - _Top: [ - for _, F in 〈1;#Sub〉 { - 〈1;F〉 - }, - ] - #Sub: 〈0;a〉.b - a: {} - } - value1: { - a: len(('sf'|'dd')) - } - value2: { - len(('sf'|'dd')) - } - incompleteArgDecimalList: { - a: (〈0;#a〉 & { - param: 123 - }) - #a: { - param: int - transformed: +〈0;param〉 - max: 〈import;list〉.Max([ - 〈1;transformed〉, - ]) - } - } - incompleteArgStringList: { - a: (〈0;#a〉 & { - param: "123" - }) - #a: { - param: string - transformed: (〈0;param〉 + "") - joined: 〈import;strings〉.Join([ - 〈1;transformed〉, - ], "-") - } - } - incompleteList: { - x: _ - decimal: 〈import;list〉.Max(〈0;x〉) - str: 〈import;strings〉.Join(〈0;x〉, "") - } - incompleteListError: { - x: (〈0;y〉 + []) - y: _ - decimal: 〈import;list〉.Max(〈0;x〉) - str: 〈import;strings〉.Join(〈0;x〉, "") - } - badListType: { - x: 2 - decimal: 〈import;list〉.Max(〈0;x〉) - str: 〈import;strings〉.Join(〈0;x〉, "") - } - badListError: { - x: (2 + 〈0;y〉) - y: "foo" - decimal: 〈import;list〉.Max(〈0;x〉) - str: 〈import;strings〉.Join(〈0;x〉, "") - } - multipleErrors: { - #T: { - params: { - x: string - y: string - } - out: 〈import;"text/template"〉.Execute("{{.x}} {{.y}}", 〈0;params〉) - } - } -} diff --git a/cue/testdata/builtins/intdiv.txtar b/cue/testdata/builtins/intdiv.txtar --- a/cue/testdata/builtins/intdiv.txtar +++ b/cue/testdata/builtins/intdiv.txtar @@ -73,35 +73,3 @@ ./in.cue:38:20 [eval] modTypeError2: cannot use 1.0 (type float) as int in argument 2 to mod: ./in.cue:39:23 --- out/compile -- ---- in.cue -{ - quo1: quo(5, 2) - quo2: quo(5, -2) - quo3: quo(-5, 2) - quo4: quo(-5, -2) - quoDivByZero: quo(2, 0) - quoTypeError1: quo(2.0, 1) - quoTypeError2: quo(2, 1.0) - rem1: rem(5, 2) - rem2: rem(5, -2) - rem3: rem(-5, 2) - rem4: rem(-5, -2) - remDivByZero: rem(2, 0) - remTypeError1: rem(2.0, 1) - remTypeError2: rem(2, 1.0) - div1: div(5, 2) - div2: div(5, -2) - div3: div(-5, 2) - div4: div(-5, -2) - divDivByZero: div(2, 0) - divTypeError1: div(2.0, 1) - divTypeError2: div(2, 1.0) - mod1: mod(5, 2) - mod2: mod(5, -2) - mod3: mod(-5, 2) - mod4: mod(-5, -2) - modDivByZero: mod(2, 0) - modTypeError1: mod(2.0, 1) - modTypeError2: mod(2, 1.0) -} diff --git a/cue/testdata/builtins/issue299.txtar b/cue/testdata/builtins/issue299.txtar --- a/cue/testdata/builtins/issue299.txtar +++ b/cue/testdata/builtins/issue299.txtar @@ -24,16 +24,3 @@ ./in.cue:3:4 ./in.cue:4:4 ./in.cue:5:4 --- out/compile -- ---- in.cue -{ - x: 〈import;list〉.UniqueItems - x: [ - string, - ...string, - ] - x: [ - "x", - "x", - ] -} diff --git a/cue/testdata/builtins/issue4208.txtar b/cue/testdata/builtins/issue4208.txtar --- a/cue/testdata/builtins/issue4208.txtar +++ b/cue/testdata/builtins/issue4208.txtar @@ -38,19 +38,3 @@ -- out/errors.txt -- [eval] invalid.foo: field not allowed: ./in.cue:10:10 --- out/compile -- ---- in.cue -{ - #Environment: ("sbx"|"stg"|"pro"|error("Must specify a valid environment")) - #Envs: { - [〈1;#Environment〉]: {} - } - valid: 〈0;#Envs〉 - valid: { - sbx: {} - } - invalid: 〈0;#Envs〉 - invalid: { - foo: {} - } -} diff --git a/cue/testdata/builtins/issue490.txtar b/cue/testdata/builtins/issue490.txtar --- a/cue/testdata/builtins/issue490.txtar +++ b/cue/testdata/builtins/issue490.txtar @@ -48,14 +48,3 @@ positions Reordering Verdict: worsening -- v3 reports different error positions; field reordering. --- out/compile -- ---- test.cue -{ - A: close({ - a: 1 - b: 2 - }) - B: (〈0;A〉 & { - c: 3 - }) -} diff --git a/cue/testdata/builtins/issue_3567.txtar b/cue/testdata/builtins/issue_3567.txtar --- a/cue/testdata/builtins/issue_3567.txtar +++ b/cue/testdata/builtins/issue_3567.txtar @@ -2,16 +2,6 @@ import "strings" a: strings.Join( [ strings.Join(["1"]), "2" ], "\n") @test(err, code=eval, contains="not enough arguments in call to strings.Join", pos=[0:4, 0:20]) --- out/compile -- ---- in.cue -{ - a: 〈import;strings〉.Join([ - 〈import;strings〉.Join([ - "1", - ]), - "2", - ], "\n") -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/builtins/matchif.txtar b/cue/testdata/builtins/matchif.txtar --- a/cue/testdata/builtins/matchif.txtar +++ b/cue/testdata/builtins/matchif.txtar @@ -46,48 +46,3 @@ Disjuncts: 0 NumCloseIDs: 48 --- out/compile -- ---- in.cue -{ - regularFields: { - [_]: matchIf({ - x!: >2 - }, { - y!: 5 - }, { - y!: 1 - }) - ok1: { - x: 10 - y: 5 - } - ok2: { - x: 11 - y: 5 - } - ok3: { - x: 2 - y: 1 - } - ok4: { - x: 1 - y: 1 - } - err1: { - x: 10 - y: 6 - } - err2: { - x: 11 - y: 6 - } - err3: { - x: 2 - y: 5 - } - err4: { - x: 1 - y: 2 - } - } -} diff --git a/cue/testdata/builtins/matchn.txtar b/cue/testdata/builtins/matchn.txtar --- a/cue/testdata/builtins/matchn.txtar +++ b/cue/testdata/builtins/matchn.txtar @@ -796,650 +796,3 @@ - explicitClose.err1.out.a.baz: v2 reports extra position info that v3 does not - issue3389.x: position differences - issue3694: position differences (2-line comment at top of file shifts line numbers) --- out/compile -- ---- closedness.cue -{ - ellipsis: { - ok: { - out: (〈0;#Schema〉 & { - field: { - shouldBeAllowed: 123 - } - }) - #Schema: { - field?: 〈0;#anything〉 - #anything: matchN(1, [ - { - ... - }, - ]) - } - } - } - openArguments: { - ok1: { - #Schema: { - { - a: matchN(1, [ - "all", - { - foo: "bar" - }, - ]) - } - } - out: (〈0;#Schema〉 & { - a: { - baz: "allowed" - } - }) - } - } - openArguments: { - err2: { - #Schema: { - { - a?: matchN(1, [ - null, - { - [string]: string - }, - { - b: { - ... - } - }, - ]) - } - } - out: (〈0;#Schema〉 & { - a: { - allowed: "once" - } - }) - } - } - explicitClose: { - err1: { - #Schema: { - { - a: matchN(1, [ - "all", - close({ - foo: "bar" - }), - ]) - } - } - out: (〈0;#Schema〉 & { - a: { - baz: "notAllowed" - } - }) - } - } - explicitClose: { - ok2: { - #Schema: { - { - a?: matchN(1, [ - null, - close({ - [string]: string - }), - close({ - b: { - ... - } - }), - ]) - } - } - out: (〈0;#Schema〉 & { - a: { - allowed: "once" - } - }) - } - } - mixed: { - ok3: { - #Schema: { - exports?: matchN(1, [ - close({ - never?: _ - }), - 〈1;#exportsObject〉, - ]) - #exports: matchN(1, [ - string, - 〈1;#exportsObject〉, - ]) - #exportsObject: { - exp1?: 〈1;#exports〉 - } - } - out: (〈0;#Schema〉 & { - exports: { - exp1: "./main-module.js" - } - }) - } - } - closedByDefinition: { - ok4: { - #Schema: { - exports?: matchN(1, [ - string, - 〈1;#exportsObject〉, - ]) - #exports: matchN(1, [ - string, - 〈1;#exportsObject〉, - ]) - #exportsObject: { - exp1?: 〈1;#exports〉 - } - } - out: (〈0;#Schema〉 & { - exports: { - exp1: "./main-module.js" - } - }) - } - } - closedByDefinition: { - err5: { - #Schema: { - exports?: matchN(1, [ - null, - 〈1;#exportsObject〉, - ]) - #exports: matchN(1, [ - null, - 〈1;#exportsObject〉, - ]) - #exportsObject: { - exp1?: 〈1;#exports〉 - } - } - out: (〈0;#Schema〉 & { - exports: { - exp1: "./main-module.js" - } - }) - } - } -} ---- in.cue -{ - #Foo: { - a: int - } - match: { - [=~"^single"]: matchN(1, [ - 〈2;#Foo〉, - ]) - singleOK: { - a: 2 - } - singleErr: { - a: "foo" - } - [=~"^incomplete"]: matchN(1, [ - 〈2;#Foo〉, - ]) - incompleteOK: { - a: int - } - incompleteErr: { - a: string - } - #A: { - a: int - b: _ - ... - } - defaults: { - [=~"^pickTop"]: matchN(1, [ - 2, - ]) - pickTopOK1: (*2|int) - pickTopOK2: int - pickTopErr: (*3|int) - [=~"^pickNested1"]: matchN(1, [ - { - a: 2 - }, - ]) - pickNested1OK1: { - a: (*2|int) - } - pickNested1OK2: { - a: int - } - pickNested1Err: { - a: (*3|int) - } - [=~"^pickNested2"]: matchN(1, [ - { - a: <=2 - }, - ]) - pickNested2OK1: { - a: (*2|int) - } - pickNested2OK2: { - a: int - } - pickNested2Err: { - a: (*3|int) - } - } - nestedOK: { - matchN(4, [ - 〈2;#A〉, - 〈2;#A〉, - 〈2;#A〉, - 〈2;#A〉, - ]) - a: 2 - b: { - matchN(4, [ - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - ]) - a: 3 - b: matchN(4, [ - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - ]) - b: { - a: 4 - } - c: matchN(4, [ - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - ]) - c: { - a: 5 - } - } - c: { - matchN(4, [ - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - ]) - a: 3 - b: matchN(4, [ - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - ]) - b: { - a: 4 - } - c: matchN(4, [ - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - 〈3;#A〉, - ]) - c: { - a: 5 - } - } - } - } - not: { - [=~"^single"]: matchN(0, [ - 〈2;#Foo〉, - ]) - singleOK: { - a: "foo" - } - singleErr: { - a: 2 - } - [=~"^double"]: matchN(0, [ - matchN(0, [ - 〈3;#Foo〉, - ]), - ]) - doubleOK: { - a: 2 - } - doubleErr: { - a: "foo" - } - } - oneOf: { - [=~"^multiple1"]: matchN(1, [ - 〈import;math〉.MultipleOf(3), - 〈import;math〉.MultipleOf(5), - ]) - multiple1Err1: 1 - multiple1OK1: 3 - multiple1OK2: 5 - multiple1Err2: 15 - } - anyOf: { - [=~"^multiple1"]: matchN(>0, [ - 〈import;math〉.MultipleOf(3), - 〈import;math〉.MultipleOf(5), - ]) - multiple1Err1: 1 - multiple1OK1: 3 - multiple1OK2: 5 - multiple1OK3: 15 - } - allOf: { - [=~"^multiple1"]: matchN(2, [ - 〈import;math〉.MultipleOf(3), - 〈import;math〉.MultipleOf(5), - ]) - multiple1Err1: 1 - multiple1Err2: 3 - multiple1Err3: 5 - multiple1OK1: 15 - } - bare: { - embed: { - t1: { - a: { - matchN(1, [ - >10, - ]) - } - b: { - 〈1;a〉 - } - } - } - embed: { - t2: { - b: { - 〈1;a〉 - } - a: { - matchN(1, [ - >10, - ]) - } - } - } - direct: { - t1: { - a: matchN(1, [ - >10, - ]) - b: 〈0;a〉 - } - } - direct: { - t2: { - b: 〈0;a〉 - a: matchN(1, [ - >10, - ]) - } - } - } - required: { - ok1: { - x: matchN(0, [ - { - foo!: string - }, - ]) - x: { - bar: 2 - } - } - ok2: { - x: matchN(0, [ - { - foo!: string - }, - ]) - } - ok3: { - x: matchN(0, [ - { - bar!: string - }, - ]) - x: { - bar: 2 - } - } - } - issue3575: { - test1: { - #x: matchN(1, [ - [ - {}, - ], - ]) - x: 〈0;#x〉 - x: [ - { - a: 1 - }, - ] - } - test2: { - #x: matchN(1, [ - {}, - ]) - x: 〈0;#x〉 - x: { - a: 1 - } - } - } -} ---- incomplete.cue -{ - incomplete: { - incomplete1: { - x: matchN(1, [ - { - foo!: string - }, - ]) - x: { - bar: 2 - } - } - incomplete2: { - x: matchN(1, [ - { - foo!: string - }, - ]) - } - incomplete3: { - x: matchN(〈import;math〉.MultipleOf(2), [ - { - bar!: int - }, - { - foo!: int - }, - ]) - x: { - bar: 2 - } - } - incomplete4: { - x: matchN(〈import;math〉.MultipleOf(2), [ - { - bar!: int - }, - { - foo!: int - }, - { - baz!: int - }, - ]) - x: { - bar: 2 - } - } - incomplete5: { - x: matchN((>1 & <=3), [ - { - bar!: int - }, - { - foo!: int - }, - { - baz!: int - }, - ]) - x: { - bar: 2 - } - } - incomplete6: { - x: matchN((2|3), [ - { - bar!: int - }, - { - foo!: int - }, - { - baz!: int - }, - ]) - x: { - bar: 2 - } - } - err1: { - x: matchN(1, [ - { - bar!: string - }, - ]) - x: { - bar: 2 - } - } - err2: { - x: matchN(0, [ - { - bar!: int - }, - { - foo!: int - }, - ]) - x: { - bar: 2 - } - } - err3: { - x: matchN(2, [ - { - bar!: string - }, - { - foo!: string - }, - ]) - x: { - bar: 2 - } - } - err4: { - x: matchN(>1, [ - { - bar!: string - }, - { - foo!: string - }, - ]) - x: { - bar: 2 - } - } - err5: { - x: matchN(<1, [ - { - bar!: int - }, - { - foo!: int - }, - ]) - x: { - bar: 2 - } - } - } - issue3389: { - x: { - bar: 2 - } - x: matchN(1, [ - { - bar: 3 - }, - { - bar: 2 - foo!: int - }, - ]) - } -} ---- issue3694.cue -{ - issue3694: { - full: { - #step: matchN(1, [ - { - uses!: _ - ... - }, - { - run!: _ - ... - }, - ]) - #step: close({ - uses?: string - run?: string - }) - s: (〈0;#step〉 & { - run: "echo hello world" - }) - } - } - issue3694: { - simple: { - #step: matchN(1, [ - { - uses!: _ - }, - ]) - #step: close({ - uses?: string - }) - } - } -} diff --git a/cue/testdata/builtins/or.txtar b/cue/testdata/builtins/or.txtar --- a/cue/testdata/builtins/or.txtar +++ b/cue/testdata/builtins/or.txtar @@ -9,39 +9,3 @@ // do not unique embedded scalars with differing values for child definitions. embed1: or([{2, #x: 1}, {2, #x: 2}]) @test(eq, {2, #x: 1} | {2, #x: 2}) --- out/compile -- ---- in.cue -{ - unwrap: or([ - 1, - 1, - 1, - ]) - unique1: or([ - 2, - 1, - 1, - 2, - ]) - unique2: or([ - { - a: 1 - }, - { - a: 1 - }, - { - a: 2 - }, - ]) - embed1: or([ - { - 2 - #x: 1 - }, - { - 2 - #x: 2 - }, - ]) -} diff --git a/cue/testdata/builtins/reclose.txtar b/cue/testdata/builtins/reclose.txtar --- a/cue/testdata/builtins/reclose.txtar +++ b/cue/testdata/builtins/reclose.txtar @@ -159,196 +159,3 @@ ./in.cue:125:15 [eval] retro.t1.err: error in call to __reclose: __reclose may only be used when explicitopen is enabled: ./old.cue:3:11 --- out/compile -- ---- in.cue -{ - noClose: { - foo: { - a: int - } - a: __reclose({ - 〈1;foo〉... - }) - t1: { - ok: (〈1;a〉 & { - b: 1 - }) - } - } - recursive: { - #x: { - foo: int - } - a: __reclose({ - 〈1;#x〉... - nested: { - field2: int - } - }) - t1: { - err: (〈1;a〉 & { - extra: "not allowed" - }) - } - t2: { - ok: (〈1;a〉 & { - nested: { - field2: 5 - } - }) - } - t3: { - ok: (〈1;a〉 & { - foo: 5 - }) - } - t4: { - err: (〈1;a〉 & { - nested: { - field2: 1 - extra: "not allowed" - } - }) - } - e: __reclose({}) - t5: { - err: (〈1;e〉 & { - extra: "not allowed" - }) - } - } - nonRecursive: { - x: __reclose({ - close({ - b: int - })... - c: int - d: { - e: int - } - }) - y: { - err: (〈1;x〉 & { - f: int - }) - } - z: { - ok: (〈1;x〉 & { - d: { - f: int - } - }) - } - } - nonRecursiveDetect: { - foo: close({ - b: {} - }) - a: __reclose({ - 〈1;foo〉... - }) - t1: { - err: (〈1;a〉 & { - f: int - }) - } - t2: { - ok: (〈1;a〉 & { - b: { - c: 1 - } - }) - } - } - mixedClose: { - #D: { - x: { - y: int - } - } - foo: close({ - b: {} - }) - a: __reclose({ - 〈1;#D〉... - 〈1;foo〉... - }) - t1: { - err: (〈1;a〉 & { - f: int - }) - } - t2: { - ok: (〈1;a〉 & { - x: { - y: 5 - } - b: { - c: 1 - } - }) - } - } - recloseWrapsClose: { - #def: { - a: { - b: int - } - } - a: __reclose(close({ - 〈1;#def〉... - })) - t1: { - err: (〈1;a〉 & { - f: int - }) - } - t2: { - err: (〈1;a〉 & { - a: { - c: 1 - } - }) - } - t3: { - ok: (〈1;a〉 & { - a: { - b: 5 - } - }) - } - } - nonStructLiterals: { - t1: { - err: __reclose("not a struct") - } - #A: { - a: int - } - t4: { - err: __reclose(〈1;#A〉) - } - } - nonStructDefinitions: { - #Def: 1 - a: __reclose({ - 〈1;#Def〉... - }) - t1: { - ok: (〈1;a〉 & 1) - } - t2: { - err: (〈1;a〉 & { - b: 1 - }) - } - } -} ---- old.cue -{ - retro: { - t1: { - err: __reclose({}) - } - } -} diff --git a/cue/testdata/builtins/validators.txtar b/cue/testdata/builtins/validators.txtar --- a/cue/testdata/builtins/validators.txtar +++ b/cue/testdata/builtins/validators.txtar @@ -366,317 +366,3 @@ Notifications: 1 NumCloseIDs: 76 --- out/compile -- ---- in.cue -{ - incompleteError1: { - MyType: { - kv: 〈import;struct〉.MinFields(1) - } - foo: (〈0;MyType〉 & { - kv: { - joel: "testing" - } - }) - } - incompleteError2: { - MyType: { - kv: { - [string]: string - } - kv: 〈import;struct〉.MinFields(1) - } - foo: (〈0;MyType〉 & { - kv: { - joel: "testing" - } - }) - } - incompleteError3: { - t: string - t: 〈import;"encoding/json"〉.Validate(string) - } - uniqueConstrains1: { - t: string - t: 〈import;"encoding/json"〉.Validate(string) - t: 〈import;"encoding/json"〉.Validate(string) - } - uniqueConstrains2: { - t: 〈import;struct〉.MaxFields(1) - t: 〈import;struct〉.MaxFields(1) - } - violation: { - #MyType: { - kv: { - [string]: string - } - kv: 〈import;struct〉.MinFields(1) - } - foo: (〈0;#MyType〉 & { - kv: { - joel: "testing" - } - kv: { - tony: "testing" - } - }) - } - conjuncts: { - kv: 〈import;struct〉.MinFields(1) - kv: 〈import;struct〉.MaxFields(3) - } - bareBuiltin: { - a: 〈import;"encoding/json"〉.Valid - a: 〈import;"encoding/json"〉.Valid - } - bareBuiltinCheck: { - a: 〈import;"encoding/json"〉.Valid - a: "3" - } - builtinValidator: { - a: 〈import;"encoding/json"〉.Valid() - a: 〈import;"encoding/json"〉.Valid() - } - builtinValidatorCheck: { - a: 〈import;"encoding/json"〉.Valid() - a: "3" - } - callOfCallToValidator: { - a: 〈import;"encoding/json"〉.Valid - b: 〈0;a〉() - e: 〈0;b〉() - e: "5" - } - validatorAsFunction: { - a: 〈import;"encoding/json"〉.Valid - b: 〈0;a〉("3") - c: 〈import;"encoding/json"〉.Valid("3") - } - issue2098: { - ok1: { - _a: [ - 1, - ..., - ] - _a: 〈import;list〉.MinItems(1) - 〈0;_a〉[0] - } - } - issue2098: { - incomplete1: { - _a: [ - ..., - ] - _a: 〈import;list〉.MinItems(1) - 〈0;_a〉[0] - } - } -} ---- issue3418.cue -{ - issue3418: { - t1: (("foo" & matchN(1, [ - (1 & 2), - ])) & matchN(1, [ - _, - ])) - } - issue3418: { - t2: (("foo" & matchN(1, [ - _, - ])) & matchN(1, [ - (1 & 2), - ])) - } - issue3418: { - t3: { - x: "foo" - x: matchN(1, [ - _, - ]) - x: matchN(1, [ - (1 & 2), - ]) - } - } - issue3418: { - t4: { - x: "foo" - x: matchN(1, [ - (1 & 2), - ]) - x: matchN(1, [ - _, - ]) - } - } -} ---- issue3474.cue -{ - issue3474: { - structValidator: { - ok: { - A: 〈import;struct〉.MinFields(1) - A: { - if true { - B: true - } - } - } - } - } - issue3474: { - structValidator: { - failAfter: { - A: 〈import;struct〉.MaxFields(1) - A: { - C: true - if true { - B: true - } - } - } - } - } - issue3474: { - structValidator: { - incomplete: { - A: 〈import;struct〉.MinFields(1) - A: { - if true {} - } - } - } - } - issue3474: { - structValidator: { - failClosed: { - #A: 〈import;struct〉.MinFields(1) - #A: { - if true {} - } - } - } - } - issue3474: { - topValidator: { - ok: { - A: matchN(1, [ - >10, - ]) - A: { - if true { - 100 - } - } - } - } - } - issue3474: { - topValidator: { - fail: { - A: matchN(1, [ - >10, - ]) - A: { - if true { - 1 - } - } - } - } - } - issue3474: { - topValidator: { - incomplete: { - A: matchN(1, [ - >10, - ]) - A: { - if true { - int - } - } - } - } - } - issue3474: { - topValidator: { - failType: { - A: matchN(1, [ - >10, - ]) - A: { - if true { - C: 1 - } - } - } - } - } -} ---- validator_is_top.cue -{ - issue3639: { - a: ({ - 〈1;#X〉 - } & 〈0;#X〉) - a: { - b: 1 - } - #X: matchN(1, [ - { - b: int - }, - ]) - } - issue3661: { - #X: matchN(1, [ - { - b!: int - }, - ]) - a: { - b: 1 - } - a: 〈0;#X〉 - ["a"]: 〈0;#X〉 - } - issue3678: { - #X: matchN(1, [ - { - a!: string - }, - { - c!: string - }, - ]) - x: { - c: "c" - } - y: 〈0;#X〉 - y: 〈0;x〉 - x: 〈0;#X〉 - } - issue3981: { - matchWithClose: { - out: { - close({ - f1: matchN(1, [ - 〈2;#openStruct〉, - ]) - }) - #openStruct: { - ... - } - } - out: { - f1: { - foo: [ - "bar", - ] - } - } - } - } -} diff --git a/cue/testdata/builtins/versionchk.txtar b/cue/testdata/builtins/versionchk.txtar --- a/cue/testdata/builtins/versionchk.txtar +++ b/cue/testdata/builtins/versionchk.txtar @@ -9,10 +9,3 @@ -- out/evalalpha -- a: builtin "error" is not available in version v0.8.0; it was added in version "v0.14.0": ./in.cue:2:4 --- out/compile -- -a: builtin "error" is not available in version v0.8.0; it was added in version "v0.14.0": - ./in.cue:2:4 ---- in.cue -{ - a: _|_(builtin "error" is not available in version v0.8.0; it was added in version "v0.14.0")("msg") -} diff --git a/cue/testdata/choosedefault/000_pick_first.txtar b/cue/testdata/choosedefault/000_pick_first.txtar --- a/cue/testdata/choosedefault/000_pick_first.txtar +++ b/cue/testdata/choosedefault/000_pick_first.txtar @@ -5,18 +5,6 @@ } | { a: 3 } @test(eq, *{a: 2} | {a: 3}) --- out/compile -- ---- in.cue -{ - a: (*5|"a"|true) - b: { - c: (*{ - a: 2 - }|{ - a: 3 - }) - } -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/choosedefault/001_simple_disambiguation_conflict.txtar b/cue/testdata/choosedefault/001_simple_disambiguation_conflict.txtar --- a/cue/testdata/choosedefault/001_simple_disambiguation_conflict.txtar +++ b/cue/testdata/choosedefault/001_simple_disambiguation_conflict.txtar @@ -2,13 +2,6 @@ a: *"a" | "b" @test(eq, *"a" | "b") b: *"b" | "a" @test(eq, *"b" | "a") c: a & b @test(eq, "a" | "b") --- out/compile -- ---- in.cue -{ - a: (*"a"|"b") - b: (*"b"|"a") - c: (〈0;a〉 & 〈0;b〉) -} -- out/eval/stats -- Leaks: 0 Freed: 14 diff --git a/cue/testdata/choosedefault/002_associativity_of_defaults.txtar b/cue/testdata/choosedefault/002_associativity_of_defaults.txtar --- a/cue/testdata/choosedefault/002_associativity_of_defaults.txtar +++ b/cue/testdata/choosedefault/002_associativity_of_defaults.txtar @@ -82,74 +82,3 @@ Disjuncts: 278 NumCloseIDs: 101 --- out/compile -- ---- complex.cue -{ - t1: { - va: { - a: 1 - b: 2 - } - vb1: { - c: 3 - } - vb2: { - c: 4 - } - vc: { - c: 4 - } - vd: string - A: (〈0;va〉|〈0;vd〉) - B: (*〈0;vb1〉|〈0;vb2〉|〈0;vd〉) - C: (*〈0;vc〉|〈0;vd〉) - p1: ((〈0;A〉 & 〈0;B〉) & 〈0;C〉) - p2: (〈0;A〉 & (〈0;B〉 & 〈0;C〉)) - } - t2: { - va: (0|1|2) - vb1: (2|3) - vb2: (0|1|4) - vc: (0|3|4) - vd: string - A: (〈0;va〉|〈0;vd〉) - B: (*〈0;vb1〉|〈0;vb2〉|〈0;vd〉) - C: (*〈0;vc〉|〈0;vd〉) - p1: ((〈0;A〉 & 〈0;B〉) & 〈0;C〉) - p2: (〈0;A〉 & (〈0;B〉 & 〈0;C〉)) - } -} ---- in.cue -{ - a: (*"a"|("b"|"c")) - b: ((*"a"|"b")|"c") - c: (*"a"|(*"b"|"c")) - x: (〈0;a〉 & 〈0;b〉) - y: (〈0;b〉 & 〈0;c〉) - s1: (*1|((*2|3) & (2|*3))) - s2: (*1|((*2|3) & (*2|3))) - s3: (*1|((*2|3) & 3)) - s4: (*1|((*2|3) & 2)) - s5: (*1|*(*2|3)) - e1: (*(1 & 2)|(*"x"|string)) - e2: ((*"x"|string)|*(1 & 2)) -} ---- issue3908.cue -{ - issue3908: { - reduced: { - (string|*null) - (string|*"str") - } - } - issue3908: { - full: { - out: (〈0;#Schema〉 & { - field: (string|*"dataDefault") - }) - #Schema: { - field: (string|*null) - } - } - } -} diff --git a/cue/testdata/compile/alias.txtar b/cue/testdata/compile/alias.txtar --- a/cue/testdata/compile/alias.txtar +++ b/cue/testdata/compile/alias.txtar @@ -7,15 +7,6 @@ a: "name" @test(eq, {x: 1, a: "name", name: 1}) } --- out/compile -- ---- in.cue -{ - dynamic: { - 〈0;a〉: 1 - x: 〈0;(〈0;a〉)〉 - a: "name" - } -} -- out/eval/stats -- Leaks: 0 Freed: 10 diff --git a/cue/testdata/compile/err_top.txtar b/cue/testdata/compile/err_top.txtar --- a/cue/testdata/compile/err_top.txtar +++ b/cue/testdata/compile/err_top.txtar @@ -26,47 +26,6 @@ nested: "_foo": _: 1 nested: "#foo": _: 1 --- out/compile -- -disallowTopAsAlias: cannot use _ as alias or let clause: - ./in.cue:2:2 -disallowTopAsLet: cannot use _ as alias or let clause: - ./in.cue:6:6 -disallowTopAsLabel: cannot use _ as label: - ./in.cue:10:2 -nested."_": cannot use _ as label: - ./in.cue:23:14 -nested."_foo": cannot use _ as label: - ./in.cue:24:17 -nested."#foo": cannot use _ as label: - ./in.cue:25:17 ---- in.cue -{ - disallowTopAsAlias: { - X: 1 - } - disallowTopAsLet: { - let _ = 1 - } - disallowTopAsLabel: { - _|_(cannot use _ as label) - a: _ - } - nested: { - "_": { - _|_(cannot use _ as label) - } - } - nested: { - "_foo": { - _|_(cannot use _ as label) - } - } - nested: { - "#foo": { - _|_(cannot use _ as label) - } - } -} -- out/evalalpha -- disallowTopAsAlias: cannot use _ as alias or let clause: ./in.cue:2:2 diff --git a/cue/testdata/compile/erralias.txtar b/cue/testdata/compile/erralias.txtar --- a/cue/testdata/compile/erralias.txtar +++ b/cue/testdata/compile/erralias.txtar @@ -10,24 +10,6 @@ for x in c {a: E} Z1=[Z2=string]: Z1 + Z2 --- out/compile -- -unreferenced alias or let clause X: - ./in.cue:1:2 -a: reference "Y" not found: - ./in.cue:4:12 -for[].a: reference "E" not found: - ./in.cue:7:16 ---- in.cue -{ - let X#1 = {} - ["foo"]: 3 - a: _|_(reference "Y" not found) - c: {} - for _, x in 〈0;c〉 { - a: _|_(reference "E" not found) - } - [string]: (〈0;(〈0;-〉)〉 + 〈0;-〉) -} -- out/evalalpha -- unreferenced alias or let clause X: ./in.cue:1:2 diff --git a/cue/testdata/compile/experiment.txtar b/cue/testdata/compile/experiment.txtar --- a/cue/testdata/compile/experiment.txtar +++ b/cue/testdata/compile/experiment.txtar @@ -12,15 +12,6 @@ -- out/errors.txt -- [eval] off: error in call to testExperiment: testing experiment disabled: ./off.cue:1:6 --- out/compile -- ---- off.cue -{ - off: testExperiment("off") -} ---- on.cue -{ - on: testExperiment("on") -} -- out/eval/stats -- Leaks: 0 Freed: 3 diff --git a/cue/testdata/compile/fields.txtar b/cue/testdata/compile/fields.txtar --- a/cue/testdata/compile/fields.txtar +++ b/cue/testdata/compile/fields.txtar @@ -3,14 +3,6 @@ "#dev": int @test(eq, int) _dev: int @test(eq, int) _#dev: int @test(eq, int) --- out/compile -- ---- in.cue -{ - #dev: int - "#dev": int - _dev: int - _#dev: int -} -- out/eval/stats -- Leaks: 0 Freed: 5 diff --git a/cue/testdata/compile/files.txtar b/cue/testdata/compile/files.txtar --- a/cue/testdata/compile/files.txtar +++ b/cue/testdata/compile/files.txtar @@ -10,24 +10,6 @@ x: {for a in a {}} @test(eq, {}) y: {{{for a in a {}}}} @test(eq, {}) --- out/compile -- ---- in.cue -{ - a: [] -} ---- out.cue -{ - x: { - for _, a in 〈1;a〉 {} - } - y: { - { - { - for _, a in 〈3;a〉 {} - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/compile/json.txtar b/cue/testdata/compile/json.txtar --- a/cue/testdata/compile/json.txtar +++ b/cue/testdata/compile/json.txtar @@ -26,22 +26,6 @@ } b: [0, 1, 2, 3, 4, 5] }) --- out/compile -- ---- in.cue -{ - a: { - key: "value" - key2: "value2" - } - b: [ - 0, - 1, - 2, - 3, - 4, - 5, - ] -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/compile/labels.txtar b/cue/testdata/compile/labels.txtar --- a/cue/testdata/compile/labels.txtar +++ b/cue/testdata/compile/labels.txtar @@ -30,66 +30,6 @@ a: _ // Should not compile to a reference. } } --- out/compile -- -bad1: comprehension values not allowed in this position: - ./in.cue:24:8 ---- in.cue -{ - dis1: ("dev"|"prd") - dis2: (*"dev"|"prd") - con1: string - let con2#1 = string - ok0: { - [string]: string - } - ok1: { - [string]: string - } - ok2: { - [〈1;con1〉]: string - } - ok3: { - [〈1;let con2#1〉]: string - } - ok4: { - ["foo"]: string - } - ok5: { - [1]: string - } - ok6: { - [1]: string - } - ok7: { - [〈1;dis1〉]: string - } - ok8: { - [〈1;dis2〉]: string - } - ok9: { - [〈1;dis2〉]: string - } - ok10: { - [{ - foo: "bar" - }]: string - } - ok11: { - [〈import;list〉.FlattenN([ - string, - ], 1)]: string - } - bad1: { - [_|_(comprehension values not allowed in this position)]: string - } - saneReferencesInComprehensions: { - for _, _ in [ - 1, - ] { - a: _ - } - } -} -- out/evalalpha -- bad1: comprehension values not allowed in this position: ./in.cue:24:8 diff --git a/cue/testdata/compile/let.txtar b/cue/testdata/compile/let.txtar --- a/cue/testdata/compile/let.txtar +++ b/cue/testdata/compile/let.txtar @@ -71,133 +71,6 @@ let N = x x: "s" } --- out/compile -- -b.let[]: cyclic references in let clause or alias: - ./in.cue:10:10 ---- alignstack.cue -{ - issue4051: { - full: { - #app: { - name: "foo" - } - let N#1 = 〈0;#app〉.name - out: { - 〈1;let N#1〉=>〈0;#app〉.name: [ - { - f1: { - f2: 〈4;let N#1〉=>〈0;#app〉.name - } - }, - ] - } - } - } - issue4051: { - reduced: { - 〈0;let N#2〉=>〈0;x〉: [ - { - f1: { - f2: 〈3;let N#2〉=>〈0;x〉 - } - }, - ] - let N#2 = 〈0;x〉 - x: "s" - } - } -} ---- in.cue -{ - a: { - let X#3 = 〈0;let Y#4〉=>〈0;c〉 - let Y#4 = 〈0;c〉 - b: 〈0;let X#3〉=>〈0;let Y#4〉=>〈0;c〉 - c: 5 - } - b: { - let X#5 = 〈0;let Y#6〉=>〈0;let X#5〉=>〈0;let Y#6〉=>_|_(cyclic references in let clause or alias) - let Y#6 = 〈0;let X#5〉=>〈0;let Y#6〉=>_|_(cyclic references in let clause or alias) - b: 〈0;let X#5〉=>〈0;let Y#6〉=>_|_(cyclic references in let clause or alias) - c: 5 - } - fieldOffset: { - a: { - p1: { - let X#7 = { - value: 〈1;let Y#8〉=>2 - } - let Y#8 = 2 - x: 〈0;let X#7〉=>{ - value: 〈1;let Y#8〉=>2 - } - } - p2: { - x: 〈0;let X#A〉=>{ - value: 〈1;let Y#9〉=>2 - } - let Y#9 = 2 - let X#A = { - value: 〈1;let Y#9〉=>2 - } - } - } - b: { - p1: { - let X#B = { - x: { - y: 〈2;let Y#C〉=>2 - } - } - let Y#C = 2 - x: 〈0;let X#B〉=>{ - x: { - y: 〈2;let Y#C〉=>2 - } - } - } - p2: { - x: 〈0;let X#E〉=>{ - x: { - y: 〈2;let Y#D〉=>2 - } - } - let Y#D = 2 - let X#E = { - x: { - y: 〈2;let Y#D〉=>2 - } - } - } - } - } - issue767: { - #Foo: { - let _#bar#F = { - value: "" - } - let _#volmnts#10 = { - x: 〈1;let _#baz#11〉=>{ - 〈1;let _#bar#F〉=>{ - value: "" - } - }.value - } - let _#baz#11 = { - 〈1;let _#bar#F〉=>{ - value: "" - } - } - out: 〈0;let _#volmnts#10〉=>{ - x: 〈1;let _#baz#11〉=>{ - 〈1;let _#bar#F〉=>{ - value: "" - } - }.value - } - } - } -} -- out/evalalpha -- b.let[]: cyclic references in let clause or alias: ./in.cue:10:10 diff --git a/cue/testdata/compile/postfixexpr.txtar b/cue/testdata/compile/postfixexpr.txtar --- a/cue/testdata/compile/postfixexpr.txtar +++ b/cue/testdata/compile/postfixexpr.txtar @@ -35,21 +35,3 @@ ./with_experiment.cue:11:8 [incomplete] d: cannot call non-concrete value fn (type _): ./with_experiment.cue:17:4 --- out/compile -- ---- with_experiment.cue -{ - #Base: { - x: int - } - a: 〈0;#Base〉... - b: 〈0;foo〉.bar... - c: (〈0;x〉 & 〈0;y〉)... - d: 〈0;fn〉()... - e: (〈0;#Base〉... & { - y: int - }) - foo: {} - x: _ - y: _ - fn: _ -} diff --git a/cue/testdata/compile/scope.txtar b/cue/testdata/compile/scope.txtar --- a/cue/testdata/compile/scope.txtar +++ b/cue/testdata/compile/scope.txtar @@ -46,51 +46,6 @@ let _schema_1 = schema -- out/errors.txt -- [structural_cycle] schema.next: structural cycle --- out/compile -- ---- in.cue -{ - a: { - { - { - 〈3;b〉 - 〈2;c〉 - d: 〈3;b〉 - e: 〈2;c〉 - } - } - c: {} - } - b: {} - s: "foo" - c: 〈0;s〉 - d: { - [〈1;s〉]: 3 - } - e: {} - (〈0;e〉 & { - e: {} - }) - p: { - { - ["foo"]: { - b: (〈1;(〈0;-〉)〉|null) - } - } - { - ["bar"]: { - b: 〈1;-〉 - } - } - } - let B#1 = { - open: int - } - f: 〈0;let B#1〉 - schema: { - next: 〈1;let _schema_1#2〉 - } - let _schema_1#2 = 〈0;schema〉 -} -- out/eval/stats -- Leaks: 1 Freed: 17 diff --git a/cue/testdata/comprehensions/015_list_comprehension.txtar b/cue/testdata/comprehensions/015_list_comprehension.txtar --- a/cue/testdata/comprehensions/015_list_comprehension.txtar +++ b/cue/testdata/comprehensions/015_list_comprehension.txtar @@ -12,33 +12,6 @@ @test(eq, [1, 1, 1, 2, 2, 3]) } d: [for x, _ in a {x}] @test(eq, [0, 1]) --- out/compile -- ---- in.cue -{ - b: { - a: 1 - b: 2 - c: 3 - d: 4 - } - a: [ - for k, v in 〈1;b〉 if (〈0;k〉 < "d") if (〈0;v〉 > 〈2;b〉.a) { - 〈1;k〉 - }, - ] - c: { - [ - for _, x in 〈2;b〉 for _, y in 〈3;b〉 if (〈1;x〉 < 〈0;y〉) { - 〈2;x〉 - }, - ] - } - d: [ - for x, _ in 〈1;a〉 { - 〈1;x〉 - }, - ] -} -- out/eval/stats -- Leaks: 0 Freed: 19 diff --git a/cue/testdata/comprehensions/045_comprehension_and_skipped_field.txtar b/cue/testdata/comprehensions/045_comprehension_and_skipped_field.txtar --- a/cue/testdata/comprehensions/045_comprehension_and_skipped_field.txtar +++ b/cue/testdata/comprehensions/045_comprehension_and_skipped_field.txtar @@ -13,24 +13,6 @@ } } @test(eq, {x: {v: {"1": 2}, _p: 3}}) --- out/compile -- ---- in.cue -{ - for key, value in { - x: { - v: 1 - } - } { - "\(〈1;key〉)": { - v: (*{ - for pod, _ in 〈3;value〉.v {} - }|{ - "\(〈3;value〉.v)": 2 - }) - _p: 3 - } - } -} -- out/eval/stats -- Leaks: 2 Freed: 8 diff --git a/cue/testdata/comprehensions/checkdefined.txtar b/cue/testdata/comprehensions/checkdefined.txtar --- a/cue/testdata/comprehensions/checkdefined.txtar +++ b/cue/testdata/comprehensions/checkdefined.txtar @@ -141,195 +141,3 @@ Notifications: 1 NumCloseIDs: 29 --- out/compile -- ---- in.cue -{ - xc: close({ - field: {} - }) - xo: { - field: {} - } - okc0: { - if (〈1;xc〉.undefined == _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - oko0: { - if (〈1;xo〉.undefined == _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - okc1: { - if (〈1;xc〉.undefined != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - oko1: { - if (〈1;xo〉.undefined != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - okc2: { - if (({} & { - s: [ - for _, y in 〈3;xc〉.undefined {}, - ] - }) != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - oko2: { - if (({} & { - s: [ - for _, y in 〈3;xo〉.undefined {}, - ] - }) != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - okc3: { - if ({ - s: [ - for _, y in 〈3;xc〉.undefined {}, - ] - } != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - oko3: { - if ({ - s: [ - for _, y in 〈3;xo〉.undefined {}, - ] - } != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - issue1969: { - okc: { - let X#1 = 〈2;xc〉.undefined - let Y#2 = ({} & { - s: [ - for _, y in 〈import;list〉.Range(0, 〈2;let X#1〉, 1) {}, - ] - }) - if (〈0;let Y#2〉 != _|_(explicit error (_|_ literal) in source)) { - 〈1;let Y#2〉 - } - } - } - issue1969: { - oko: { - let X#3 = 〈2;xo〉.undefined - let Y#4 = ({} & { - s: [ - for _, y in 〈import;list〉.Range(0, 〈2;let X#3〉, 1) {}, - ] - }) - if (〈0;let Y#4〉 != _|_(explicit error (_|_ literal) in source)) { - 〈1;let Y#4〉 - } - } - } -} ---- incomplete.cue -{ - checkIncomplete: { - t1: { - f: { - [string]: { - if (〈0;a〉 != _|_(explicit error (_|_ literal) in source)) { - b: "d\(〈1;a〉)" - } - a: string - } - } - f: { - blah: {} - } - } - } -} ---- issue2245.cue -{ - yo: { - f: int - g: (〈0;f〉 < 10) - } - okyo: { - if (〈1;yo〉 != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } - okyog: { - if (〈1;yo〉.g != _|_(explicit error (_|_ literal) in source)) { - a: 1 - } - } -} ---- structs.cue -{ - structs: { - bare: { - t1: (({ - y: 2 - } & { - x: 3 - }) != _|_(explicit error (_|_ literal) in source)) - } - bare: { - f2: (({ - y: 2 - } & { - x: 3 - }) == _|_(explicit error (_|_ literal) in source)) - } - bare: { - f3: (({ - x: 1 - y: 2 - } & { - x: 3 - }) != _|_(explicit error (_|_ literal) in source)) - } - bare: { - t4: (({ - x: 1 - y: 2 - } & { - x: 3 - }) == _|_(explicit error (_|_ literal) in source)) - } - select: { - t1: (({ - y: 2 - } & { - x: 3 - }).y != _|_(explicit error (_|_ literal) in source)) - } - select: { - f2: (({ - y: 2 - } & { - x: 3 - }).y == _|_(explicit error (_|_ literal) in source)) - } - select: { - f3: (({ - x: 1 - y: 2 - } & { - x: 3 - }).y != _|_(explicit error (_|_ literal) in source)) - } - select: { - t4: (({ - x: 1 - y: 2 - } & { - x: 3 - }).y == _|_(explicit error (_|_ literal) in source)) - } - } -} diff --git a/cue/testdata/comprehensions/closed.txtar b/cue/testdata/comprehensions/closed.txtar --- a/cue/testdata/comprehensions/closed.txtar +++ b/cue/testdata/comprehensions/closed.txtar @@ -164,133 +164,3 @@ Disjuncts: 14 NumCloseIDs: 46 --- out/compile -- ---- in.cue -{ - dynamicTop: { - #D: { - for k, v in { - foo: 123 - } { - 〈1;k〉: 〈1;v〉 - } - } - } - dynamicDepth1: { - #D: { - a: { - foo: 123 - } - b: { - for k, v in 〈1;a〉 { - 〈1;k〉: 〈1;v〉 - } - } - } - } - allowed: { - #D: { - if true { - d: int - } - } - vErr: (〈0;#D〉 & { - d: 5 - }) - } - disallowed: { - #D: { - if false { - d: int - } - } - vErr: (〈0;#D〉 & { - d: 5 - }) - } - comprehensionIsEmbed: { - #A: { - size: (int|*1) - } - #B: { - kind: string - if true { - 〈2;#A〉 - } - } - x: (〈0;#B〉 & { - kind: "A" - }) - } - noEraseDefinition: { - #Foo: [ - if true { - a: int - }, - ] - a: { - (〈1;#Foo〉 & [ - { - b: 2 - }, - ]) - } - } - issue1956: { - #Details: { - size: (int|*1) - } - #Thing: { - kind: ("KindA"|"KindB") - if (〈0;kind〉 == "KindA") { - 〈2;#Details〉 - } - } - x: (〈0;#Thing〉 & { - kind: "KindA" - }) - } - dedupTodo: { - #sub: { - c: _ - if (〈0;c〉.n == "c") { - X: { - test: 〈2;c〉 - } - } - } - out: 〈0;#sub〉 - out: { - c: { - n: "c" - } - c: { - n: string - } - } - } -} ---- v3issues.cue -{ - issue3483: { - #Schema: { - schemaField: int - } - out1: { - out2: (〈1;#Schema〉 & { - if false { - schemaField: 3 - } - }) - } - } - issue3486: { - #schema: {} - if true { - out: { - 〈2;#schema〉 - extra: "foo" - } - } - } -} diff --git a/cue/testdata/comprehensions/deferfieldsetknown.txtar b/cue/testdata/comprehensions/deferfieldsetknown.txtar --- a/cue/testdata/comprehensions/deferfieldsetknown.txtar +++ b/cue/testdata/comprehensions/deferfieldsetknown.txtar @@ -13,31 +13,3 @@ cfg: resources: _ out: {for n, _ in cfg.resources {(n): "x"}} } & {cfg: result}).out @test(eq, {x: "x"}) --- out/compile -- ---- in.cue -{ - #PDB: { - y: int - } - result: { - resources: { - if true { - x: (〈3;#PDB〉 & { - y: 1 - }) - } - } - } - out: ({ - cfg: { - resources: _ - } - out: { - for n, _ in 〈1;cfg〉.resources { - 〈1;n〉: "x" - } - } - } & { - cfg: 〈1;result〉 - }).out -} diff --git a/cue/testdata/comprehensions/else.txtar b/cue/testdata/comprehensions/else.txtar --- a/cue/testdata/comprehensions/else.txtar +++ b/cue/testdata/comprehensions/else.txtar @@ -196,291 +196,3 @@ Disjuncts: 0 NumCloseIDs: 69 --- out/compile -- ---- in.cue -{ - ifTrue: { - if true { - a: 1 - } else { - b: 2 - } - } - ifFalse: { - if false { - a: 1 - } else { - b: 2 - } - } - forNonEmpty: { - for _, x in [ - 1, - 2, - ] { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - forEmpty: { - for _, x in [] { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - forFilteredAll: { - for _, x in [ - 1, - 2, - 3, - ] if (〈0;x〉 > 10) { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - forFilteredSome: { - for _, x in [ - 1, - 2, - 3, - ] if (〈0;x〉 > 1) { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - ifTrueForEmpty: { - if true for _, x in [] { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - ifFalseForNonEmpty: { - if false for _, x in [ - 1, - 2, - ] { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - ifTrueForNonEmpty: { - if true for _, x in [ - 1, - 2, - ] { - "\(〈1;x〉)": 〈1;x〉 - } else { - empty: true - } - } - ifIfBothTrue: { - if true if true { - a: 1 - } else { - b: 2 - } - } - ifIfFirstFalse: { - if false if true { - a: 1 - } else { - b: 2 - } - } - ifIfSecondFalse: { - if true if false { - a: 1 - } else { - b: 2 - } - } - tryTryBothSucceed: { - a: 1 - b: 2 - try x = 〈0;a〉? try y = 〈1;b〉? { - result: (〈2;x〉 + 〈1;y〉) - } else { - default: 0 - } - } - missing?: int - tryTryFirstFails: { - b: 2 - try x = 〈1;missing〉? try y = 〈1;b〉? { - result: (〈2;x〉 + 〈1;y〉) - } else { - default: -1 - } - } - tryTrySecondFails: { - a: 1 - try x = 〈0;a〉? try y = 〈2;missing〉? { - result: (〈2;x〉 + 〈1;y〉) - } else { - default: -2 - } - } - listIfTrue: [ - if true { - 1 - } else { - 2 - }, - ] - listIfFalse: [ - if false { - 1 - } else { - 2 - }, - ] - listForEmpty: [ - for _, x in [] { - 〈1;x〉 - } else { - 0 - }, - ] - listForNonEmpty: [ - for _, x in [ - 1, - 2, - ] { - (〈1;x〉 * 2) - } else { - 0 - }, - ] - elseMultipleFields: { - if false { - a: 1 - } else { - b: 2 - c: 3 - } - } - elseEmbeds: { - existing: 1 - if false { - added: 2 - } else { - fallback: 3 - } - } - outerScope: { - let threshold#1 = 10 - for _, x in [] { - 〈1;x〉 - } else { - fallbackField: 〈1;let threshold#1〉 - } - } - ifNestedBody: { - if false { - a: { - b: 1 - } - } else { - c: 2 - } - } - ifNestedElse: { - if false { - a: 1 - } else { - b: { - c: 2 - } - } - } - ifNestedBoth: { - if false { - a: { - b: 1 - } - } else { - c: { - d: 2 - } - } - } - ifDeeplyNested: { - if false { - a: { - b: { - c: 1 - } - } - } else { - a: { - b: { - c: 2 - } - } - } - } - forNestedEmpty: { - for _, x in [] { - a: { - b: { - 〈3;x〉: 〈3;x〉 - } - } - } else { - a: { - b: { - none: true - } - } - } - } - forNestedNonEmpty: { - for _, x in [ - 1, - ] { - a: { - b: { - "\(〈3;x〉)": 〈3;x〉 - } - } - } else { - a: { - b: { - none: true - } - } - } - } - nestedOuterFallback: { - for _, x in [] { - for _, y in [ - 1, - ] { - 〈1;y〉 - } else { - inner: true - } - } else { - outer: true - } - } - nestedInnerFallback: { - for _, x in [ - 1, - ] { - for _, y in [] { - 〈1;y〉 - } else { - inner: true - } - } else { - outer: true - } - } -} diff --git a/cue/testdata/comprehensions/else_compile_errors.txtar b/cue/testdata/comprehensions/else_compile_errors.txtar --- a/cue/testdata/comprehensions/else_compile_errors.txtar +++ b/cue/testdata/comprehensions/else_compile_errors.txtar @@ -38,33 +38,3 @@ ./in.cue:5:49 letVarInElse.bad: reference "y" not found: ./in.cue:10:61 --- out/compile -- -forVarInElse.bad: reference "i" not found: - ./in.cue:5:49 -letVarInElse.bad: reference "y" not found: - ./in.cue:10:61 ---- in.cue -{ - forVarInElse: { - for _, i in [ - 1, - 2, - 3, - ] { - "\(〈1;i〉)": 〈1;i〉 - } else { - bad: _|_(reference "i" not found) - } - } - letVarInElse: { - for _, x in [ - 1, - 2, - 3, - ] let y = (〈0;x〉 * 2) { - "\(〈2;x〉)": 〈1;y〉 - } else { - bad: _|_(reference "y" not found) - } - } -} diff --git a/cue/testdata/comprehensions/else_on_error.txtar b/cue/testdata/comprehensions/else_on_error.txtar --- a/cue/testdata/comprehensions/else_on_error.txtar +++ b/cue/testdata/comprehensions/else_on_error.txtar @@ -29,28 +29,3 @@ ./in.cue:15:14 [user] explicit error (_|_ literal) in source: ./in.cue:21:11 --- out/compile -- ---- in.cue -{ - forSourceError: { - for _, x in "not-a-list" { - "\(〈1;x〉)": 〈1;x〉 - } else { - fallbackField: true - } - } - ifConditionError: { - if ("not" + 1) { - a: 1 - } else { - b: 2 - } - } - forSourceBottom: { - for _, x in _|_(explicit error (_|_ literal) in source) { - "\(〈1;x〉)": 〈1;x〉 - } else { - fallbackField: true - } - } -} diff --git a/cue/testdata/comprehensions/errors.txtar b/cue/testdata/comprehensions/errors.txtar --- a/cue/testdata/comprehensions/errors.txtar +++ b/cue/testdata/comprehensions/errors.txtar @@ -84,42 +84,3 @@ Disjuncts: 6 NumCloseIDs: 12 --- out/compile -- ---- in.cue -{ - circularIf: { - #list: { - tail: (〈1;#list〉|*null) - if (〈0;tail〉 != null) {} - } - } - circularFor: { - #list: { - tail: (〈1;#list〉|*null) - for _, x in (〈0;tail〉 != null) {} - } - } - userError: { - a: (string|*_|_(explicit error (_|_ literal) in source)) - if (〈0;a〉 != "") {} - } - intField: { - for i, _ in [ - 1, - 2, - ] { - 〈1;i〉: {} - } - } - conflictRangingOverSelf: { - x: { - name: string - age: int - } - x: { - for k, _ in 〈1;x〉 { - 〈1;k〉: 〈1;k〉 - } - } - } -} diff --git a/cue/testdata/comprehensions/fields.txtar b/cue/testdata/comprehensions/fields.txtar --- a/cue/testdata/comprehensions/fields.txtar +++ b/cue/testdata/comprehensions/fields.txtar @@ -104,54 +104,3 @@ Disjuncts: 0 NumCloseIDs: 12 --- out/compile -- ---- in.cue -{ - dynamic: { - for _, s in [ - "foo", - ] { - 〈1;s〉: 1 - "\(〈1;s〉)bar": 2 - } - } - ignoreOptional: { - #x: { - a?: string - b?: string - c: string - } - y: { - for k, v in 〈1;#x〉 { - 〈1;k〉: "exists" - } - } - } - missingRequiredError: { - #x: { - a!: string - b?: string - c: string - } - y: { - for k, v in 〈1;#x〉 { - 〈1;k〉: "exists" - } - } - } - issue560: { - #User: { - tags_str: string - tags_map: { - for k, v in 〈import;strings〉.Split(〈1;tags_str〉, " ") { - "\(〈1;v〉)": string - } - "{a}": string - } - } - user: { - 〈1;#User〉 - tags_str: "b {c}" - } - } -} diff --git a/cue/testdata/comprehensions/for.txtar b/cue/testdata/comprehensions/for.txtar --- a/cue/testdata/comprehensions/for.txtar +++ b/cue/testdata/comprehensions/for.txtar @@ -30,44 +30,3 @@ MisalignedConjunct: 1 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - b: { - for k, v in 〈1;a〉 { - "\(〈1;k〉)": (〈1;v〉 + 1) - } - } - a: { - b: 1 - c: 2 - } - x: { - for k, v in 〈1;y〉 { - "\(〈1;k〉)": 〈1;v〉 - } - } - y: {} - k: { - for _, v in 〈1;e〉 { - 〈1;v〉 - } - } - e: int - comprehensionBinds: { - a: { - for _, _ in [ - 1, - ] { - a: _ - } - } - b: { - for _, _ in [ - 1, - ] { - a: _ - } - } - } -} diff --git a/cue/testdata/comprehensions/iferror.txtar b/cue/testdata/comprehensions/iferror.txtar --- a/cue/testdata/comprehensions/iferror.txtar +++ b/cue/testdata/comprehensions/iferror.txtar @@ -137,104 +137,6 @@ ./in.cue:105:8 ./in.cue:107:11 ./in.cue:108:3 --- out/compile -- ---- in.cue -{ - a: { - b: 2 - c: int - } - wrongConcreteType: { - if 〈1;a〉.b { - 2 - } - } - wrongType: { - if 〈1;a〉.c { - 2 - } - } - incomplete: { - err1: { - if 〈2;a〉.d { - 2 - } - } - } - incomplete: { - err2: { - list: [ - 1, - 2, - 3, - ] - for _, x in 〈0;list〉 if 〈3;a〉.d { - 〈1;x〉 - } - } - } - useDefault: { - a: { - x: (*"foo"|string) - if (〈0;x〉 != _|_(explicit error (_|_ literal) in source)) { - y: 〈1;x〉 - } - } - issue809: { - #A: { - a: string - b: (*〈0;a〉|string) - } - s: { - [string]: (〈1;#A〉 & { - a: 〈1;-〉 - }) - } - s: { - bar: _ - } - foo: [ - for _, a in 〈1;s〉 if (〈0;a〉.b != _|_(explicit error (_|_ literal) in source)) { - 〈1;a〉 - }, - ] - } - } - issue1972: { - err1: { - #patchs: [] - 〈0;#patchs〉 - #someCondition: _ - if 〈0;#someCondition〉 {} - } - err1: { - someCondition: _ - patchs: [ - ...{}, - ] - 〈0;patchs〉 - if 〈0;someCondition〉 { - patchs: _ - } - } - err2: { - #patchs: [] - 〈0;#patchs〉 - #someCondition: _ - if 〈0;#someCondition〉 {} - } - err3: { - someCondition: _ - patchs: [ - ...{}, - ] - 〈0;patchs〉 - if 〈0;someCondition〉 { - patchs: _ - } - } - } -} -- out/eval/stats -- Leaks: 1 Freed: 40 diff --git a/cue/testdata/comprehensions/incomplete.txtar b/cue/testdata/comprehensions/incomplete.txtar --- a/cue/testdata/comprehensions/incomplete.txtar +++ b/cue/testdata/comprehensions/incomplete.txtar @@ -24,19 +24,3 @@ Disjuncts: 7 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - cond: bool - src: {} - top: _ - a: [ - if 〈1;cond〉 {}, - ] - b: [ - for _, x in 〈1;src〉.foo {}, - ] - c: { - for _, x in 〈1;top〉 {} - } -} diff --git a/cue/testdata/comprehensions/issue1732.txtar b/cue/testdata/comprehensions/issue1732.txtar --- a/cue/testdata/comprehensions/issue1732.txtar +++ b/cue/testdata/comprehensions/issue1732.txtar @@ -241,142 +241,3 @@ Notifications: 1 NumCloseIDs: 38 --- out/compile -- ---- in.cue -{ - networkingv1: { - metav1: { - #LabelSelector: { - matchLabels: { - [string]: string - } - } - } - #NetworkPolicy: { - spec: 〈1;#NetworkPolicySpec〉 - } - #NetworkPolicySpec: { - ingress: [ - ...〈2;#NetworkPolicyIngressRule〉, - ] - egress: [ - ...〈2;#NetworkPolicyEgressRule〉, - ] - } - #NetworkPolicyIngressRule: { - from: [ - ...〈2;#NetworkPolicyPeer〉, - ] - } - #NetworkPolicyEgressRule: { - to: [ - ...〈2;#NetworkPolicyPeer〉, - ] - } - #NetworkPolicyPeer: { - namespaceSelector: (null|〈1;metav1〉.#LabelSelector) - } - } - global_config: { - #GlobalConfig: { - auth0: { - enabled: bool - } - } - } - common: { - #SomeConfig: { - enabled: bool - if 〈0;enabled〉 { - foo: string - } - } - } - foo: { - #Values: { - global: 〈2;global_config〉.#GlobalConfig - } - } - #Config: { - tenant: { - id: string - } - auth0: (〈1;common〉.#SomeConfig & { - enabled: bool - if 〈0;enabled〉 { - foo: "\(〈2;tenant〉.id)-value" - } - }) - charts: { - foo: (〈2;foo〉.#Values & { - global: 〈3〉.global - }) - } - global: (〈1;global_config〉.#GlobalConfig & { - auth0: { - enabled: 〈3〉.auth0.enabled - } - }) - } - #NetworkPolicy: 〈0;networkingv1〉.#NetworkPolicy - #Flux: { - 〈1;#Config〉 - charts: _ - formatOutput: { - ... - } - _outputs(:config): { - ... - } - for _chartName, _chartValues in 〈0;charts〉 { - _outputs(:config): { - "\(〈2;_chartName(:config)〉)": {} - } - } - _outputs(:config): { - for _, ns in [ - "ns", - ] { - "\(〈1;ns〉)/network": (〈4;#NetworkPolicy〉 & { - spec: { - ingress: [ - { - from: [ - { - namespaceSelector: { - matchLabels: { - tenant: 〈12〉.tenant.id - } - } - }, - ] - }, - ] - egress: [ - { - to: [ - { - namespaceSelector: { - matchLabels: { - tenant: 〈12〉.tenant.id - } - } - }, - ] - }, - ] - } - }) - } - } - for _, ns in [ - "ns", - ] { - for k, v in 〈2;_outputs(:config)〉 { - formatOutput: { - "\(〈2;k〉)": 〈2;v〉 - } - } - } - } -} diff --git a/cue/testdata/comprehensions/issue2171.txtar b/cue/testdata/comprehensions/issue2171.txtar --- a/cue/testdata/comprehensions/issue2171.txtar +++ b/cue/testdata/comprehensions/issue2171.txtar @@ -9,18 +9,6 @@ for k, v in do {do: (k): v} @test(eq, {do: hello: {}}) --- out/compile -- ---- in.cue -{ - do: { - hello: {} - } - for k, v in 〈0;do〉 { - do: { - 〈2;k〉: 〈2;v〉 - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 3 diff --git a/cue/testdata/comprehensions/issue2481.txtar b/cue/testdata/comprehensions/issue2481.txtar --- a/cue/testdata/comprehensions/issue2481.txtar +++ b/cue/testdata/comprehensions/issue2481.txtar @@ -101,55 +101,3 @@ Disjuncts: 0 NumCloseIDs: 22 --- out/compile -- ---- in.cue -{ - out: { - for _, k in 〈1;keys〉 { - if (〈3;values〉[〈1;k〉] != _|_(explicit error (_|_ literal) in source)) { - val: 〈2;k〉 - if (〈0;val〉 != _|_(explicit error (_|_ literal) in source)) { - 〈3;k〉 - } - } - } - } - multiLets: { - for _, k in 〈1;keys〉 { - if (〈3;values〉[〈1;k〉] != _|_(explicit error (_|_ literal) in source)) { - let val#1multi = 〈2;k〉 - if (〈0;let val#1〉 != _|_(explicit error (_|_ literal) in source)) { - 〈3;k〉 - } - } - } - } - keys: [ - "a", - "b", - ] - values: { - b: "member" - c: "foo" - } - full: { - out: { - for k, _ in 〈1;#github_team_membership〉 { - if (〈3;values〉[〈1;k〉] != _|_(explicit error (_|_ literal) in source)) { - let val#2multi = 〈4;values〉[〈2;k〉] - if ((〈0;let val#2〉 != null) && ((〈0;let val#2〉 & string) != _|_(explicit error (_|_ literal) in source))) { - 〈3;k〉: 〈1;let val#2〉 - } - } - } - } - #github_team_membership: { - team_id: string - role: string - } - values: { - role: "member" - username: "foo" - } - } -} diff --git a/cue/testdata/comprehensions/issue287.txtar b/cue/testdata/comprehensions/issue287.txtar --- a/cue/testdata/comprehensions/issue287.txtar +++ b/cue/testdata/comprehensions/issue287.txtar @@ -23,23 +23,3 @@ MisalignedConjunct: 1 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - if (〈0;#E〉["x"] != _|_(explicit error (_|_ literal) in source)) { - #E: { - y: true - } - } - if (〈0;#E〉["y"] != _|_(explicit error (_|_ literal) in source)) { - z: true - } - #E: { - [_]: bool - } - #E: { - x: true - } - #E: _ - z: _ -} diff --git a/cue/testdata/comprehensions/issue293.txtar b/cue/testdata/comprehensions/issue293.txtar --- a/cue/testdata/comprehensions/issue293.txtar +++ b/cue/testdata/comprehensions/issue293.txtar @@ -66,41 +66,3 @@ Disjuncts: 0 NumCloseIDs: 15 --- out/compile -- ---- in.cue -{ - #T: { - if true { - x: close({ - f1: int - }) - } - x: _ - } - z: (〈0;#T〉 & { - x: { - f1: 99 - f2: "i want to disallow this" - } - }) - t: 〈0;#C〉 - #C: { - if true { - p: _ - } - } - t: { - p: "foo" - } -} ---- variant1.cue -{ - #V1: { - x: close({ - f1: int - }) - x: { - f2: 2 - } - } -} diff --git a/cue/testdata/comprehensions/issue3762.txtar b/cue/testdata/comprehensions/issue3762.txtar --- a/cue/testdata/comprehensions/issue3762.txtar +++ b/cue/testdata/comprehensions/issue3762.txtar @@ -134,118 +134,3 @@ Notifications: 8 NumCloseIDs: 25 --- out/compile -- ---- in.cue -{ - full: { - kube: { - node: { - n1: { - _CL: "l" - _cs: { - 〈1;_CL〉: 〈4;_a〉[〈1;_CL〉] - } - _cs: { - 〈1;_CL〉: { - opts: {} - } - } - } - } - } - _a: { - l: { - _ba?: string - opts: { - if (〈1;_ba〉 != _|_(explicit error (_|_ literal) in source)) { - b: 〈2;_ba〉 - } - } - } - } - for k, _ in (〈0;_a〉 & 〈0;_b〉) { - x: 5 - } - _a: { - [_]: { - vms: [ - { - name: "hello" - }, - ] - } - } - _b: { - [_]: { - vms: [ - { - name: "again" - }, - ] - } - } - } - reduced: { - p1: { - _cs: (〈0;_a〉.l & { - opts: {} - }) - _a: { - l: { - _ba?: string - opts: { - if (〈1;_ba〉 != _|_(explicit error (_|_ literal) in source)) { - b: 〈2;_ba〉 - } - } - vms: "hello" - } - } - _b: { - l: { - vms: "again" - } - } - for k, _ in (〈0;_a〉 & 〈0;_b〉) { - x: 5 - } - } - } - reduced: { - p2: { - for k, _ in (〈0;_a〉 & 〈0;_b〉) { - x: 5 - } - _cs: (〈0;_a〉.l & { - opts: {} - }) - _a: { - l: { - _ba?: string - opts: { - if (〈1;_ba〉 != _|_(explicit error (_|_ literal) in source)) { - b: 〈2;_ba〉 - } - } - vms: "hello" - } - } - _b: { - l: { - vms: "again" - } - } - } - } - reference: { - _x: { - f: true - } - _y: { - f: false - } - for k, _ in (〈0;_x〉 & 〈0;_y〉) { - ok: true - } - } -} diff --git a/cue/testdata/comprehensions/issue3763.txtar b/cue/testdata/comprehensions/issue3763.txtar --- a/cue/testdata/comprehensions/issue3763.txtar +++ b/cue/testdata/comprehensions/issue3763.txtar @@ -114,93 +114,3 @@ Disjuncts: 0 NumCloseIDs: 38 --- out/compile -- ---- full.cue -{ - full: { - _core_v1: { - #cp: { - hostPort?: &(int, >=-2147483648, <=2147483647) - cp: &(int, >=-2147483648, <=2147483647) - } - } - k: { - n: { - n1: { - _CL: "l" - } - } - } - let nc#1 = { - _ports: { - [_]: 〈2;_core_v1〉.#cp - } - } - _cl: { - [_]: (〈1;let nc#1〉 & { - _ports: { - "1": {} - "2": {} - "3": {} - } - }) - } - k: { - n: { - [_]: { - _CL: string - _cs: { - 〈1;_CL〉: 〈4;_cl〉[〈1;_CL〉] - } - } - } - } - for _, n in 〈0;k〉.n { - let cps#2multi = [ - for _, c in 〈2;n〉._cs for _, cps in 〈0;c〉._ports { - 〈1;cps〉 - }, - ] - ports: [ - for _, cp in 〈1;let cps#2〉 if (〈0;cp〉.hostPort != _|_(explicit error (_|_ literal) in source)) { - port: "\(〈1;cp〉.hostPort)" - }, - ] - } - _cl: { - l: {} - } - } -} ---- reduced.cue -{ - reduced: { - A: { - x1: { - y?: int - } - } - A: { - x2: { - y?: int - } - } - A: { - x3: { - y?: int - } - } - if true { - let Z#3 = [ - for _, x in 〈2;A〉 { - 〈1;x〉 - }, - ] - B: [ - for _, z in 〈1;let Z#3〉 if (〈0;z〉.y != _|_(explicit error (_|_ literal) in source)) { - b: 1 - }, - ] - } - } -} diff --git a/cue/testdata/comprehensions/issue3929.txtar b/cue/testdata/comprehensions/issue3929.txtar --- a/cue/testdata/comprehensions/issue3929.txtar +++ b/cue/testdata/comprehensions/issue3929.txtar @@ -224,107 +224,3 @@ MaxConjunctInfos: 8 MaxReqSets: 15 MaxRedirect: 3 --- out/compile -- ---- in.cue -{ - reduced: { - #Input: { - name: string - age: ("one"|"two") - if (〈0;name〉 != _|_(explicit error (_|_ literal) in source)) { - if true { - age: "one" - } - } - } - #def1: { - _in(:main): _ - def1: (〈1;#def2〉 & { - _in(:main): 〈1;_in(:main)〉 - }) - } - #def2: { - _in(:main): _ - def2: (〈1;#def3〉 & { - _in(:main): 〈1;_in(:main)〉 - }) - } - #def3: { - _in(:main): 〈1;#Input〉 - def3: 〈0;_in(:main)〉.age - } - in: { - name: "foobar" - } - out: (〈0;#def1〉 & { - _in(:main): 〈1;in〉 - }).def1 - } - full: { - cronjob: { - [string]: 〈1;#CronjobConfig〉 - } - #CronjobConfig: { - 〈1;#PodConfig〉 - } - #PodConfig: { - 〈1;#ContainerConfig〉 - } - #ContainerConfig: { - image: string - imagePullPolicy: ("IfNotPresent"|"Always"|"Never") - if (〈0;image〉 != _|_(explicit error (_|_ literal) in source)) { - if (〈import;strings〉.HasSuffix(〈1;image〉, ":latest") == true) { - imagePullPolicy: ("IfNotPresent"|*"Always"|"Never") - } - if (〈import;strings〉.HasSuffix(〈1;image〉, ":latest") != true) { - imagePullPolicy: (*"IfNotPresent"|"Always"|"Never") - } - } - } - _#cronjob(:main): { - _config(:main): 〈1;#CronjobConfig〉 - out: { - spec: { - jobTemplate: { - spec: { - template: (〈5;_#pod(:main)〉 & { - _config(:main): 〈5;_config(:main)〉 - }) - } - } - } - } - } - _#pod(:main): { - _config(:main): 〈1;#PodConfig〉 - spec: { - containers: [ - { - (〈4;_#container(:main)〉 & { - _config(:main): 〈4;_config(:main)〉 - }) - }, - ] - } - } - _#container(:main): { - _config(:main): 〈1;#ContainerConfig〉 - imagePullPolicy: 〈0;_config(:main)〉.imagePullPolicy - } - cronjob: { - foobar: { - image: "foobar:latest" - } - } - for k, v in 〈0;cronjob〉 { - objects: { - cronjob: { - "\(〈3;k〉)": (〈4;_#cronjob(:main)〉 & { - _config(:main): 〈4;v〉 - }).out - } - } - } - } -} diff --git a/cue/testdata/comprehensions/issue436.txtar b/cue/testdata/comprehensions/issue436.txtar --- a/cue/testdata/comprehensions/issue436.txtar +++ b/cue/testdata/comprehensions/issue436.txtar @@ -36,24 +36,3 @@ Disjuncts: 12 NumCloseIDs: 11 --- out/compile -- ---- in.cue -{ - #a: { - val: string - result: string - } - a: (〈0;#a〉 & { - val: (*"default"|string) - result: (*"not-matched"|string) - if (〈0;val〉 == "match") { - result: "matched" - } - }) - match: (〈0;a〉 & { - val: "match" - }) - not: (〈0;a〉 & { - val: "other" - }) -} diff --git a/cue/testdata/comprehensions/issue507.txtar b/cue/testdata/comprehensions/issue507.txtar --- a/cue/testdata/comprehensions/issue507.txtar +++ b/cue/testdata/comprehensions/issue507.txtar @@ -39,33 +39,3 @@ Disjuncts: 4 NumCloseIDs: 4 --- out/compile -- ---- in.cue -{ - somelist: ([ - ...string, - ]|*[]) - foo: [ - for _, e in 〈1;somelist〉 { - "hello foo: \(〈1;e〉)" - }, - ] - otherlist: [ - "something", - ] - z: [ - for _, e in 〈1;otherlist〉 { - "hello z: \(〈1;e〉)" - }, - ] - extlist: ([ - ...string, - ]|*[ - "something", - ]) - bar: [ - for _, e in 〈1;extlist〉 { - "hello bar: \(〈1;e〉)" - }, - ] -} diff --git a/cue/testdata/comprehensions/issue837.txtar b/cue/testdata/comprehensions/issue837.txtar --- a/cue/testdata/comprehensions/issue837.txtar +++ b/cue/testdata/comprehensions/issue837.txtar @@ -108,83 +108,3 @@ Disjuncts: 8 NumCloseIDs: 17 --- out/compile -- ---- in.cue -{ - #DeploymentManifest: (〈0;#Manifest〉 & { - ref: { - kind: "deployment" - } - }) - #Manifest: { - ref: 〈1;#ManifestRef〉 - description: 〈1;#KumoriKinds〉[〈0;ref〉.kind] - } - #ManifestRef: { - kind: 〈1;#KindsNames〉 - } - #KindsNames: ("service"|"deployment") - #KumoriKinds: { - deployment: 〈1;#Deployment〉 - } - #KumoriKinds: { - [string]: { - ... - } - } - #DoDeploy: { - _params: { - manifest: 〈2;#DeploymentManifest〉 - } - deployment: { - description: { - let dep#1 = 〈2;_params〉.manifest.description - service: (〈3;#Configure〉 & { - _params: { - hsize: 〈2;let dep#1〉.hsize - } - }).service - } - } - } - #Configure: { - _params: { - hsize: { - [string]: 〈3;#RoleSize〉 - } - } - service: { - description: { - let configed#2 = (〈3;#RelabelService〉 & { - _params: { - hsize: 〈4;_params〉.hsize - } - role: "admin" - }).out - role: 〈0;let configed#2〉.role - } - } - } - #RelabelService: { - _params: { - hsize: 〈2;#RoleSize〉 - } - out: { - labstr: 〈1;_params〉.label - } - } - #RoleSize: { - $_instances: (>=0|*1) - } - #Deployment: { - service: 〈1;#ServiceManifest〉 - hsize: { - [〈1;service〉.description.#roles]: 〈2;#RoleSize〉 - } - } - #ServiceManifest: (〈0;#Manifest〉 & { - ref: { - kind: "service" - } - }) -} diff --git a/cue/testdata/comprehensions/issue843.txtar b/cue/testdata/comprehensions/issue843.txtar --- a/cue/testdata/comprehensions/issue843.txtar +++ b/cue/testdata/comprehensions/issue843.txtar @@ -86,52 +86,3 @@ Disjuncts: 12 NumCloseIDs: 24 --- out/compile -- ---- in.cue -{ - #d1: { - as: [ - ...string, - ] - #c: [ - (〈2;#f1〉 & { - as: 〈import;list〉.Concat([ - [ - "go", - ], - 〈3;as〉, - ]) - }), - ] - } - #d2: { - p: (*"."|string) - #c: [ - (〈2;#f2〉 & { - from: (〈3;#d1〉 & { - as: [ - 〈4;p〉, - ] - }) - }), - ] - } - #c1: { - #c: [ - ...〈2;#o〉, - ] - _ - ... - } - #o: (〈0;#f1〉|〈0;#f2〉) - #f1: { - do: "f1" - as: [ - ...string, - ] - } - #f2: { - do: "f2" - from: 〈1;#c1〉 - } -} diff --git a/cue/testdata/comprehensions/lists.txtar b/cue/testdata/comprehensions/lists.txtar --- a/cue/testdata/comprehensions/lists.txtar +++ b/cue/testdata/comprehensions/lists.txtar @@ -19,20 +19,3 @@ Unifications: 7 Conjuncts: 8 Disjuncts: 7 --- out/compile -- ---- in.cue -{ - a: [ - { - a: 1 - }, - { - b: (2 & 3) - }, - ] - b: [ - for _, x in 〈1;a〉 { - 〈1;x〉 - }, - ] -} diff --git a/cue/testdata/comprehensions/multi.txtar b/cue/testdata/comprehensions/multi.txtar --- a/cue/testdata/comprehensions/multi.txtar +++ b/cue/testdata/comprehensions/multi.txtar @@ -42,49 +42,3 @@ Disjuncts: 0 NumCloseIDs: 21 --- out/compile -- ---- in.cue -{ - list: [ - 2, - 3, - ] - a: [ - 3, - for _, x in 〈1;list〉 { - 〈1;x〉 - }, - for _, x in 〈1;list〉 { - 〈1;x〉 - }, - ] - b: [ - 3, - if true { - 3 - }, - for _, x in 〈1;list〉 if (〈0;x〉 > 2) { - 〈1;x〉 - }, - ] - issue574: { - greet: true - bye: true - message1: [ - if 〈1;greet〉 { - "hello" - }, - "how are you doing?", - "bye", - ] - message2: [ - if !〈1;greet〉 { - "hello" - }, - "how are you doing?", - if 〈1;bye〉 { - "bye" - }, - ] - } -} diff --git a/cue/testdata/comprehensions/nested.txtar b/cue/testdata/comprehensions/nested.txtar --- a/cue/testdata/comprehensions/nested.txtar +++ b/cue/testdata/comprehensions/nested.txtar @@ -116,108 +116,3 @@ Disjuncts: 10 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - service: { - "node-exporter": { - spec: { - ports: [ - { - name: "metrics" - port: 9100 - protocol: "TCP" - }, - ] - } - } - } - deployment: { - "node-exporter": { - spec: { - template: { - spec: { - containers: [ - { - ports: [ - { - containerPort: 9100 - name: "scrape" - }, - ] - }, - ] - } - } - } - } - } - service: { - [string]: { - spec: { - ports: [ - ...{ - port: int - protocol: (*"TCP"|"UDP") - name: (string|*"client") - }, - ] - } - } - } - deployment: { - [string]: {} - } - deployment: { - [_]: (〈1;_spec(:kube)〉 & {}) - } - _spec(:kube): { - _name(:kube): string - spec: { - template: { - spec: { - containers: [ - { - name: 〈5;_name(:kube)〉 - }, - ] - } - } - } - } - _spec(:kube): { - spec: { - template: { - spec: { - containers: [ - ...{ - ports: [ - ...{ - _export(:kube): (*true|false) - }, - ] - }, - ] - } - } - } - } - for k, v in 〈0;deployment〉 { - service: { - "\(〈2;k〉)": { - spec: { - selector: 〈4;v〉.spec.template.metadata.labels - } - spec: { - ports: [ - for _, c in 〈5;v〉.spec.template.spec.containers for _, p in 〈0;c〉.ports if 〈0;p〉._export(:kube) { - let Port#1 = 〈1;p〉.containerPort - port: (*〈0;let Port#1〉|int) - targetPort: (*〈0;let Port#1〉|int) - }, - ] - } - } - } - } -} diff --git a/cue/testdata/comprehensions/nested2.txtar b/cue/testdata/comprehensions/nested2.txtar --- a/cue/testdata/comprehensions/nested2.txtar +++ b/cue/testdata/comprehensions/nested2.txtar @@ -548,370 +548,3 @@ Notifications: 5 NumCloseIDs: 217 --- out/compile -- ---- in.cue -{ - given: { - INC: { - USD: 2.0 - } - USD: { - GBP: 3.0 - } - } - hydrated: { - for k, v in 〈1;given〉 { - for k1, r in 〈1;v〉 { - "\(〈3;k〉)": { - "\(〈4;k〉)": 1.0 - } - "\(〈1;k1〉)": { - "\(〈2;k1〉)": 1.0 - } - "\(〈3;k〉)": { - "\(〈2;k1〉)": 〈2;r〉 - } - "\(〈1;k1〉)": { - "\(〈4;k〉)": number - } - } - } - } - foo: { - a: 10 - if (〈0;a〉 < 20) { - if (〈1;a〉 < 50) { - b: 20 - } - } - } - indirectlyNested: { - a: true - if true { - b: { - if 〈2;a〉 { - 〈3;a〉 - } - } - } - } - directlyNestedEmpty: { - a: true - if true { - if 〈1;a〉 {} - } - } - directlyDoublyNestedEmpty: { - a: true - if true { - if 〈1;a〉 {} - } - } - indirectlyDoublyNestedEmpty: { - a: true - b: { - if true { - if 〈2;a〉 { - if 〈3;a〉 { - 〈4;a〉 - } - } - if 〈2;a〉 { - 〈3;a〉 - } - } - } - } - indirectlyDoublyNested: { - a: true - if true { - if 〈1;a〉 { - if 〈2;a〉 { - b: 1 - } - } - if 〈1;a〉 { - c: 1 - } - } - } - issue1974: { - X: { - foo: { - bar: "" - baz: "" - } - } - out: { - for k, v in 〈1;X〉 for vk, vv in 〈0;v〉 { - "\(〈2;k〉)": { - "\(〈2;vk〉)": 〈2;vv〉 - } - } - } - } -} ---- issue3940.cue -{ - issue3940: { - reduced1: { - 〈0;X〉 - a: { - b: 〈1;X〉 - } - a: { - b: { - a: { - b: { - y: 〈4;X〉 - } - } - } - } - X: { - a: {} - objects: { - for _, v in 〈1;a〉 for _, _ in ({} & 〈0;v〉).objects {} - } - } - } - } - issue3940: { - reduced2: { - 〈0;X〉 - a: { - b: 〈1;X〉 - } - a: { - b: { - a: { - b: { - y: 〈4;X〉 - } - } - } - } - X: { - a: {} - objects: { - for _, v in 〈1;a〉 for _, _ in ({} & 〈0;v〉).objects {} - } - } - } - } - issue3940: { - reduced3: { - a: 〈0;E〉 - a: { - i: { - x: 〈2;E〉 - } - } - a: { - i: { - x: { - i: { - x: 〈4;E〉 - } - } - } - } - E: { - i: {} - o: [ - for _, m in 〈1;i〉 for _, v in ({} & 〈0;m〉).o {}, - ] - } - } - } - issue3940: { - reduced4: { - out: (〈0;Exporter〉 & { - _imports: [ - { - objects: { - ... - } - #export: (〈3;Exporter〉 & { - _imports: [ - { - #export: 〈6;Exporter〉 - }, - ] - }) - }, - ] - }) - Exporter: { - _imports: [ - ..., - ] - objects: [ - for _, v in 〈1;_imports〉 for _, obj in ({} & 〈0;v〉.#export).objects { - 〈1;obj〉 - }, - ] - } - } - } - issue3940: { - let: { - 〈0;X〉 - a: { - b: 〈1;X〉 - } - a: { - b: { - a: { - b: { - y: 〈4;X〉 - } - } - } - } - X: { - a: {} - objects: { - for _, v in 〈1;a〉 let x = ({} & 〈0;v〉) for _, _ in 〈0;x〉.objects {} - } - } - } - } - issue3940: { - full: { - out: (〈0;#Exporter〉 & { - _imports: [ - 〈2;_branch〉, - ] - #conf: { - global: { - region: "Europe" - } - } - }) - _branch: { - objects: { - branch: { - #conf: { - ... - } - region: 〈0;#conf〉.global.region - } - } - imports: [ - 〈2;_leaf〉, - ] - #export: (〈1;#Exporter〉 & { - _objects: 〈1;objects〉 - _imports: 〈1;imports〉 - }) - } - _leaf: { - objects: { - leaf: { - #conf: { - ... - } - region: 〈0;#conf〉.global.region - } - } - #export: (〈1;#Exporter〉 & { - _objects: 〈1;objects〉 - }) - } - #Exporter: { - #conf: { - ... - } - _objects: { - ... - } - _imports: [ - ..., - ] - objects: [ - for name, obj in (〈1;_objects〉 & { - [string]: { - #conf: 〈3;#conf〉 - } - }) { - 〈1;name〉: 〈1;obj〉 - }, - for _, import in 〈1;_imports〉 for _, obj in ({ - #conf: 〈3;#conf〉 - } & 〈0;import〉.#export).objects { - 〈1;obj〉 - }, - ] - } - } - } -} ---- issue3990.cue -{ - issue3990: { - _imports: [ - 〈1;_noVolumes〉, - 〈1;_someVolumes〉, - ] - _noVolumes: { - name: "noVolumes" - exportObjs: { - deployment: (〈2;_Deployment〉 & { - volumes: [] - }) - } - } - _someVolumes: { - name: "someVolumes" - exportObjs: { - deployment: (〈2;_Deployment〉 & { - volumes: [ - { - name: "data" - }, - ] - }) - } - } - for _, import in 〈0;_imports〉 for _, obj in ({ - extra: "unused" - } & 〈0;import〉).exportObjs { - 〈2;import〉.name: 〈1;obj〉 - } - _Deployment: { - _names: { - for _, v in 〈2〉.volumes { - 〈1;v〉.name: 〈1;v〉.name - } - } - if (len(〈0;_names〉) > 0) { - volumeNames: [ - for _, v in 〈2;_names〉 { - 〈1;v〉 - }, - ] - } - } - } -} ---- pending.cue -{ - T: int - for _, C in 〈0;Y〉 { - let X#1multi = 〈1;C〉.M - T: 〈0;let X#1〉.V - } - Y: { - x: { - M: { - V: 1 - } - for _, _ in 〈0;M〉 { - if true { - M: {} - } - } - } - } -} diff --git a/cue/testdata/comprehensions/nestembed.txtar b/cue/testdata/comprehensions/nestembed.txtar --- a/cue/testdata/comprehensions/nestembed.txtar +++ b/cue/testdata/comprehensions/nestembed.txtar @@ -35,32 +35,3 @@ Disjuncts: 0 NumCloseIDs: 6 --- out/compile -- ---- in.cue -{ - DeleteThis: [ - "this", - "that", - ] - useful_infra: { - gcp: { - cluters: 10 - } - aws: { - clusters: 20 - } - this: { - clusters: 1 - } - that: { - clusters: 2 - } - } - New_infra: { - for k, v in 〈1;useful_infra〉 { - if !〈import;list〉.Contains(〈3;DeleteThis〉, 〈1;k〉) { - "\(〈2;k〉)": 〈2;v〉 - } - } - } -} diff --git a/cue/testdata/comprehensions/open_iter_writeback.txtar b/cue/testdata/comprehensions/open_iter_writeback.txtar --- a/cue/testdata/comprehensions/open_iter_writeback.txtar +++ b/cue/testdata/comprehensions/open_iter_writeback.txtar @@ -40,38 +40,3 @@ keys: ["b", "a"] }) } --- out/compile -- ---- in.cue -{ - openIter: { - src: { - a: 1 - b: 2 - ... - if true { - c: 3 - } - } - keys: [ - for k, _ in 〈1;src〉 { - 〈1;k〉 - }, - ] - } - defOpen: { - #T: { - [string]: int - if true { - a: 1 - } - } - inst: (〈0;#T〉 & { - b: 2 - }) - keys: [ - for k, _ in 〈1;inst〉 { - 〈1;k〉 - }, - ] - } -} diff --git a/cue/testdata/comprehensions/optional_ref_yield.txtar b/cue/testdata/comprehensions/optional_ref_yield.txtar --- a/cue/testdata/comprehensions/optional_ref_yield.txtar +++ b/cue/testdata/comprehensions/optional_ref_yield.txtar @@ -56,39 +56,3 @@ -- out/errors.txt -- [incomplete] optionalStaysOptional.x.bar: cannot reference optional field: foo: ./in.cue:22:11 --- out/compile -- ---- in.cue -{ - optionalUpgradesViaSiblingComp: { - x: { - bar: 〈1;x〉.foo - foo?: int - if true { - foo: 5 - } - } - x: { - bar: int - } - } - optionalStaysOptional: { - x: { - bar: 〈1;x〉.foo - foo?: int - } - x: { - bar: _ - } - } - pendingBecomesMember: { - x: { - bar: 〈1;x〉.foo - if true { - foo: 5 - } - } - x: { - bar: int - } - } -} diff --git a/cue/testdata/comprehensions/pushdown.txtar b/cue/testdata/comprehensions/pushdown.txtar --- a/cue/testdata/comprehensions/pushdown.txtar +++ b/cue/testdata/comprehensions/pushdown.txtar @@ -1543,1447 +1543,3 @@ Disjuncts: 44 NumCloseIDs: 264 --- out/compile -- ---- in.cue -{ - linkChildren: { - w: 1 - v: { - x: 1 - if true { - y: 1 - if true { - z: 1 - rw: 〈3;w〉 - rx: 〈2;x〉 - ry: 〈1;y〉 - rz: 〈0;z〉 - n1a: { - na: [ - 〈5;w〉, - 〈4;x〉, - 〈3;y〉, - 〈2;z〉, - ] - } - n2a: { - n1a: { - na: [ - 〈6;w〉, - 〈5;x〉, - 〈4;y〉, - 〈3;z〉, - ] - } - } - n2z: { - n1z: { - nz: 〈2;z〉 - } - } - } - } - } - } - fail: { - a: { - if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { - b: 1 - } - } - } - embed: { - fail1: 〈0;#C1〉 - #C1: { - if false { - p: _ - } - } - fail1: { - p: "foo" - } - success2: 〈0;#C2〉 - #C2: { - if true { - p: _ - } - } - success2: { - p: "foo" - } - success3: 〈0;#C3〉 - #C3: {} - success3: { - if false { - p: { - q: 1 - } - } - } - success4: { - #X: { - y: string - } - x: { - y: string - } - x: { - for _, _ in [ - "iter-once", - ] { - 〈3;#X〉 - if false { - y: "foo" - } - } - } - } - fail4: 〈0;#C4〉 - #C4: {} - fail4: { - if true { - p: { - q: 1 - } - } - } - incomplete5: { - a: bool - if 〈0;a〉 { - p: { - q: 1 - } - } - } - incomplete6: { - if false { - p: 1 - } - p: (〈0;q〉 + 1) - q: int - } - incomplete7: { - p: (〈0;q〉 + 1) - q: int - if false { - q: 1 - } - } - } - mixedFieldsSuccess: { - a: { - for _, s in [ - "foo", - ] { - "\(〈1;s〉)": 1 - X: 1 - } - } - b: { - #Def: { - for _, s in [ - "foo", - ] { - "\(〈1;s〉)": 1 - X: 1 - } - } - } - b: { - x: 〈1;b〉.#Def - } - b: { - x: { - X: _ - } - } - b: { - x: { - foo: _ - } - } - c: { - #Def: { - X: int - foo: int - } - } - c: { - x: 〈1;c〉.#Def - } - c: { - x: { - for _, s in [ - "foo", - ] { - "\(〈1;s〉)": 1 - X: 1 - } - } - } - } - fieldMismatch: { - a: { - 2 - if true { - x: 3 - } - } - } - noStackOverflowStructCycle: { - #list: { - tail: 〈1;#list〉 - if (〈0;tail〉 != null) { - sum: 〈1;tail〉.sum - } - } - list: { - tail: 〈1;list〉 - if (〈0;tail〉 != null) { - sum: 〈1;tail〉.sum - } - } - } - provideIncompleteSuccess: { - t1: { - #a: { - if 〈0;b〉 { - c: 4 - } - b: bool - } - x: ((〈0;#a〉 & { - b: true - }) & { - c: 4 - }) - y: 〈0;x〉 - } - t2: { - #a: { - if 〈0;b〉 { - c: 4 - } - b: true - } - #c: {} - a: { - if 〈0;b〉 { - c: { - d: 4 - } - } - b: true - c: 〈1;#c〉 - } - } - } - voidArcs: { - scopes: { - x: 1 - a: { - y: 2 - if true { - b: 〈2;x〉 - c: { - d: 〈3;x〉 - } - e: 〈1;y〉 - f: { - g: 〈2;y〉 - } - } - } - } - drop: { - x: 1 - a: { - y: 2 - if false { - b: 〈2;x〉 - c: { - d: 〈3;x〉 - } - e: 〈1;y〉 - f: { - g: 〈2;y〉 - } - } - } - } - } - cyclicError: { - a: { - x: bool - y: bool - if 〈1;a〉.x { - y: true - } - if 〈1;a〉.y { - x: true - } - b: {} - } - c: 〈0;a〉.b - } - midwayReferences: { - a: { - for i, j in { - a: 1 - b: 2 - } { - x: { - y: { - z: { - 〈4;i〉: 〈4;j〉 - } - } - } - } - x: { - y: {} - } - } - b: 〈0;a〉.x - c: 〈0;a〉.x.y - d: 〈0;a〉.x.y.z - } - closedCheck: { - success1: { - a: { - b: { - [string]: 〈2;#D〉 - } - } - #D: { - d: string - if (〈0;d〉 != "c") { - e: string - } - } - a: { - b: { - c: { - d: "d" - e: "ok" - } - } - } - } - } - closedCheck: { - success2: { - a: { - b: { - [string]: 〈2;#D〉 - } - } - #D: { - d: string - if (〈0;d〉 != "c") { - ("foo" + "bar"): string - } - } - a: { - b: { - c: { - d: "d" - foobar: "ok" - } - } - } - } - } - closedCheck: { - success3: { - a: { - b: { - [string]: 〈2;#D〉 - } - } - #D: { - d: string - e: { - if (〈1;d〉 != "c") { - string - } - } - } - a: { - b: { - c: { - d: "d" - e: "ok" - } - } - } - } - } - emptyComprehensionIncomplete: { - a: {} - b: { - if 〈1;a〉.b {} - } - } - voidEliminationSuccess: { - t1: { - [string]: { - b: bool - if !〈0;b〉 {} - } - if false { - a: { - b: true - } - } - } - } - voidEliminationSuccess: { - t2: { - components: { - sinks: { - [string]: (〈1;#C〉 & { - kind: string - configuration: { - if (〈1;kind〉 != "source") { - inputs: { - required: true - } - } - } - }) - } - #C: { - kind: string - configuration: { - [string]: { - required: bool - if !〈0;required〉 { - common: bool - } - } - } - } - } - components: { - sinks: { - blah: { - kind: "source" - } - } - } - } - } - voidEliminationSuccess: { - derefRef1: { - a: { - [string]: { - c: { - [string]: 〈3;E〉 - } - } - } - a: { - b: { - c: { - if false { - d: { - e: true - } - } - } - } - } - E: { - e: bool - f: !〈0;e〉 - } - } - } - voidEliminationSuccess: { - derefRef2: { - a: { - [string]: { - c: { - [string]: 〈3;E〉 - } - } - } - a: { - b: { - c: { - if false { - d: { - e: true - } - } - } - } - } - E: 〈0;#F〉 - #F: { - e: bool - f: !〈0;e〉 - } - } - } - voidEliminationSuccess: { - derefDisj1: { - a: { - [string]: { - c: { - [string]: 〈3;E〉 - } - } - } - a: { - b: { - c: { - if false { - d: { - e: true - } - } - } - } - } - E: ({ - e: bool - f: !〈0;e〉 - }|{ - g: bool - h: !〈0;g〉 - }) - } - } - voidEliminationSuccess: { - derefDisj2: { - a: { - [string]: { - c: { - [string]: (〈3;E〉 & 〈3;E〉) - } - } - } - a: { - b: { - c: { - if false { - d: { - e: true - } - } - } - } - } - E: ({ - e: bool - f: !〈0;e〉 - }|{ - g: bool - h: !〈0;g〉 - }) - } - } - voidEliminationSuccess: { - bulk1: { - a: { - b: {} - } - a: { - [string]: { - c: { - e: string - if false { - e: "" - } - } - d: 〈0;c〉.e - } - } - } - } - voidEliminationSuccess: { - opt1: { - a: { - b: {} - } - a: { - b?: { - c: { - e: string - if false { - e: "" - } - } - d: 〈0;c〉.e - } - } - } - } - voidEliminationSuccess: { - noCycle1: { - _x: 〈0;a〉.b - a: { - c: { - h: "stream" - } - b: { - if (〈1;c〉.g != _|_(explicit error (_|_ literal) in source)) {} - } - c: { - if false { - g: _ - } - } - } - } - } - voidEliminationSuccess: { - noCycle2: { - a: { - c: { - h: "stream" - } - b: { - if (〈1;c〉.g != _|_(explicit error (_|_ literal) in source)) {} - } - c: { - if false { - g: _ - } - } - } - _x: 〈0;a〉.b - } - } - voidLookup: { - a: { - x: { - z: 〈2;a〉.y.z.void - } - } - a: { - y: { - c: _ - z: {} - } - } - a: { - [string]: { - c: { - for k, v in 〈1;z〉 { - 〈1;k〉: null - } - } - z: { - if false { - err: {} - } - } - } - } - } - topElimination: { - a: int - _ - if true { - x: (〈1;a〉 + 1) - } - } - voidEliminationSuccess: { - drop1: { - t: { - #ok: (*true|bool) - if 〈0;#ok〉 { - x: int - } - } - s: (〈0;t〉 & { - #ok: false - }) - } - } - explicitDefaultError: { - a: (string|*_|_(explicit error (_|_ literal) in source)) - if (〈0;a〉 != "") {} - } - allArcsSuccess: { - p1: { - x: { - for k, _ in 〈1;y〉 { - 〈1;k〉: null - } - } - y: { - if false { - x: {} - } - } - } - } - allArcsSuccess: { - p2: { - y: { - if false { - x: {} - } - } - x: { - for k, _ in 〈1;y〉 { - 〈1;k〉: null - } - } - } - } - structShare: { - ok1: { - a: { - [string]: 〈1;E〉 - } - E: {} - a: { - if true { - d: { - e: true - } - } - } - } - } - structShare: { - err1: { - x: { - [string]: 〈1;x〉.#E - } - x: { - #E: {} - } - if true { - x: { - d: { - e: true - } - } - } - } - } -} ---- issue1759.cue -{ - unity: { - success1: { - #Config: { - name: string - type: string - } - #AnyConfig: { - 〈1;#Config〉 - ... - } - #Env: { - name: string - configurations: { - [string]: 〈2;#AnyConfig〉 - } - } - envs: { - e1: (〈1;#Env〉 & { - configurations: { - c1: 〈3;#Config〉 - } - }) - } - envs: { - [string]: { - configurations: { - [string]: { - type: "foo" - if (〈0;type〉 == "terraform") { - backend: { - type: "s3" - } - } - } - } - } - } - } - } - issue1759: { - _ports_map: {} - if (len(〈0;_ports_map〉) > 0) { - port: 〈1;_ports_map〉.a.port - } - if true { - _ports_map: { - a: { - port: "80" - } - } - } - } - arcAlignment: { - t1: { - [string]: { - if true {} - } - if false { - c: _ - } - } - } -} ---- issue2111.cue -{ - letPushdown: { - _c: { - y: 1 - } - a: { - for k, v in 〈1;_c〉 { - let x#1multi = 〈1;v〉 - if (〈0;let x#1〉 != _|_(explicit error (_|_ literal) in source)) {} - } - } - } -} ---- issue2113.cue -{ - nestedWithEmbeddingOK: { - c: [ - 1, - ] - a: { - for k, v in 〈1;c〉 { - { - x: 1 - } - if (〈3;a〉.x != _|_(explicit error (_|_ literal) in source)) {} - } - } - } - nestedWithDynamicFieldOK: { - _c: { - y: 1 - } - a: { - for k, v in 〈1;_c〉 { - if (〈0;("\(〈1;k〉)")〉 != _|_(explicit error (_|_ literal) in source)) {} - "\(〈1;k〉)": 1 - } - } - } - errorPropagation: { - deployment: _ - for k, v in 〈0;deployment〉 { - for k1, v2 in 〈1;v〉.env2 { - deployment: { - 〈4;k〉: { - x1: 1 - } - } - } - } - for _, id in [ - "elem", - ] { - deployment: { - 〈2;id〉: { - x2: 2 - } - } - } - } -} ---- issue2131.cue -{ - issue2131: { - tests: { - windows: { - eg1: { - in: "c:\\d" - } - eg2: { - in: "c:\\test" - } - eg3: { - in: "c:\\test\\d" - } - } - for os, examples in 〈1;tests〉 for k, v in 〈0;examples〉 { - 〈2;os〉: { - 〈2;k〉: { - out: "test" - } - } - } - } - } -} ---- issue2208.cue -{ - voidErrorIncomplete: { - #Schema: { - [string]: { - required: bool - if !〈0;required〉 {} - } - } - root: 〈0;#Schema〉 - root: { - if false { - child: { - required: false - } - } - } - } -} ---- issue3533.cue -{ - issue3533: { - #ObjectMeta: { - namespace?: string - } - out: { - for i, _ in [ - "iter-once", - ] { - metadata: 〈3;#ObjectMeta〉 - if false { - metadata: { - namespace: "foo" - } - } - } - } - out: { - metadata: { - namespace: (*"default"|string) - } - } - } -} ---- issue3535.cue -{ - issue3535: { - hidden: { - #X: { - kind: string - output: {} - } - foo: (〈0;#X〉 & { - kind: string - if (〈0;kind〉 == "foo") { - _hidden: {} - } - }) - foo: { - kind: "foo" - } - } - } - issue3535: { - regular: { - #X: { - kind: string - output: {} - } - foo: (〈0;#X〉 & { - kind: string - if (〈0;kind〉 == "foo") { - regular: {} - } - }) - foo: { - kind: "foo" - } - } - } - issue3535: { - def: { - #X: { - kind: string - output: {} - } - foo: (〈0;#X〉 & { - kind: string - if (〈0;kind〉 == "foo") { - #def: {} - } - }) - foo: { - kind: "foo" - } - } - } -} ---- issue3621.cue -{ - issue3621: { - reduced: { - t1: { - if true { - a: 〈0;b1〉.b2.b3 - b1: { - b2: { - b3: "Foo" - } - } - } - } - } - } - issue3621: { - reduced: { - t2: { - outer: {} - if true { - inner: { - inner2: { - name: "Foo" - } - } - outer: { - b: 〈1;inner〉.inner2.name - } - } - } - } - } - issue3621: { - full: { - hello: "world" - outer: { - [string]: { - name: 〈1;-〉 - } - } - if true { - inner: { - inner2: { - name: "Employees" - description: "All employees" - privacy: "secret" - create_default: false - } - } - outer: { - outer2: { - bar: 〈2;inner〉.inner2.name - } - } - } - } - } -} ---- issue3708.cue -{ - issue3708: { - out: 〈0;people〉.bob.kind - people: { - [string]: { - kind: "person" - name?: string - } - } - if true { - people: { - bob: { - name: "Bob" - } - } - } - } -} ---- issue3729.cue -{ - issue3729: { - withDisjunction: { - #Root: { - sub1?: { - #sub2?: bool - } - } - root?: (null|〈0;#Root〉) - if true { - root: { - sub1?: { - #sub2: true - } - } - } - } - } - issue3729: { - withoutDisjunction: { - root?: null - if true { - root: { - #sub1?: { - #sub2: true - } - } - } - } - } - issue3729: { - withoutDisjunctionWithEmbed: { - root?: null - if true { - root: { - _ - #sub1?: { - #sub2: true - } - } - } - } - } - issue3729: { - definitionsOnly: { - #Root: { - #sub1?: { - #sub2?: bool - } - } - root?: (null|〈0;#Root〉) - if true { - root: { - #sub1?: { - #sub2: true - } - } - } - } - } - issue3729: { - withEmbed: { - incomplete: { - #Root: { - #sub1?: { - #sub2?: bool - } - } - root?: (null|〈0;#Root〉) - if true { - root: { - _ - #sub1?: { - #sub2: true - } - } - } - } - } - } - issue3729: { - full: { - #Application: { - spec: 〈1;#ApplicationSpec〉 - } - #ApplicationSpec: { - syncPolicy?: (null|〈1;#SyncPolicy〉) - } - #SyncPolicy: { - automated?: (null|〈1;#SyncPolicyAutomated〉) - } - #SyncPolicyAutomated: { - prune?: bool - selfHeal?: bool - } - argoApp: (〈0;#Application〉 & { - spec: { - if true { - syncPolicy: { - automated: { - prune: true - selfHeal: true - } - } - } - } - }) - argoApp: { - spec: { - _syncpolicy: "selfhealprune" - } - } - } - } -} ---- issue3935.cue -{ - issue3935: { - reduced: { - out: (〈0;#A〉|〈0;#B〉) - out: (〈0;#B〉 & { - y: { - x: "bar" - } - }) - #A: { - y: { - other: int - } - } - #B: { - if true { - x: 〈1;y〉.x - } - y!: { - x!: _ - } - } - } - } - issue3935: { - full: { - out: (〈0;#SchemaOther〉|〈0;#SchemaSelected〉) - out: (〈0;#SchemaSelected〉 & { - spec: { - name: "foo" - config: { - namespace: "bar" - } - } - }) - #SchemaOther: { - spec: { - otherOptional?: int - otherRegular: int - otherRequired!: int - } - } - #SchemaSelected: { - spec!: { - name!: string - config!: _ - } - if true { - namespace: 〈1;_specConfig〉.namespace - } - _specConfig: 〈0;spec〉.config - } - } - } -} ---- pending.cue -{ - arcTypeAcrossTwo: { - a?: { - b?: ({ - c?: (null|{}) - }|null) - } - if true { - a: { - b: { - c: { - d: true - } - } - } - } - } - issue3894: { - reduced: { - p1: { - ({ - a: string - }|{ - b: { - value: string - } - }) - if true { - b: { - value: "true" - } - } - } - } - } - issue3894: { - reduced: { - p2: { - ({ - b: { - value: string - } - }|{ - a: string - }) - if true { - b: { - value: "true" - } - } - } - } - } - issue3894: { - full: { - #Output: ({ - a?: string - }|{ - b?: { - value: string - } - }) - out: 〈0;#Output〉 - out: { - if (true == true) { - b: { - value: "true" - } - } - } - } - } -} ---- reflect.cue -{ - unifyDynamicReflectSuccess: { - for _, s in [ - "foo", - ] { - X: { - ... - } - "\(〈1;s〉)": { - X: { - ... - } - Y: 〈import;"encoding/json"〉.Marshal(〈0;X〉) - } - } - [string]: { - X: { - if true { - x: { - y: {} - } - } - } - } - } -} ---- rework.cue -{ - regression1: { - #Primary: { - _Y: _ - let _X#2 = 〈0;_Y〉 - if (len(〈0;let _X#2〉.spec.command) > 0) { - command: 〈1;let _X#2〉.spec.command - } - } - #Rollout: { - _X: _ - out: ((〈1;#Primary〉 & { - _Y: 〈1;_X〉 - }) & 〈0;_X〉.patch) - } - x: { - spec: { - command: [ - "a", - ] - } - patch: {} - } - out: (〈0;#Rollout〉 & { - _X: 〈1;x〉 - }) - } - regression2: { - #Primary: { - _Y: _ - if (len(〈0;_Y〉.spec.command) > 0) { - command: 〈1;_Y〉.spec.command - } - } - #Rollout: { - _X: _ - out: ((〈1;#Primary〉 & { - _Y: 〈1;_X〉 - }) & 〈0;_X〉.patch) - } - x: { - spec: { - command: [ - "a", - ] - } - patch: {} - } - out: (〈0;#Rollout〉 & { - _X: 〈1;x〉 - }) - } - letCycleSelf: { - #X: { - let this#3 = 〈1〉 - hosts: { - [string]: _ - } - for h, _ in 〈0;let this#3〉.hosts { - out: { - 〈2;h〉: 1 - } - } - for h, _ in 〈0;let this#3〉.hosts { - out: { - 〈2;h〉: 2 - } - } - } - x: { - [string]: 〈1;#X〉 - } - x: { - a: {} - } - } -} ---- rework2.cue -{ - letCycleSelfKeyword: { - #E: { - let s#4 = 〈1〉 - hosts: _ - for _, hv in 〈0;let s#4〉.hosts { - out: { - 〈2;hv〉.x: "a" - } - } - } - env: (〈0;#E〉 & { - hosts: { - h1: { - x: "k" - } - } - }) - } - letCycleSelfKeyword2: { - #E: { - let s#5 = 〈1〉 - ... - for _, hv in 〈0;let s#5〉.hosts { - let n#6 = 〈2;let s#5〉.networks - a: 〈0;let n#6〉 - } - } - env: (〈0;#E〉 & { - hosts: { - h1: 1 - } - networks: { - n1: "x" - } - }) - } -} diff --git a/cue/testdata/comprehensions/try.txtar b/cue/testdata/comprehensions/try.txtar --- a/cue/testdata/comprehensions/try.txtar +++ b/cue/testdata/comprehensions/try.txtar @@ -605,552 +605,3 @@ Disjuncts: 0 NumCloseIDs: 173 --- out/compile -- ---- in.cue -{ - a: 1 - b: 2 - c?: int - incomplete: int - success: { - try { - result: (〈2;a〉? + 〈2;b〉?) - } - } - single: { - x: 5 - try { - y: (〈1;x〉? * 2) - } - } - fallbackDef: 42 - elseNotTriggered: { - try { - v: 〈2;fallbackDef〉? - } else { - fallback: 0 - } - } - elseTriggered: { - try { - v: 〈2;c〉? - } else { - fallback: -1 - } - } - elseMultiField: { - try { - x: 〈2;c〉? - y: 〈2;c〉? - } else { - fallback: true - } - } - emptyOnFail: { - try { - z: (〈2;c〉? + 1) - } - } - mixedRefs: { - try { - x: 〈2;a〉? - y: 〈2;c〉? - } else { - fallback: true - } - } - incompleteOK: { - try { - x: 〈2;incomplete〉? - } else { - fallback: 23 - } - } - incompleteNestedBody: { - try { - x: { - y: 〈3;incomplete〉? - } - } else { - fallback: 23 - } - } - requiredUnfilled: { - a!: _ - try { - x: 〈1;a〉? - } else { - fallback: 23 - } - } - requiredFilled: { - a!: _ - a: 5 - try { - x: 〈1;a〉? - } else { - fallback: 23 - } - } - requiredWithType: { - a!: int - try { - x: 〈1;a〉? - } else { - fallback: 23 - } - } - forWithDefinedSource: { - try { - for _, x in [ - 〈3;b〉?, - ] { - val: 〈1;x〉 - } - } - } - forWithUndefinedSource: { - try { - for _, x in [ - 〈3;c〉?, - ] { - val: 〈1;x〉 - } - } else { - empty: true - } - } - nested: { - outer: { - try { - inner: 〈3;a〉? - } - } - multi: { - try { - first: 〈3;a〉? - } - try { - second: 〈3;b〉? - } - } - deepNested: { - try { - level1: { - level2: 〈4;a〉? - } - } - } - } - complexExpr: { - binOp: { - try { - sum: (〈3;a〉? + 〈3;b〉?) - prod: (〈3;a〉? * 〈3;b〉?) - } - } - list: { - try { - items: [ - 〈4;a〉?, - 〈4;b〉?, - (〈4;a〉? + 〈4;b〉?), - ] - } - } - } - selectorTests: { - data: { - nested: { - value: 100 - } - } - definedSelector: { - try { - v: 〈2;data〉.nested.value? - } - } - } - closedness: { - #Def: { - f: int - } - d: 〈0;#Def〉 - exists: { - try { - v: 〈2;#Def〉.f? - } - } - notExistsDef: { - try { - v: 〈2;#Def〉.g? - } - } - notExistsValue: { - try { - v: 〈2;d〉.g? - } - } - } - indexTests: { - closedList: [ - 10, - 20, - 30, - ] - openList: [ - 10, - 20, - 30, - ..., - ] - definedIndex: { - try { - v: 〈2;closedList〉[0]? - } - } - middleIndex: { - try { - v: 〈2;closedList〉[1]? - } - } - outOfRangeClosed: { - try { - v: 〈2;closedList〉[10]? - } else { - fallback: -1 - } - } - outOfRangeClosedNoElse: { - try { - v: 〈2;closedList〉[100]? - } - } - outOfRangeOpen: { - try { - v: 〈2;openList〉[10]? - } else { - fallback: -1 - } - } - outOfRangeOpenNoElse: { - try { - v: 〈2;openList〉[100]? - } - } - multipleIndex: { - try { - x: 〈2;closedList〉[0]? - y: 〈2;closedList〉[1]? - z: 〈2;closedList〉[2]? - } - } - } - edgeCases: { - emptyBody: { - try {} - } - literalOnly: { - try { - x: 42 - } - } - firstFails: { - try { - x: 〈3;c〉? - y: 〈3;a〉? - } else { - skipped: true - } - } - secondFails: { - try { - x: 〈3;a〉? - y: 〈3;c〉? - } else { - skipped: true - } - } - referenceError: { - a: (1 / 0) - a: { - _b: 2 - } - direct: { - try { - v: 〈2;a〉? - } else { - skipped: true - } - } - dontSkipError1: { - try { - 〈2;a〉._b? - } else { - skipped: true - } - } - dontSkipError2: { - try { - 〈2;a〉?._b? - } else { - skipped: true - } - } - } - } - refIntoTry: { - source: { - try { - val: 〈3;a〉? - } - } - ref: 〈0;source〉.val - nestedSource: { - try { - inner: { - try { - deep: 〈5;b〉? - } - } - } - } - nestedRef: 〈0;nestedSource〉.inner.deep - nestedSkipped?: { - try { - 〈3;c〉? - } - } - mixedSource: { - try { - foo: 〈2;nestedSkipped〉? - } - bar?: 1 - baz: 1 - } - skippedRef: { - try { - v: 〈2;mixedSource〉.foo? - } else { - missing: true - } - } - failedRef1: { - try { - v: 〈2;mixedSource〉.foo - } else { - missing: true - } - } - failedRef2: { - try { - v: 〈2;mixedSource〉.foo - } else { - missing: true - } - } - successRef: { - try { - v: 〈2;mixedSource〉.baz? - } else { - missing: true - } - } - } - errorPrecedence: { - typeErrorDefined: { - try { - v: (〈3;a〉? + "string") - } else { - fallback: "ok" - } - } - typeErrorUndefined: { - try { - v: (〈3;c〉? + "string") - } else { - fallback: "ok" - } - } - divByZero: { - try { - v: (〈3;a〉? / 0) - } else { - fallback: "ok" - } - } - conflictError: { - try { - v: (〈3;a〉? & "notanint") - } else { - fallback: "ok" - } - } - mixedError: { - try { - x: 〈3;c〉? - y: (1 / 0) - } else { - fallback: "ok" - } - } - mixedErrorMultiple: { - try { - x: 〈3;a〉? - y: 〈3;c〉? - z: (〈3;a〉? / 0) - } else { - fallback: "ok" - } - } - } - assignmentForm: { - basicDefined: { - try x = 〈2;a〉? { - result: 〈1;x〉 - } - } - basicUndefined: { - try x = 〈2;c〉? { - result: 〈1;x〉 - } else { - fallback: 0 - } - } - noElseUndefined: { - try x = 〈2;c〉? { - result: 〈1;x〉 - } - } - withExpression: { - try sum = (〈2;a〉? + 〈2;b〉?) { - result: 〈1;sum〉 - } - } - withFailingExpr: { - try sum = (〈2;a〉? + 〈2;c〉?) { - result: 〈1;sum〉 - } else { - fallback: -1 - } - } - chained: { - try x = 〈2;a〉? try y = 〈3;b〉? { - result: (〈2;x〉 + 〈1;y〉) - } - } - withSelector: { - data: { - inner: 42 - } - try v = 〈0;data〉.inner? { - result: 〈1;v〉 - } - } - withIndex: { - list: [ - 10, - 20, - 30, - ] - try v = 〈0;list〉[1]? { - result: 〈1;v〉 - } - } - withOutOfRangeIndex: { - list: [ - 10, - 20, - 30, - ] - try v = 〈0;list〉[10]? { - result: 〈1;v〉 - } else { - fallback: -1 - } - } - withOutOfRangeIndexOpen: { - list: [ - 10, - 20, - 30, - ..., - ] - try v = 〈0;list〉[10]? { - result: 〈1;v〉 - } else { - fallback: -1 - } - } - nestedUse: { - try x = 〈2;a〉? { - inner: { - value: (〈2;x〉 * 2) - } - } - } - chainedOneFails: { - try x = 〈2;a〉? try y = 〈3;c〉? { - result: (〈2;x〉 + 〈1;y〉) - } - } - withRealError: { - try x = (〈2;a〉? / 0) { - result: 〈1;x〉 - } else { - fallback: "ok" - } - } - withFor: { - try x = 〈2;b〉? for i, v in [ - 1, - 2, - ] { - "\(〈1;i〉)": (〈2;x〉 + 〈1;v〉) - } - } - withIf: { - try x = 〈2;a〉? if (〈0;x〉 > 0) { - positive: 〈1;x〉 - } - } - withLet: { - try x = 〈2;a〉? let y = (〈0;x〉 * 2) { - doubled: 〈1;y〉 - } - } - } - recursive: { - t1: { - try { - for _, x in [ - 〈4;b〉?, - ] { - 〈1;x〉 - } - } - } - } - recursive: { - t2: { - try { - { - x: 〈4;b〉? - y: 〈4;c〉? - } - } - } - } - recursive: { - t3: { - try { - { - x: 〈4;b〉? - y: 〈4;c〉? - } - } else { - z: 23 - } - } - } -} diff --git a/cue/testdata/comprehensions/try_compile_errors.txtar b/cue/testdata/comprehensions/try_compile_errors.txtar --- a/cue/testdata/comprehensions/try_compile_errors.txtar +++ b/cue/testdata/comprehensions/try_compile_errors.txtar @@ -76,48 +76,3 @@ ./in.cue:11:8 optionalInForSource: optional marker (?) is only valid within a try clause: ./in.cue:16:14 --- out/compile -- -structFormNotLast: struct-form try clause must be the last clause in a comprehension: - ./in.cue:5:5 -optionalOutsideTry.b: optional marker (?) is only valid within a try clause: - ./in.cue:11:8 -optionalInForSource: optional marker (?) is only valid within a try clause: - ./in.cue:17:14 -optionalInAssignmentBody.try[].x: optional marker (?) is only valid within a try clause: - ./in.cue:24:21 -invalidUseOfOptional.x: reference "c" not found: - ./in.cue:29:14 ---- in.cue -{ - structFormNotLast: { - _|_(struct-form try clause must be the last clause in a comprehension) - } - optionalOutsideTry: { - a: 1 - b: 〈0;a〉? - } - optionalInForSource: { - a?: [ - 1, - 2, - 3, - ] - for _, x in 〈0;a〉? { - "\(〈1;x〉)": 〈1;x〉 - } - } - optionalInAssignmentBody: { - a: 1 - b: 2 - try y = 〈0;a〉? { - x: 〈2;b〉? - } else { - fallback: 23 - } - } - invalidUseOfOptional: { - try { - x: _|_(reference "c" not found) - } - } -} diff --git a/cue/testdata/cycle/015_reference_across_tuples_and_back.txtar b/cue/testdata/cycle/015_reference_across_tuples_and_back.txtar --- a/cue/testdata/cycle/015_reference_across_tuples_and_back.txtar +++ b/cue/testdata/cycle/015_reference_across_tuples_and_back.txtar @@ -7,20 +7,6 @@ b: {e: 3, f: 3} }) } --- out/compile -- ---- in.cue -{ - t1: { - a: { - c: 〈1;b〉.e - d: 〈1;b〉.f - } - b: { - e: 3 - f: 〈1;a〉.c - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/cycle/021_delayed_constraint_failure.txtar b/cue/testdata/cycle/021_delayed_constraint_failure.txtar --- a/cue/testdata/cycle/021_delayed_constraint_failure.txtar +++ b/cue/testdata/cycle/021_delayed_constraint_failure.txtar @@ -16,15 +16,6 @@ [eval] x: conflicting values 101 and 100: ./in.cue:5:4 ./in.cue:6:4 --- out/compile -- ---- in.cue -{ - a: (〈0;b〉 - 100) - b: (〈0;a〉 + 110) - b: 200 - x: 100 - x: (〈0;x〉 + 1) -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/cycle/023_reentrance.txtar b/cue/testdata/cycle/023_reentrance.txtar --- a/cue/testdata/cycle/023_reentrance.txtar +++ b/cue/testdata/cycle/023_reentrance.txtar @@ -63,41 +63,3 @@ Disjuncts: 0 NumCloseIDs: 117 --- out/compile -- ---- in.cue -{ - fibRec: { - nn: int - out: (〈1;fib〉 & { - n: 〈1;nn〉 - }).out - } - fib: { - n: int - if (〈0;n〉 >= 2) { - out: ((〈2;fibRec〉 & { - nn: (〈2;n〉 - 2) - }).out + (〈2;fibRec〉 & { - nn: (〈2;n〉 - 1) - }).out) - } - if (〈0;n〉 < 2) { - out: 〈1;n〉 - } - } - fib1: (〈0;fib〉 & { - n: 1 - }).out - fib2: (〈0;fib〉 & { - n: 2 - }).out - fib3: (〈0;fib〉 & { - n: 3 - }).out - fib7: (〈0;fib〉 & { - n: 7 - }).out - fib12: (〈0;fib〉 & { - n: 12 - }).out -} diff --git a/cue/testdata/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar b/cue/testdata/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar --- a/cue/testdata/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar +++ b/cue/testdata/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar @@ -25,27 +25,6 @@ ./in.cue:4:10 a2: unresolved disjunction: a1: ./in.cue:4:10 --- out/compile -- ---- in.cue -{ - a1: (*0|1) - a1: (〈0;a3〉 - 〈0;a2〉) - a2: (*0|1) - a2: (〈0;a3〉 - 〈0;a1〉) - a3: 1 - b1: ((*0|1) & 〈0;b2〉) - b2: ((0|*1) & 〈0;b1〉) - c1: ((*{ - a: 1 - }|{ - b: 1 - }) & 〈0;c2〉) - c2: ((*{ - a: 2 - }|{ - b: 2 - }) & 〈0;c1〉) -} -- out/eval/stats -- Leaks: 0 Freed: 52 diff --git a/cue/testdata/cycle/049_self-reference_cycles_conflicts_with_strings.txtar b/cue/testdata/cycle/049_self-reference_cycles_conflicts_with_strings.txtar --- a/cue/testdata/cycle/049_self-reference_cycles_conflicts_with_strings.txtar +++ b/cue/testdata/cycle/049_self-reference_cycles_conflicts_with_strings.txtar @@ -10,17 +10,6 @@ [eval] a.x: conflicting values "hey!?" and "hey": ./in.cue:2:5 ./in.cue:5:7 --- out/compile -- ---- in.cue -{ - a: { - x: (〈0;y〉 + "?") - y: (〈0;x〉 + "!") - } - a: { - x: "hey" - } -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar b/cue/testdata/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar --- a/cue/testdata/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar +++ b/cue/testdata/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar @@ -10,25 +10,6 @@ b: {x: 2} | {z: 2, y: 3, x: 1} c: {y: 3, x: 1, z: 2} | {z: 3} }) --- out/compile -- ---- in.cue -{ - a: ((〈0;b〉 & { - x: 1 - })|{ - y: 1 - }) - b: ({ - x: 2 - }|(〈0;c〉 & { - z: 2 - })) - c: ((〈0;a〉 & { - y: 3 - })|{ - z: 3 - }) -} -- out/eval/stats -- Leaks: 6 Freed: 46 diff --git a/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar b/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar --- a/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar +++ b/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar @@ -158,40 +158,3 @@ Disjuncts: 21 NumCloseIDs: 17 --- out/compile -- ---- in.cue -{ - xa1: ((〈0;xa2〉 & 8)|(〈0;xa4〉 & 9)) - xa2: (〈0;xa3〉 + 2) - xa3: (6 & (〈0;xa1〉 - 2)) - xa4: (〈0;xa2〉 + 2) - xb1: ((〈0;xb2〉 & 8)|(〈0;xb4〉 & 9)) - xb2: (〈0;xb3〉 + 2) - xb3: ((6 & (〈0;xb1〉 - 2))|(〈0;xb4〉 & 9)) - xb4: (〈0;xb2〉 + 2) - xc1: ((〈0;xc2〉 & 8)|(〈0;xc4〉 & 9)|(〈0;xc5〉 & 9)) - xc2: (〈0;xc3〉 + 2) - xc3: (6 & (〈0;xc1〉 - 2)) - xc4: (〈0;xc2〉 + 1) - xc5: (〈0;xc2〉 + 2) - xd1: ((〈0;xd2〉 & 8)|(〈0;xd4〉 & 9)|(〈0;xd5〉 & 9)) - xd2: (〈0;xd3〉 + 2) - xd3: (6 & (〈0;xd1〉 - 2)) - xd4: (〈0;xd2〉 + 1) - xd5: (〈0;xd2〉 + 2) - xd1: 8 - xe1: ((〈0;xe2〉 & 8)|(〈0;xe4〉 & 9)|(〈0;xe5〉 & 9)) - xe2: (〈0;xe3〉 + 2) - xe3: (6 & (〈0;xe1〉 - 2)) - xe4: (〈0;xe2〉 + 1) - xe5: (〈0;xe2〉 + 2) - xe1: 9 - xf1: ((〈0;xf2〉 & 8)|(〈0;xf4〉 & 9)) - xf2: (〈0;xf3〉 + 2) - xf3: ((6 & (〈0;xf1〉 - 2))|(〈0;xf4〉 & 9)) - xf4: (〈0;xf2〉 + 2) - z1: ((〈0;z2〉 + 1)|(〈0;z3〉 + 5)) - z2: (〈0;z3〉 + 2) - z3: (〈0;z1〉 - 3) - z3: 8 -} diff --git a/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar b/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar --- a/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar +++ b/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar @@ -100,35 +100,3 @@ Disjuncts: 17 NumCloseIDs: 14 --- out/compile -- ---- in.cue -{ - xa1: ((〈0;xa2〉 & 8)|*(〈0;xa4〉 & 9)) - xa2: (〈0;xa3〉 + 2) - xa3: (6 & (〈0;xa1〉 - 2)) - xa4: (〈0;xa2〉 + 2) - xb1: (*(〈0;xb2〉 & 8)|(〈0;xb4〉 & 9)) - xb2: (〈0;xb3〉 + 2) - xb3: (*(6 & (〈0;xb1〉 - 2))|(〈0;xb4〉 & 9)) - xb4: (〈0;xb2〉 + 2) - xc1: (*(〈0;xc2〉 & 8)|(〈0;xc4〉 & 9)|(〈0;xc5〉 & 9)) - xc2: (〈0;xc3〉 + 2) - xc3: (6 & (〈0;xc1〉 - 2)) - xc4: (〈0;xc2〉 + 1) - xc5: (〈0;xc2〉 + 2) - xd1: (*(〈0;xd2〉 & 8)|(〈0;xd4〉 & 9)|(〈0;xd5〉 & 9)) - xd2: (〈0;xd3〉 + 2) - xd3: (6 & (〈0;xd1〉 - 2)) - xd4: (〈0;xd2〉 + 1) - xd5: (〈0;xd2〉 + 2) - xe1: (*(〈0;xe2〉 & 8)|(〈0;xe4〉 & 9)|(〈0;xe5〉 & 9)) - xe2: (〈0;xe3〉 + 2) - xe3: (6 & (〈0;xe1〉 - 2)) - xe4: (〈0;xe2〉 + 1) - xe5: (〈0;xe2〉 + 2) - xe1: 9 - z1: (*(〈0;z2〉 + 1)|(〈0;z3〉 + 5)) - z2: (〈0;z3〉 + 2) - z3: (〈0;z1〉 - 3) - z3: 8 -} diff --git a/cue/testdata/cycle/builtins.txtar b/cue/testdata/cycle/builtins.txtar --- a/cue/testdata/cycle/builtins.txtar +++ b/cue/testdata/cycle/builtins.txtar @@ -469,413 +469,3 @@ [structural_cycle] selfCycle.yamlValidatePartial.x.y: invalid value "{}" (does not satisfy encoding/yaml.ValidatePartial): structural cycle: ./yamlcycle.cue:60:8 ./yamlcycle.cue:61:8 --- out/compile -- ---- cycle.cue -{ - noCycle: { - t1: { - 〈0;_s〉 - _s: { - #x: matchN(1, [ - 〈2;_s〉, - ]) - #x: {} - } - } - } - issue3649: { - noCycle: { - t1: { - data: 〈0;#c〉 - data: { - a: { - b: "foo" - } - } - #c: { - b?: string - a?: matchN(1, [ - 〈2;#c〉, - ]) - } - } - } - } - issue3649: { - noCycle: { - t2: { - x: 〈0;c〉 - x: { - y: { - a: { - d: { - b: "foo" - } - } - } - } - c: { - b?: string - y: { - a?: matchN(1, [ - { - d: 〈4;c〉 - }, - ]) - } - } - } - } - } - issue3649: { - cycle: { - t1: { - data: 〈0;#c〉 - data: { - a: { - b: "foo" - } - } - #c: { - b: string - a: matchN(1, [ - 〈2;#c〉, - ]) - } - } - } - } - issue4037: { - cycle: { - _intlike: matchN(1, [ - 〈import;strconv〉.Atoi(〈1〉), - ]) - f: ("1233" & 〈0;_intlike〉) - } - } -} ---- in.cue -{ - builtinCyclePerm: { - X: "mod.test" - Y: { - #components: 〈import;regexp〉.FindNamedSubmatch("^(?P[[:alnum:].]+)$", 〈1;X〉) - host: 〈0;#components〉.host - } - X: 〈0;Y〉.host - } -} ---- issue3634.cue -{ - issue3634: { - full: { - #Schema: { - required?: [ - ...string, - ] - properties?: { - [string]: (null|〈2;#Schema〉) - } - } - out: len(([ - ...〈1;#Schema〉, - ] & 〈import;list〉.Repeat([ - { - 〈2;#Schema〉 - properties: { - foo: { - required: [ - "bar", - "baz", - ] - } - } - }, - ], 3))) - } - } - issue3634: { - reduced: { - #D: { - b?: int - a?: 〈1;#D〉 - } - out: len((〈0;#D〉 & 〈import;list〉.Repeat([ - (〈1;#D〉 & { - a: { - b: 1 - } - }), - ], 1)[0])) - } - } -} ---- issue3743.cue -{ - issue3743: { - #transform: { - in: _ - out: [ - if false { - 〈2;out〉 - }, - 〈1;in〉, - ] - } - docs: [ - (〈1;#transform〉 & { - in: "x" - }).out, - ] - out: 〈import;"encoding/yaml"〉.MarshalStream(〈0;docs〉) - } -} ---- jsoncycle.cue -{ - jsonCycle: { - t1: { - x: { - y: 〈import;"encoding/json"〉.Validate(〈1;x〉) - } - x: { - y: "{}" - } - } - } -} ---- listmatchncycle.cue -{ - listMatchN: { - structCycle: { - x: { - y: 〈import;list〉.MatchN(1, 〈1;x〉) - } - x: { - y: [ - {}, - ] - } - } - } - listMatchN: { - ok: { - x: { - y?: 〈import;list〉.MatchN(1, 〈1;x〉) - } - z: 〈0;x〉 - z: { - y: [ - {}, - ] - } - } - } -} ---- matchn.cue -{ - issue3410: { - 〈0;_s〉 - _s: { - #x: matchN(1, [ - 〈2;_s〉, - [ - ...〈3;_s〉, - ], - ]) - } - } - issue3420: { - matches1: { - #S: matchN(1, [ - _, - _|_(explicit error (_|_ literal) in source), - ]) - s: 2 - } - } - issue3443: { - matchIf: { - #S: 〈1;matchIf〉({ - x?: "b" - }, { - n?: (〈1;#S〉 & (int|{})) - }, _) - } - noCycle: { - #S: matchN(1, [ - { - n?: (〈2;#S〉 & (int|{})) - }, - ]) - noHang: { - s: 〈1;#S〉 - s: { - n: { - n: _ - } - } - } - } - noCycle2: { - #S: matchN(1, [ - { - n?: (int|〈2;#S〉) - }, - ]) - } - cycle1: { - #S: matchN(1, [ - { - n: 〈2;#S〉 - }, - ]) - ok: { - s: 〈1;#S〉 - s: _ - } - cycle: { - s: 〈1;#S〉 - s: { - n: { - n: _ - } - } - } - } - cycle2: { - fail: { - #S: (matchN(1, [ - { - n: 〈2;#S〉 - }, - ]) & { - n: { - n: { - n: _ - } - } - }) - } - } - } - issue3633: { - final: { - data: ({} & 〈0;#s〉) - #s: matchN(1, [ - matchN(1, [ - { - a!: _ - }, - ]), - ]) - } - } - issue3842: { - reduced: { - #recursive: [ - ...(matchIf({ - source?: "multi" - }, 〈1;#recursive〉, _) & { - source?: string - }), - ] - } - } -} ---- yamlcycle.cue -{ - yamlNoCycle: { - #c: { - b?: string - a?: 〈import;"encoding/yaml"〉.Validate(〈1;#c〉) - } - data: 〈0;#c〉 - data: { - a: "{a: \"b: foo\"}" - } - } - selfCycle: { - t1: { - c: matchN(1, [ - { - d: 〈2;c〉 - }, - ]) - c: { - d: {} - } - } - } - selfCycle: { - t2: { - c: matchN(1, [ - { - d: 〈2;c〉 - }, - ]) - c: {} - } - } - selfCycle: { - yamlVal: { - t1: { - x: { - y: 〈import;"encoding/yaml"〉.Validate(〈1;x〉) - } - x: { - y: "{}" - } - } - } - } - selfCycle: { - yamlVal: { - t2: { - x: { - y: 〈import;"encoding/yaml"〉.Validate(〈1;x〉) - } - x: { - y: "{}" - } - x: { - y: 〈import;"encoding/yaml"〉.Validate(〈1;x〉) - } - x: { - y: "{}" - } - } - } - } - selfCycle: { - yamlFun: { - t1: { - x: { - y?: 〈import;"encoding/yaml"〉.Validate("{}", 〈1;x〉) - } - } - } - } - selfCycle: { - yamlFun: { - t2: { - z: (〈0;x〉 & _|_(no sharing)) - z: { - y: "{}" - } - x: { - y: 〈import;"encoding/yaml"〉.Validate("{}", 〈1;x〉) - } - } - } - } - selfCycle: { - yamlValidatePartial: { - x: { - y: 〈import;"encoding/yaml"〉.ValidatePartial(〈1;x〉) - } - x: { - y: "{}" - } - } - } -} diff --git a/cue/testdata/cycle/chain.txtar b/cue/testdata/cycle/chain.txtar --- a/cue/testdata/cycle/chain.txtar +++ b/cue/testdata/cycle/chain.txtar @@ -512,298 +512,3 @@ Notifications: 3 NumCloseIDs: 1501 --- out/compile -- ---- in.cue -{ - chain: { - t1: { - #maxiter: 2 - x: 〈0;a〉.x0 - a: { - for k, _ in [ - 0, - 1, - ] { - "x\(〈1;k〉)": (〈3;#DepthF〉 & { - #in: 〈4;a〉["x\((〈2;k〉 + 1))"] - }).#out - } - } - a: { - x2: null - } - #DepthF: { - #in: _ - #out: {} - } - } - } - chain: { - t2: { - p1: { - X: 1 - for _, v in 〈import;list〉.Concat([ - [ - 0, - 〈2;X〉, - ], - [], - ]) { - x: { - "x\(〈2;v〉)": {} - } - } - x: _ - 〈0;x〉.x0 - } - } - } - chain: { - t2: { - p2: { - for _, v in 〈import;list〉.Concat([ - [ - 0, - 〈2;X〉, - ], - [], - ]) { - x: { - "x\(〈2;v〉)": {} - } - } - x: _ - 〈0;x〉.x0 - X: 1 - } - } - } - chain: { - t3: { - p1: { - X: 1 - for _, v in 〈import;list〉.Range(0, 〈0;X〉, 1) { - x: { - "x\(〈2;v〉)": {} - } - } - x: _ - 〈0;x〉.x0 - } - } - } - chain: { - t3: { - p1: { - for _, v in 〈import;list〉.Range(0, 〈0;X〉, 1) { - x: { - "x\(〈2;v〉)": {} - } - } - x: _ - 〈0;x〉.x0 - X: 1 - } - } - } -} ---- issue2052.cue -{ - issue2052: { - reduced: { - t1: { - A: { - a: _ - } - Depth: { - #maxiter: 1 - if (〈import;math〉.Abs(〈0;#maxiter〉) == 1) { - funcs: { - "\(0)": 〈3;A〉 - } - } - funcs: {} - 〈0;funcs〉["0"] - } - } - } - } - issue2052: { - reduced: { - t2: { - A: { - a: _ - } - Depth: { - maxiter: 1 - for k, v in 〈import;list〉.Range(0, 〈0;maxiter〉, 1) { - funcs: { - "\(0)": 〈4;A〉 - } - } - funcs: {} - 〈0;funcs〉["0"] - } - } - } - } - issue2052: { - medium: { - t1: { - #Depth: { - #maxiter: 4 - for k, v in 〈import;list〉.Range(0, 〈0;#maxiter〉, 1) { - #funcs: { - "\(〈2;k〉)": (〈4;#DepthF〉 & { - #next: 〈2;#funcs〉["\((〈3;k〉 + 1))"] - }).#func - } - } - #funcs: { - "\(〈1;#maxiter〉)": null - } - 〈0;#funcs〉["0"] - } - #DepthF: { - #next: _ - #func: { - #in: _ - #basic: (string|null) - out: { - if ((〈1;#in〉 & 〈1;#basic〉) != _|_(explicit error (_|_ literal) in source)) { - 1 - } - if ((〈1;#in〉 & 〈1;#basic〉) == _|_(explicit error (_|_ literal) in source)) { - (〈import;list〉.Max([ - for k, v in 〈3;#in〉 { - (〈6;#next〉 & { - #in: 〈2;v〉 - }).out - }, - ]) + 1) - } - } - } - } - tree: "bar" - d: (〈0;#Depth〉 & { - #in: 〈1;tree〉 - }) - } - } - } - issue2052: { - medium: { - t2: { - #Depth: { - #maxiter: 4 - for k, v in 〈import;list〉.Range(0, 〈0;#maxiter〉, 1) { - #funcs: { - "\(〈2;k〉)": (〈4;#DepthF〉 & { - #next: 〈2;#funcs〉["\((〈3;k〉 + 1))"] - }).#func - } - } - #funcs: { - for k, v in 〈import;list〉.Range(0, 〈1;#maxiter〉, 1) { - "\(〈1;k〉)": (〈4;#DepthF〉 & { - #next: 〈4;#funcs〉["\((〈2;k〉 + 1))"] - }).#func - } - } - #funcs: { - "\(〈1;#maxiter〉)": null - } - 〈0;#funcs〉["0"] - } - #DepthF: { - #next: _ - #func: { - #in: _ - #basic: (string|null) - out: { - if ((〈1;#in〉 & 〈1;#basic〉) != _|_(explicit error (_|_ literal) in source)) { - 1 - } - if ((〈1;#in〉 & 〈1;#basic〉) == _|_(explicit error (_|_ literal) in source)) { - (〈import;list〉.Max([ - for k, v in 〈3;#in〉 { - (〈6;#next〉 & { - #in: 〈2;v〉 - }).out - }, - ]) + 1) - } - } - } - } - tree: "bar" - d: (〈0;#Depth〉 & { - #in: 〈1;tree〉 - }) - } - } - } - issue2052: { - full: { - #RecurseN: { - #maxiter: (&(int, >=0)|*4) - #funcFactory: { - #next: _ - #func: _ - } - for k, v in 〈import;list〉.Range(0, 〈0;#maxiter〉, 1) { - #funcs: { - "\(〈2;k〉)": (〈3;#funcFactory〉 & { - #next: 〈2;#funcs〉["\((〈3;k〉 + 1))"] - }).#func - } - } - #funcs: { - "\(〈1;#maxiter〉)": null - } - 〈0;#funcs〉["0"] - } - #DepthF: { - #next: _ - #func: { - #in: _ - #basic: (int|number|string|bytes|null) - out: { - if ((〈1;#in〉 & 〈1;#basic〉) != _|_(explicit error (_|_ literal) in source)) { - 1 - } - if ((〈1;#in〉 & 〈1;#basic〉) == _|_(explicit error (_|_ literal) in source)) { - let depths#1 = [ - for k, v in 〈3;#in〉 { - (〈6;#next〉 & { - #in: 〈2;v〉 - }).out - }, - ] - (〈import;list〉.Max(〈0;let depths#1〉) + 1) - } - } - } - } - #Depth: (〈0;#RecurseN〉 & { - #maxiter: 11 - #funcFactory: 〈1;#DepthF〉 - }) - tree: { - a: { - foo: "bar" - a: { - b: { - c: "d" - } - } - } - cow: "moo" - } - d: (〈0;#Depth〉 & { - #in: 〈1;tree〉 - }) - } - } -} diff --git a/cue/testdata/cycle/compbottom.txtar b/cue/testdata/cycle/compbottom.txtar --- a/cue/testdata/cycle/compbottom.txtar +++ b/cue/testdata/cycle/compbottom.txtar @@ -114,49 +114,3 @@ Disjuncts: 0 NumCloseIDs: 72 --- out/compile -- ---- in.cue -{ - simple: { - #message: "^(message: (?P.*))?$" - p1: { - X: "message: hello" - #aux: { - if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { - message: "" - } - if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { - message: ("message: " + 〈2;Y〉.message) - } - } - Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) - X: 〈0;#aux〉.message - } - } - medium: { - #userHostPort: "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$" - p1: { - Y: { - userinfo: "user" - host: "mod.test" - } - X: (〈0;#X〉.userinfo + 〈0;#X〉.host) - #X: { - if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { - userinfo: "" - } - if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { - userinfo: (〈2;Y〉.userinfo + "@") - } - host: 〈1;Y〉.host - } - Y: { - if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { - userinfo: 〈2;#Y〉.userinfo - } - host: 〈1;#Y〉.host - } - #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) - } - } -} diff --git a/cue/testdata/cycle/compbottom2.txtar b/cue/testdata/cycle/compbottom2.txtar --- a/cue/testdata/cycle/compbottom2.txtar +++ b/cue/testdata/cycle/compbottom2.txtar @@ -417,444 +417,3 @@ Notifications: 2 NumCloseIDs: 112 --- out/compile -- ---- in.cue -{ - self: { - fail: { - a: { - if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { - b: 1 - } - } - } - isConcreteFail: { - t1: { - a: { - if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { - b: 1 - } - b: int - } - } - } - isConcreteFail: { - t2: { - a: { - if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { - b: 1 - } - b?: int - } - } - } - isNotConcrete: { - t1: { - a: { - if (〈1;a〉.b != _|_(explicit error (_|_ literal) in source)) { - b: 1 - } - b: int - } - } - } - isNotConcrete: { - t2: { - a: { - if (〈1;a〉.b != _|_(explicit error (_|_ literal) in source)) { - b: 1 - } - b?: int - } - } - } - } -} ---- issue3836.cue -{ - issue3836: { - hidden: { - _Value: { - foo?: _ - bar?: _ - if ((〈0;foo〉|〈0;bar〉) == _|_(explicit error (_|_ literal) in source)) { - bar: { - type: "bar" - } - } - out: [ - if (〈1;bar〉 != _|_(explicit error (_|_ literal) in source)) { - "bar is set" - }, - ] - } - 〈0;_Value〉.out - } - } - issue3836: { - exposed: { - foo?: _ - bar?: _ - if ((〈0;foo〉|〈0;bar〉) == _|_(explicit error (_|_ literal) in source)) { - bar: { - type: "bar" - } - } - out: [ - if (〈1;bar〉 != _|_(explicit error (_|_ literal) in source)) { - "bar is set" - }, - ] - } - } -} ---- issue3838.cue -{ - issue3838: { - #T: { - subject: { - in: { - opt?: { - foo: int - } - } - out: [ - if (〈1;in〉.opt != _|_(explicit error (_|_ literal) in source)) { - 〈2;in〉.opt.foo - }, - 0, - ][0] - } - _test: { - assert: { - pass: bool - } - assert: ({ - notOk: _ - pass: false - }|{ - invoke: _ - res: 〈2;subject〉.out - pass: true - }) - } - results: 〈0;_test〉.assert.pass - } - (〈0;#T〉 & { - _test: { - assert: { - invoke: "foo" - } - } - }).results - } -} ---- mutual.cue -{ - mutual: { - noConflicts: { - a: { - if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { - new: "" - } - } - b: { - if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { - new: "" - } - } - } - mutualCycleFail: { - b: { - if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { - foo: "" - } - } - a: { - if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { - bar: "" - } - } - } - brokenCycleSuccess: { - a: { - if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { - foo: "" - } - } - b: { - if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { - bar: "" - } - } - a: { - bar: "" - } - } - allowOneDirectionalDependency: { - p1: { - a: { - if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { - bar: "" - } - } - b: { - if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { - new: "" - } - } - } - p2: { - a: { - if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { - new: "" - } - } - b: { - if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { - foo: "" - } - } - } - } - oneDirectionalBrokenConflictSuccess: { - b: { - foo: "" - } - a: { - if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { - bar: "" - } - } - b: { - if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { - new: "" - } - } - } - } -} ---- mutualsamestruct.cue -{ - sameStruct: { - chainSuccess: { - a: { - raises?: {} - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - ret?: {} - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - foo: { - a: 1 - } - } - } - } - chainSuccess: { - b: { - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - foo: { - a: 1 - } - } - raises?: {} - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - ret?: {} - } - } - cycleFail: { - t1: { - p1: { - raises?: {} - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - ret?: {} - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - raises: { - a: 1 - } - } - } - } - } - cycleFail: { - t1: { - p2: { - ret?: {} - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - raises: { - a: 1 - } - } - raises?: {} - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - } - } - } - cycleFail: { - t2: { - p1: { - raises: {} - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - ret: {} - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - raises: { - a: 1 - } - } - } - } - } - cycleFail: { - t2: { - p2: { - ret: {} - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - raises: { - a: 1 - } - } - raises: {} - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - } - } - } - cycleFail: { - t3: { - p1: { - raises: _ - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - ret: _ - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - raises: { - a: 1 - } - } - } - } - } - cycleFail: { - t3: { - p2: { - ret: _ - if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { - raises: { - a: 1 - } - } - raises: _ - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret: { - a: 1 - } - } - } - } - } - defCloseSuccess: { - #Example: { - raises?: { - runtime?: string - } - if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { - ret?: _ - } - } - expr: (〈0;#Example〉 & { - ret: 2 - }) - } - } -} ---- nestedchain.cue -{ - nestedChain: { - cycleFail: { - if (〈0;#E〉.x != _|_(explicit error (_|_ literal) in source)) { - #E: { - y: true - } - } - if (〈0;#E〉.y == _|_(explicit error (_|_ literal) in source)) { - #E: { - x: true - } - } - #E: { - [_]: bool - } - } - brokenCycleSuccess: { - if (〈0;#E〉.x != _|_(explicit error (_|_ literal) in source)) { - #E: { - y: true - } - } - if (〈0;#E〉.y == _|_(explicit error (_|_ literal) in source)) { - #E: { - x: true - } - } - #E: { - [_]: bool - } - #E: { - x: true - } - } - doubleAddfail: { - if (〈0;#E〉.x == _|_(explicit error (_|_ literal) in source)) { - #E: { - y: true - } - } - if (〈0;#E〉.y == _|_(explicit error (_|_ literal) in source)) { - #E: { - x: true - } - } - #E: { - [_]: bool - } - } - trippleSuccess: { - if (〈0;#E〉.x != _|_(explicit error (_|_ literal) in source)) { - #E: { - y: true - } - } - if (〈0;#E〉.y != _|_(explicit error (_|_ literal) in source)) { - z: true - } - #E: { - x: true - } - } - } -} diff --git a/cue/testdata/cycle/compbottomnofinal.txtar b/cue/testdata/cycle/compbottomnofinal.txtar --- a/cue/testdata/cycle/compbottomnofinal.txtar +++ b/cue/testdata/cycle/compbottomnofinal.txtar @@ -186,87 +186,3 @@ Notifications: 1 NumCloseIDs: 76 --- out/compile -- ---- in.cue -{ - minimal: { - a: { - if (〈1;b〉.port == _|_(explicit error (_|_ literal) in source)) { - port: "" - } - } - b: { - if (〈1;a〉.port == _|_(explicit error (_|_ literal) in source)) { - port: "" - } - } - } - small: { - #userHostPort: "^(:(?P\\d+))?$" - p1: { - #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;#X〉.port) - #X: { - if (〈1;#Y〉.port == _|_(explicit error (_|_ literal) in source)) { - port: "" - } - if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) { - port: (":" + 〈import;strconv〉.FormatInt(〈2;#Y〉.port, 10)) - } - } - } - } - medium: { - #userHostPort: "^(:(?P\\d+))?$" - p1: { - #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;#X〉.port) - Y: { - if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) { - port: 〈import;strconv〉.Atoi(〈2;#Y〉.port) - } - } - #X: { - if (〈1;Y〉.port == _|_(explicit error (_|_ literal) in source)) { - port: "" - } - if (〈1;Y〉.port != _|_(explicit error (_|_ literal) in source)) { - port: (":" + 〈import;strconv〉.FormatInt(〈2;Y〉.port, 10)) - } - } - } - } - large: { - #userHostPort: "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)(:(?P\\d+))?$" - p1: { - Y: { - userinfo: "user" - host: "mod.test" - } - X: ((〈0;#X〉.userinfo + 〈0;#X〉.host) + 〈0;#X〉.port) - #X: { - if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { - userinfo: "" - } - if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { - userinfo: (〈2;Y〉.userinfo + "@") - } - host: 〈1;Y〉.host - if (〈1;Y〉.port == _|_(explicit error (_|_ literal) in source)) { - port: "" - } - if (〈1;Y〉.port != _|_(explicit error (_|_ literal) in source)) { - port: (":" + 〈import;strconv〉.FormatInt(〈2;Y〉.port, 10)) - } - } - Y: { - if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { - userinfo: 〈2;#Y〉.userinfo - } - host: 〈1;#Y〉.host - if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) { - port: 〈import;strconv〉.Atoi(〈2;#Y〉.port) - } - } - #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) - } - } -} diff --git a/cue/testdata/cycle/comprehension.txtar b/cue/testdata/cycle/comprehension.txtar --- a/cue/testdata/cycle/comprehension.txtar +++ b/cue/testdata/cycle/comprehension.txtar @@ -829,732 +829,3 @@ ./issue2229.cue:16:28 structural cycle: ./issue2229.cue:16:24 --- out/compile -- ---- in.cue -{ - A: { - a: { - parent: "" - children: [ - for k, v in 〈3;A〉 if (〈0;v〉.parent == 〈0;k〉) { - 〈1;k〉 - }, - ] - } - b: { - parent: "a" - children: [ - for k, v in 〈3;A〉 if (〈0;v〉.parent == 〈0;k〉) { - 〈1;k〉 - }, - ] - } - } - B: { - a: { - parent: "" - children: [ - for k, v in 〈3;B〉 for _, w in 〈0;v〉.children { - 〈2;k〉 - }, - ] - } - } - Issue486: { - A: { - a: { - parent: "" - children: [ - ...string, - ] - } - b: { - parent: "a" - children: [ - ...string, - ] - } - c: { - parent: "b" - children: [ - ...string, - ] - } - } - A: { - [string]: { - children: [ - for k, v in 〈3;A〉 if (〈0;v〉.parent == 〈3;-〉) { - 〈1;k〉 - }, - ] - } - } - } - issue1666: { - #E: { - f1: { - [string]: (〈2;#E〉|[ - ...〈3;#E〉, - ]) - } - f2: { - [string]: { - t: 〈3;#E〉 - } - } - } - _e: 〈0;#E〉 - _e: { - f2: { - a: _ - } - } - e: (〈0;_e〉 & { - f1: { - for fk, s in 〈2;_e〉.f2 { - 〈1;fk〉: 〈1;s〉.t - } - } - }) - } - issue779: { - X: 〈0;Y〉.message - STATE: { - for k, v in 〈1;Y〉 { - if (〈1;k〉 != "message") { - "\(〈2;k〉)": 〈2;v〉 - } - } - } - Y: (〈0;STATE〉 & { - message: 〈1;X〉 - }) - X: "test" - STATE: { - code: 101 - } - } - selfReferential: { - T1: { - S: { - d: "bar" - } - T: { - e: { - S: { - a: "foo" - } - } - } - for s, v in 〈0;S〉 for t, _ in 〈1;T〉 { - T: { - 〈2;t〉: { - S: { - 〈5;s〉: 〈5;v〉 - } - } - } - } - } - } - selfReferential: { - list: { - panels: [ - for i, _ in 〈1;panels〉 { - id: 〈1;i〉 - }, - ] - panels: [ - {}, - {}, - {}, - ] - } - } - selfReferential: { - insertionError: { - A: { - foo: 1 - for _, x in 〈1;A〉 { - "foo3": 1 - } - } - } - } - selfReferential: { - acrossOr: { - t1: { - p1: { - o: (〈0;#Output〉 & { - retry: { - reject: "ok" - } - }) - #AllOutputs: { - reject: string - resource: string - retry: 〈1;#Output〉 - } - #Output: or([ - for name, config in 〈1;#AllOutputs〉 { - 〈1;name〉: 〈1;config〉 - }, - ]) - } - } - } - } - selfReferential: { - acrossOr: { - t1: { - p2: { - #Output: or([ - for name, config in 〈1;#AllOutputs〉 { - 〈1;name〉: 〈1;config〉 - }, - ]) - o: (〈0;#Output〉 & { - retry: { - reject: "ok" - } - }) - #AllOutputs: { - reject: string - resource: string - retry: 〈1;#Output〉 - } - } - } - } - } - selfReferential: { - acrossOr: { - t1: { - p3: { - #Output: or([ - for name, config in 〈1;#AllOutputs〉 { - 〈1;name〉: 〈1;config〉 - }, - ]) - #AllOutputs: { - reject: string - resource: string - retry: 〈1;#Output〉 - } - o: (〈0;#Output〉 & { - retry: { - reject: "ok" - } - }) - } - } - } - } - selfReferential: { - acrossOr: { - t2: { - p1: { - d: or([ - for x, y in 〈1;#A〉 { - 〈1;y〉 - }, - ]) - o: (〈0;d〉 & { - b: 2 - }) - #A: { - d1: int - d2: string - d3: { - b: 〈2;d〉 - } - } - } - } - } - } - selfReferential: { - acrossOr: { - t2: { - p2: { - o: (〈0;d〉 & { - b: 2 - }) - d: or([ - for x, y in 〈1;#A〉 { - 〈1;y〉 - }, - ]) - #A: { - d1: int - d2: string - d3: { - b: 〈2;d〉 - } - } - } - } - } - } - selfReferential: { - acrossOr: { - t2: { - p3: { - o: (〈0;d〉 & { - b: 2 - }) - #A: { - d1: int - d2: string - d3: { - b: 〈2;d〉 - } - } - d: or([ - for x, y in 〈1;#A〉 { - 〈1;y〉 - }, - ]) - } - } - } - } - issue1881: { - p1: { - o: (〈0;#Output〉 & { - retry: { - output: { - reject: "ok" - } - } - }) - #AllOutputs: { - reject: string - resource: string - retry: { - output: 〈2;#Output〉 - } - } - #Output: or([ - for name, config in 〈1;#AllOutputs〉 { - 〈1;name〉: 〈1;config〉 - }, - ]) - } - } - issue1881: { - p2: { - #AllOutputs: { - reject: string - resource: string - retry: { - output: 〈2;#Output〉 - } - } - o: (〈0;#Output〉 & { - retry: { - output: { - reject: "ok" - } - } - }) - #Output: or([ - for name, config in 〈1;#AllOutputs〉 { - 〈1;name〉: 〈1;config〉 - }, - ]) - } - } - issue1881: { - p3: { - #AllOutputs: { - reject: string - resource: string - retry: { - output: 〈2;#Output〉 - } - } - #Output: or([ - for name, config in 〈1;#AllOutputs〉 { - 〈1;name〉: 〈1;config〉 - }, - ]) - o: (〈0;#Output〉 & { - retry: { - output: { - reject: "ok" - } - } - }) - } - } - siblingInsertion: { - t1: { - p1: { - D: { - logging: _ - } - deployment: _ - for k, v in 〈0;deployment〉 for k1, v2 in 〈0;v〉.env2 { - deployment: { - 〈3;k〉: { - env: { - 〈4;k1〉: 〈4;v2〉 - } - } - } - } - for id, v in 〈0;D〉 { - deployment: { - 〈2;id〉: { - env2: { - ENV: "True" - } - } - } - } - } - } - } - siblingInsertion: { - t1: { - p2: { - D: { - logging: _ - } - deployment: _ - for id, v in 〈0;D〉 { - deployment: { - 〈2;id〉: { - env2: { - ENV: "True" - } - } - } - } - for k, v in 〈0;deployment〉 for k1, v2 in 〈0;v〉.env2 { - deployment: { - 〈3;k〉: { - env: { - 〈4;k1〉: 〈4;v2〉 - } - } - } - } - } - } - } - siblingInsertion: { - t2: { - p1: { - D: { - logging: _ - } - deployment: _ - for k, v in 〈0;deployment〉 { - for k1, v2 in 〈1;v〉.env2 { - deployment: { - 〈4;k〉: { - env: { - 〈4;k1〉: 〈4;v2〉 - } - } - } - } - } - for id, v in 〈0;D〉 { - deployment: { - 〈2;id〉: { - env2: { - ENV: "True" - } - } - } - } - } - } - } - siblingInsertion: { - t2: { - p2: { - D: { - logging: _ - } - deployment: _ - for k, v in 〈0;deployment〉 { - for k1, v2 in 〈1;v〉.env2 { - deployment: { - 〈4;k〉: { - env: { - 〈4;k1〉: 〈4;v2〉 - } - } - } - } - } - for id, v in 〈0;D〉 { - deployment: { - 〈2;id〉: { - env2: { - ENV: "True" - } - } - } - } - } - } - } - selfReferential: { - fail: { - a: {} - b: (〈0;a〉.x != "") - if 〈0;b〉 {} - } - } - issue2367: { - a: _ - for _, x in [ - 〈1;a〉, - ] { - a: 〈1;x〉 - } - } - issue2310: { - original: { - #s: { - #_1: string - #_2: string - #_3: string - 〈import;strings〉.Replace(〈0;#_1〉, 〈0;#_2〉, 〈0;#_3〉, -1) - } - #sub: { - #a: string - _#X: [ - 〈1;#a〉, - for _, i in 〈import;list〉.Range(0, len(〈2;#subs〉), 1) { - (〈4;#subs〉[〈1;i〉] & { - #_1: 〈4;_#X〉[〈2;i〉] - _ - }) - }, - ] - 〈0;_#X〉[(len(〈0;_#X〉) - 1)] - } - res: (〈0;#sub〉 & { - #a: "aaa" - _ - }) - #subs: [ - (〈1;#s〉 & { - #_2: "a" - #_3: "b" - _ - }), - (〈1;#s〉 & { - #_2: "c" - #_3: "d" - _ - }), - (〈1;#s〉 & { - #_2: "e" - #_3: "f" - _ - }), - ] - } - } - issue2310: { - reduced: { - res: { - 〈0;#X〉[3] - #X: [ - "X", - for i, _ in 〈2;#subs〉 { - 〈4;#s〉 - #str: 〈3;#X〉[〈1;i〉] - }, - ] - } - #s: { - #str: string - (〈0;#str〉 + "a") - } - #subs: [ - 0, - 1, - 2, - ] - } - } -} ---- issue2229.cue -{ - issue2229: { - full_ok: { - build: (bool|*true) - test: (bool|*true) - make: [ - for k, v in 〈2〉 if ((〈0;v〉 & true) != _|_(explicit error (_|_ literal) in source)) { - 〈1;k〉 - }, - ] - } - } - issue2229: { - reduced_fail: { - x: true - y: [ - for _, v in 〈2〉 if (〈0;v〉 & true) { - _ - }, - ] - } - } -} ---- issue2405.cue -{ - issue2405: { - #Copy: ({ - param: { - ... - } - result: { - for k, v in 〈1;param〉 { - 〈1;k〉: (〈4;#Copy〉 & { - param: 〈2;v〉 - }).result - } - } - }|{ - param: [ - ..., - ] - result: [ - for _, v in 〈1;param〉 { - (〈4;#Copy〉 & { - param: 〈2;v〉 - }).result - }, - ] - }|{ - param: number - result: 〈0;param〉 - }) - foo: 〈0;#Copy〉 - foo: { - param: { - a: [ - { - b: 134 - }, - ] - } - } - } -} ---- issue3903.cue -{ - issue3903: { - reduced: { - s1: 〈0;#Schema〉 - s1: { - _deps: [ - 〈2;#Schema〉, - ] - } - #Schema: { - _deps: [ - ..., - ] - objs: [ - for _, dep in 〈1;_deps〉 for _, obj in (〈0;dep〉 & {}).objs { - 〈1;obj〉 - }, - ] - } - } - } - issue3903: { - full: { - s1: (〈0;#Schema〉 & { - _deps: [ - 〈2;s2〉, - ] - _local: [ - "s1 local", - ] - }) - s2: (〈0;#Schema〉 & { - _local: [ - "s2 local", - ] - }) - #Schema: { - _local: [ - ...string, - ] - _deps: [ - ..., - ] - objs: [ - for _, obj in 〈1;_local〉 { - 〈1;obj〉 - }, - for _, dep in 〈1;_deps〉 for _, obj in (〈0;dep〉 & {}).objs { - 〈1;obj〉 - }, - ] - } - } - } -} ---- issue3941.cue -{ - issue3941: { - full: { - #Metadata: { - name: string - } - #Resource: { - metadata: 〈1;#Metadata〉 - } - out: { - _metadata: { - name: "foo" - } - resource: { - [string]: { - [string]: 〈3;#Resource〉 - } - } - _names: [ - 〈1;_metadata〉.name, - ] - for _, name in 〈0;_names〉 { - resource: { - level1: { - 〈3;name〉: { - metadata: 〈5;_metadata〉 - } - } - } - } - } - } - } -} ---- issue4100.cue -{ - issue4100: { - a: { - let l#1 = [ - 0, - ] - if (〈0;let l#1〉 != _|_(explicit error (_|_ literal) in source)) { - 〈1;let l#1〉[:] - } - } - for _, _ in 〈0;a〉 {} - } -} diff --git a/cue/testdata/cycle/constraints.txtar b/cue/testdata/cycle/constraints.txtar --- a/cue/testdata/cycle/constraints.txtar +++ b/cue/testdata/cycle/constraints.txtar @@ -306,389 +306,6 @@ appear as ~(...) references rather than expanded structs (cyclicRing.t1.D.a, selfTriggerCycle.t1.a, brokenRing.t1.p1.D.a?, brokenRing.t1.p2.T.b). v2 additionally reports cyclicRing.t1.D.a.b as structural cycle. --- out/compile -- ---- in.cue -{ - safeCycle: { - simple2: { - y: { - [string]: { - b: { - c: 〈3;y〉 - } - } - } - x: 〈0;y〉 - x: { - c: 〈1;y〉 - } - } - } - safeCycle: { - long1: { - y: { - [string]: { - b: 〈2;y〉 - } - } - x: 〈0;y〉 - x: { - c: { - b: { - e: { - b: { - c: _ - } - } - } - } - } - } - } - safeCycle: { - long2: { - a: { - [string]: { - b: 〈2;a〉 - } - } - x: 〈0;a〉 - x: { - c: { - b: { - c: { - b: { - c: {} - } - } - } - } - } - } - } - noCyclePattern: _ - noCyclePattern: { - t1: { - #D: { - [string]: 〈1;#D〉 - } - a: {} - [string]: 〈0;#D〉 - [string]: { - b: { - c: {} - } - } - } - } - noCyclePattern: { - t2: { - #D: { - [string]: { - x: 〈2;#D〉 - } - } - a: {} - [string]: 〈0;#D〉 - [string]: { - b: { - x: { - c: {} - } - } - } - } - } - noCyclePattern: { - t3: { - _D: { - [string]: 〈1;_T〉 - } - _T: { - x: 〈1;_D〉 - } - [string]: 〈0;_D〉 - [string]: { - b: { - x: { - c: {} - } - } - } - a: {} - } - } - noCyclePattern: { - t4: { - _D: { - [string]: { - x: 〈2;_T〉 - } - } - _T: { - y: 〈1;_D〉 - } - [string]: 〈0;_D〉 - [string]: { - b: { - x: {} - } - } - a: {} - } - } - noCyclePattern: { - t5: { - _D: { - [string]: { - x: 〈2;_T〉 - } - } - _T: { - y: 〈1;_D〉 - } - [string]: 〈0;_D〉 - [string]: { - b: { - x: { - y: { - c: { - x: {} - } - } - } - } - } - a: {} - } - } - noCyclePattern: { - t6: { - #D: { - [string]: 〈1;#E〉 - } - #E: { - t: 〈1;#T〉 - } - #T: { - { - object: 〈2;#S〉 - } - } - #S: { - y: 〈1;#D〉 - } - [string]: { - x: 〈1;#D〉 - } - [string]: { - x: { - r: { - t: { - object: { - y: { - foo: { - t: { - object: {} - } - } - } - } - } - } - } - } - bar: {} - } - } - noCancelSelfInvoke: { - t1: { - y: { - [string]: { - b: 〈2;y〉 - } - } - x: 〈0;y〉 - x: { - c: 〈1;x〉 - } - } - } - selfTriggerCycle: _ - selfTriggerCycle: { - t1: { - a: 〈0;#T〉 - #T: { - [string]: 〈1;#T〉 - b: {} - } - } - } - selfTriggerCycle: { - t2: { - #T: { - [string]: { - a: 〈1〉 - } - } - b: 〈0;#T〉 - b: { - c: {} - } - } - } - selfTriggerCycle: { - long1: { - a: { - [string]: { - b: 〈2;a〉 - } - } - a: { - c: { - b: { - c: { - b: { - c: {} - } - } - } - } - } - } - } - selfTriggerCycle: { - issue1503: { - a: (〈0;#T〉 & { - a: { - one: { - link: { - a: { - two: {} - } - } - } - } - }) - #T: { - a: { - [string]: { - link: 〈3;#T〉 - } - } - a: { - b: {} - } - } - } - } - mutuallyTriggeringCycle: { - t1: { - y: { - [string]: { - b: 〈2;y〉 - } - } - x: 〈0;y〉 - x: { - c: 〈1;y〉 - } - } - } -} ---- issue3476.cue -{ - issue3476: { - #a: (〈0;#b〉 & { - x: _ - }).x - #b: { - x?: 〈0;#c〉 - #c: { - [string]: 〈1;#c〉 - } - } - } -} ---- issue3509.cue -{ - issue3509: { - out: (〈0;#job〉.step & "foo") - #job: (〈0;#Workflow〉 & { - job: _ - }).job - #Workflow: { - job: { - step: string - } - #matrixConfig: ([ - ...〈1;#matrixConfig〉, - ]|string) - matrix?: { - [string]: [ - ...〈2;#matrixConfig〉, - ] - } - } - } -} ---- ring.cue -{ - brokenRing: { - t1: { - p1: { - D: { - a?: 〈1;T〉 - } - T: { - b: 〈1;D〉 - } - } - p2: { - T: { - b: 〈1;D〉 - } - D: { - a?: 〈1;T〉 - } - } - } - } - brokenRing: { - t2: { - p1: { - D: { - [string]: 〈1;T〉 - } - T: { - b: 〈1;D〉 - } - } - } - } - brokenRing: { - t2: { - p2: { - T: { - b: 〈1;D〉 - } - D: { - [string]: 〈1;T〉 - } - } - } - } - cyclicRing: { - t1: { - D: { - a: 〈1;T〉 - } - T: { - b: 〈1;D〉 - } - } - } -} -- out/eval/stats -- Leaks: 4 Freed: 190 diff --git a/cue/testdata/cycle/cycle_with_bounds.txtar b/cue/testdata/cycle/cycle_with_bounds.txtar --- a/cue/testdata/cycle/cycle_with_bounds.txtar +++ b/cue/testdata/cycle/cycle_with_bounds.txtar @@ -8,17 +8,6 @@ bar: 0 @test(eq, 0) foo: 1 @test(eq, 1) --- out/compile -- ---- in.cue -{ - #Value: int - foo: 〈0;#Value〉 - foo: !=〈0;bar〉 - bar: 〈0;#Value〉 - bar: !=〈0;foo〉 - bar: 0 - foo: 1 -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/cycle/disjunction.txtar b/cue/testdata/cycle/disjunction.txtar --- a/cue/testdata/cycle/disjunction.txtar +++ b/cue/testdata/cycle/disjunction.txtar @@ -109,71 +109,3 @@ Disjuncts: 73 NumCloseIDs: 20 --- out/compile -- ---- in.cue -{ - cycle: { - a: 〈1;cycle〉 - } - r1a: (〈0;cycle〉|int) - r1b: (int|〈0;cycle〉) - r2a: (〈0;cycle〉|1) - r2b: (1|〈0;cycle〉) - r3a: (〈0;cycle〉|null) - r3b: (null|〈0;cycle〉) - r4a: (〈0;cycle〉|{}) - r4b: ({}|〈0;cycle〉) - r5a: (〈0;cycle〉|[]) - r5b: ([]|〈0;cycle〉) - s1a: { - x: (〈1;s1a〉|int) - } - s1b: { - x: (int|〈1;s1b〉) - } - s2a: { - x: (〈1;s2a〉|1) - } - s2b: { - x: (1|〈1;s2b〉) - } - s3a: { - x: (〈1;s3a〉|null) - } - s3b: { - x: (null|〈1;s3b〉) - } - s4a: { - x: (〈1;s4a〉|{}) - } - s4b: { - x: ({}|〈1;s4b〉) - } - s5a: { - x: (〈1;s5a〉|[]) - } - s5b: { - x: ([]|〈1;s5b〉) - } -} ---- issue3042.cue -{ - issue3042: { - #foo: =~"^foo" - #nesting: (string|{ - name?: 〈1;#foo〉 - [string]: 〈1;#nesting〉 - }|[ - ...〈1;#nesting〉, - ]) - data: (〈0;#nesting〉 & { - secret: { - infra: [ - { - name: "bar1" - }, - ] - } - }) - } -} diff --git a/cue/testdata/cycle/evaluate.txtar b/cue/testdata/cycle/evaluate.txtar --- a/cue/testdata/cycle/evaluate.txtar +++ b/cue/testdata/cycle/evaluate.txtar @@ -202,148 +202,3 @@ Disjuncts: 4 NumCloseIDs: 47 --- out/compile -- ---- in.cue -{ - letCycleOK: { - t1: { - b: 〈0;c〉 - let X#1 = 〈0;b〉 - c: 〈0;let X#1〉 - } - } - letCycleOK: { - t2: { - a: { - b: 1 - let X#2 = 〈1;a〉 - c: 〈0;let X#2〉.b - } - } - } - letCycleFail: { - t1: { - a: { - b: 1 - let X#3 = 〈1;a〉 - c: 〈0;let X#3〉 - } - } - } - letCycleFail: { - t2: { - a: { - let X#4 = 〈1;a〉 - if (〈0;let X#4〉 == _|_(explicit error (_|_ literal) in source)) {} - x: { - y: "" - } - } - } - } - listCycleOK: { - a: 〈0;b〉 - b: and([ - 〈1;c〉, - ]) - c: 〈0;a〉 - } - disjunctionCycle: { - a: 〈0;b〉 - b: and((1|〈0;c〉)) - c: 〈0;a〉 - } - forCycle: { - #A: { - a: 〈1;#B〉 - } - #B: or([ - for _, x in 〈1;#A〉 { - b: 〈1;x〉 - }, - ]) - } - letCycleWithAnd: { - a: { - d: 〈1;b〉 - } - b: and([ - for _, x in 〈1;a〉 let y = 〈0;x〉 { - 〈1;y〉 - }, - ]) - c: 〈0;a〉 - } - closeCycle: { - a: 〈0;b〉 - b: close({ - d: 〈1;c〉 - }) - c: 〈0;a〉 - } - structCycle: { - a: 〈0;b〉 - b: and([ - { - d: 〈2;c〉 - }, - ]) - c: 〈0;a〉 - } - embedCycle: { - a: 〈0;b〉 - b: close({ - 〈1;c〉 - }) - c: 〈0;a〉 - } - listAddCycle: { - a: 〈0;b〉 - b: 〈import;list〉.Concat([ - [ - 〈2;c〉, - ], - [ - 〈2;c〉, - ], - ]) - c: 〈0;a〉 - } - listMulCycle: { - a: 〈0;b〉 - b: 〈import;list〉.Repeat([ - { - a: { - b: 〈3;c〉 - } - }, - ], 3) - c: 〈0;a〉 - } - closeFail: { - #T: { - [_]: _ - } - #T: close({ - a: string - }) - x: 〈0;#T〉 - x: { - b: "foo" - } - } - printCycle: { - a: { - X: 〈1;a〉 - if 〈0;X〉 {} - } - } -} ---- self.cue -{ - issue3978: { - a: { - if (〈1〉.missing != _|_(explicit error (_|_ literal) in source)) {} - } - } -} diff --git a/cue/testdata/cycle/expression.txtar b/cue/testdata/cycle/expression.txtar --- a/cue/testdata/cycle/expression.txtar +++ b/cue/testdata/cycle/expression.txtar @@ -121,106 +121,3 @@ Disjuncts: 0 NumCloseIDs: 34 --- out/compile -- ---- in.cue -{ - t1: { - a: { - a1: (〈0;a0〉 + 2) - b1: (〈0;a1〉 - 2) - a0: 〈0;X〉 - X: 〈0;b1〉 - X: 5.0 - } - } - t1: { - b: { - X: 5.0 - a1: (〈0;a0〉 + 2) - b1: (〈0;a1〉 - 2) - a0: 〈0;X〉 - X: 〈0;b1〉 - } - } - t1: { - c: { - a1: (〈0;a0〉 + 2) - b1: (〈0;a1〉 - 2) - X: 5.0 - a0: 〈0;X〉 - X: 〈0;b1〉 - } - } - t1: { - c: { - b1: (〈0;a1〉 - 2) - a1: (〈0;a0〉 + 2) - X: 5.0 - a0: 〈0;X〉 - X: 〈0;b1〉 - } - } - t1: { - c: { - b1: (〈0;a1〉 - 2) - X: 5.0 - a1: (〈0;a0〉 + 2) - a0: 〈0;X〉 - X: 〈0;b1〉 - } - } - t1total: { - for _, v in 〈1;t1〉 { - 〈1;v〉 - } - } - t2: { - a: { - a0: 〈0;X〉 - a1: (〈0;a0〉 * 2) - Y: 〈0;a1〉 - b0: 〈0;Y〉 - b1: (〈0;b0〉 / 2) - X: 〈0;b1〉 - X: 5.0 - } - } - t2: { - b: { - b0: 〈0;Y〉 - b1: (〈0;b0〉 / 2) - X: 〈0;b1〉 - a0: 〈0;X〉 - a1: (〈0;a0〉 * 2) - Y: 〈0;a1〉 - X: 5.0 - } - } - t2: { - c: { - b0: 〈0;Y〉 - b1: (〈0;b0〉 / 2) - X: 〈0;b1〉 - X: 5.0 - a0: 〈0;X〉 - a1: (〈0;a0〉 * 2) - Y: 〈0;a1〉 - } - } - t2: { - d: { - b0: 〈0;Y〉 - b1: (〈0;b0〉 / 2) - X: 〈0;b1〉 - a0: 〈0;X〉 - a1: (〈0;a0〉 * 2) - Y: 〈0;a1〉 - X: 5.0 - } - } - t2total: { - for _, v in 〈1;t2〉 { - 〈1;v〉 - } - } -} diff --git a/cue/testdata/cycle/freeze.txtar b/cue/testdata/cycle/freeze.txtar --- a/cue/testdata/cycle/freeze.txtar +++ b/cue/testdata/cycle/freeze.txtar @@ -125,147 +125,3 @@ Disjuncts: 0 NumCloseIDs: 54 --- out/compile -- ---- comprehension.cue -{ - comprehension: { - t1: _ - } - comprehension: { - t1: { - ok: { - x: { - y: {} - } - for _, _ in 〈0;x〉 { - if true { - x: { - z: { - a: {} - } - } - } - } - if true { - if true { - x: { - z: { - a: {} - } - } - } - } - } - } - } - comprehension: { - t2: { - err: { - a: { - x: 1 - for k, v in 〈1;a〉 { - (〈1;k〉 + "q"): 〈1;v〉 - } - } - } - } - } - comprehension: { - t3: { - err: { - a: { - x: 1 - } - b: { - y: 1 - } - a: { - for k, v in 〈1;b〉 { - (〈1;k〉 + "q"): 〈1;v〉 - } - } - b: { - for k, v in 〈1;a〉 { - 〈1;k〉: 〈1;v〉 - } - } - } - } - } - comprehension: { - t4: { - ok: { - x: { - y: {} - } - for _, _ in 〈0;x〉 { - if true { - x: { - y: { - a: {} - } - } - } - } - } - } - } - comprehension: { - moreSpecific: { - ok: { - a: { - x: int - for k, v in 〈1;a〉 { - 〈1;k〉: 1 - } - } - } - } - } - comprehension: { - moreSpecific: { - err: { - a: { - x: { - y: 1 - } - for k, v in 〈1;a〉 if (len(〈0;v〉) > 0) { - 〈1;k〉: { - z: 1 - } - } - } - } - } - } -} ---- in.cue -{ - freezing: { - t1: { - ok: { - #a: { - x: "a" - } - len(〈0;#a〉) - } - } - } -} ---- issue3178.cue -{ - issue3178: { - input: [ - "Value", - ] - output: { - ... - } - for _, name in 〈0;input〉 { - output: { - "\(〈2;name〉)": true - } - } - for name, v in 〈0;output〉 {} - } -} diff --git a/cue/testdata/cycle/inline.txtar b/cue/testdata/cycle/inline.txtar --- a/cue/testdata/cycle/inline.txtar +++ b/cue/testdata/cycle/inline.txtar @@ -261,249 +261,3 @@ Disjuncts: 0 NumCloseIDs: 202 --- out/compile -- ---- inlineexpand.cue -{ - inlined: { - X: { - input: { - a: _ - } - output: 〈0;input〉.a - } - root: { - a: (〈1;X〉 & { - input: 〈2;root〉 - }).output - } - } - expanded1: { - hasCycle: { - X: { - input: { - a: _ - } - output: 〈0;input〉.a - } - root: { - a: 〈0;_a〉.output - _a: (〈1;X〉 & { - input: 〈2;root〉 - }) - } - } - } - expanded2: { - noCycle: { - X: { - input: { - a: _ - } - output: 〈0;input〉.a - } - root: { - a: 〈1;_a〉.output - } - _a: (〈0;X〉 & { - input: 〈1;root〉 - }) - } - } - issue3731: { - reduced: { - #lookup: { - input: { - ... - } - output: [ - for _, v in 〈1;input〉 if (〈0;v〉.show != _|_(explicit error (_|_ literal) in source)) { - 〈1;v〉 - }, - ] - } - root: { - self: { - show: true - } - others: (〈1;#lookup〉 & { - input: 〈2;root〉 - }).output - } - } - } - issue3731: { - expanded: { - #lookup: { - input: { - ... - } - output: [ - for _, v in 〈1;input〉 if (〈0;v〉.show != _|_(explicit error (_|_ literal) in source)) { - 〈1;v〉 - }, - ] - } - root: { - self: { - show: true - } - others: 〈0;_others〉.output - _others: (〈1;#lookup〉 & { - input: 〈2;root〉 - }) - } - } - } - issue3731: { - full: { - #Workspace: { - workspaceA?: {} - workspaceB?: {} - } - #AccountConfig: { - workspaces: 〈1;#Workspace〉 - siblings?: [ - ...string, - ] - } - #AccountConfigSub1: { - 〈1;#AccountConfig〉 - workspaces: { - workspaceA: {} - } - } - #AccountConfigSub2: { - 〈1;#AccountConfig〉 - workspaces: { - workspaceB: {} - } - } - tree: { - env1: { - region1: { - "env1-r1-account-sub1": 〈3;#AccountConfigSub1〉 - "env1-r1-account-sub2-1": 〈3;#AccountConfigSub2〉 - } - } - } - #lookupSiblings: { - envtree: { - ... - } - out: [ - for region, v in 〈1;envtree〉 for account, config in 〈0;v〉 if (〈0;config〉.workspaces.workspaceB != _|_(explicit error (_|_ literal) in source)) { - 〈1;account〉 - }, - ] - } - tree: { - env1: { - [_]: { - [_]: (〈3;#AccountConfig〉 & { - siblings: (〈4;#lookupSiblings〉 & { - envtree: 〈4;env1〉 - }).out - }) - } - } - } - } - } -} ---- x.cue -{ - inline: { - small: { - f: { - n: int - out: (〈1;f〉 & { - n: (〈1;n〉 - 1) - }).out - } - } - } - inline: { - medium: { - f2: (〈0;f〉 & { - n: 2 - }).out - fRec: { - nn: int - out: (〈1;f〉 & { - n: 〈1;nn〉 - }).out - } - f: { - n: int - out: (〈1;fRec〉 & { - nn: (〈1;n〉 - 1) - }).out - } - } - } - inline: { - patterns: { - f: { - n: (〈1;f〉 & { - n: {} - }).n - } - f: { - n: {} - } - [string]: { - n: {} - } - f: { - [string]: {} - } - f: {} - } - } - inline: { - acrossFields: { - fail1: { - f: { - in: number - out: (〈0;in〉 + 1) - } - k00: 0 - k10: (〈0;f〉 & { - in: 〈1;k00〉 - }).out - k20: (〈0;f〉 & { - in: 〈1;k10〉 - }).out - k30: (〈0;f〉 & { - in: 〈1;k20〉 - }).out - k10: (〈0;f〉 & { - in: 〈1;k30〉 - }).out - } - } - } - inline: { - acrossFields: { - ok1: { - f: { - in: number - out: 〈0;in〉 - } - k00: 0 - k10: (〈0;f〉 & { - in: 〈1;k00〉 - }).out - k20: (〈0;f〉 & { - in: 〈1;k10〉 - }).out - k30: (〈0;f〉 & { - in: 〈1;k20〉 - }).out - k10: (〈0;f〉 & { - in: 〈1;k30〉 - }).out - } - } - } -} diff --git a/cue/testdata/cycle/inline_non_recursive.txtar b/cue/testdata/cycle/inline_non_recursive.txtar --- a/cue/testdata/cycle/inline_non_recursive.txtar +++ b/cue/testdata/cycle/inline_non_recursive.txtar @@ -188,187 +188,3 @@ Notifications: 1 NumCloseIDs: 169 --- out/compile -- ---- in.cue -{ - ok1: { - f: { - in: number - out: 〈0;in〉 - } - k00: 0 - k10: (〈0;f〉 & { - in: 〈1;k00〉 - }).out - k20: (〈0;f〉 & { - in: 〈1;k10〉 - }).out - k30: (〈0;f〉 & { - in: 〈1;k20〉 - }).out - } - ok2: { - f: { - in: number - out: 〈0;in〉 - } - k00: 0 - k10: { - (〈1;f〉 & { - in: 〈2;k00〉 - }).out - } - k20: { - (〈1;f〉 & { - in: 〈2;k10〉 - }).out - } - k30: { - (〈1;f〉 & { - in: 〈2;k20〉 - }).out - } - } - ok3: { - f: { - in: number - out: 〈0;in〉 - } - k00: 0 - k10: { - close((〈1;f〉 & { - in: 〈2;k00〉 - })).out - } - k20: { - close((〈1;f〉 & { - in: 〈2;k10〉 - })).out - } - k30: { - close((〈1;f〉 & { - in: 〈2;k20〉 - })).out - } - } - ok4: { - f: { - in: number - out: 〈0;in〉 - } - k00: 0 - k10: { - out: { - (〈2;f〉 & { - in: 〈3;k00〉 - }).out - } - }.out - k20: { - out: { - (〈2;f〉 & { - in: 〈3;k10〉 - }).out - } - }.out - k30: { - out: { - (〈2;f〉 & { - in: 〈3;k20〉 - }).out - } - }.out - } - issue1708: { - #add10: { - in: number - a10: { - i: 〈1;in〉 - o: (〈0;i〉 + 10) - } - out: 〈0;a10〉.o - } - k00: 0 - k10: (〈0;#add10〉 & { - in: 〈1;k00〉 - }).out - k20: (〈0;#add10〉 & { - in: 〈1;k10〉 - }).out - k30: (〈0;#add10〉 & { - in: 〈1;k20〉 - }).out - } -} ---- issue3182.cue -{ - issue3182: { - first: { - t1: { - x: { - a: 〈1;x〉 - }.a - } - } - first: { - t2: { - x: { - a: { - b: 〈2;x〉 - } - }.a - } - } - second: { - { - t: 〈1;x〉 - }.t.y - x: { - y: { - x: { - y: { - a: 1 - } - } - } - } - } - third: { - { - p: { - x: 〈1;p〉 - y: 1 - } - }.p.x.y - } - } -} ---- select.cue -{ - select: { - direct: { - #Step: (〈0;#Job〉 & { - opt: _ - }).opt - #Job: matchN(1, [ - 〈3;#NormalJob〉, - ]) - } - } - select: { - indirect: { - #Step: 〈0;#Job〉.opt - #Job: (matchN(1, [ - 〈3;#NormalJob〉, - ]) & { - opt: _ - }) - } - } - #NormalJob: { - req!: int - opt?: { - run?: string - } - } -} diff --git a/cue/testdata/cycle/issue1960.txtar b/cue/testdata/cycle/issue1960.txtar --- a/cue/testdata/cycle/issue1960.txtar +++ b/cue/testdata/cycle/issue1960.txtar @@ -77,101 +77,3 @@ -- out/evalalpha -- t2.z.hello: unreferenced alias or let clause q: ./issue1960.cue:18:3 --- out/compile -- -t2.z.hello: unreferenced alias or let clause q: - ./issue1960.cue:18:3 ---- issue1960.cue -{ - t1: { - z: { - blah: { - s: [ - for _, z in 〈3;z〉 {}, - ] - } - } - z: { - hello: { - for _, x in 〈0;p〉 {} - let q#1 = 〈2;z〉.blah - p: 〈0;let q#1〉.r - p: { - t: 1 - } - } - } - } - t2: { - z: { - blah: { - s: [ - for _, z in 〈3;z〉 {}, - ] - } - } - z: { - hello: { - for _, x in 〈0;p〉 {} - let q#2 = 〈2;z〉.blah - p: { - t: 1 - } - } - } - } - t3: { - #z: { - n: string - p: { - t: "e" - } - s: [ - ...string, - ] - _p: { - n: string - e: { - p: {} - } - } - r: 〈0;_p〉[〈0;p〉.t] - for _, pl in 〈0;r〉.p { - if 〈1;pl〉.blah {} - } - } - #i: { - 〈1;#z〉 - t: "i" - r: { - e: {} - } - } - #c: { - 〈1;#z〉 - t: "c" - n: string - } - z: { - [=~"^b"]: (〈1;#i〉 & { - s: [ - for n, z in 〈3;z〉 if (〈0;z〉.t == "c") if (〈0;z〉.n == 〈3;-〉) { - 〈1;n〉 - }, - ] - }) - } - z: { - [=~"^h"]: (〈1;#c〉 & { - n: string - let q#3 = 〈2;z〉[〈0;n〉] - p: 〈0;let q#3〉.r.e - }) - } - z: { - blah: {} - hello: { - n: "blah" - } - } - } -} diff --git a/cue/testdata/cycle/issue241.txtar b/cue/testdata/cycle/issue241.txtar --- a/cue/testdata/cycle/issue241.txtar +++ b/cue/testdata/cycle/issue241.txtar @@ -44,38 +44,3 @@ Disjuncts: 32 NumCloseIDs: 4 --- out/compile -- ---- in.cue -{ - #Value: (0|1) - foo: 〈0;#Value〉 - foo: !=〈0;bar〉 - bar: 〈0;#Value〉 - bar: !=〈0;foo〉 - #Value: (0|1) - Foo: 〈0;#Value〉 - Foo: !=〈0;Bar〉 - Bar: 〈0;#Value〉 - Bar: !=〈0;Foo〉 - Bar: 0 - cell: { - a: (0|1) - } - cell: { - a: !=〈1;cell〉.b - } - cell: { - b: (0|1) - } - cell: { - b: !=〈1;cell〉.a - } - cell: { - a: 0 - } - cell: { - b: _ - } - a: 〈0;cell〉.a - b: 〈0;cell〉.b -} diff --git a/cue/testdata/cycle/issue242.txtar b/cue/testdata/cycle/issue242.txtar --- a/cue/testdata/cycle/issue242.txtar +++ b/cue/testdata/cycle/issue242.txtar @@ -108,201 +108,3 @@ Disjuncts: 52 NumCloseIDs: 8 --- out/compile -- ---- in.cue -{ - #size: 2 - #CellValue: (0|1|2|3) - cell: { - "0": { - "0": 〈2;#CellValue〉 - } - } - cell: { - "0": { - "0": !=〈2;cell〉["0"]["1"] - } - } - cell: { - "0": { - "0": !=〈2;cell〉["1"]["0"] - } - } - cell: { - "0": { - "0": !=〈2;cell〉["1"]["1"] - } - } - cell: { - "0": { - "1": 〈2;#CellValue〉 - } - } - cell: { - "0": { - "1": !=〈2;cell〉["0"]["0"] - } - } - cell: { - "0": { - "1": !=〈2;cell〉["1"]["0"] - } - } - cell: { - "0": { - "1": !=〈2;cell〉["1"]["1"] - } - } - cell: { - "1": { - "0": 〈2;#CellValue〉 - } - } - cell: { - "1": { - "0": !=〈2;cell〉["0"]["0"] - } - } - cell: { - "1": { - "0": !=〈2;cell〉["0"]["1"] - } - } - cell: { - "1": { - "0": !=〈2;cell〉["1"]["1"] - } - } - cell: { - "1": { - "1": 〈2;#CellValue〉 - } - } - cell: { - "1": { - "1": !=〈2;cell〉["0"]["0"] - } - } - cell: { - "1": { - "1": !=〈2;cell〉["0"]["1"] - } - } - cell: { - "1": { - "1": !=〈2;cell〉["1"]["0"] - } - } - cell: { - "0": { - "0": 0 - } - } - cell: { - "0": { - "1": 1 - } - } - cell: { - "1": { - "0": 2 - } - } - cell: { - "1": { - "1": 3 - } - } - cell2: { - a: (0|1) - } - cell2: { - a: !=〈1;cell2〉.b - } - cell2: { - b: (0|1) - } - cell2: { - b: !=〈1;cell2〉.a - } - cell2: { - a: _ - } - cell2: { - b: 1 - } - cell3: { - a: (0|1) - } - cell3: { - a: !=〈1;cell3〉.b - } - cell3: { - b: (0|1) - } - cell3: { - b: !=〈1;cell3〉.a - } - cell3: { - a: 0 - } - cell3: { - b: _ - } - cell4: { - a: (0|1) - } - cell4: { - a: !=〈1;cell4〉.b - } - cell4: { - b: (0|1) - } - cell4: { - b: !=〈1;cell4〉.a - } - cell4: { - b: _ - } - cell4: { - a: 0 - } - cell5: { - b: (0|1) - } - cell5: { - b: !=〈1;cell5〉.a - } - cell5: { - a: (0|1) - } - cell5: { - a: !=〈1;cell5〉.b - } - cell5: { - b: _ - } - cell5: { - a: 0 - } - a: 〈0;#CellValue〉 - a: !=〈0;b〉 - a: !=〈0;c〉 - a: !=〈0;d〉 - b: 〈0;#CellValue〉 - b: !=〈0;a〉 - b: !=〈0;c〉 - b: !=〈0;d〉 - c: 〈0;#CellValue〉 - c: !=〈0;a〉 - c: !=〈0;b〉 - c: !=〈0;d〉 - d: 〈0;#CellValue〉 - d: !=〈0;a〉 - d: !=〈0;b〉 - d: !=〈0;c〉 - a: 0 - b: 1 - c: 2 - d: 3 -} diff --git a/cue/testdata/cycle/issue2526.txtar b/cue/testdata/cycle/issue2526.txtar --- a/cue/testdata/cycle/issue2526.txtar +++ b/cue/testdata/cycle/issue2526.txtar @@ -10,12 +10,3 @@ @test(err, code=structural_cycle, path=x.y, contains="structural cycle", pos=[]) -- out/errors.txt -- [structural_cycle] x.y: structural cycle --- out/compile -- ---- in.cue -{ - 〈0;x〉 - x: { - 〈0;y〉 - y: 〈1;x〉 - } -} \ No newline at end of file diff --git a/cue/testdata/cycle/issue306.txtar b/cue/testdata/cycle/issue306.txtar --- a/cue/testdata/cycle/issue306.txtar +++ b/cue/testdata/cycle/issue306.txtar @@ -18,13 +18,3 @@ Unifications: 5 Conjuncts: 5 Disjuncts: 0 --- out/compile -- ---- in.cue -{ - a: 12 - #Controller: { - settings: { - controller: 〈2;#Controller〉 - } - } -} diff --git a/cue/testdata/cycle/issue3118.txtar b/cue/testdata/cycle/issue3118.txtar --- a/cue/testdata/cycle/issue3118.txtar +++ b/cue/testdata/cycle/issue3118.txtar @@ -112,35 +112,3 @@ Disjuncts: 0 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - #TimeSpan: { - start: float - duration: float - end: float - start: (〈0;end〉 - 〈0;duration〉) - duration: (〈0;end〉 - 〈0;start〉) - end: (〈0;start〉 + 〈0;duration〉) - start: <=〈0;end〉 - } - examples: { - [string]: 〈1;#TimeSpan〉 - } - examples: { - eg1: { - start: 10.0 - duration: 2.1 - } - } - examples: { - eg2: { - start: 10.0 - } - } - examples: { - eg3: { - end: 10.0 - } - } -} diff --git a/cue/testdata/cycle/issue3527.txtar b/cue/testdata/cycle/issue3527.txtar --- a/cue/testdata/cycle/issue3527.txtar +++ b/cue/testdata/cycle/issue3527.txtar @@ -237,35 +237,3 @@ self?: (_){ _ } } } --- out/compile -- ---- in.cue -{ - _taxPayer(:p): { - self: {} - } - let sam#1 = { - taxPayer: 〈1;_taxPayer(:p)〉 - } - assert: { - invoke: 〈1;let sam#1〉 - invoke: _ - res: (〈1;subject〉 & { - in: 〈1;invoke〉 - }) - } - subject: { - in: 〈1;#ReturnData〉 - _computed(:p): (〈1;#computeF1040〉 & { - in: 〈1;in〉 - }) - } - #computeF1040: { - in: 〈1;#ReturnData〉 - } - #ReturnData: { - taxPayer?: 〈1;#TaxPayer〉 - } - #TaxPayer: { - self?: _ - } -} diff --git a/cue/testdata/cycle/issue3570.txtar b/cue/testdata/cycle/issue3570.txtar --- a/cue/testdata/cycle/issue3570.txtar +++ b/cue/testdata/cycle/issue3570.txtar @@ -16,12 +16,3 @@ ./in.cue:2:1 2 errors in empty disjunction:: ./in.cue:3:6 --- out/compile -- ---- in.cue -{ - foo: { - foo: (25|44) - } - 〈0;foo〉 - foo: 〈0;foo〉 -} diff --git a/cue/testdata/cycle/issue3571.txtar b/cue/testdata/cycle/issue3571.txtar --- a/cue/testdata/cycle/issue3571.txtar +++ b/cue/testdata/cycle/issue3571.txtar @@ -76,51 +76,3 @@ with their full #T contents, while v3 represents them as ~(simplified.#T). Similarly in `issue3571.a`, v2 expands `in` and `#in` fully, while v3 uses shared references like ~(issue3571.a.in.g.#in) and ~(issue3571.a.#in.g.#in). --- out/compile -- ---- in.cue -{ - simplified: { - 〈0;#T〉 - in: _ - x: 〈0;#T〉 - x: { - x: 〈1;#T〉 - } - #T: { - in: 〈0;x〉 - x: _ - } - } - issue3571: { - a: 〈0;#T〉 - a: { - in: { - f: true - } - } - a: { - #in: { - g: 〈2;#T〉 - g: { - #in: { - f: 〈4;#T〉 - } - } - g: { - #in: { - f: { - #in: { - x: true - } - } - } - } - f?: _ - } - } - #T: { - in: 〈0;#in〉 - #in: _ - } - } -} diff --git a/cue/testdata/cycle/issue3827.txtar b/cue/testdata/cycle/issue3827.txtar --- a/cue/testdata/cycle/issue3827.txtar +++ b/cue/testdata/cycle/issue3827.txtar @@ -50,41 +50,3 @@ Notifications: 2 NumCloseIDs: 7 --- out/compile -- ---- in.cue -{ - reduced: { - A: { - b: (〈1;A〉.c & {}).x - } - A: (null|{ - c: { - x: 1 - } - }) - } - full: { - out: (〈0;#Workflow〉.#Step & { - uses: "actions/upload-artifact@v3" - with: { - name: "foo" - path: "bar" - } - }) - #Workflow: { - #Step: (〈1;#Workflow〉.steps & { - x: {} - }).x - } - #Workflow: (null|{ - steps: { - [string]: { - uses?: string - with?: { - [string]: string - } - } - } - }) - } -} diff --git a/cue/testdata/cycle/issue4203.txtar b/cue/testdata/cycle/issue4203.txtar --- a/cue/testdata/cycle/issue4203.txtar +++ b/cue/testdata/cycle/issue4203.txtar @@ -49,43 +49,3 @@ variable: "{kind1}" }] }) --- out/compile -- ---- in.cue -{ - _listBuilder: { - kind: "kind1" - _deps: [ - ..., - ] - _kindJoin: { - _objs: [ - ..., - ] - _out: 〈import;strings〉.Join([ - for _, d in 〈1;_objs〉 { - 〈1;d〉.kind - }, - ], ",") - } - _depKinds: { - (〈1;_kindJoin〉 & { - _objs: 〈2;_deps〉 - }) - }._out - variable: (("{" + 〈0;_depKinds〉) + "}") - } - output: _ - if true { - _input: [ - { - 〈3;_listBuilder〉 - _deps: [ - { - 〈5;_listBuilder〉 - }, - ] - }, - ] - output: 〈0;_input〉[0].variable - } -} diff --git a/cue/testdata/cycle/issue4210.txtar b/cue/testdata/cycle/issue4210.txtar --- a/cue/testdata/cycle/issue4210.txtar +++ b/cue/testdata/cycle/issue4210.txtar @@ -27,46 +27,3 @@ [structural_cycle] t2.a.b.c.c: structural cycle [structural_cycle] t3.a.b.c.d.d: structural cycle [structural_cycle] t4.x.y.z.z: structural cycle --- out/compile -- ---- in.cue -{ - t1: { - a: { - b: { - c: { - 〈3;a〉 - }.b - } - } - } - t2: { - a: { - b: { - c: { - (〈3;a〉 & _) - }.b - } - } - } - t3: { - a: { - b: { - c: { - d: { - 〈4;a〉.b - }.c - } - } - } - } - t4: { - x: { - y: { - z: { - 〈3;a〉 - }.y - } - } - a: 〈0;x〉 - } -} diff --git a/cue/testdata/cycle/issue4228.txtar b/cue/testdata/cycle/issue4228.txtar --- a/cue/testdata/cycle/issue4228.txtar +++ b/cue/testdata/cycle/issue4228.txtar @@ -378,104 +378,3 @@ } } -- out/eval -- --- out/compile -- ---- export.cue -{ - let _globalScope#1 = 〈1〉 - #export: { - #entries: [ - ..., - ] - manifests: [ - for _, _entry in 〈1;#entries〉 for _, _ns in 〈0;_entry(:main)〉 for _kind, _objs in 〈0;_ns(:main)〉 for _name, _obj in 〈0;_objs(:main)〉 { - 〈1;_obj(:main)〉.k8s - }, - ] - yamlStream: 〈import;"encoding/yaml"〉.MarshalStream(〈0;manifests〉) - } - #manifests: { - 〈1;#export〉 - #entries: [ - 〈2;let _globalScope#1〉, - ] - }.yamlStream -} ---- in.cue -{ - _objectBase(:main): { - name: string - k8s: { - metadata: { - name: 〈3〉.name - } - } - } - _namespacedResource(:main): { - 〈1;_objectBase(:main)〉 - namespace: string - k8s: { - metadata: { - namespace: 〈3〉.namespace - } - } - } - _allValuesAreValidStructs(:main): { - [_]: { - (*{}|error("<- invalid \(〈1〉)")) - } - } - _setTypeMeta(:main): { - #apiVersion!: string - #kind!: string - #template: { - k8s: { - apiVersion: 〈3〉.#apiVersion - kind: 〈3〉.#kind - } - } - } - _resourceKindsBase(:main): { - _base(:main)!: _ - [string]: { - 〈2;_allValuesAreValidStructs(:main)〉 - 〈2;_setTypeMeta(:main)〉 - #resourceSchema: _ - #template: { - 〈2;_base(:main)〉 - k8s: 〈1;#resourceSchema〉 - } - [_]: 〈0;#template〉 - } - } - _namespacedResourceKinds(:main): { - 〈1;_resourceKindsBase(:main)〉 - _base(:main): 〈1;_namespacedResource(:main)〉 - [string]: { - [string]: { - namespace: string - } - } - app: { - #apiVersion: "argoproj.io/v1alpha1" - #kind: "Application" - #resourceSchema: { - spec?: { - revisionHistoryLimit?: int - } - } - #template: { - revisionHistoryLimit: (*3|int) - k8s: { - spec: { - revisionHistoryLimit: 〈3〉.revisionHistoryLimit - } - } - } - } - } - argocd: (〈0;_namespacedResourceKinds(:main)〉 & { - app: { - apps: {} - } - }) -} diff --git a/cue/testdata/cycle/issue4230.txtar b/cue/testdata/cycle/issue4230.txtar --- a/cue/testdata/cycle/issue4230.txtar +++ b/cue/testdata/cycle/issue4230.txtar @@ -21,28 +21,3 @@ regions: ["west"] app: {region: "west"} }) --- out/compile -- ---- in.cue -{ - #transform: { - _input: { - ... - } - _output: [ - if (〈1;_input〉.app != _|_(explicit error (_|_ literal) in source)) { - 〈2;_input〉.app.region - }, - ] - } - x: { - regions: (〈1;#transform〉 & { - _input: 〈2〉 - })._output - app: { - region: (or([ - "west", - "east", - ]) & "west") - } - } -} diff --git a/cue/testdata/cycle/issue4244.txtar b/cue/testdata/cycle/issue4244.txtar --- a/cue/testdata/cycle/issue4244.txtar +++ b/cue/testdata/cycle/issue4244.txtar @@ -48,23 +48,3 @@ [incomplete] #schema.prefix: invalid interpolation: index out of range [0] with length 1: ./in.cue:8:12 ./in.cue:5:22 --- out/compile -- ---- in.cue -{ - #schema: { - let splits#1 = 〈import;strings〉.Split(〈0;id〉, "_never_") - let prefix#2 = 〈0;let splits#1〉[0] - #ID: =~"^\(〈0;let prefix#2〉)$" - #SubID: =~"^\(〈0;let prefix#2〉):sub$" - id: 〈0;#ID〉 - subid: 〈0;#SubID〉 - } - case1: (〈0;#schema〉 & { - id: "foo" - subid: "foo:sub" - }) - case2: (〈0;#schema〉 & { - subid: "foo:sub" - id: "foo" - }) -} diff --git a/cue/testdata/cycle/issue4253.txtar b/cue/testdata/cycle/issue4253.txtar --- a/cue/testdata/cycle/issue4253.txtar +++ b/cue/testdata/cycle/issue4253.txtar @@ -24,28 +24,3 @@ gateway: whoami2: {} } @test(eq, at=gateway.whoami2, {foo: 1, k8s: {foo: 1}}) --- out/compile -- ---- in.cue -{ - x: { - #tmpl: { - let _self#1 = 〈1〉 - foo: 1 - k8s: { - foo: 〈1;let _self#1〉.foo - } - } - #allowed: =~"^[a-z0-9]+$" - [string]: { - [string]: { - 〈2;#tmpl〉 - if ((〈2;#allowed〉 & 〈1;-〉) == _|_(explicit error (_|_ literal) in source)) { - error("bad: \(〈2;-〉)") - } - } - } - gateway: { - whoami2: {} - } - } -} diff --git a/cue/testdata/cycle/issue429.txtar b/cue/testdata/cycle/issue429.txtar --- a/cue/testdata/cycle/issue429.txtar +++ b/cue/testdata/cycle/issue429.txtar @@ -123,51 +123,6 @@ er3.min: invalid value 5 (out of bound <5): ./in.cue:46:7 ./in.cue:64:7 --- out/compile -- ---- in.cue -{ - #Size: { - res: (&(int, >=0)|*0) - min: (>〈0;res〉|*(1 + 〈0;res〉)) - max: (>〈0;min〉|*〈0;min〉) - } - s0: (〈0;#Size〉 & { - res: 1 - }) - s1: (〈0;#Size〉 & { - min: 5 - }) - s2: (〈0;#Size〉 & { - max: 5 - }) - s3: (〈0;#Size〉 & { - min: 5 - max: 10 - }) - es3: (〈0;#Size〉 & { - min: 10 - max: 5 - }) - #nonEmptyRange: { - min: (*1|int) - min: <〈0;max〉 - max: >〈0;min〉 - } - r1: (〈0;#nonEmptyRange〉 & { - min: 3 - }) - r2: (〈0;#nonEmptyRange〉 & { - max: 5 - }) - r3: (〈0;#nonEmptyRange〉 & { - min: 3 - max: 6 - }) - er3: (〈0;#nonEmptyRange〉 & { - min: 5 - max: 5 - }) -} -- out/eval/stats -- Leaks: 23 Freed: 75 diff --git a/cue/testdata/cycle/issue494.txtar b/cue/testdata/cycle/issue494.txtar --- a/cue/testdata/cycle/issue494.txtar +++ b/cue/testdata/cycle/issue494.txtar @@ -45,82 +45,3 @@ Unifications: 36 Conjuncts: 59 Disjuncts: 0 --- out/compile -- ---- in.cue -{ - _Q: [ - { - pos: 0 - }, - { - pos: 1 - }, - ] - a: { - [string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])] - } - a: { - ben: [ - {}, - ] - } - b: { - [string]: 〈1;_Q〉[0:1] - } - b: { - ben: [ - {}, - ] - } - c: { - [string]: [ - ...{ - l: len(〈3;a〉[〈2;-〉]) - }, - ] - } - c: { - ben: [ - {}, - ] - } - #d: { - [string]: ([ - ...{ - pos: &(int, >=0) - }, - ] & 〈1;_Q〉[0:len(〈1;#d〉[〈0;-〉])]) - } - #d: { - ben: [ - {}, - ] - } - d: 〈0;#d〉 - e: { - [string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)] - } - e: { - ben: [ - {}, - ..., - ] - } - f: { - [string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)] - } - f: { - ben: [ - {}, - ] - } - g: { - [string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])] - } - g: { - ben: [ - {}, - {}, - ] - } -} diff --git a/cue/testdata/cycle/issue502.txtar b/cue/testdata/cycle/issue502.txtar --- a/cue/testdata/cycle/issue502.txtar +++ b/cue/testdata/cycle/issue502.txtar @@ -105,86 +105,3 @@ -- out/errors.txt -- [structural_cycle] reduced.t1.#T.x.y.z.x.y.z: structural cycle [structural_cycle] reduced.t1.a.x.y.z.x.y.z.x.y.z: structural cycle --- out/compile -- ---- in.cue -{ - #T: { - config: _ - body: _ - mas: { - [string]: { - cfg: _ - _link: 〈3;#T〉 - link: (〈0;_link〉 & { - config: 〈1;cfg〉 - }) - } - } - } - #a: (〈0;#T〉 & { - config: { - a: int - } - body: 〈0;config〉.a - mas: { - one: { - cfg: { - b: 〈3;config〉.a - } - _link: { - config: { - b: int - } - body: 〈0;config〉.b - mas: { - two: { - cfg: { - c: 〈3;config〉.b - } - _link: { - config: { - c: int - } - body: 〈0;config〉.c - } - } - } - } - } - } - }) - a: (〈0;#a〉 & { - config: { - a: 34 - } - }) -} ---- reduced.cue -{ - reduced: { - t1: { - #T: { - x: { - y?: { - V: _ - z: ((〈3;#T〉 & 〈0;V〉) & {}) - } - } - } - a: 〈0;#T〉 - a: { - x: { - y: { - V: { - x: { - y: { - V: {} - } - } - } - } - } - } - } - } -} diff --git a/cue/testdata/cycle/issue990.txtar b/cue/testdata/cycle/issue990.txtar --- a/cue/testdata/cycle/issue990.txtar +++ b/cue/testdata/cycle/issue990.txtar @@ -205,98 +205,3 @@ MaxConjunctInfos: 6 MaxReqSets: 19 MaxRedirect: 4 --- out/compile -- ---- in.cue -{ - #AC: { - k: "simple" - d: 〈1;#C〉 - } - #AS: { - k: "complex" - d: 〈1;#S〉 - } - #R: { - a: (〈1;#AC〉|〈1;#AS〉) - } - #S: { - n: string - r: { - [string]: 〈2;#R〉 - } - } - #C: { - n: string - } - #sub: { - #p: 〈1;#AS〉 - dict: { - [string]: _ - } - for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "complex") { - let subs#1multi = (〈3;#sub〉 & { - #p: 〈2;rd〉.a - }) - for sn, sd in 〈0;let subs#1〉.dict { - dict: { - "\(〈4;rn〉)_\(〈2;sn〉)": 〈2;sd〉 - } - } - } - for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "simple") { - dict: { - "\(〈2;rn〉)": 〈2;rd〉 - } - } - } - _test: { - c1: 〈1;#AC〉 - c1: { - d: { - n: "c1" - } - } - s3: 〈1;#AS〉 - s3: { - d: { - n: "s3" - r: { - r1: { - a: 〈4;c1〉 - } - } - } - } - s2: 〈1;#AS〉 - s2: { - d: { - n: "s2" - r: { - r1: { - a: 〈4;c1〉 - } - r2: { - a: 〈4;s3〉 - } - } - } - } - s1: 〈1;#AS〉 - s1: { - d: { - n: "s1" - r: { - r1: { - a: 〈4;c1〉 - } - r2: { - a: 〈4;s2〉 - } - } - } - } - } - out: (〈0;#sub〉 & { - #p: 〈1;_test〉.s1 - }) -} diff --git a/cue/testdata/cycle/patterns.txtar b/cue/testdata/cycle/patterns.txtar --- a/cue/testdata/cycle/patterns.txtar +++ b/cue/testdata/cycle/patterns.txtar @@ -40,37 +40,3 @@ Notifications: 1 NumCloseIDs: 7 --- out/compile -- ---- in.cue -{ - [!~"^[.]"]: 〈0;c〉 - a: 〈0;b〉 - b: { - [string]: int - } - c: { - a: int - } - [string]: 〈0;c〉 - a: 〈0;b〉 - b: { - [string]: int - } - c: { - a: int - } -} ---- issue3326.cue -{ - issue3326: { - _self: { - x: [ - ...and(〈1;x〉), - ] - } - 〈0;_self〉 - x: [ - 1, - ] - } -} diff --git a/cue/testdata/cycle/self.txtar b/cue/testdata/cycle/self.txtar --- a/cue/testdata/cycle/self.txtar +++ b/cue/testdata/cycle/self.txtar @@ -383,491 +383,3 @@ Disjuncts: 100 NumCloseIDs: 86 --- out/compile -- ---- in.cue -{ - expr: { - error1: { - a: 3 - a: (〈0;a〉 + 1) - } - } - expr: { - error2: { - a: (〈0;a〉 + 1) - a: 3 - } - } - listConcat: { - error1: { - a: [ - "1", - "2", - ] - a: 〈import;list〉.Concat([ - 〈1;a〉, - [ - "3", - ], - ]) - } - } - listConcat: { - error2: { - a: 〈import;list〉.Concat([ - [ - "3", - ], - 〈1;a〉, - ]) - a: [ - "1", - "2", - ] - } - } - selfEmbed: { - ok1: { - a: 〈0;x〉 - Y: 〈0;x〉 - x: { - 〈1;Y〉 - } - } - } - selfEmbed: { - ok2: { - Y: 〈0;x〉.b - a: 〈0;x〉 - x: { - b: { - 〈2;Y〉 - } - } - } - } - selfEmbed: { - ok3: { - Y: 〈0;x〉 - a: 〈0;x〉 - x: { - 〈1;Y〉 - } - } - } - selfEmbed: { - ok4: { - a: 〈0;x〉 - x: { - 〈1;Y〉 - } - Y: 〈0;x〉 - } - } - selfEmbed: { - ok5: { - x: { - 〈1;Y〉 - } - a: 〈0;x〉 - Y: 〈0;x〉 - } - } - selfEmbed: { - ok6: { - x: { - b: { - 〈2;Y〉 - } - } - Y: 〈0;x〉.b - a: 〈0;x〉 - } - } - disjSelf: { - ok1: { - #A: (string|〈0;#A〉) - x: 〈0;#A〉 - } - } - disjSelf: { - ok2: { - x: 〈0;#A〉 - #A: (string|〈0;#A〉) - } - } - disjSelf: { - ok3: { - #A: (〈0;#A〉|string) - x: 〈0;#A〉 - } - } - disjSelf: { - ok4: { - x: 〈0;#A〉 - #A: (〈0;#A〉|string) - } - } - disjEmbed: { - ok1: { - #A: (string|{ - 〈1;#A〉 - }) - x: 〈0;#A〉 - } - } - disjEmbed: { - ok2: { - x: 〈0;#A〉 - #A: (string|{ - 〈1;#A〉 - }) - } - } - disjEmbed: { - ok3: { - #A: ({ - 〈1;#A〉 - }|string) - x: 〈0;#A〉 - } - } - disjEmbed: { - ok4: { - x: 〈0;#A〉 - #A: ({ - 〈1;#A〉 - }|string) - } - } - disjList: _ - disjList: { - ok1: { - #A: (string|[ - 〈1;#A〉, - ]) - x: 〈0;#A〉 - y: 〈0;x〉 - y: [ - [ - [ - [ - string, - ], - ], - ], - ] - } - } - disjList: { - ok2: { - x: 〈0;#A〉 - #A: (string|[ - 〈1;#A〉, - ]) - } - } - disjList: { - ok3: { - #A: ([ - 〈1;#A〉, - ]|string) - x: 〈0;#A〉 - } - } - disjList: { - ok4: { - x: 〈0;#A〉 - #A: ([ - 〈1;#A〉, - ]|string) - } - } -} ---- old.cue -{ - name: "foo" - dynamicSelf: { - ok1: { - 〈2;name〉: (string|〈0;(〈2;name〉)〉) - x: 〈0;(〈2;name〉)〉 - } - } - dynamicSelf: { - ok2: { - x: 〈0;(〈2;name〉)〉 - 〈2;name〉: (string|〈0;(〈2;name〉)〉) - } - } - dynamicSelf: { - ok3: { - 〈2;name〉: (〈0;(〈2;name〉)〉|string) - x: 〈0;(〈2;name〉)〉 - } - } - dynamicSelf: { - ok4: { - x: 〈0;(〈2;name〉)〉 - 〈2;name〉: (〈0;(〈2;name〉)〉|string) - } - } - dynamicEmbed: { - ok1: { - 〈2;name〉: (string|{ - 〈1;(〈2;name〉)〉 - }) - x: 〈0;(〈2;name〉)〉 - } - } - dynamicEmbed: { - ok2: { - x: 〈0;(〈2;name〉)〉 - 〈2;name〉: (string|{ - 〈1;(〈2;name〉)〉 - }) - } - } - dynamicEmbed: { - ok3: { - 〈2;name〉: ({ - 〈1;(〈2;name〉)〉 - }|string) - x: 〈0;(〈2;name〉)〉 - } - } - dynamicEmbed: { - ok4: { - x: 〈0;(〈2;name〉)〉 - 〈2;name〉: ({ - 〈1;(〈2;name〉)〉 - }|string) - } - } - dynamicList: _ - dynamicList: { - ok1: { - 〈2;name〉: (string|[ - 〈1;(〈2;name〉)〉, - ]) - x: 〈0;(〈2;name〉)〉 - y: 〈0;x〉 - y: [ - [ - [ - [ - string, - ], - ], - ], - ] - } - } - dynamicList: { - ok2: { - x: 〈0;(〈2;name〉)〉 - 〈2;name〉: (string|[ - 〈1;(〈2;name〉)〉, - ]) - } - } - dynamicList: { - ok3: { - 〈2;name〉: ([ - 〈1;(〈2;name〉)〉, - ]|string) - x: 〈0;(〈2;name〉)〉 - } - } - dynamicList: { - ok4: { - x: 〈0;(〈2;name〉)〉 - 〈2;name〉: ([ - 〈1;(〈2;name〉)〉, - ]|string) - } - } - dynamicPatternSelf: { - ok1: { - [string]: (string|〈0;(〈0;-〉)〉) - } - } - dynamicPatternSelf: { - ok2: { - [string]: (〈0;(〈0;-〉)〉|string) - } - } - dynamicPatternEmbed: { - ok1: { - [string]: (string|{ - 〈1;(〈0;-〉)〉 - }) - } - } - dynamicPatternEmbed: { - ok2: { - [string]: ({ - 〈1;(〈0;-〉)〉 - }|string) - } - } - dynamicPatternList: { - ok1: { - [string]: (string|[ - 〈1;(〈0;-〉)〉, - ]) - } - } - dynamicPatternList: { - ok2: { - [string]: ([ - 〈1;(〈0;-〉)〉, - ]|string) - } - } - valueSelf: { - ok1: { - y: { - (string|〈1〉) - } - x: 〈0;y〉 - } - } - valueSelf: { - ok2: { - x: 〈0;y〉 - y: { - (string|〈1〉) - } - } - } - valueSelf: { - ok3: { - y: { - (〈1〉|string) - } - x: 〈0;y〉 - } - } - valueSelf: { - ok4: { - x: 〈0;y〉 - y: { - (〈1〉|string) - } - } - } - valueEmbed: { - ok1: { - y: { - (string|{ - 〈2〉 - }) - } - x: 〈0;y〉 - } - } - valueEmbed: { - ok2: { - x: 〈0;y〉 - y: { - (string|{ - 〈2〉 - }) - } - } - } - valueEmbed: { - ok3: { - y: { - ({ - 〈2〉 - }|string) - } - x: 〈0;y〉 - } - } - valueEmbed: { - ok4: { - x: 〈0;y〉 - y: { - ({ - 〈2〉 - }|string) - } - } - } - valueList: { - ok1: { - y: { - (string|[ - 〈2〉, - ]) - } - x: 〈0;y〉 - } - } - valueList: { - ok2: { - x: 〈0;y〉 - y: { - (string|[ - 〈2〉, - ]) - } - } - } - valueList: { - ok3: { - y: { - ([ - 〈2〉, - ]|string) - } - x: 〈0;y〉 - } - } - valueList: { - ok4: { - x: 〈0;y〉 - y: { - ([ - 〈2〉, - ]|string) - } - } - } - issue1729: { - t1: { - #x: { - (〈1;#x〉|{}) - } - x: (〈0;#x〉 & {}) - } - } - issue1729: { - t2: { - x: (〈0;#x〉 & {}) - #x: { - (〈1;#x〉|{}) - } - } - } -} ---- selfnew.cue -{ - issue4125: { - t1_self: { - let Root#1 = 〈1〉 - a: 〈0;let Root#1〉.a - } - } -} ---- selfold.cue -{ - issue4125: { - t2_alias: { - let Y#2 = 〈1〉 - b: 〈0;let Y#2〉.b - } - } -} diff --git a/cue/testdata/cycle/structural.txtar b/cue/testdata/cycle/structural.txtar --- a/cue/testdata/cycle/structural.txtar +++ b/cue/testdata/cycle/structural.txtar @@ -1004,838 +1004,3 @@ Disjuncts: 149 NumCloseIDs: 172 --- out/compile -- ---- edge.cue -{ - resolveToAncestor: { - t1: { - X: { - a: 〈0;b〉.a - b: 〈1;X〉 - } - } - t2: { - X: { - b: 〈1;X〉 - a: 〈0;b〉.a - } - } - } -} ---- in.cue -{ - a1: { - f: [ - 〈1;f〉, - ] - } - a2: { - f: 〈0;f〉 - } - a3: { - f: { - g: 〈1;f〉 - } - } - a4: { - a: [ - (〈1;a〉|int), - ] - } - a5: { - a: { - b: (〈1;a〉|int) - } - } - a6: { - a: (〈0;a〉|int) - } - a7: { - a: 〈0;c〉.x - b: { - x: 〈1;c〉 - y: "foo" - } - c: { - x: 〈1;b〉.y - y: 3 - } - } - b1: { - b: (〈0;a〉 & [ - 1, - ]) - a: [ - (〈1;a〉|int), - ] - } - b2: { - a: [ - (〈1;a〉|int), - ] - b: (〈0;a〉 & [ - 1, - ]) - } - b3: { - x: { - a: [ - (〈1;a〉|int), - ] - } - b: (〈0;x〉 & { - a: [ - 1, - ] - }) - } - b4: { - b: (〈0;x〉.y & [ - 1, - ]) - x: { - y: [ - 〈1;y〉, - ] - } - } - b4: { - cond1: { - b: (〈0;x〉.y & { - _z: false - [ - 1, - ] - }) - x: { - y: { - _z: (*true|bool) - if 〈0;_z〉 { - [ - 〈3;y〉, - ] - } - } - } - } - } - b4: { - cond2: { - x: { - y: { - _z: (*true|bool) - if 〈0;_z〉 { - [ - 〈3;y〉, - ] - } - } - } - b: (〈0;x〉.y & { - _z: false - [ - 1, - ] - }) - } - } - b5: { - b: (〈0;x〉.y & { - a: [ - 1, - ] - }) - x: { - y: { - a: [ - (〈1;a〉|int), - ] - } - } - } - b6: { - b: (〈0;x〉 & { - a: [ - 1, - ] - }) - x: { - a: [ - 〈1;a〉, - ] - } - } - b7: { - b: (〈0;a〉 & [ - [ - 1, - ], - ]) - a: [ - 〈1;a〉, - ] - } - b8: { - x: 〈0;a〉 - a: { - f: 〈1;b〉 - } - b: (〈0;a〉|string) - } - b9: { - #a: (string|〈0;#b〉|〈0;#ref〉) - #b: { - c: [ - 〈2;#a〉, - 〈2;#a〉, - 〈2;#a〉, - ] - } - #ref: { - ref: string - } - x: (〈0;#b〉|〈0;#ref〉) - } - b10: { - a: close({ - b: (string|〈1;a〉|〈1;c〉) - }) - c: close({ - d: (string|〈1;a〉) - }) - d: { - d: { - b: string - } - } - } - b11: { - #list: { - tail: (〈1;#list〉|*null) - if (〈0;tail〉 != null) {} - } - } - b12: { - #list: { - value: int - tail: (〈1;#list〉|*null) - if (〈0;tail〉 != null) { - sum: (〈1;value〉 + 〈1;tail〉.sum) - } - if (〈0;tail〉 == null) { - sum: 〈1;value〉 - } - } - list1: 〈0;#list〉 - list1: { - value: 1 - tail: { - value: 2 - tail: { - value: 3 - tail: { - value: 4 - } - } - } - } - } - b12b: { - #list: { - tail: 〈1;#list〉 - if (〈0;tail〉 != null) { - sum: 〈1;tail〉.sum - } - } - list1: 〈0;#list〉 - list1: { - tail: { - tail: {} - } - } - } - b13: { - root: { - a: [ - for _, x in 〈2;root〉 { - 〈1;x〉 - }, - ] - } - } - b14: { - root: { - a: [ - ...int, - ] - for _, x in 〈0;a〉 { - "\(〈1;x〉)": {} - } - b: [ - for _, x in 〈2;root〉 { - 〈1;x〉 - }, - ] - } - } - b15: { - root: { - a: { - for _, x in 〈2;root〉 { - 〈1;x〉 - } - } - } - } - p1: { - #T: { - a: { - [string]: { - link: 〈3;#T〉 - } - } - } - a: (〈0;#T〉 & { - a: { - one: { - link: { - a: { - two: {} - } - } - } - } - }) - } - p2: { - #T: { - a: { - [string]: { - link: 〈3;#T〉 - } - } - a: { - b: {} - } - } - a: (〈0;#T〉 & { - a: { - one: { - link: { - a: { - two: {} - } - } - } - } - }) - } - p3: { - #S: { - #T: { - a: { - [string]: { - link: 〈3;#T〉 - } - } - } - } - #U: { - 〈1;#S〉 - #T: { - a: { - b: {} - } - } - } - a: (〈0;#U〉.#T & { - a: { - one: { - link: { - a: { - two: {} - } - } - } - } - }) - } - p4: { - #T: { - a: [ - ...{ - link: 〈3;#T〉 - }, - ] - } - a: (〈0;#T〉 & { - a: [ - { - link: { - a: [ - {}, - ] - } - }, - ] - }) - } - p5: { - #T: { - a: [ - ...{ - link: 〈3;#T〉 - }, - ] - a: [ - {}, - ] - } - a: (〈0;#T〉 & { - a: [ - { - link: { - a: [ - {}, - ] - } - }, - ] - }) - } - p6: { - #S: { - #T: { - a: [ - ...{ - link: 〈3;#T〉 - }, - ] - } - } - #U: { - 〈1;#S〉 - #T: { - a: [ - {}, - ] - } - } - a: (〈0;#U〉.#T & { - a: [ - { - link: { - a: [ - {}, - ] - } - }, - ] - }) - } - c1: { - a: { - b: {} - c: (〈1;a〉 & 〈0;b〉) - } - } - d1: { - a: { - b: { - c: { - d: { - h: int - t: 〈4;r〉 - } - } - } - } - r: 〈0;a〉.b - x: 〈0;a〉.b.c - } - d2: { - x: 〈0;a〉.b.c - r: 〈0;a〉.b - a: { - b: { - c: { - d: { - h: int - t: 〈4;r〉 - } - } - } - } - } - d3: { - config: { - a: { - b: { - c: 〈2;indirect〉 - } - } - indirect: [ - 〈1;a〉.b, - null, - ][〈0;i〉] - i: (int|*1) - } - x: (〈0;config〉 & { - i: 0 - }) - } - shortPathFail: _ - shortPathFail: { - doubleRef: { - a: 〈0;#List〉 - #List: { - Next: (〈1;#List〉|*null) - } - } - } - shortPathFail: { - elipsis: { - t1: { - #Foo: { - ref: (null|〈1;#Foo〉) - } - #Foo: { - ... - } - } - t2: { - Foo: { - ref: 〈1;Foo〉 - } - Foo: { - ... - } - } - } - } - patternFail: { - issue2374: { - [string]: { - b: 〈1;(〈0;-〉)〉 - } - a: { - r: 0 - } - } - } - shortPathFail: { - comprehension: { - #list: { - tail: (〈1;#list〉|*null) - if (〈0;tail〉 != null) {} - } - } - } - withLetFail: { - schema: { - next: 〈1;let _schema_1#1〉 - } - let _schema_1#1 = 〈0;schema〉 - } - fieldsSumInfinite: { - issue3310: { - cheeseburger: 3.00 - fries: 2.00 - sprite: 1.00 - total: 〈import;list〉.Sum([ - for _, v in 〈2;issue3310〉 { - 〈1;v〉 - }, - ]) - } - } - listOptOK: { - list: { - head: int - tail?: 〈1;list〉 - } - a: (〈0;list〉 & { - head: 3 - tail: { - head: 2 - } - }) - } - issue2545: { - #A: { - B?: 〈1;#B〉 - } - #B: { - A: 〈1;#A〉 - } - } - e1: { - a: 〈0;a〉 - a: { - c: 〈1;a〉 - } - b: { - c: 〈1;b〉 - } - b: 〈0;b〉 - } - e2: { - a: { - 〈1;a〉 - } - a: { - c: 〈1;a〉 - } - b: { - c: 〈1;b〉 - } - b: { - 〈1;b〉 - } - } - e3: { - a: [ - 〈1;a〉, - ] - a: { - c: 〈1;a〉 - } - b: [ - 〈1;b〉, - ] - b: { - c: 〈1;b〉 - } - } - e4: { - a: [ - (〈1;a〉|{}), - ] - a: [ - [ - { - c: 1 - }, - ], - ] - b: [ - [ - { - c: 1 - }, - ], - ] - b: [ - (〈1;b〉|{}), - ] - } - e5: { - a: { - c: (〈1;a〉|int) - } - a: (〈0;a〉|int) - b: (〈0;b〉|int) - b: { - c: (〈1;b〉|int) - } - } - nestedList: { - v1e: { - x: [ - (〈1;x〉|int), - 1, - ] - y: (〈0;x〉 & [ - [ - [ - 2, - ], - 1, - ], - 1, - ]) - } - v2e: { - y: (〈0;x〉 & [ - [ - [ - 2, - ], - 1, - ], - 1, - ]) - x: [ - (〈1;x〉|int), - 1, - ] - } - v1: { - x: [ - (〈1;x〉|int), - 1, - ] - y: (〈0;x〉 & [ - [ - [ - 2, - 1, - ], - 1, - ], - 1, - ]) - } - v2: { - y: (〈0;x〉 & [ - [ - [ - 2, - 1, - ], - 1, - ], - 1, - ]) - x: [ - (〈1;x〉|int), - 1, - ] - } - } - v3: { - list: { - head: int - tail: (〈1;list〉|null) - } - myList: 〈0;list〉 - myList: { - head: 2 - tail: { - head: 3 - tail: { - head: 4 - } - } - } - } - v4: { - list: { - head: int - tail: (〈1;list〉|1) - } - myList: 〈0;list〉 - myList: { - head: 2 - tail: { - head: 3 - } - } - } - v5: { - list: { - head: int - tail: (〈1;list〉|{}) - } - myList: 〈0;list〉 - myList: { - head: 2 - tail: { - head: 3 - } - } - } - z1: { - y: { - f: { - h: 〈1;g〉 - } - g: _ - } - x: { - f: _ - g: 〈0;f〉 - } - z: (〈0;x〉 & 〈0;y〉) - } - crossRefNoCycle: { - t1: { - T: { - x: _ - y: 〈0;x〉 - } - C: ({ - x: 〈1;T〉 - } & 〈0;T〉) - } - } - crossRefNoCycle: { - t2: { - T: { - x: _ - y: 〈0;x〉 - } - C: (〈0;T〉 & { - x: 〈1;T〉 - }) - } - } - crossRefNoCycle: { - t3: { - T: { - x: _ - y: 〈0;x〉 - z: 〈0;y〉 - } - C: (〈0;T〉 & { - x: 〈1;T〉 - }) - } - } - crossRefNoCycle: { - t4: { - T: { - x: _ - y: 〈0;x〉 - z: 〈0;y〉 - } - C: (〈0;T〉 & { - x: (〈1;T〉 & { - x: 〈2;T〉 - }) - }) - } - } - crossRefNoCycle: { - t5: { - T: { - y: 〈1〉.x - } - C: (〈0;T〉 & { - x: 〈1;T〉 - }) - } - } - n1: { - a: { - b: int - } - } - n2: { - 〈1;n1〉 - a: 〈1;n1〉 - } - n3: { - 〈1;n1〉 - } - n4: { - 〈1;n1〉 - x: { - 〈2;n1〉 - y: { - 〈3;n1〉 - z: int - } - } - } -} diff --git a/cue/testdata/cycle/with_defaults.txtar b/cue/testdata/cycle/with_defaults.txtar --- a/cue/testdata/cycle/with_defaults.txtar +++ b/cue/testdata/cycle/with_defaults.txtar @@ -31,20 +31,3 @@ Disjuncts: 6 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - range1: { - min: (*1|int) - range: >〈0;min〉 - range: 8 - } - range2: { - min: (*1|int) - max: (int & >〈0;min〉) - } - rg: 〈0;range2〉 - rg: { - max: 8 - } -} diff --git a/cue/testdata/definitions/026_combined_definitions.txtar b/cue/testdata/definitions/026_combined_definitions.txtar --- a/cue/testdata/definitions/026_combined_definitions.txtar +++ b/cue/testdata/definitions/026_combined_definitions.txtar @@ -31,54 +31,6 @@ ./in.cue:8:17 [eval] #D4.env.b: field not allowed: ./in.cue:23:7 --- out/compile -- ---- in.cue -{ - #D1: { - env: { - a: "A" - } - env: { - b: "B" - } - #def: { - a: "A" - } - #def: { - b: "B" - } - } - d1: (〈0;#D1〉 & { - env: { - c: "C" - } - }) - #D2: { - a: int - } - #D2: { - b: int - } - #D3: { - env: { - a: "A" - } - } - #D3: { - env: { - b: "B" - } - } - #D4: { - env: 〈1;#DC〉 - env: { - b: int - } - } - #DC: { - a: int - } -} -- out/eval/stats -- Leaks: 0 Freed: 29 diff --git a/cue/testdata/definitions/028_recursive_closing_starting_at_non-definition.txtar b/cue/testdata/definitions/028_recursive_closing_starting_at_non-definition.txtar --- a/cue/testdata/definitions/028_recursive_closing_starting_at_non-definition.txtar +++ b/cue/testdata/definitions/028_recursive_closing_starting_at_non-definition.txtar @@ -9,31 +9,6 @@ } } A: z & {a: {#B: {c: e: 2}}} @test(eq, {a: #B: c: {e: 2, d: 1, f: 1}}) --- out/compile -- ---- in.cue -{ - z: { - a: { - #B: { - c: { - d: 1 - } - c: { - f: 1 - } - } - } - } - A: (〈0;z〉 & { - a: { - #B: { - c: { - e: 2 - } - } - } - }) -} -- out/eval/stats -- Leaks: 0 Freed: 14 diff --git a/cue/testdata/definitions/032_definitions_with_embedding.txtar b/cue/testdata/definitions/032_definitions_with_embedding.txtar --- a/cue/testdata/definitions/032_definitions_with_embedding.txtar +++ b/cue/testdata/definitions/032_definitions_with_embedding.txtar @@ -33,32 +33,6 @@ Disjuncts: 0 NumCloseIDs: 11 --- out/compile -- ---- in.cue -{ - #E: { - a: { - b: int - } - } - #S: { - 〈1;#E〉 - a: { - c: int - } - b: 3 - } - #e1: (〈0;#S〉 & { - a: { - d: 4 - } - }) - #v1: (〈0;#S〉 & { - a: { - c: 4 - } - }) -} -- out/diff-v2-v3.txt -- Reordering / missing positions. Verdict: worsening -- v3 reports fewer error positions; field reordering. diff --git a/cue/testdata/definitions/033_Issue_#153.txtar b/cue/testdata/definitions/033_Issue_#153.txtar --- a/cue/testdata/definitions/033_Issue_#153.txtar +++ b/cue/testdata/definitions/033_Issue_#153.txtar @@ -45,30 +45,6 @@ Disjuncts: 4 Notifications: 1 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - Foo: { - listOfCloseds: [ - ...〈2;#Closed〉, - ] - } - #Closed: { - a: (int|*0) - } - Junk: { - b: 2 - } - (〈0;Foo〉 & { - listOfCloseds: [ - { - for k, v in 〈3;Junk〉 { - "\(〈1;k〉)": 〈1;v〉 - } - }, - ] - }) -} -- out/diff-v2-v3.txt -- missing error positions: v3 reports fewer positions than v2. listOfCloseds.0.b: field not allowed: diff --git a/cue/testdata/definitions/036_closing_with_failed_optional.txtar b/cue/testdata/definitions/036_closing_with_failed_optional.txtar --- a/cue/testdata/definitions/036_closing_with_failed_optional.txtar +++ b/cue/testdata/definitions/036_closing_with_failed_optional.txtar @@ -53,39 +53,3 @@ Disjuncts: 4 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - #k1: ({ - a: int - b?: int - } & 〈0;#A〉) - #k2: (〈0;#A〉 & { - a: int - b?: int - }) - o1: ({ - a?: 3 - } & { - a?: 4 - }) - #o2: ({ - a?: 3 - } & { - a?: 4 - }) - #d1: ({ - a?: 2 - b: 4 - }|{ - a?: 3 - c: 5 - }) - v1: (〈0;#d1〉 & { - a?: 3 - b: 4 - }) - #A: { - a: int - } -} diff --git a/cue/testdata/definitions/036_optionals_in_open_structs.txtar b/cue/testdata/definitions/036_optionals_in_open_structs.txtar --- a/cue/testdata/definitions/036_optionals_in_open_structs.txtar +++ b/cue/testdata/definitions/036_optionals_in_open_structs.txtar @@ -11,22 +11,6 @@ [=~"^[m-z]*$"]: int aaa: 3 }) --- out/compile -- ---- in.cue -{ - A: { - [=~"^[a-s]*$"]: int - } - B: { - [=~"^[m-z]*$"]: int - } - #C: { - (〈1;A〉 & 〈1;B〉) - } - c: (〈0;#C〉 & { - aaa: 3 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 6 diff --git a/cue/testdata/definitions/037_closing_with_comprehensions.txtar b/cue/testdata/definitions/037_closing_with_comprehensions.txtar --- a/cue/testdata/definitions/037_closing_with_comprehensions.txtar +++ b/cue/testdata/definitions/037_closing_with_comprehensions.txtar @@ -38,51 +38,6 @@ ./in.cue:4:11 [eval] #E.f3: field not allowed: ./in.cue:30:3 --- out/compile -- ---- in.cue -{ - #A: { - f1: int - f2: int - } - for k, v in { - f3: int - } { - a: (〈2;#A〉 & { - "\(〈2;k〉)": 〈2;v〉 - }) - } - #B: { - for k, v in { - f1: int - } { - "\(〈1;k〉)": 〈1;v〉 - } - } - #C: { - f1: _ - for k, v in { - f1: int - } { - "\(〈1;k〉)": 〈1;v〉 - } - } - #D: { - for k, v in { - f1: int - } { - "\(〈1;k〉)": 〈1;v〉 - } - ... - } - #E: (〈0;#A〉 & { - for k, v in { - f3: int - } { - "\(〈1;k〉)": 〈1;v〉 - } - }) -} -- out/eval/stats -- Leaks: 0 Freed: 28 diff --git a/cue/testdata/definitions/037_conjunction_of_optional_sets.txtar b/cue/testdata/definitions/037_conjunction_of_optional_sets.txtar --- a/cue/testdata/definitions/037_conjunction_of_optional_sets.txtar +++ b/cue/testdata/definitions/037_conjunction_of_optional_sets.txtar @@ -39,27 +39,5 @@ Disjuncts: 0 NumCloseIDs: 14 --- out/compile -- ---- in.cue -{ - #A: { - [=~"^[a-s]*$"]: int - } - #B: { - [=~"^[m-z]*$"]: int - } - #C: (〈0;#A〉 & 〈0;#B〉) - c: 〈0;#C〉 - c: { - aaa: 3 - } - #D: { - (〈1;#A〉 & 〈1;#B〉) - } - d: 〈0;#D〉 - d: { - aaa: 3 - } -} -- out/diff-v2-v3.txt -- Missing positions: v3 reports fewer positions than v2 for the "field not allowed" errors. diff --git a/cue/testdata/definitions/038_continue_recursive_closing_for_optionals.txtar b/cue/testdata/definitions/038_continue_recursive_closing_for_optionals.txtar --- a/cue/testdata/definitions/038_continue_recursive_closing_for_optionals.txtar +++ b/cue/testdata/definitions/038_continue_recursive_closing_for_optionals.txtar @@ -20,20 +20,6 @@ Disjuncts: 0 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - #S: { - [string]: { - a: int - } - } - a: (〈0;#S〉 & { - v: { - b: int - } - }) -} -- out/diff-v2-v3.txt -- Missing positions: v3 reports fewer positions than v2 for the "field not allowed" error. a.v.b: field not allowed: diff --git a/cue/testdata/definitions/039_augment_closed_optionals.txtar b/cue/testdata/definitions/039_augment_closed_optionals.txtar --- a/cue/testdata/definitions/039_augment_closed_optionals.txtar +++ b/cue/testdata/definitions/039_augment_closed_optionals.txtar @@ -16,32 +16,6 @@ #B } d: #D & {aaa: 4} @test(eq, {aaa: 4}) --- out/compile -- ---- in.cue -{ - #A: { - [=~"^[a-s]*$"]: int - } - #B: { - [=~"^[m-z]*?"]: int - } - #C: { - (〈1;#A〉 & 〈1;#B〉) - { - [=~"^Q*$"]: int - } - } - c: (〈0;#C〉 & { - QQ: 3 - }) - #D: { - 〈1;#A〉 - 〈1;#B〉 - } - d: (〈0;#D〉 & { - aaa: 4 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/definitions/comprehensions.txtar b/cue/testdata/definitions/comprehensions.txtar --- a/cue/testdata/definitions/comprehensions.txtar +++ b/cue/testdata/definitions/comprehensions.txtar @@ -29,18 +29,3 @@ Disjuncts: 0 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - issue595: { - #cfgs: [ - { - name: "foo" - }, - ] - _name: 〈0;#cfgs〉[0].name - for _, cfg in 〈0;#cfgs〉 { - files: 〈1;cfg〉.nam - } - } -} diff --git a/cue/testdata/definitions/defembed.txtar b/cue/testdata/definitions/defembed.txtar --- a/cue/testdata/definitions/defembed.txtar +++ b/cue/testdata/definitions/defembed.txtar @@ -35,25 +35,6 @@ Disjuncts: 0 NumCloseIDs: 6 --- out/compile -- ---- in.cue -{ - a: { - 〈1;#A〉 - } - a: { - c: 1 - } - #A: { - b: 1 - } - b: { - 〈1;#A〉 - leaf: "leaf value" - interpolation: "more \(〈0;leaf_ref〉)" - leaf_ref: 〈0;leaf〉 - } -} -- out/diff-v2-v3.txt -- Positions: v3 reports fewer positions than v2 for the "field not allowed" error. Reordering. diff --git a/cue/testdata/definitions/dynamic.txtar b/cue/testdata/definitions/dynamic.txtar --- a/cue/testdata/definitions/dynamic.txtar +++ b/cue/testdata/definitions/dynamic.txtar @@ -56,40 +56,3 @@ NumCloseIDs: 2 -- out/diff-v2-v3.txt -- Disjunctions with defaults: needs @test(final) for x.a.b.c field. --- out/compile -- ---- evalv3regress.cue -{ - chained: { - x: { - 〈0;a〉.b: "foo" - 〈1;x〉.hello: "true" - a: { - b: "hello" - } - } - } -} ---- in.cue -{ - #A: { - a: "foo" - "\(〈0;a〉)": 3 - } - #B: { - a: { - b: { - c: string - d: 2 - } - } - } - #C: { - a: { - b: { - c: (*"d"|string) - 〈0;c〉: 2 - } - } - } - x: (〈0;#B〉 & 〈0;#C〉) -} diff --git a/cue/testdata/definitions/embed.txtar b/cue/testdata/definitions/embed.txtar --- a/cue/testdata/definitions/embed.txtar +++ b/cue/testdata/definitions/embed.txtar @@ -100,90 +100,6 @@ MaxConjunctInfos: 7 MaxReqSets: 12 MaxRedirect: 2 --- out/compile -- ---- in.cue -{ - deployment: { - [string]: 〈1;#Deployment〉 - } - deployment: { - foo: { - spec: { - replicas: 1 - } - } - } - #Deployment: { - 〈1;#TypeMeta〉 - spec: 〈1;#Spec〉 - } - #Spec: { - replicas: int - } - #TypeMeta: {} - recloseSimple: { - #foo: {} - a: ({ - 〈1;#foo〉 - } & { - b: int - }) - } - reclose1: { - #D: { - x: int - y: int - } - #a: { - 〈1;#D〉 - b: { - c: int - } - } - z: 〈0;#a〉.b - z: { - d: 3 - } - } - reclose2: { - #D: { - x: int - y: int - } - a: { - 〈1;#D〉 - b: { - c: int - } - } - z: 〈0;a〉.b - z: { - d: 3 - } - } - reclose3: { - #Step: { - (〈1;#A〉|〈1;#B〉) - 〈1;#Common〉 - } - #Common: { - Name: string - } - #A: { - 〈1;#Common〉 - Something: int - } - #B: { - 〈1;#Common〉 - Else: int - } - x: 〈0;#Step〉 - x: (〈0;#A〉 & { - Name: "a" - Something: 4 - }) - } -} -- out/diff-v2-v3.txt -- Reordering. Missing error positions: v3 reports fewer positions than v2. diff --git a/cue/testdata/definitions/exclude.txtar b/cue/testdata/definitions/exclude.txtar --- a/cue/testdata/definitions/exclude.txtar +++ b/cue/testdata/definitions/exclude.txtar @@ -115,103 +115,3 @@ Disjuncts: 0 NumCloseIDs: 18 --- out/compile -- ---- in.cue -{ - excludeLet: { - #D: { - let X#1 = {} - #foo: 〈0;let X#1〉 - f: _ - } - a: 〈0;#D〉 - a: { - let X#2 = { - a: 1 - } - f: 〈0;let X#2〉 - } - } - definition: { - err1: { - #D: { - #foo: { - a: int - } - } - a: 〈0;#D〉 - a: { - #foo: { - b: int - } - } - } - ok1: { - #D: {} - a: 〈0;#D〉 - a: { - #foo: { - b: int - } - } - } - } - hidden: { - err1: { - #D: { - _foo(:p): { - a: int - } - } - a: 〈0;#D〉 - a: { - _foo(:p): { - b: int - } - } - } - ok1: { - #D: {} - a: 〈0;#D〉 - a: { - _foo(:p): { - b: int - } - } - } - } -} ---- regress.cue -{ - definition: { - ok2: { - #Tree: { - #Leaf: { - leaf: string - } - #Branch: { - branch?: 〈1;#Leaf〉 - } - root: 〈0;#Branch〉 - } - out: 〈import;"encoding/json"〉.Marshal((〈0;#Tree〉 & { - root: {} - })) - } - } - hidden: { - ok2: { - out: (〈0;#Workflow〉 & { - _hidden(:p): (〈1;#step〉 & { - run: "foo bar" - }) - }) - #Workflow: {} - #step: matchN(1, [ - { - run!: _ - }, - ]) - } - } -} diff --git a/cue/testdata/definitions/explicitopen.txtar b/cue/testdata/definitions/explicitopen.txtar --- a/cue/testdata/definitions/explicitopen.txtar +++ b/cue/testdata/definitions/explicitopen.txtar @@ -295,562 +295,3 @@ f9: combinenew.f9.ok is in error because two f9 declarations conflict. f14/f15: combinenew.f14.err and f15.err are NOT in error (v3 allows these). Structure sharing: NewOpen2: ~(#A), combinenew.f4.ok ~(NewClosed1), combinenew.f18.ok ~(NewClosed1). --- out/compile -- ---- issues.cue -{ - issue4150: { - #Def: { - a: int - } - x: (〈0;#Def〉... & { - a: 42 - b: 42 - }) - foo: { - a: int - } - bar: { - b: int - } - y: (〈0;foo〉... & 〈0;bar〉...) - z: 1... - } -} ---- new.cue -{ - NewClosed1: { - 〈1;#A〉 - } - #NewClosed2: { - 〈1;#A〉... - b: 1 - } - NewOpen1: { - 〈1;#A〉... - b: 1 - } - NewOpen2: 〈0;#A〉... - useOld1: { - t1: { - err: (〈2;Old1〉 & { - c: 3 - }) - } - t2: { - err: { - 〈3;Old1〉 - c: 3 - } - } - t3: { - ok: { - 〈3;Old1〉... - c: 3 - } - } - } - useOld2: { - t1: { - err: (〈2;#Old2〉 & { - c: 3 - }) - } - t2: { - err: { - 〈3;#Old2〉 - c: 3 - } - } - t3: { - ok: { - 〈3;#Old2〉... - c: 3 - } - } - } - combinenew: { - a0: { - ok: (〈2;#A〉 & 〈2;NewClosed1〉) - } - a1: { - ok: { - 〈3;#A〉 - 〈3;NewClosed1〉 - } - } - a2: { - ok: (〈2;NewClosed1〉 & 〈2;NewOpen2〉) - } - a3: { - ok: { - 〈3;NewClosed1〉 - 〈3;NewOpen2〉 - } - } - a4: { - ok: { - 〈3;NewClosed1〉... - 〈3;NewOpen2〉 - } - } - a5: { - ok: (〈2;NewOpen2〉 & 〈2;NewClosed1〉) - } - a6: { - ok: { - 〈3;NewOpen2〉 - 〈3;NewClosed1〉 - } - } - a7: { - ok: { - 〈3;NewOpen2〉... - 〈3;NewClosed1〉 - } - } - b0: { - ok: (〈2;Old1〉 & 〈2;#NewClosed2〉) - } - b1: { - ok: (〈2;#Old2〉 & 〈2;#NewClosed2〉) - } - b2: { - ok: (〈2;#NewClosed2〉 & 〈2;Old1〉) - } - b3: { - ok: (〈2;#NewClosed2〉 & 〈2;#Old2〉) - } - c1: { - ok: { - 〈3;#NewClosed2〉 - 〈3;Old1〉 - } - } - c2: { - ok: { - 〈3;#NewClosed2〉 - 〈3;#Old2〉 - } - } - c3: { - ok: { - 〈3;Old1〉 - 〈3;#NewClosed2〉 - } - } - c4: { - ok: { - 〈3;#Old2〉 - 〈3;#NewClosed2〉 - } - } - d0: { - ok: { - 〈3;#NewClosed2〉 - 〈3;Old1〉... - } - } - d1: { - ok: { - 〈3;#NewClosed2〉 - 〈3;#Old2〉... - } - } - d2: { - ok: { - 〈3;#NewClosed2〉... - 〈3;Old1〉 - } - } - d3: { - ok: { - 〈3;#NewClosed2〉... - 〈3;#Old2〉 - } - } - d4: { - ok: { - 〈3;#NewClosed2〉... - 〈3;Old1〉... - } - } - d5: { - ok: { - 〈3;#NewClosed2〉... - 〈3;#Old2〉... - } - } - d6: { - ok: { - 〈3;Old1〉... - 〈3;#NewClosed2〉 - } - } - d7: { - ok: { - 〈3;#Old2〉... - 〈3;#NewClosed2〉 - } - } - d8: { - ok: { - 〈3;Old1〉 - 〈3;#NewClosed2〉... - } - } - d9: { - ok: { - 〈3;#Old2〉 - 〈3;#NewClosed2〉... - } - } - d10: { - ok: { - 〈3;Old1〉... - 〈3;#NewClosed2〉... - } - } - d11: { - ok: { - 〈3;#Old2〉... - 〈3;#NewClosed2〉... - } - } - e0: { - err: (〈2;#A〉 & 〈2;Old1〉) - } - e1: { - err: (〈2;#A〉 & 〈2;#Old2〉) - } - e2: { - err: (〈2;#A〉 & 〈2;#NewClosed2〉) - } - e3: { - err: (〈2;#A〉 & 〈2;NewOpen1〉) - } - e4: { - err: { - 〈3;#A〉 - 〈3;Old1〉 - } - } - e5: { - err: { - 〈3;#A〉 - 〈3;#Old2〉 - } - } - e6: { - err: { - 〈3;#A〉 - 〈3;#NewClosed2〉 - } - } - e7: { - err: { - 〈3;#A〉 - 〈3;NewOpen1〉 - } - } - e8: { - ok: { - 〈3;#A〉... - 〈3;Old1〉 - } - } - e9: { - ok: { - 〈3;#A〉... - 〈3;#Old2〉 - } - } - e10: { - ok: { - 〈3;#A〉... - 〈3;#NewClosed2〉 - } - } - e11: { - ok: { - 〈3;#A〉... - 〈3;NewOpen1〉 - } - } - f0: { - err: (〈2;NewClosed1〉 & 〈2;Old1〉) - } - f1: { - err: (〈2;NewClosed1〉 & 〈2;#Old2〉) - } - f2: { - err: (〈2;NewClosed1〉 & 〈2;#NewClosed2〉) - } - f3: { - err: (〈2;NewClosed1〉 & 〈2;NewOpen1〉) - } - f4: { - ok: (〈2;NewClosed1〉 & 〈2;NewClosed1〉) - } - f5: { - err: { - 〈3;NewClosed1〉 - 〈3;Old1〉 - } - } - f6: { - err: { - 〈3;NewClosed1〉 - 〈3;#Old2〉 - } - } - f7: { - err: { - 〈3;NewClosed1〉 - 〈3;#NewClosed2〉 - } - } - f8: { - err: { - 〈3;NewClosed1〉 - 〈3;NewOpen1〉 - } - } - f9: { - ok: { - 〈3;NewClosed1〉 - 〈3;NewClosed1〉 - } - } - f9: { - ok: { - 〈3;NewClosed1〉... - 〈3;Old1〉 - } - } - f10: { - ok: { - 〈3;NewClosed1〉... - 〈3;#Old2〉 - } - } - f11: { - ok: { - 〈3;NewClosed1〉... - 〈3;NewClosed1〉 - } - } - f12: { - ok: { - 〈3;NewClosed1〉... - 〈3;#NewClosed2〉 - } - } - f13: { - ok: { - 〈3;NewClosed1〉... - 〈3;NewOpen1〉 - } - } - f14: { - err: (〈2;Old1〉 & 〈2;NewClosed1〉) - } - f15: { - err: (〈2;#Old2〉 & 〈2;NewClosed1〉) - } - f16: { - err: (〈2;#NewClosed2〉 & 〈2;NewClosed1〉) - } - f17: { - err: (〈2;NewOpen1〉 & 〈2;NewClosed1〉) - } - f18: { - ok: (〈2;NewClosed1〉 & 〈2;NewClosed1〉) - } - } -} ---- old.cue -{ - #A: { - a: 1 - } - Old1: { - { - 〈2;#A〉 - b: 1 - } - } - #Old2: { - { - 〈2;#A〉 - b: 1 - } - } - useNewClosed1: { - t1: { - err: (〈2;NewClosed1〉 & { - c: 3 - }) - } - t2: { - ok: { - 〈3;NewClosed1〉 - c: 3 - } - } - } - useNewClosed2: { - t1: { - err: (〈2;#NewClosed2〉 & { - c: 3 - }) - } - t2: { - ok: { - 〈3;#NewClosed2〉 - c: 3 - } - } - } - useNewOpen1: { - t1: { - ok: (〈2;NewOpen1〉 & { - c: 3 - }) - } - t2: { - ok: { - 〈3;NewOpen1〉 - c: 3 - } - } - } - useNewOpen2: { - t1: { - ok: (〈2;NewOpen2〉 & { - c: 3 - }) - } - t2: { - ok: { - 〈3;NewOpen2〉 - c: 3 - } - } - } - combineold: { - a0: { - ok: (〈2;#A〉 & 〈2;NewClosed1〉) - } - a1: { - ok: { - 〈3;#A〉 - 〈3;NewClosed1〉 - } - } - a2: { - ok: (〈2;NewClosed1〉 & 〈2;NewOpen2〉) - } - a3: { - ok: { - 〈3;NewClosed1〉 - 〈3;NewOpen2〉 - } - } - b0: { - ok: (〈2;Old1〉 & 〈2;#NewClosed2〉) - } - b1: { - ok: (〈2;#Old2〉 & 〈2;#NewClosed2〉) - } - c1: { - ok: { - 〈3;#NewClosed2〉 - 〈3;Old1〉 - } - } - c2: { - ok: { - 〈3;#NewClosed2〉 - 〈3;#Old2〉 - } - } - e0: { - err: (〈2;#A〉 & 〈2;Old1〉) - } - e1: { - err: (〈2;#A〉 & 〈2;#Old2〉) - } - e2: { - err: (〈2;#A〉 & 〈2;#NewClosed2〉) - } - e3: { - err: (〈2;#A〉 & 〈2;NewOpen1〉) - } - e4: { - ok: { - 〈3;#A〉 - 〈3;Old1〉 - } - } - e5: { - ok: { - 〈3;#A〉 - 〈3;#Old2〉 - } - } - e6: { - ok: { - 〈3;#A〉 - 〈3;#NewClosed2〉 - } - } - e7: { - ok: { - 〈3;#A〉 - 〈3;NewOpen1〉 - } - } - f0: { - err: (〈2;NewClosed1〉 & 〈2;Old1〉) - } - f1: { - err: (〈2;NewClosed1〉 & 〈2;#Old2〉) - } - f2: { - err: (〈2;NewClosed1〉 & 〈2;#NewClosed2〉) - } - f3: { - err: (〈2;NewClosed1〉 & 〈2;NewOpen1〉) - } - f4: { - ok: { - 〈3;NewClosed1〉 - 〈3;Old1〉 - } - } - f5: { - ok: { - 〈3;NewClosed1〉 - 〈3;#Old2〉 - } - } - f6: { - ok: { - 〈3;NewClosed1〉 - 〈3;NewClosed1〉 - } - } - f7: { - ok: { - 〈3;NewClosed1〉 - 〈3;#NewClosed2〉 - } - } - f8: { - ok: { - 〈3;NewClosed1〉 - 〈3;NewOpen1〉 - } - } - } -} diff --git a/cue/testdata/definitions/fields.txtar b/cue/testdata/definitions/fields.txtar --- a/cue/testdata/definitions/fields.txtar +++ b/cue/testdata/definitions/fields.txtar @@ -419,447 +419,3 @@ Error positions: v3 reports fewer positions than v2. Field reordering differences between v2 and v3. Verdict: worsening -- v3 reports fewer error positions than v2; field reordering. --- out/compile -- ---- in.cue -{ - ok: { - t1: { - c: 〈0;#R〉 - c: [ - { - b: int - }, - ] - #R: [ - ..., - ] - } - } - ok: { - t2: { - #A: _ - l: 〈0;#A〉 - l: { - f: "hi" - } - } - } - ok: { - t3: { - #A: { - f: { - ... - } - } - #A1: { - 〈1;#A〉 - } - s: { - [string]: 〈1;#A1〉 - } - s: { - foo: { - f: { - d: { - foo: 1 - } - } - } - } - } - } - ok: { - t4: { - #T: { - a: { - b: 1 - } - } - W: { - { - 〈2;#T〉 - } - b: { - c: 2 - } - } - } - } - ok: { - t5: { - #A: { - 〈1;Common〉 - _ - } - Common: {} - x: 〈0;#A〉 - x: { - c: int - } - } - } - ok: { - t6: { - #A: { - 〈1;Common〉 - ... - } - Common: {} - x: 〈0;#A〉 - x: { - c: int - } - } - } - ok: { - t7: { - a: { - 〈1;#A〉 - 〈1;#B〉 - } - #A: { - b: { - f: 1 - } - } - #B: { - b: { - g: 1 - } - } - } - } - ok: { - t8: { - foo: 〈0;#X〉 - #X: { - a: { - b: { - c: { - C: 1 - } - } - } - for k, _ in 〈0;a〉 { - a: { - 〈2;k〉: { - c: { - D: 2 - } - } - } - } - } - } - } - ok: { - t9: { - c: 〈0;#R〉 - c: [ - { - b: int - }, - ] - #R: [ - ..., - ] - } - } - ok: { - t10: { - #A: _ - l: 〈0;#A〉 - l: { - f: "hi" - } - } - } - ok: { - t11: { - #A: { - f: { - ... - } - } - #A1: { - 〈1;#A〉 - } - s: { - [string]: 〈1;#A1〉 - } - s: { - foo: { - f: { - d: { - foo: "bar" - } - } - } - } - } - } - ok: { - t12: { - #T: { - a: { - b: 1 - } - } - W: { - { - 〈2;#T〉 - } - b: { - c: 2 - } - } - } - } - ok: { - t13: { - #A: { - 〈1;Common〉 - _ - } - Common: {} - x: 〈0;#A〉 - x: { - c: int - } - } - } - ok: { - t14: { - #A: { - 〈1;Common〉 - ... - } - Common: {} - x: 〈0;#A〉 - x: { - c: int - } - } - } - err: { - t1: { - #D: (_ & { - a: 2 - }) - a: 〈0;#D〉 - a: { - disallowed: 1 - } - } - } - err: { - t2: { - #S: { - { - c: { - d: 1 - } - } - } - V: 〈0;#S〉 - V: { - c: { - e: 1 - } - } - } - } - err: { - t3: { - #D: {} - a: 〈0;#D〉 - a: { - c: "C" - } - } - } - err: { - t4: { - a: 〈0;#A〉 - #A: { - b: { - f: 1 - } - } - a: { - b: { - h: 1 - } - } - } - } - err: { - t5: { - a: { - 〈1;#A〉 - 〈1;#B〉 - } - #A: { - b: { - f: 1 - } - } - #B: { - b: { - g: 1 - } - } - b: 〈0;a〉 - b: { - b: { - h: 1 - } - } - } - } - err: { - t6: { - a: { - 〈1;#A〉 - 〈1;#B〉 - } - #A: { - b: { - c: { - d: { - e: { - f: 1 - } - } - } - } - } - #B: { - b: { - c: { - d: { - e: { - g: 1 - } - } - } - } - } - b: 〈0;a〉 - b: { - b: { - c: { - d: { - e: { - h: 1 - } - } - } - } - } - } - } - err: { - t7: { - #D: (_ & { - a: 2 - }) - a: 〈0;#D〉 - a: { - b: 1 - } - } - } - err: { - t8: { - #S: { - { - c: { - d: 1 - } - } - } - V: 〈0;#S〉 - V: { - c: { - e: 1 - } - } - } - } -} ---- issue1830.cue -{ - issue1830: { - #x: { - y: { - z?: { - name: string - } - } - } - egs: { - x1: ((〈1;#x〉 & { - y: { - z: _ - } - }).y.z & { - name: "blah" - age1: 5 - }) - x2: ((〈1;#x〉.y & { - z: _ - }).z & { - name: "blah" - age2: 5 - }) - } - } -} ---- issue3491.cue -{ - issue3491: { - #Schema: { - field?: {} - } - a: (〈0;#Schema〉 & { - field: {} - }) - a: 〈0;b〉 - b: { - #Extra: {} - } - } -} ---- validators.cue -{ - validator: { - open: { - #Schema: { - matchN(1, [ - 〈1;#x〉, - ]) - #x: { - trailingComma?: "all" - } - } - data: { - trailingComma: "all" - } - data: 〈0;#Schema〉 - } - } - validator: { - keepClosed: { - #X: { - 〈import;struct〉.MaxFields(1) - a?: int - b?: int - } - x: 〈0;#X〉 - x: { - c: 1 - } - } - } -} diff --git a/cue/testdata/definitions/files.txtar b/cue/testdata/definitions/files.txtar --- a/cue/testdata/definitions/files.txtar +++ b/cue/testdata/definitions/files.txtar @@ -45,31 +45,6 @@ Notifications: 1 NumCloseIDs: 13 --- out/compile -- ---- box.cue -{ - (〈0;#Config〉 & { - console: 〈1;dark〉 - }) -} ---- in.cue -{ - #theme: { - color: string - ctermbg: string - } - dark: (〈0;#theme〉 & { - color: "dark" - ctermbg: "239" - }) - light: (〈0;#theme〉 & { - color: "light" - ctermbg: "254" - }) - #Config: { - console: (〈1;dark〉|*〈1;light〉) - } -} -- out/diff-v2-v3.txt -- Reordering. Disjunctions with defaults: needs @test(final) for console field. diff --git a/cue/testdata/definitions/hidden.txtar b/cue/testdata/definitions/hidden.txtar --- a/cue/testdata/definitions/hidden.txtar +++ b/cue/testdata/definitions/hidden.txtar @@ -58,34 +58,3 @@ -- out/diff-v2-v3.txt -- g: v2 evaluator expands g to {f: 4}; v3 uses structure sharing (~(f._val(:foo))). Verdict: improvement -- v3 uses structure sharing for g; more efficient. --- out/compile -- ---- in.cue -{ - #def: { - _name(:foo): { - d: int - } - } - d: (〈import;"mod.test/pkg"〉.#D & { - _name(:foo): { - d: int - } - _val(:foo): { - f: 4 - } - }) - e: ((〈import;"mod.test/pkg"〉.#D & 〈0;#def〉) & { - _name(:foo): { - c: int - } - _val(:foo): { - g: int - } - }) - f: (〈import;"mod.test/pkg"〉.#D & { - _val(:foo): { - f: 4 - } - }) - g: 〈0;f〉._val(:foo) -} diff --git a/cue/testdata/definitions/issue271.txtar b/cue/testdata/definitions/issue271.txtar --- a/cue/testdata/definitions/issue271.txtar +++ b/cue/testdata/definitions/issue271.txtar @@ -24,21 +24,6 @@ Conjuncts: 20 Disjuncts: 0 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - #T: { - [_]: _ - } - #T: close({ - a: string - }) - x: 〈0;#T〉 - x: { - a: "hello" - b: "foo" - } -} -- out/diff-v2-v3.txt -- Positions: v3 reports fewer positions than v2 for the "field not allowed" error. x.b: field not allowed: @@ -47,4 +32,4 @@ - ./in.cue:3:5 ./in.cue:6:2 -No newline at end of right file. \ No newline at end of file +No newline at end of right file. diff --git a/cue/testdata/definitions/issue317.txtar b/cue/testdata/definitions/issue317.txtar --- a/cue/testdata/definitions/issue317.txtar +++ b/cue/testdata/definitions/issue317.txtar @@ -68,60 +68,3 @@ Conjuncts: 96 Disjuncts: 6 NumCloseIDs: 21 --- out/compile -- ---- in.cue -{ - #T: { - #Schema: { - [_]: 〈2;#D〉 - } - concrete: 〈0;#Schema〉 - } - #D: { - fieldWithDefault: (*0|int) - ... - } - s: (〈0;#T〉 & { - #Schema: { - foo: { - otherField: string - } - } - concrete: { - foo: { - otherField: "hello" - } - } - }) - #Container: { - Env: { - [string]: { - name: string - value: string - } - } - } - #Deployment: { - #Containers: { - [string]: 〈2;#Container〉 - } - containers: [ - for _, c in 〈1;#Containers〉 { - 〈1;c〉 - }, - ] - } - Something: { - 〈1;#Deployment〉 - #Containers: { - "a thing": { - Env: { - foobar: { - value: "foo" - } - } - } - } - } - x: (〈0;Something〉 & 〈0;#Deployment〉) -} diff --git a/cue/testdata/definitions/issue320.txtar b/cue/testdata/definitions/issue320.txtar --- a/cue/testdata/definitions/issue320.txtar +++ b/cue/testdata/definitions/issue320.txtar @@ -30,21 +30,6 @@ Conjuncts: 14 Disjuncts: 0 NumCloseIDs: 7 --- out/compile -- ---- in.cue -{ - #Foo: { - x: string - 〈1;#More〉 - } - #More: { - [=~"^x-"]: _ - } - foo: (〈0;#Foo〉 & { - x: "hello" - y: "goodbye" - }) -} -- out/diff-v2-v3.txt -- Positions: v3 reports fewer positions than v2 for the "field not allowed" error. Verdict: worsening -- v3 reports fewer error positions than v2. diff --git a/cue/testdata/definitions/issue342.txtar b/cue/testdata/definitions/issue342.txtar --- a/cue/testdata/definitions/issue342.txtar +++ b/cue/testdata/definitions/issue342.txtar @@ -38,30 +38,6 @@ } Z: X.test_3_bar.ref @test(eq, "FOO") --- out/compile -- ---- in.cue -{ - X: { - #Simple: { - ref: string - } - #Complex: { - ({ - ref: string - }|{ - local: string - }) - } - var: "bar" - test_1: 〈0;#Complex〉 - "test_2_\(〈0;var〉)": 〈0;#Simple〉 - "test_3_\(〈0;var〉)": 〈0;#Complex〉 - test_3_bar: { - ref: "FOO" - } - } - Z: 〈0;X〉.test_3_bar.ref -} -- out/eval/stats -- Leaks: 2 Freed: 18 diff --git a/cue/testdata/definitions/issue359.txtar b/cue/testdata/definitions/issue359.txtar --- a/cue/testdata/definitions/issue359.txtar +++ b/cue/testdata/definitions/issue359.txtar @@ -81,60 +81,6 @@ } } }) --- out/compile -- ---- in.cue -{ - #simple: { - peso: (*1|int) - edad: (*2|int) - } - good: (〈0;#simple〉 & { - peso: 4 - }) - #complex: { - things: { - [string]: 〈2;#simple〉 - } - } - #many: (〈0;#complex〉 & { - things: { - hola: { - peso: 2 - } - } - things: { - sol: { - peso: 3 - } - } - }) - bad: (〈0;#many〉 & { - things: { - hola: { - peso: 2 - } - } - }) - many: (〈0;#complex〉 & { - things: { - hola: { - peso: 2 - } - } - things: { - sol: { - peso: 3 - } - } - }) - notbad: (〈0;many〉 & { - things: { - hola: { - peso: 2 - } - } - }) -} -- out/eval/stats -- Leaks: 9 Freed: 72 diff --git a/cue/testdata/definitions/issue367.txtar b/cue/testdata/definitions/issue367.txtar --- a/cue/testdata/definitions/issue367.txtar +++ b/cue/testdata/definitions/issue367.txtar @@ -7,32 +7,6 @@ } }) instance: #special1 & {l1: l2: l3: 34} @test(eq, {l1: {l2: {l3: 34, l4: 26}}}) --- out/compile -- ---- in.cue -{ - #def1: { - l1: { - ["l2"]: { - l3: int - l4: 26 - } - } - } - #special1: (〈0;#def1〉 & { - l1: { - l2: { - l3: <100 - } - } - }) - instance: (〈0;#special1〉 & { - l1: { - l2: { - l3: 34 - } - } - }) -} -- out/eval/stats -- Leaks: 0 Freed: 13 diff --git a/cue/testdata/definitions/issue370.txtar b/cue/testdata/definitions/issue370.txtar --- a/cue/testdata/definitions/issue370.txtar +++ b/cue/testdata/definitions/issue370.txtar @@ -21,24 +21,6 @@ c1 age: 5 } @test(eq, {age: 5, name: "cueckoo"}) --- out/compile -- ---- x.cue -{ - #C1: { - name: string - } - #C2: { - 〈1;#C1〉 - age: int - } - c1: (〈0;#C1〉 & { - name: "cueckoo" - }) - c2: (〈0;#C2〉 & { - 〈1;c1〉 - age: 5 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/definitions/issue3834.txtar b/cue/testdata/definitions/issue3834.txtar --- a/cue/testdata/definitions/issue3834.txtar +++ b/cue/testdata/definitions/issue3834.txtar @@ -163,124 +163,3 @@ -- out/diff-v2-v3.txt -- Disjunction handling: _a: _ | close({y!: z?: _}) uses disjunction; needs @test(final) for precise testing. Verdict: cosmetic -- Disjunction with @test(final) annotation artifact. No semantic change. --- out/compile -- ---- in.cue -{ - X: { - _a: { - foo: true - } - _a: (_|close({ - y!: { - z?: _ - } - })) - _b: (〈0;_a〉 & { - y: {} - }) - concrete: 〈0;_b〉.y - isTrue: (〈0;concrete〉 != _|_(explicit error (_|_ literal) in source)) - } - { - 〈1;X〉 - } - sub: { - t1: { - X: { - _a: { - foo: true - } - _a: (_|close({ - y!: { - z?: _ - } - })) - _b: (〈0;_a〉 & { - y: {} - }) - concrete: 〈0;_b〉.y - } - { - 〈1;X〉 - } - } - } - sub: { - t2: { - X: { - _a: { - foo: true - } - _a: (_|close({ - y!: { - z?: _ - } - })) - _b: (〈0;_a〉 & { - y: {} - }) - concrete: 〈0;_b〉.y - } - 〈0;X〉 - } - } - sub: { - t3: { - #X: { - _a: { - foo: true - } - _a: (_|close({ - y!: { - z?: _ - } - })) - _b: (〈0;_a〉 & { - y: {} - }) - concrete: 〈0;_b〉.y - } - { - 〈1;#X〉 - } - } - } - sub: { - t4: { - #X: { - _a: { - foo: true - } - _a: (_|close({ - y!: { - z?: _ - } - })) - _b: (〈0;_a〉 & { - y: {} - }) - concrete: 〈0;_b〉.y - } - 〈0;#X〉 - } - } - full: { - #Foo: { - _data: { - Foo: true - } - _data: (_|close({ - Extra!: { - optional?: _ - } - })) - _dataWithExtra: (〈0;_data〉 & { - Extra: {} - }) - out: (〈0;_dataWithExtra〉.Extra != _|_(explicit error (_|_ literal) in source)) - } - { - 〈1;#Foo〉 - } - } -} diff --git a/cue/testdata/definitions/issue3851.txtar b/cue/testdata/definitions/issue3851.txtar --- a/cue/testdata/definitions/issue3851.txtar +++ b/cue/testdata/definitions/issue3851.txtar @@ -30,31 +30,6 @@ Notifications: 2 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - #App: { - name?: string - sub1?: { - sub2?: (null|_) - } - } - #Output: (null|〈0;#App〉) - out: (〈0;#Output〉 & { - name: "foo" - sub1: { - sub2: ({}|_) - } - sub1: { - sub2: { - sub3: { - let _let#1 = "bar" - foo: 〈0;let _let#1〉 - } - } - } - }) -} -- out/diff-v2-v3.txt -- Disjunctions with defaults: needs @test(final) for default field selection v3: sub2 is (#struct); v2: sub2 is (struct) diff --git a/cue/testdata/definitions/issue4000.txtar b/cue/testdata/definitions/issue4000.txtar --- a/cue/testdata/definitions/issue4000.txtar +++ b/cue/testdata/definitions/issue4000.txtar @@ -67,64 +67,6 @@ spec: [...#RuleGroup] } #TypeMeta: kind: string | *"default" --- out/compile -- ---- in.cue -{ - items: 〈import;list〉.Sort(〈0;#List〉.items, { - x: {} - y: {} - less: (〈0;x〉.kind < 〈0;y〉.kind) - }) - #List: { - items: 〈import;list〉.Concat(〈1;_items〉) - } - _items: [ - 〈1;#VMRuleList〉, - ] - #VMRuleList: ([ - ...(null|〈1;#VMRule〉), - ] & [ - { - spec: [ - { - rules: [ - { - expr: "x" - }, - ] - }, - ] - }, - { - spec: [ - { - rules: [ - { - expr: "y" - }, - ] - }, - ] - }, - ]) - #RuleGroup: { - rules: [ - ...〈2;#Rule〉, - ] - } - #Rule: { - expr: string - } - #VMRule: { - 〈1;#TypeMeta〉 - spec: [ - ...〈2;#RuleGroup〉, - ] - } - #TypeMeta: { - kind: (string|*"default") - } -} -- out/eval/stats -- Leaks: 18 Freed: 36 diff --git a/cue/testdata/definitions/issue419.txtar b/cue/testdata/definitions/issue419.txtar --- a/cue/testdata/definitions/issue419.txtar +++ b/cue/testdata/definitions/issue419.txtar @@ -36,22 +36,3 @@ Disjuncts: 4 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - #A: { - a: string - } - #B: { - b: string - } - #X: (〈0;#A〉|〈0;#B〉) - l: [ - ...〈1;#X〉, - ] - l: [ - { - b: "bar" - }, - ] -} diff --git a/cue/testdata/definitions/issue471.txtar b/cue/testdata/definitions/issue471.txtar --- a/cue/testdata/definitions/issue471.txtar +++ b/cue/testdata/definitions/issue471.txtar @@ -45,24 +45,3 @@ Disjuncts: 2 NumCloseIDs: 4 --- out/compile -- ---- in.cue -{ - #a: ((〈0;#c〉|〈0;#d〉) & { - name: string - }) - #a1: (〈0;#c〉 & { - name: string - }) - #a2: (〈0;#d〉 & { - name: string - }) - #c: { - name: string - age: int - } - #d: { - name: string - address: string - } -} diff --git a/cue/testdata/definitions/issue483.txtar b/cue/testdata/definitions/issue483.txtar --- a/cue/testdata/definitions/issue483.txtar +++ b/cue/testdata/definitions/issue483.txtar @@ -14,30 +14,6 @@ alpha?: bravo?: charlie?: bool } #Root: {...} --- out/compile -- ---- in.cue -{ - out: { - 〈1;instance〉 - } - instance: (〈0;#Type〉 & { - alpha: { - bravo: { - charlie: true - } - } - }) - #Type: (〈0;#Root〉 & { - alpha?: { - bravo?: { - charlie?: bool - } - } - }) - #Root: { - ... - } -} -- out/eval/stats -- Leaks: 0 Freed: 14 diff --git a/cue/testdata/definitions/issue491.txtar b/cue/testdata/definitions/issue491.txtar --- a/cue/testdata/definitions/issue491.txtar +++ b/cue/testdata/definitions/issue491.txtar @@ -37,45 +37,6 @@ }] } } @test(eq, {Args: {Repos: [{Var: "REPO1", Pattern: *"*" | string}]}}) --- out/compile -- ---- in.cue -{ - #Prestep: { - Args: (*null|_) - } - #PrestepNewUser: (〈0;#Prestep〉 & { - Args: 〈1;#NewUser〉 - }) - #NewUser: { - Repos: [ - ...〈2;#Repo〉, - ] - } - #Repo: { - Var: string - Pattern: (*"*"|string) - } - x: [ - ...〈1;#Repo〉, - ] - x: [ - { - Var: "REPO1" - }, - ] - y: (〈0;#Repo〉 & { - Var: "REPO1" - }) - z: (〈0;#PrestepNewUser〉 & { - Args: { - Repos: [ - { - Var: "REPO1" - }, - ] - } - }) -} -- out/eval/stats -- Leaks: 9 Freed: 33 diff --git a/cue/testdata/definitions/issue493.txtar b/cue/testdata/definitions/issue493.txtar --- a/cue/testdata/definitions/issue493.txtar +++ b/cue/testdata/definitions/issue493.txtar @@ -13,22 +13,6 @@ #Both: #App | #Atom t1: #Both & {body: 3} @test(eq, {body: 3, other: {}}) --- out/compile -- ---- in.cue -{ - #Artifact: { - body: _ - other: { - [string]: int - } - } - #App: 〈0;#Artifact〉 - #Atom: 〈0;#Artifact〉 - #Both: (〈0;#App〉|〈0;#Atom〉) - t1: (〈0;#Both〉 & { - body: 3 - }) -} -- out/eval/stats -- Leaks: 6 Freed: 15 diff --git a/cue/testdata/definitions/issue496.txtar b/cue/testdata/definitions/issue496.txtar --- a/cue/testdata/definitions/issue496.txtar +++ b/cue/testdata/definitions/issue496.txtar @@ -11,17 +11,6 @@ } @test(shareID=lN) l: #N @test(shareID=lN) --- out/compile -- ---- in.cue -{ - #A: _ - #N: (〈0;#A〉 & { - _E: { - name: "hello" - } - }) - l: 〈0;#N〉 -} -- out/eval/stats -- Leaks: 0 Freed: 6 diff --git a/cue/testdata/definitions/issue497.txtar b/cue/testdata/definitions/issue497.txtar --- a/cue/testdata/definitions/issue497.txtar +++ b/cue/testdata/definitions/issue497.txtar @@ -11,19 +11,6 @@ } @test(shareID=lN) @test(eq, {f: {j: {n: "hi"}}}) l: #N @test(shareID=lN) --- out/compile -- ---- in.cue -{ - #A: _ - #N: (〈0;#A〉 & { - f: { - j: { - n: "hi" - } - } - }) - l: 〈0;#N〉 -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/definitions/issue533.txtar b/cue/testdata/definitions/issue533.txtar --- a/cue/testdata/definitions/issue533.txtar +++ b/cue/testdata/definitions/issue533.txtar @@ -38,24 +38,6 @@ Disjuncts: 0 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - #x: { - Name: string - } - _#x(:x): { - Name: string - } - x1: (〈0;#x〉 & { - Name: "hello" - Age: 50 - }) - x2: (〈0;_#x(:x)〉 & { - Name: "hello" - Age: 50 - }) -} -- out/diff-v2-v3.txt -- Positions: v3 reports fewer positions than v2 for the "field not allowed" errors. Verdict: worsening -- v3 reports fewer error positions than v2. diff --git a/cue/testdata/definitions/issue539.txtar b/cue/testdata/definitions/issue539.txtar --- a/cue/testdata/definitions/issue539.txtar +++ b/cue/testdata/definitions/issue539.txtar @@ -30,17 +30,3 @@ Disjuncts: 4 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - #Schema: { - ... - } - Component: { - hostname: (string|*"localhost") - _#foo: { - hello: "world" - } - } - hello: (〈0;#Schema〉 & 〈0;Component〉) -} diff --git a/cue/testdata/definitions/list.txtar b/cue/testdata/definitions/list.txtar --- a/cue/testdata/definitions/list.txtar +++ b/cue/testdata/definitions/list.txtar @@ -5,24 +5,6 @@ #R: { w: [{}, ...] } --- out/compile -- ---- in.cue -{ - c: (〈0;#R〉 & { - w: [ - {}, - { - b: int - }, - ] - }) - #R: { - w: [ - {}, - ..., - ] - } -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/definitions/root1.txtar b/cue/testdata/definitions/root1.txtar --- a/cue/testdata/definitions/root1.txtar +++ b/cue/testdata/definitions/root1.txtar @@ -22,12 +22,3 @@ Notifications: 1 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - root1: 1 - #Root1: { - x: {} - } - (〈0;#Root1〉 & {}) -} diff --git a/cue/testdata/definitions/root2.txtar b/cue/testdata/definitions/root2.txtar --- a/cue/testdata/definitions/root2.txtar +++ b/cue/testdata/definitions/root2.txtar @@ -20,10 +20,3 @@ Notifications: 1 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - root2: 1 - #Root2: {} - 〈0;#Root2〉 -} diff --git a/cue/testdata/definitions/root3.txtar b/cue/testdata/definitions/root3.txtar --- a/cue/testdata/definitions/root3.txtar +++ b/cue/testdata/definitions/root3.txtar @@ -21,14 +21,3 @@ Notifications: 1 NumCloseIDs: 4 --- out/compile -- ---- in.cue -{ - x: _ - #D: { - b: 〈1;x〉 - } - (〈0;#D〉 & { - b: _ - }) -} diff --git a/cue/testdata/definitions/root4.txtar b/cue/testdata/definitions/root4.txtar --- a/cue/testdata/definitions/root4.txtar +++ b/cue/testdata/definitions/root4.txtar @@ -34,19 +34,6 @@ Notifications: 2 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - #schema: { - a!: bool - } - (〈0;_hidden〉 & 〈0;#schema〉) - _hidden: { - a: true - notAllowed: true - } - allowed: true -} -- out/diff-v2-v3.txt -- Positions: v3 reports fewer positions than v2 for the "field not allowed" error. Reordering. diff --git a/cue/testdata/definitions/root5.txtar b/cue/testdata/definitions/root5.txtar --- a/cue/testdata/definitions/root5.txtar +++ b/cue/testdata/definitions/root5.txtar @@ -72,34 +72,6 @@ Notifications: 4 NumCloseIDs: 7 --- out/compile -- ---- in.cue -{ - 〈0;_schema〉 - _schema: 〈0;#Schema〉 - #Schema: { - a?: { - b?: string - } - } - a: { - b: "foo" - } - c: "foo" - x: { - 〈0;_schema〉 - _schema: 〈0;#Schema〉 - #Schema: { - a?: { - b?: string - } - } - a: { - b: "foo" - } - c: "foo" - } -} -- out/diff-v2-v3.txt -- Reordering Verdict: cosmetic -- Field reordering only. No semantic change. diff --git a/cue/testdata/definitions/root6.txtar b/cue/testdata/definitions/root6.txtar --- a/cue/testdata/definitions/root6.txtar +++ b/cue/testdata/definitions/root6.txtar @@ -39,29 +39,3 @@ MaxConjunctInfos: 3 MaxReqSets: 7 MaxRedirect: 2 --- out/compile -- ---- in.cue -{ - c: "foo" - a: { - b: int - } - 〈0;#Schema〉 - #Schema: close({ - a: { - b: int - } - }) - x: { - c: "foo" - a: { - b: int - } - 〈0;#Schema〉 - #Schema: close({ - a: { - b: int - } - }) - } -} diff --git a/cue/testdata/definitions/root7.txtar b/cue/testdata/definitions/root7.txtar --- a/cue/testdata/definitions/root7.txtar +++ b/cue/testdata/definitions/root7.txtar @@ -16,17 +16,3 @@ Notifications: 1 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - root: { - input: { - #deps: { - root: {} - } - } - } - { - 〈1;root〉.input.#deps - } -} diff --git a/cue/testdata/definitions/root8.txtar b/cue/testdata/definitions/root8.txtar --- a/cue/testdata/definitions/root8.txtar +++ b/cue/testdata/definitions/root8.txtar @@ -29,31 +29,5 @@ Notifications: 1 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - root: { - input: { - foo: { - metadata: { - name: (*"foo"|string) - } - id: "id-\(〈0;metadata〉.name)" - #deps: { - [string]: _ - } - #deps: { - root: {} - } - spec: { - replicas: 1 - } - } - } - } - { - 〈1;root〉.input.foo.#deps - } -} -- out/diff-v2-v3.txt -- Disjunctions with defaults: needs @test(final) for default field selection diff --git a/cue/testdata/definitions/typocheck.txtar b/cue/testdata/definitions/typocheck.txtar --- a/cue/testdata/definitions/typocheck.txtar +++ b/cue/testdata/definitions/typocheck.txtar @@ -1084,1107 +1084,3 @@ Errors differ between v2 and v3 evaluators (v3 reports fewer positions). Structure sharing differences between v2 and v3. Verdict: mix -- improvement: v3 uses structure sharing. worsening: v3 reports fewer error positions. --- out/compile -- ---- chaineddef.cue -{ - issue3920: { - out: { - 〈1;#A〉 - a: { - b: "out" - } - } - #A: { - a?: 〈1;#B〉 - } - #B: { - c?: string - } - } - onlyCloseDirectStruct: { - #foo: {} - x: { - y: { - { - a: 〈3;#foo〉 - } - } - } - x: { - y: { - b: 1 - } - } - } - closeInEmbed: { - x: { - close({ - { - ["d"]: { - f: int - } - } - }) - } - x: { - d: { - e: 1 - } - } - } -} ---- cycle.cue -{ - issue4006: { - #A: { - 〈1;#B〉 - fieldA: string - } - #B: { - 〈1;#A〉 - } - #C: (〈0;#A〉 & {}) - out: (〈0;#C〉 & 〈0;#B〉) - } -} ---- disjunction.cue -{ - issue3947: { - full: { - #Schema: { - allowed?: string - } - _defaults: { - disallowed: (_|*"default value") - } - out: (〈0;#Schema〉 & 〈0;_defaults〉) - } - } - issue3957: { - reduced: { - c: { - a: "bar" - } - c: (〈0;#B〉 & { - a: (string|*"foo") - }) - #B: { - b?: string - } - } - } - issue3957: { - full: { - #oneof: ({ - a: string - }|{ - b?: [ - ...string, - ] - }) - c: (〈0;#oneof〉 & { - a: (string|*"foo") - }) - c: { - a: "bar" - } - } - } - issue3957: { - derived: { - t1: { - #Schema: { - in: (string|[ - ...string, - ]) - out: 〈import;list〉.FlattenN([ - 〈1;in〉, - ], 1) - } - x: (〈0;#Schema〉 & { - in: "foo" - }) - } - } - } - issue3957: { - derived: { - t2: { - #Schema: { - in: (string|[ - ...string, - ]) - let _flat#1 = 〈import;list〉.FlattenN([ - 〈1;in〉, - ], 1) - out: 〈0;let _flat#1〉 - } - out: (〈0;#Schema〉 & { - in: "foo" - }) - } - } - } -} ---- ellipsis.cue -{ - nestedEllipsis: { - minimal: { - out: (〈0;#Schema〉 & { - extra: "foo" - }) - #Schema: { - 〈1;#meta〉 - ... - } - #meta: {} - } - } - nestedEllipsis: { - nestedWithPatterns: { - out: (〈0;#Schema〉 & { - objs: { - obj1: { - extra: "foo" - } - } - }) - #Schema: { - [_]: { - [_]: { - 〈2;#meta〉 - ... - } - } - #meta: { - name?: int - } - objs?: _ - } - } - } - issue4015: { - reduced: { - #X: { - ... - } - out: { - 〈1;#X〉 - a: { - b: string - } - } - out: { - a: { - c: "h" - b: "x" - } - } - } - } - issue4015: { - nested: { - #X: { - foo: { - ... - } - } - out: { - 〈1;#X〉 - foo: { - a: { - b: string - } - } - } - out: { - foo: { - a: { - c: "h" - b: "x" - } - } - } - } - } - issue4015: { - full: { - #Schema: { - cfg: { - foo: { - enabled: (bool|*false) - fooField: string - } - bar: { - barField: string - } - } - capacity: (int|*3) - } - #MoreCapacity: { - capacity: 30 - ... - } - out: 〈0;#Schema〉 - out: { - 〈1;#MoreCapacity〉 - cfg: { - foo: { - enabled: true - } - } - } - out: { - cfg: { - foo: { - fooField: "h" - } - bar: { - barField: "x" - } - } - } - } - } -} ---- embedelim.cue -{ - issue3921: { - top: { - #A: 〈0;#B〉 - #A: { - b: string - } - #B: _ - a: { - (〈1;#A〉 & {}) - } - } - } - issue3921: { - hidden: { - #A: 〈0;#B〉 - #A: { - _hidden: { - b: string - } - } - #B: {} - a: { - (〈1;#A〉 & { - _hidden: {} - }) - } - } - } - issue3921: { - full: { - out: (〈0;#templateList〉 & 〈0;#defineMap〉) - #templateList: { - #stepMap: { - [string]: _ - } - stepList: [ - for _, c in 〈1;#stepMap〉 { - 〈1;c〉 - }, - ] - } - #defineMap: { - #stepMap: { - foo: (〈2;#Step〉 & { - image: "bar" - #config: {} - }) - } - stepList: _ - } - #Step: (〈0;#StepInner〉 & { - image: string - #config: { - version: string - } - }) - #StepInner: { - image: string - } - } - } -} ---- in.cue -{ - embed: { - simple: { - #A: { - b: 1 - } - a: { - 〈1;#A〉 - } - a: { - err: 1 - } - } - } - embed: { - andInStruct: { - #Foo: { - a: int - } - a: { - (〈1;#Foo〉 & { - err: 2 - }) - } - } - } - embed: { - embedDefWithEmbedding: { - #Foo: { - { - a: int - } - } - a: { - (〈1;#Foo〉 & { - err: 2 - }) - } - } - } - embed: { - embedComprehension: { - #Foo: { - if true { - a: int - } - } - a: { - (〈1;#Foo〉 & { - err: 2 - }) - } - } - } - embed: { - fieldWithAnd: { - #A: {} - { - a: (〈1;#A〉 & { - err: 3 - }) - } - } - } - embed: { - embedAndRecursive: { - #A: { - a: int - } - B: { - x: 〈1;#A〉 - } - (〈0;B〉 & { - x: { - err: 2 - } - }) - } - } - embed: { - andEmbed: { - #A: { - b: int - } - #B: { - b: int - } - #D: { - (〈1;#A〉 & 〈1;#B〉) - } - d: (〈0;#D〉 & { - err: 3 - }) - } - } - and: { - transitive: { - ok: { - Z: { - a: string - } - #Y: 〈0;Z〉 - #X: (〈0;#Y〉 & 〈0;Z〉) - out: (〈0;#X〉 & { - a: "foo" - }) - } - } - } - and: { - transitive: { - err: { - Z: { - a: string - } - #Y: 〈0;Z〉 - #X: (〈0;#Y〉 & 〈0;Z〉) - out: (〈0;#X〉 & { - err: "foo" - }) - } - } - } - and: { - transitiveWithEmbed: { - ok: { - Z: { - a: string - } - #X: (〈0;#Y〉 & 〈0;Z〉) - #Y: { - 〈1;Z〉 - } - out: (〈0;#X〉 & { - a: "foo" - }) - } - } - } - and: { - transitiveWithEmbed: { - err: { - Z: { - a: string - } - #X: (〈0;#Y〉 & 〈0;Z〉) - #Y: { - 〈1;Z〉 - } - out: (〈0;#X〉 & { - err: "foo" - }) - } - } - } - embed: { - nonDef: { - t1: { - X: { - a: string - } - #Y: (〈0;#Z〉 & 〈0;X〉) - #Z: { - 〈1;X〉 - b?: string - } - } - } - } - embed: { - defAndHidden: { - full: { - _stepCommon: { - Name: string - } - #Step: (〈0;#Command〉 & 〈0;_stepCommon〉) - #Command: { - 〈1;_stepCommon〉 - Path?: string - } - out: (〈0;#Step〉 & { - Name: "foo" - }) - } - } - } - embed: { - withIndirect: { - A: 〈0;#B〉 - #B: { - b: int - } - (〈0;A〉 & { - err: 2 - }) - } - } -} ---- inline.cue -{ - embedInline: { - #Schema: { - a: "hello" - b: { - { - x: { - c: "foo" - } - }.x - } - b: { - c: string - d: "never printed" - } - } - out: (〈0;#Schema〉 & _|_(no sharing)) - } - issue3853: { - #Schema: { - a: "hello" - b: { - { - x: { - c: "foo" - } - }.x - } - b: { - c: string - d: "never printed" - } - } - out: { - x: (〈1;#Schema〉 & {}).a - }.x - } -} ---- issue3832.cue -{ - issue3832: { - _person: { - self: { - firstName: "Sam" - } - } - #T: { - _subject: { - in: _ - out: { - let self#2 = 〈1;in〉.self - outFirstName: 〈0;let self#2〉.firstName - } - } - _assert: { - pass: _ - } - _assert: ({ - check!: _ - pass: "never" - }|{ - invoke!: _ - pass: (〈1;_subject〉 & { - in: 〈1;invoke〉 - }).out - }) - results: 〈0;_assert〉.pass - } - (〈0;#T〉 & { - _assert: { - invoke: 〈2;_person〉 - } - }) - } -} ---- issue3833.cue -{ - issue3833: { - ok: { - out: { - (〈1;#A〉 & { - a: 〈2;#B〉 - }) - } - #A: { - a: { - b: string - ... - } - ... - } - #C: { - c: string - } - #B: { - (〈1;#C〉 & { - c: "foo" - }) - b: "foo" - } - } - } - issue3833: { - evalv2Issue: { - out: { - (〈1;#A〉 & { - a: 〈2;#B〉 - }) - } - #A: { - a: { - b: string - } - ... - } - #C: { - c: string - } - #B: { - (〈1;#C〉 & { - c: "foo" - }) - b: "foo" - } - } - } -} ---- issue3837.cue -{ - issue3837: { - reduced: { - A: { - 〈1;#Embed〉 - extra: "foo" - } - out: { - { - x: (〈2;A〉 & _|_(no sharing)) - } - } - #Embed: {} - } - } - issue3837: { - full: { - #Embed: {} - #A: { - 〈1;#Embed〉 - extra: "foo" - } - #B: (〈0;#C〉|{}) - #C: { - bar: string - } - out: (〈0;#B〉 & { - bar: "baz" - { - #def: (〈2;#A〉 & _|_(no sharing)) - } - }) - } - } -} ---- issue3839.cue -{ - issue3839: { - reduced: { - x: { - (〈1;A〉 & _|_(no sharing)) - } - x: { - y: 1 - } - #B: {} - A: { - 〈1;#B〉 - ... - } - } - } - issue3839: { - full: { - _globals: { - glb: { - globalField: "" - } - } - #GlobalContext: { - globalField: string - } - #Context: { - glb: 〈1;#GlobalContext〉 - out: 〈0;glb〉 - } - out: { - ingress: { - (〈2;#Ingress〉 & { - #def: (〈3;#Context〉 & 〈3;_globals〉).out - }) - } - ingress?: { - foo: 1234 - bar: "http" - } - } - #Embed: { - #def: { - ... - } - } - #Ingress: { - 〈1;#Embed〉 - ... - } - } - } -} ---- issue3843.cue -{ - dedupPattern: { - t1: { - p1: { - A: { - #Z: { - [string]: _ - } - x: 〈0;#Z〉 - x: { - y: { - z: 1 - } - } - } - B: (〈0;A〉 & _|_(no sharing)) - out: (〈0;A〉.#Z & 〈0;B〉.x) - } - } - } - dedupPattern: { - t1: { - p2: { - A: { - #Z: { - [string]: _ - } - x: 〈0;#Z〉 - x: { - y: { - z: 1 - } - } - } - B: (〈0;A〉 & _|_(no sharing)) - out: (〈0;B〉.x & 〈0;A〉.#Z) - } - } - } -} ---- issue3858.cue -{ - orig: { - t1: { - #Image: { - embed: { - image: "foo:v1" - } - } - #JobConfig: { - image: 〈1;#Image〉 - job: (〈1;#Job〉 & { - 〈1;image〉.embed - }) - } - #Job: { - image: string - vcs: "git" - args: [ - ...string, - ] - env: { - [string]: string - } - } - #Output: { - _in: _ - out: (〈0;_in〉 & {}) - } - (〈0;#Output〉 & { - _in: (〈1;#JobConfig〉 & {}).job - }) - } - } - reduced: { - t1: { - Y: { - a: { - e: "foo" - } - b: (〈1;X〉 & { - 〈1;a〉 - }) - } - X: { - e: string - f: 1 - } - #Z: { - _in: _ - out: (〈0;_in〉 & _|_(no sharing)) - } - (〈0;#Z〉 & { - _in: 〈1;Y〉 - }) - } - } - orig: { - t2: { - #JobConfig: { - image: { - spec: { - image: "someimage" - } - } - job: (〈1;#Job〉 & { - 〈1;image〉.spec - }) - } - #Job: { - image: string - env: "FOO" - } - #Output: { - in: _ - out: (〈0;in〉 & {}).input - } - out: (〈0;#Output〉 & { - in: { - input: (〈2;#JobConfig〉 & {}).job - } - }) - } - } - reduced: { - t2: { - Y: { - a: { - e: "foo" - } - b: (〈1;X〉 & { - 〈1;a〉 - }) - } - X: { - e: string - f: 1 - } - #Z: { - _in: _ - out: 〈0;_in〉 - } - (〈0;#Z〉 & { - _in: 〈1;Y〉 - }) - } - } -} ---- issue3934.cue -{ - issue3934: { - out: (〈0;#Foo〉 & { - foo: { - if false { - extra: { - nested: 123 - } - } - } - }) - #Foo: { - foo?: (null|〈1;#Bar〉|*{ - bar: 3 - }) - } - #Bar: { - bar?: int - extra?: (null|{ - ... - }) - } - } -} ---- issue3964.cue -{ - issue3964: { - reduced: { - #Output: { - 〈1;#Embedded〉 - } - #Embedded: { - name: string - (〈1;#Unused〉|〈1;#Used〉) - } - #Unused: {} - #Used: {} - } - } - issue3964: { - full: { - out: (〈0;#Output〉 & { - name: "oauth2" - used: "bar" - }) - #Output: { - 〈1;#Embedded〉 - } - #Embedded: { - name: string - (〈1;#Unused〉|〈1;#Used〉) - } - #Unused: { - unused: string - } - #Used: { - used: string - } - } - } -} ---- large.cue -{ - full: { - #Resource: { - someMsg: string - obs: ({}|*{ - missing: true - }) - let pickMsg#3 = [ - if 〈1;obs〉.missing { - msg: "\(〈2;someMsg〉)" - }, - { - msg: "bar" - }, - ][0] - patches: [ - { - op: "add" - path: "/metadata" - value: 〈2;let pickMsg#3〉.msg - }, - ] - } - #Patches: { - [string]: _ - } - #JSONPatch: { - namespace?: string - patch: [ - ...〈2;#JSONOp〉, - ] - output: (〈1;#Patches〉 & { - 〈1;namespace〉: 〈1;patch〉 - }) - } - #JSONOp: ({ - op: "add" - path: string - value: _ - }|{ - op: "remove" - path: string - }) - #Main: { - namespace: string - output: 〈0;let jsonPatch#4〉.output - let jsonPatch#4 = (〈1;#JSONPatch〉 & { - let base#7 = (〈2;#Resource〉 & {}) - let withMsg#8 = (〈0;let base#7〉 & { - someMsg: "foo" - }) - namespace: 〈1;namespace〉 - patch: 〈0;let withMsg#8〉.patches - }) - } - out: (〈0;#Main〉 & { - namespace: "ns1" - }).output - } -} ---- validators.cue -{ - embed: { - normalValidator: { - #X: { - 〈import;struct〉.MaxFields(1) - a?: int - b?: int - } - x: 〈0;#X〉 - x: { - err: 1 - } - } - } - embed: { - openValidator: { - t1: { - #X: { - matchN(0, []) - a?: int - b?: int - } - x: 〈0;#X〉 - x: { - err: 1 - } - } - } - } - embed: { - openValidator: { - t2: { - Y: matchN(1, [ - 〈1;X〉, - ]) - X: { - b?: 〈1;Y〉 - } - a: 〈0;X〉 - a: { - b: 1 - } - } - } - } - disjunction: { - withErr: { - t1: { - params: {} - out: (〈0;#Schema1〉 & { - b1: { - b2: { - b3: 〈3;params〉.mayExistLater - } - } - }) - #Schema1: { - b1?: (null|〈1;#Schema2〉) - } - #Schema2: { - b2?: (null|{ - b3?: string - }) - } - } - } - } - embed: { - nestedValidator: { - #types: { - z?: 〈import;list〉.UniqueItems - } - x: { - y: { - z: [ - 1, - ] - } - } - x: { - 〈1;#def〉 - y?: 〈1;#types〉 - } - #def: {} - } - } -} diff --git a/cue/testdata/definitions/visibility.txtar b/cue/testdata/definitions/visibility.txtar --- a/cue/testdata/definitions/visibility.txtar +++ b/cue/testdata/definitions/visibility.txtar @@ -26,17 +26,5 @@ Disjuncts: 0 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - #foo: { - name: string - } - foo: (〈0;#foo〉 & { - _name: "foo" - _#name: "bar" - #name: "baz" - }) -} -- out/diff-v2-v3.txt -- Reordering: v3 outputs fields in different order than v2 (name appears after hidden fields in v3). diff --git a/cue/testdata/disjunctions/019_ips.txtar b/cue/testdata/disjunctions/019_ips.txtar --- a/cue/testdata/disjunctions/019_ips.txtar +++ b/cue/testdata/disjunctions/019_ips.txtar @@ -31,40 +31,6 @@ ] MyIP: [10, 10, 10, 10] }) --- out/compile -- ---- in.cue -{ - IP: 〈import;list〉.Repeat([ - &(int, >=0, <=255), - ], 4) - Private: (*[ - 192, - 168, - &(int, >=0, <=255), - &(int, >=0, <=255), - ]|[ - 10, - &(int, >=0, <=255), - &(int, >=0, <=255), - &(int, >=0, <=255), - ]|[ - 172, - (>=16 & <=32), - &(int, >=0, <=255), - &(int, >=0, <=255), - ]) - Inst: (〈0;Private〉 & [ - _, - 10, - ..., - ]) - MyIP: (〈0;Inst〉 & [ - _, - _, - 10, - 10, - ]) -} -- out/eval/stats -- Leaks: 10 Freed: 52 diff --git a/cue/testdata/disjunctions/confluence.txtar b/cue/testdata/disjunctions/confluence.txtar --- a/cue/testdata/disjunctions/confluence.txtar +++ b/cue/testdata/disjunctions/confluence.txtar @@ -24,30 +24,3 @@ addr: "10.10.10.10" @test(eq, {addr: "10.10.10.10"}) } --- out/compile -- ---- in.cue -{ - issue3993: { - reduced: { - x: (〈import;net〉.IPv4|=~"fail") - x: { - if 〈import;net〉.IPv4(〈1;x〉) { - =~"^10\\." - } - } - x: "10.10.10.10" - } - } - issue3993: { - full: { - addr!: (string & (〈import;net〉.IPv4|〈import;net〉.IPv6)) - if 〈import;net〉.IPv4(〈0;addr〉) { - addr: 〈import;strings〉.HasPrefix("10.") - } - if 〈import;net〉.IPv6(〈0;addr〉) { - addr: 〈import;strings〉.HasPrefix("2a02:") - } - addr: "10.10.10.10" - } - } -} diff --git a/cue/testdata/disjunctions/crossembed.txtar b/cue/testdata/disjunctions/crossembed.txtar --- a/cue/testdata/disjunctions/crossembed.txtar +++ b/cue/testdata/disjunctions/crossembed.txtar @@ -38,13 +38,3 @@ Disjuncts: 2 NumCloseIDs: 4 --- out/compile -- ---- in.cue -{ - out: 〈import;"foo.test/main/imported"〉 - out: { - either: { - foo: "world" - } - } -} diff --git a/cue/testdata/disjunctions/defaults.txtar b/cue/testdata/disjunctions/defaults.txtar --- a/cue/testdata/disjunctions/defaults.txtar +++ b/cue/testdata/disjunctions/defaults.txtar @@ -30,34 +30,6 @@ #Bar: {fieldFoo: _, fieldBar: *_ | string} }) } --- out/compile -- ---- in.cue -{ - passToSingleValue: { - p1: (_|*((_|*"x") & "y")) - } - passToSingleValue: { - p2: (_|*((*"x"|_) & "y")) - } - passToSingleValue: { - p3: (*((_|*"x") & "y")|_) - } - passToSingleValue: { - p4: (*((*"x"|_) & "y")|_) - } - issue3779: { - out: (〈0;#Foo〉 & { - fieldFoo: "foo" - }) - #Foo: (〈0;#Bar〉 & { - fieldFoo: (string|*"foo-default") - }) - #Bar: { - fieldFoo: _ - fieldBar: (string|*〈0;fieldFoo〉) - } - } -} -- out/eval/stats -- Leaks: 7 Freed: 39 diff --git a/cue/testdata/disjunctions/defembed.txtar b/cue/testdata/disjunctions/defembed.txtar --- a/cue/testdata/disjunctions/defembed.txtar +++ b/cue/testdata/disjunctions/defembed.txtar @@ -57,45 +57,6 @@ a: *"a" | "b" | "c" }) } --- out/compile -- ---- in.cue -{ - x: { - m1: ((1|(*2|3)) & (>=2 & <=3)) - m2: ((1|(*2|3)) & (2|3)) - m3: ((*1|*(*2|3)) & (2|3)) - } - y1: (〈0;x〉 & { - { - m4: ((〈2;x〉.m1 + 〈2;x〉.m2) + 〈2;x〉.m3) - } - }) - y2: { - 〈1;x〉 - { - m4: ((〈2;y2〉.m1 + 〈2;y2〉.m2) + 〈2;y2〉.m3) - } - } - y3: { - 〈1;x〉 - { - m4: ((〈2;y3〉.m1 + 〈2;y3〉.m2) + 〈2;y3〉.m3) - } - } - y4: (〈0;x〉 & { - { - m4: ((〈2;y4〉.m1 + 〈2;y4〉.m2) + 〈2;y4〉.m3) - } - }) - z: { - b: ((*"a"|"b")|"c") - ({ - a: 〈1;b〉 - }|{ - b: int - }) - } -} -- out/eval/stats -- Leaks: 40 Freed: 120 diff --git a/cue/testdata/disjunctions/discriminator.txtar b/cue/testdata/disjunctions/discriminator.txtar --- a/cue/testdata/disjunctions/discriminator.txtar +++ b/cue/testdata/disjunctions/discriminator.txtar @@ -287,110 +287,3 @@ Disjuncts: 92 NumCloseIDs: 30 --- out/compile -- ---- in.cue -{ - noKind: { - manyWithStructEmbed: { - #Def: ({ - <10 - _hidden: "field" - }|>200|string) - out: (〈0;#Def〉 & 123) - } - manyStructsEmpty: { - #Def: ({ - f1!: int - }|{ - f2!: int - }|string) - out: (〈0;#Def〉 & {}) - } - manyScalars: { - #Def: (1|2|3) - out: (〈0;#Def〉 & 123) - } - zeroScalars: { - #Def: (int|string|null) - out: (〈0;#Def〉 & true) - } - } - byKind: { - nullableStructRegular: { - #Def1: { - f1: (null|〈1;#Def2〉) - } - #Def2: { - f2: (null|〈1;#Def3〉) - } - #Def3: { - f3: (null|int) - } - out: (〈0;#Def1〉 & { - f1: { - f2: { - f3: "not an int" - } - } - }) - } - nullableStructRequired: { - #Def1: { - f1!: (null|〈1;#Def2〉) - } - #Def2: { - f2!: (null|〈1;#Def3〉) - } - #Def3: { - f3!: (null|int) - } - out: (〈0;#Def1〉 & { - f1: { - f2: { - f3: "not an int" - } - } - }) - } - nullableStructOptional: { - #Def1: { - f1?: (null|〈1;#Def2〉) - } - #Def2: { - f2?: (null|〈1;#Def3〉) - } - #Def3: { - f3?: (null|int) - } - out: (〈0;#Def1〉 & { - f1: { - f2: { - f3: "not an int" - } - } - }) - } - nullableList: { - #Def1: [ - ...(null|〈1;#Def2〉), - ] - #Def2: [ - ...(null|〈1;#Def3〉), - ] - #Def3: [ - ...(null|int), - ] - out: (〈0;#Def1〉 & [ - [ - [ - "not an int", - ], - ], - ]) - } - scalarConstraints: { - #Def: (>10|""|null|false) - out: (〈0;#Def〉 & 5) - } - } -} diff --git a/cue/testdata/disjunctions/edge.txtar b/cue/testdata/disjunctions/edge.txtar --- a/cue/testdata/disjunctions/edge.txtar +++ b/cue/testdata/disjunctions/edge.txtar @@ -203,149 +203,3 @@ issue4251_notC, issue4251_notB, issue4251_notB_reversed: these are only evaluated correctly by v3. cyclicalInsertInDisjunction.err1: should be an error for both evaluators but both produce concrete values. preseveBottomSemantics: both evaluators are incorrect; result should be _ or _|{}. --- out/compile -- ---- in.cue -{ - cyclicalInsertInDisjunction: { - ok1: { - c: { - d: 〈0;e〉 - e: _ - } - c: ({ - d: 1 - e: 2 - }|{ - d: 2 - e: 2 - }) - } - maybe1: { - c: { - d: 〈1;c〉.e - } - c: ({ - d: 1 - e: 2 - }|{ - d: 2 - e: 2 - }) - } - err1: { - x: 〈0;c〉.e - c: { - d: 〈1;x〉 - } - c: ({ - d: 1 - e: 2 - }|{ - d: 2 - e: 2 - }) - } - err2: { - x: div(〈0;c〉.e, 2) - c: { - d: 〈1;x〉 - } - c: ({ - d: 1 - e: 2 - }|{ - d: 2 - e: 3 - }) - } - err3: { - x: 〈0;c〉.e - c: { - d: (1|2|〈1;x〉) - } - c: ({ - d: 1 - e: 2 - }|{ - d: 2 - e: 3 - }) - } - } - preseveBottomSemantics: { - ok: { - #x: { - (〈1;#x〉|{}) - } - } - } - eliminateOpenVariant: { - ok: { - c: ({ - a: 1 - }|〈0;#b〉) - #b: { - a: 1 - } - } - } - cyclicSelfElimination: { - ok: { - y: (1|{ - y: 1 - }) - 〈0;y〉 - } - } - issue4251_notC: { - #NotC: { - string - _must: (true & (〈1〉 != "c")) - } - a: 〈0;#NotC〉 - a: ("a"|"b") - a: "a" - } - issue4251_notB: { - #NotB: { - string - _must: (true & (〈1〉 != "b")) - } - a: 〈0;#NotB〉 - a: ("a"|"b") - a: "a" - } - issue4251_notB_reversed: { - #NotB: { - string - _must: (true & (〈1〉 != "b")) - } - a: 〈0;#NotB〉 - a: ("b"|"a") - a: "a" - } -} ---- panic.cue -{ - panic1: { - #TypeFoo: { - name: "foo" - foo_field: string - } - #TypeBar: { - 〈1;#TypeBar2〉 - bar_field?: string - } - #TypeBar2: { - name: "bar" - } - objs: { - obj1: { - type: (〈2;#TypeFoo〉|〈2;#TypeBar〉) - type: (*〈2;objs〉["missing"]|〈2;#TypeFoo〉|〈2;#TypeBar〉) - } - } - out: (〈0;#TypeFoo〉|〈0;#TypeBar〉) - out: 〈0;objs〉["obj1"].type - } -} diff --git a/cue/testdata/disjunctions/elimination.txtar b/cue/testdata/disjunctions/elimination.txtar --- a/cue/testdata/disjunctions/elimination.txtar +++ b/cue/testdata/disjunctions/elimination.txtar @@ -1171,1325 +1171,3 @@ NumCloseIDs: 323 -- out/todo.txt -- issue2685: only evaluated by v3 evaluator. --- out/compile -- ---- in.cue -{ - disambiguateClosed: { - b: (〈0;#Def〉 & 〈0;a〉) - a: 〈0;#Def〉 - #Def: { - ({ - x: true - }|{ - y: true - }) - } - } - alwaysCheckMatchers1: { - b: ({ - [=~"^xxxx$"]: int - }|null) - b: ({ - c: string - }|null) - b: { - c: "yyyyy" - } - } - alwaysCheckPatterns2: { - a: 〈0;#X〉 - a: 〈0;b〉 - b: 〈0;#X〉 - b: { - c: "yyyyy" - } - #X: (string|{ - c: string - { - [=~"^xxxx$"]: int - } - }) - } - nestedNonMonotonic: { - resolved: { - n1: { - x: ({ - a: 〈import;struct〉.MinFields(2) - }|null) - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: { - d: 1 - } - }|null) - } - } - } - nestedNonMonotonic: { - resolved: { - n2: { - x: ({ - a: { - b: 〈import;struct〉.MinFields(2) - } - }|null) - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - } - } - } - nestedNonMonotonic: { - eliminated: { - n1: { - p1: { - x: ({ - a: 〈import;struct〉.MaxFields(1) - }|null) - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: { - d: 1 - } - }|null) - } - } - } - } - nestedNonMonotonic: { - eliminated: { - n1: { - p2: { - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: 〈import;struct〉.MaxFields(1) - }|null) - x: ({ - a: { - d: 1 - } - }|null) - } - } - } - } - nestedNonMonotonic: { - eliminated: { - n1: { - p2: { - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: { - d: 1 - } - }|null) - x: ({ - a: 〈import;struct〉.MaxFields(1) - }|null) - } - } - } - } - nestedNonMonotonic: { - eliminated: { - n2: { - p1: { - x: ({ - a: { - b: 〈import;struct〉.MaxFields(1) - } - }|null) - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - } - } - } - } - nestedNonMonotonic: { - eliminated: { - n2: { - p2: { - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: 〈import;struct〉.MaxFields(1) - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - } - } - } - } - nestedNonMonotonic: { - eliminated: { - n2: { - p2: { - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - x: ({ - a: { - b: 〈import;struct〉.MaxFields(1) - } - }|null) - } - } - } - } - nestedNonMonotonic: { - incomplete: { - a: { - n1: { - p1: { - x: ({ - a: 〈import;struct〉.MinFields(2) - }|null) - x: ({ - a: { - c: 1 - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - a: { - n1: { - p2: { - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: 〈import;struct〉.MinFields(2) - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - a: { - n2: { - p1: { - x: ({ - a: { - b: 〈import;struct〉.MinFields(2) - } - }|null) - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - a: { - n2: { - p2: { - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: 〈import;struct〉.MinFields(2) - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - b: { - n1: { - p1: { - x: ({ - a: 〈import;struct〉.MinFields(3) - }|null) - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: { - d: 1 - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - b: { - n1: { - p2: { - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: 〈import;struct〉.MinFields(3) - }|null) - x: ({ - a: { - d: 1 - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - b: { - n1: { - p3: { - x: ({ - a: { - c: 1 - } - }|null) - x: ({ - a: { - d: 1 - } - }|null) - x: ({ - a: 〈import;struct〉.MinFields(3) - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - b: { - n2: { - p1: { - x: ({ - a: { - b: 〈import;struct〉.MinFields(3) - } - }|null) - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - b: { - n2: { - p1: { - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: 〈import;struct〉.MinFields(3) - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - } - } - } - } - } - nestedNonMonotonic: { - incomplete: { - b: { - n2: { - p1: { - x: ({ - a: { - b: { - c: 1 - } - } - }|null) - x: ({ - a: { - b: { - d: 1 - } - } - }|null) - x: ({ - a: { - b: 〈import;struct〉.MinFields(3) - } - }|null) - } - } - } - } - } - preserveClosedness: { - small: { - p1: { - #A: (〈0;#B〉 & { - a: string - }) - #B: { - (*{}|{ - a: string - }) - (*{}|{ - b: int - }) - } - } - } - } - preserveClosedness: { - small: { - p2: { - #A: (〈0;#B〉 & { - a: string - }) - #B: { - ({ - a: string - }|*{}) - (*{}|{ - b: int - }) - } - } - } - } - preserveClosedness: { - medium: { - p1: { - #A: (〈0;#B〉 & { - a: string - }) - #B: { - (*{}|{ - a: string - }|{ - b: string - }) - (*{}|{ - c: int - }|{ - d: string - }) - } - } - } - } - preserveClosedness: { - medium: { - p2: { - #A: (〈0;#B〉 & { - a: string - }) - #B: { - ({ - a: string - }|*{}|{ - b: string - }) - (*{}|{ - c: int - }|{ - d: string - }) - } - } - } - } - preserveClosedness: { - medium: { - p3: { - #A: (〈0;#B〉 & { - a: string - }) - #B: { - ({ - a: string - }|{ - b: string - }|*{}) - (*{}|{ - c: int - }|{ - d: string - }) - } - } - } - } - noChildError: _ - noChildError: { - issue1608: { - myValue: (〈0;#type〉 & { - fieldName: "some string" - }) - #type: { - fieldName: 〈1;#subtype〉 - } - #subtype: (string|{ - foo: string - }|{ - bar: 〈1;#subtype〉 - }) - } - } - noChildError: { - t1: { - #D: ({ - b: string - }|{ - c: 〈1;#D〉 - }) - o: (〈0;#D〉 & { - b: "test" - }) - } - } - noChildError: { - t2: { - o: (〈0;#D〉 & { - b: "test" - }) - #D: ({ - b: string - }|{ - c: 〈1;#D〉 - }) - } - } - noChildError: { - t3: { - #D: ({ - a: null - }|{ - b: string - }|{ - c: 〈1;#D〉 - }) - o: (〈0;#D〉 & { - b: "test" - }) - } - } - noChildError: { - t4: { - o: (〈0;#D〉 & { - b: "test" - }) - #D: ({ - a: null - }|{ - b: string - }|{ - c: 〈1;#D〉 - }) - } - } - issue1924: { - t1: { - m: { - a: 2 - } - x: (*[ - 〈1;m〉.b, - ]|2) - } - } - issue1924: { - t2: { - m: { - a: 2 - } - x: (*{ - v: 〈1;m〉.b - }|3) - } - } - issue1924: { - t3: { - m: { - a: 2 - } - x: (*〈0;m〉.b|1) - } - } - issue1838: { - t1: { - p?: [] - a: ([ - for _, k in 〈1;p〉 { - 〈1;k〉 - }, - ]|null) - } - } - issue1838: { - t2: { - p?: [] - a: (null|[ - for _, k in 〈1;p〉 { - 〈1;k〉 - }, - ]) - } - } - noHang: { - #T: ([ - "a", - 〈1;#T〉, - ]|[ - "d", - ...〈1;#T〉, - ]) - x: 〈0;#T〉 - #X: 〈0;x〉 - #X: 〈0;#T〉 - } - issue1940: { - #T: ([ - "a", - 〈1;#T〉, - ]|[ - "b", - 〈1;#T〉, - ]|[ - "c", - 〈1;#T〉, - ]|[ - "d", - [ - ...〈2;#T〉, - ], - ]) - #A: { - type: 〈1;#T〉 - } - #B: { - [string]: 〈1;#A〉 - } - #C: (〈0;#B〉 & { - x: 〈1;#A〉 - }) - } -} ---- issue1417.cue -{ - issue1417: { - #ID: (!~"^a"|=~"^ab$"|=~"^aB$") - #ID: (=~"^a"|!~"[A-Z]") - ids: ([ - ...〈1;#ID〉, - ] & [ - "xyz", - "ab", - "aB", - ]) - } -} ---- issue2209full.cue -{ - issue2209: { - simplified: { - t1: { - #SpecFoo: { - foo: { - min: 1 - } - } - #SpecBar: { - bar: { - min: 1 - } - } - spec: { - bar: {} - } - spec: (〈0;#SpecFoo〉|〈0;#SpecBar〉) - out: { - ({ - nullFoo: null - }|{ - nullBar: null - }) - ({ - minFoo: int - }|{ - minBar: int - }) - if (〈0;X〉.bar != _|_(explicit error (_|_ literal) in source)) { - minBar: 〈1;X〉.bar.min - } - X: 〈1;spec〉 - } - } - } - } - issue2209: { - simplified: { - t2: { - #SpecFoo: { - foo: {} - } - #SpecBar: { - bar: { - x: 1 - } - } - spec: { - bar: {} - } - spec: (*〈0;#SpecFoo〉|〈0;#SpecBar〉) - if (〈0;spec〉.bar != _|_(explicit error (_|_ literal) in source)) { - BAZ: 〈1;spec〉.bar.x - } - ({ - f1: int - }|{ - b2: int - }) - ({ - f2: int - }|{ - b2: int - }) - } - } - } - issue2209: { - simplified: { - t3: { - #A: { - v: 1 - } - ({ - f1: int - }|{ - b2: int - }) - ({ - f2: int - }|{ - b2: int - }) - BAZ: 〈0;S〉.y - S: (*〈0;#A〉|〈0;#B〉) - #B: { - x: 1 - y: 1 - } - S: { - x: 1 - } - } - } - } - issue2209: { - full: { - Foo: (〈0;#Abstract〉 & { - spec: { - foo: {} - } - }) - Bar: (〈0;#Abstract〉 & { - spec: { - bar: {} - } - }) - #Abstract: { - spec: 〈1;_#Spec〉 - resource: (〈1;_Thing〉 & { - _X: { - spec: 〈3〉.spec - } - }) - } - _#Spec: (*〈0;_#SpecFoo〉|〈0;_#SpecBar〉) - _#SpecFoo: { - foo: { - min: (int|*10) - max: (int|*20) - } - } - _#SpecBar: { - bar: { - min: (int|*30) - max: (int|*40) - } - } - _Thing: (〈0;#Constrained〉 & { - _X: _ - spec: { - if (〈1;_X〉.spec.foo != _|_(explicit error (_|_ literal) in source)) { - minFoo: 〈2;_X〉.spec.foo.min - maxFoo: 〈2;_X〉.spec.foo.max - } - if (〈1;_X〉.spec.bar != _|_(explicit error (_|_ literal) in source)) { - minBar: 〈2;_X〉.spec.bar.min - maxBar: 〈2;_X〉.spec.bar.max - } - } - }) - #Constrained: (〈0;#Base〉 & { - spec: ({ - minFoo: (int|*10) - maxFoo: (int|*20) - minBar?: null - maxBar?: null - }|{ - minBar: (int|*30) - maxBar: (int|*40) - minFoo?: null - maxFoo?: null - }) - spec: (*{ - fuga?: null - }|{ - hoge?: null - }) - }) - #Base: { - spec: { - minFoo?: (null|int) - maxFoo?: (null|int) - minBar?: (null|int) - maxBar?: (null|int) - hoge?: (null|bool) - fuga?: (null|bool) - } - } - } - } -} ---- issue2246.cue -{ - issue2246: { - simplified: { - #FormFoo: { - fooID: string - } - #FormBar: { - barID: string - } - #Form: { - (〈1;#FormFoo〉|〈1;#FormBar〉) - } - data: { - fooID: "123" - } - out1: (〈0;#Form〉 & 〈0;data〉) - out2: (〈0;#Form〉 & 〈0;out1〉) - } - } - issue2246: { - full: { - data: { - forms: [ - { - fooID: "00-0000001" - }, - ] - } - form1040: (〈0;#compute〉 & { - in: 〈1;data〉 - }).out - #K1: { - #_base: { - common: 3 - } - #FormFoo: { - 〈1;#_base〉 - fooID: string - } - #FormBar: { - 〈1;#_base〉 - barID: string - } - #Form: { - (〈1;#FormFoo〉|〈1;#FormBar〉) - } - } - #Input: { - forms: [ - ...〈2;#K1〉.#Form, - ] - } - #summarizeReturn: { - in: 〈1;#Input〉 - out: [ - for _, k in 〈1;in〉.forms { - 〈1;k〉.common - }, - ] - } - #compute: { - in: 〈1;#Input〉 - out: (〈1;#summarizeReturn〉 & { - in: 〈1;in〉 - }).out - } - } - } -} ---- issue2263.cue -{ - issue2263: { - simplified: { - metrics: 〈0;#Metric〉 - #Metric: { - (〈1;#IDSource〉|{}) - (〈1;#TargetAverage〉|{}) - } - metrics: { - id: "foo" - avg: 60 - } - #IDSource: { - id: string - } - #TargetAverage: { - avg: number - } - } - } - issue2263: { - full: { - metrics: [ - ...〈1;#Metric〉, - ] - metrics: [ - { - id: "foo" - avg: 60 - }, - { - id: "bar" - value: 80 - }, - { - uri: "baz" - avg: 70 - }, - { - uri: "qux" - value: 90 - }, - ] - #Metric: { - 〈1;#Source〉 - 〈1;#Target〉 - } - #Source: (〈0;#IDSource〉|〈0;#URISource〉) - #Target: (〈0;#TargetAverage〉|〈0;#TargetValue〉) - #IDSource: { - id: string - } - #URISource: { - uri: string - } - #TargetAverage: { - avg: number - } - #TargetValue: { - value: number - } - } - } -} ---- issue2685.cue -{ - issue2685: { - #Foo: ({ - bar: int - opt?: int - }|*{ - opt: int - }) - foo: 〈0;#Foo〉 - foo: { - bar: 0 - } - { - foo: 〈1;#Foo〉 - } - } -} ---- issue3149.cue -{ - issue3149: { - #valid: { - name!: ((=~"^Foo"|"an exception") & (=~"Foo$"|"an exception")) - } - list: [ - ...〈1;#valid〉, - ] - list: [ - { - name: "FooBarFoo" - }, - { - name: "FooBazFoo" - }, - { - name: "FooQuuxFoo" - }, - { - name: "an exception" - }, - ] - } -} ---- issue3528.cue -{ - issue3528: { - original: { - workflows: [ - ...〈1;#Workflow〉, - ] - workflows: [ - 〈1;test〉, - ] - test: (〈0;#Workflow〉 & {}) - #Workflow: { - container: { - [string]: (string|〈1;#container〉) - } - #container: (string|{ - volumes?: [ - ...string, - ] - }) - } - } - } - issue3528: { - reduced: { - a?: 〈0;#A〉 - a: (〈0;#A〉 & {}) - #A: { - A: { - [string]: (1|〈1;#a〉) - } - #a: (2|{ - v: 1 - }) - } - } - } - issue3528: { - counter: {} - } - issue3528: { - nested: { - t1: { - ({ - v: 1 - }|(2|3)) - ({ - v: 1 - }|(2|3)) - ({ - v: 1 - }|(2|3)) - ({ - v: 1 - }|(2|3)) - } - } - } - issue3528: { - nested: { - t2: { - ({ - v: 1 - }|2) - ({ - v: 1 - }|(2|3)) - ({ - v: 1 - }|2) - ({ - v: 1 - }|2) - } - } - } -} ---- issue3784.cue -{ - issue3784: { - reduced: { - #Schema: { - a: ({ - kind: "A" - b: { - c?: string - } - b: {} - }|{ - kind: "B" - }) - } - out: 〈0;#Schema〉 - out: { - a: { - kind: "A" - b: { - c: "x" - } - } - } - } - } - issue3784: { - full: { - #Schema: { - pages?: { - build_type?: ("legacy"|"workflow") - source?: { - branch?: string - path?: string - } - cname?: string - } - pages?: ({ - build_type!: "legacy" - source!: { - branch!: _ - } - }|close({ - build_type!: "workflow" - cname?: _ - })) - } - out: (〈0;#Schema〉 & { - pages: { - cname: "foo.com" - build_type: "legacy" - source: { - branch: "main" - path: "/" - } - } - }) - } - } - issue3784: { - variant1: { - #Schema: { - pages: { - build_type?: ("legacy"|"workflow") - source: { - branch?: string - path?: string - } - cname?: string - } - pages?: ({ - build_type!: "legacy" - source!: { - branch!: _ - } - }|close({ - build_type!: "workflow" - cname?: _ - })) - } - } - } - issue3784: { - variant2: { - #Schema: ({ - build_type!: "legacy" - source!: { - branch!: _ - } - }|close({ - build_type!: "workflow" - cname?: _ - })) - a: 〈0;#Schema〉 - a: { - build_type?: ("legacy"|"workflow") - source: { - branch?: string - path?: string - } - cname?: string - } - } - } -} ---- issue3958.cue -{ - issue3958: { - t1: { - #schema: (int|*1) - #schema: (int|*3) - test1: (〈0;#schema〉 & { - (int|*2) - }) - test2: (〈0;#schema〉 & { - (int|*4) - }) - } - } - issue3958: { - t2: { - a: ((((int|*4) & (int|*1)) & (int|*3)) & (int|*8)) - b: (((int|*4) & (int|*1)) & (int|*3)) - } - } -} ---- issue770.cue -{ - issue770: { - #A: { - v: ("a"|"b"|"c") - } - h: { - [string]: 〈1;#A〉 - } - h: { - a: { - v: (*"a"|string) - } - } - h: { - [=~"^b"]: { - v: (*〈2;h〉.a.v|string) - } - } - h: { - [=~"^c"]: { - v: (*〈2;h〉.b.v|string) - } - } - h: { - b: _ - } - h: { - boo: _ - } - h: { - c: _ - } - h: { - coo: _ - } - } -} diff --git a/cue/testdata/disjunctions/embed.txtar b/cue/testdata/disjunctions/embed.txtar --- a/cue/testdata/disjunctions/embed.txtar +++ b/cue/testdata/disjunctions/embed.txtar @@ -118,119 +118,3 @@ Notifications: 6 NumCloseIDs: 39 --- out/compile -- ---- in.cue -{ - default: { - y: (*1|{ - a: 2 - }) - 〈0;y〉 - } - unambiguous: { - y: (1|{ - a: 2 - }) - 〈0;y〉 - } - forDefault: { - y: (*1|{ - a: 2 - }) - for _, x in [ - 1, - ] { - 〈2;y〉 - } - } - openDefault: { - #y: (*1|{ - a: 2 - }) - 〈0;#y〉 - } - openAmbiguous: { - #y: (1|{ - a: 2 - }) - 〈0;#y〉 - } - forceStruct: { - #y: (1|{ - a: 2 - }) - 〈0;#y〉 - {} - } - defaultsMulti: { - a: { - #def: { - (*{}|{ - a: string - }|{ - b: string - }) - (*{}|{ - c: string - }|{ - d: string - }) - } - a: (〈0;#def〉 & { - a: "foo" - }) - } - b: { - #def: { - (*{}|{ - a: string - }|{ - b: string - }) - (*{}|{ - c: string - }|{ - d: string - }) - (*{}|{ - d: string - }|{ - e: string - }) - } - a: (〈0;#def〉 & { - a: "foo" - e: "bar" - }) - } - } - nested: { - a: (1|2|*((3|4|*(5|6|*7)) & (3|4|(*7|8)))) - } -} ---- issue3415.cue -{ - issue3415: { - full: { - A: (〈0;#A〉 & { - i: { - (〈0;_a〉 + 〈0;_b〉) - _a: 1 - _b: 10 - } - }) - #A: { - i: (*0|number) - } - } - } - issue3415: { - reduced: { - a: { - (1 + 〈0;#b〉) - #b: 10 - } - a: (*0|number) - } - } -} diff --git a/cue/testdata/disjunctions/errors.txtar b/cue/testdata/disjunctions/errors.txtar --- a/cue/testdata/disjunctions/errors.txtar +++ b/cue/testdata/disjunctions/errors.txtar @@ -284,233 +284,3 @@ NumCloseIDs: 51 -- out/todo.txt -- issue4022: only evaluated by v3 evaluator. --- out/compile -- ---- in.cue -{ - issue570: { - results: 〈0;#DecodeOutput〉 - results: { - result: "hello" - } - #Output: ({ - result: _ - }|{ - error: string - }) - #DecodeOutput: (〈0;#Output〉 & { - result?: [ - ...string, - ] - ... - }) - } - issue516: { - #Def: ({ - match: { - metrics: { - string: {} - } - } - }|{}) - x: 〈0;#Def〉 - x: { - match: { - metrics: { - foo: {} - } - } - } - } - explicitDefaultError: { - a: (string|*_|_(explicit error (_|_ literal) in source)) - if (〈0;a〉 != "") {} - } - issue2916: { - b: _ - [_]: { - c: (&(int, >=0)|*1) - } - [string]: { - c: (>=3|*3) - } - } - issue3157: { - foo: (*42|_) - foo: (*43|bool) - } -} ---- issue3576.cue -{ - issue3576: { - reduced: { - #A: { - a!: string - } - #B: { - if false { - dummy: {} - } - } - foo: (〈0;#B〉|〈0;#A〉) - foo: { - a: "1" - } - } - } - issue3576: { - full: { - #Run: { - run!: string - options?: (〈1;#Option〉|[ - 〈2;#Option〉, - ..., - ]) - if (〈0;options〉 != _|_(explicit error (_|_ literal) in source)) { - optionsValue: 〈1;options〉 - } - } - #Copy: { - copy!: string - options?: (〈1;#Option〉|[ - 〈2;#Option〉, - ..., - ]) - if (〈0;options〉 != _|_(explicit error (_|_ literal) in source)) { - optionsValue: 〈1;options〉 - } - } - #Option: {} - foo: (〈0;#Run〉|〈0;#Copy〉) - foo: { - run: "make" - } - } - } -} ---- issue3581.cue -{ - issue3581: { - reduced: { - list: ([ - ..., - ]|*[]) - list: [ - "\(〈1;c〉)", - ] - c: _ - } - } -} ---- issue3599.cue -{ - issue3599: { - full: { - #Action: { - action: ({ - read!: string - write?: _|_(explicit error (_|_ literal) in source) - }|{ - write!: string - read?: _|_(explicit error (_|_ literal) in source) - }) - } - #Minio: { - container: (〈1;#Action〉 & { - action: ({ - read!: string - write?: _|_(explicit error (_|_ literal) in source) - }|{ - write!: string - read?: _|_(explicit error (_|_ literal) in source) - }) - }) - doWrite: (bool|*true) - container: { - action: 〈1;defaultAction〉 - } - defaultAction: { - if 〈1;doWrite〉 { - write: "somefile.txt" - } - if !〈1;doWrite〉 { - read: "somefile.txt" - } - } - } - } - } - issue3599: { - reduced: { - p1: { - ({ - a?: (1 & 2) - }|{ - a: string - b?: (1 & 2) - }) - ({}|{}) - } - } - } - issue3599: { - reduced: { - p2: { - ({}|{}) - ({ - a?: (1 & 2) - }|{ - a: string - b?: (1 & 2) - }) - } - } - } - issue3599: { - let: { - ({}|{ - a: (〈0;let B#1〉|1) - let B#1 = (1 & 2) - }) - ({}|{}) - } - } -} ---- optionalerror.cue -{ - issue4022: { - reduced: { - #NonNamespaced: { - metadata: { - namespace?: _|_(explicit error (_|_ literal) in source) - } - } - #NullOrNonNamespaced: (int|〈0;#NonNamespaced〉) - out: 〈0;#NullOrNonNamespaced〉 - out: 〈0;#NonNamespaced〉 - out: { - metadata: {} - } - } - } - issue4022: { - full: { - #NonNamespaced: { - metadata: { - name!: string - namespace?: _|_(explicit error (_|_ literal) in source) - ... - } - ... - } - #NullOrNonNamespaced: (null|〈0;#NonNamespaced〉) - out: 〈0;#NullOrNonNamespaced〉 - out: 〈0;#NonNamespaced〉 - out: { - metadata: { - name: "foo" - } - apiVersion: "v1" - } - } - } -} diff --git a/cue/testdata/disjunctions/incomplete.txtar b/cue/testdata/disjunctions/incomplete.txtar --- a/cue/testdata/disjunctions/incomplete.txtar +++ b/cue/testdata/disjunctions/incomplete.txtar @@ -132,75 +132,3 @@ Disjuncts: 42 NumCloseIDs: 9 --- out/compile -- ---- in.cue -{ - issue700: { - a: { - y: "y" - } - test1: (*〈0;a〉.x|1) - test2: (*〈0;a〉.y|1) - } - lookup: { - x: { - name: "Hello" - } - y: 〈0;x〉.a - ok1: (*〈0;x〉.a|〈0;x〉) - ok2: (〈0;x〉|*〈0;x〉.a) - ok3: (〈0;x〉.a|*〈0;x〉) - ok4: (*〈0;x〉|〈0;x〉.a) - ok5: (〈0;x〉|〈0;x〉.a) - ok5: (〈0;x〉.a|〈0;x〉) - allFail1: (〈0;x〉.a|〈0;x〉.b) - allFail2: (〈0;x〉.a|〈0;x〉.b) - } - func: { - s: string - ok1: (〈import;"encoding/yaml"〉.MarshalStream(〈0;s〉)|〈import;"encoding/yaml"〉.Marshal(〈0;s〉)) - } - issue782: { - a: { - inner: string - interpolation: (*"\(〈0;inner〉)"|string) - interpolation: "override" - } - b: { - inner: string - interpolation: (string|*"\(〈0;inner〉)") - interpolation: "override" - } - c: { - inner: string - interpolation: ("\(〈0;inner〉)"|string) - interpolation: "override" - } - d: { - inner: string - interpolation: (string|"\(〈0;inner〉)") - interpolation: "override" - } - } -} ---- issue3680.cue -{ - issue3680: { - t1: { - ({}|{ - a?: _|_(explicit error (_|_ literal) in source) - b?: _|_(explicit error (_|_ literal) in source) - }) - ({}|{}) - } - } - issue3680: { - t2: { - x: ({}|{ - a?: _|_(explicit error (_|_ literal) in source) - b?: _|_(explicit error (_|_ literal) in source) - }) - x: ({}|{}) - } - } -} diff --git a/cue/testdata/disjunctions/issue2209.txtar b/cue/testdata/disjunctions/issue2209.txtar --- a/cue/testdata/disjunctions/issue2209.txtar +++ b/cue/testdata/disjunctions/issue2209.txtar @@ -174,130 +174,6 @@ -- out/todo.txt -- full: evalv2 produced errors ("empty disjunction") for full.Bar.resource.spec and reduced.Bar.out.minBar; evalv3 evaluates both correctly without errors. --- out/compile -- ---- input.cue -{ - full: { - Foo: (〈0;#Abstract〉 & { - spec: { - foo: {} - } - }) - Bar: (〈0;#Abstract〉 & { - spec: { - bar: {} - } - }) - #Abstract: { - spec: 〈1;_#Spec〉 - resource: (〈1;_Thing〉 & { - _X: { - spec: 〈3〉.spec - } - }) - } - _#Spec: (*〈0;_#SpecFoo〉|〈0;_#SpecBar〉) - _#SpecFoo: { - foo: { - min: (int|*10) - max: (int|*20) - } - } - _#SpecBar: { - bar: { - min: (int|*30) - max: (int|*40) - } - } - _Thing: (〈0;#Constrained〉 & { - _X: _ - spec: { - if (〈1;_X〉.spec.foo != _|_(explicit error (_|_ literal) in source)) { - minFoo: 〈2;_X〉.spec.foo.min - maxFoo: 〈2;_X〉.spec.foo.max - } - if (〈1;_X〉.spec.bar != _|_(explicit error (_|_ literal) in source)) { - minBar: 〈2;_X〉.spec.bar.min - maxBar: 〈2;_X〉.spec.bar.max - } - } - }) - #Constrained: (〈0;#Base〉 & { - spec: ({ - minFoo: (int|*10) - maxFoo: (int|*20) - minBar?: null - maxBar?: null - }|{ - minBar: (int|*30) - maxBar: (int|*40) - minFoo?: null - maxFoo?: null - }) - spec: (*{ - fuga?: null - }|{ - hoge?: null - }) - }) - #Base: { - spec: { - minFoo?: (null|int) - maxFoo?: (null|int) - minBar?: (null|int) - maxBar?: (null|int) - hoge?: (null|bool) - fuga?: (null|bool) - } - } - } - reduced: { - Foo: (〈0;#Obj〉 & { - spec: { - foo: {} - } - }) - Bar: (〈0;#Obj〉 & { - spec: { - bar: {} - } - }) - #Obj: { - spec: (*〈1;#SpecFoo〉|〈1;#SpecBar〉) - out: (〈1;#Out〉 & { - _Xspec: 〈2〉.spec - if (〈0;_Xspec〉.foo != _|_(explicit error (_|_ literal) in source)) { - minFoo: 〈1;_Xspec〉.foo.min - } - if (〈0;_Xspec〉.bar != _|_(explicit error (_|_ literal) in source)) { - minBar: 〈1;_Xspec〉.bar.min - } - }) - } - #SpecFoo: { - foo: { - min: (int|*10) - } - } - #SpecBar: { - bar: { - min: (int|*20) - } - } - #Out: { - ({ - minFoo: int - }|{ - minBar: int - }) - (*{ - nullFoo: null - }|{ - nullBar: null - }) - } - } -} -- out/eval/stats -- Leaks: 92 Freed: 910 diff --git a/cue/testdata/disjunctions/issue3850.txtar b/cue/testdata/disjunctions/issue3850.txtar --- a/cue/testdata/disjunctions/issue3850.txtar +++ b/cue/testdata/disjunctions/issue3850.txtar @@ -110,98 +110,3 @@ Disjuncts: 22 NumCloseIDs: 18 --- out/compile -- ---- issue3850.cue -{ - issue3850: { - full: { - global: { - glb1: { - glb2: "123" - } - } - out: ({ - foo?: _ - }|{}) - out: ({ - foo?: _ - }|{}) - out: 〈0;#WithFoo〉 - #WithFoo: { - _global: 〈1;global〉 - foo: 〈0;_global〉.glb1.glb2 - } - } - } - issue3850: { - incomplete: { - global: { - glb1: { - glb2: "123" - } - } - out: ({ - foo?: _ - }|{}) - out: ({ - foo?: _ - }|{}) - out: 〈0;#WithFoo〉 - #WithFoo: { - _global: 〈1;global〉 - foo: 〈0;_global〉.glb1.glb2 - ... - } - } - } - issue3850: { - p2p: { - out: (*{}|_) - out: (*{}|_) - out: { - reg: 〈0;#def〉 - #def: { - foo: 〈2;_global〉 - } - } - _global: "global value" - } - } -} ---- issue3875.cue -{ - issue3875: { - full: { - _global: { - name: "foo" - } - out: { - desc: { - _hidden: 〈2;_global〉.name - name: 〈0;_hidden〉 - } - } - out: (〈0;#Schema〉|"never") - #Schema: { - desc: { - ... - } - } - } - } - issue3875: { - reduced: { - global: { - a: "foo" - } - out: { - desc: { - a: 〈0;b〉 - b: 〈2;global〉.a - } - } - out: (〈0;S〉|null) - S: {} - } - } -} diff --git a/cue/testdata/disjunctions/issue3857.txtar b/cue/testdata/disjunctions/issue3857.txtar --- a/cue/testdata/disjunctions/issue3857.txtar +++ b/cue/testdata/disjunctions/issue3857.txtar @@ -106,89 +106,3 @@ Disjuncts: 26 NumCloseIDs: 25 --- out/compile -- ---- in.cue -{ - reduced: { - t1: { - S: { - if true { - a: 〈2;U〉 - } - } - x: 〈0;S〉 - x: { - ["a"]: { - b: (1|〈2;T〉) - } - d: { - b: 〈2;x〉.a - } - } - T: 1 - U: { - b: (1|1) - } - } - } - issue3851: { - t1: { - #Top: _ - #Config: { - disj: (_|*"default") - shared: _ - } - #Schema: { - [string]: 〈1;#Config〉 - if true { - one: { - shared: "foo" - } - } - } - out: 〈0;#Schema〉 - out: { - ["one"]: { - disj: (_|〈2;#Top〉) - } - two: { - shared: 〈2;out〉.one.shared - } - } - } - } - issue3851: { - t2: { - #Top: _ - #Config: { - disj: (_|*{}) - shared: _ - } - #Env: { - conf: { - [string]: 〈2;#Config〉 - } - if true { - conf: { - one: { - shared: "foo" - } - } - } - } - env1: 〈0;#Env〉 - [string]: { - conf: { - ["one"]: { - disj: ({}|〈3;#Top〉) - } - } - conf: { - two: { - shared: 〈2;conf〉.one.shared - } - } - } - } - } -} diff --git a/cue/testdata/disjunctions/issue4339.txtar b/cue/testdata/disjunctions/issue4339.txtar --- a/cue/testdata/disjunctions/issue4339.txtar +++ b/cue/testdata/disjunctions/issue4339.txtar @@ -15,16 +15,3 @@ // TODO: we should be able to use @test(final) here, avoiding the defaults. *{one: 1, enable: *true | false, extra: 1} | {one: 1, enable: *true | false}, ) --- out/compile -- ---- in.cue -{ - _withExtra: { - extra: 〈1;out〉.one - } - out: { - (*〈1;_withExtra〉|{}) - one: 1 - enable: (*true|false) - if 〈0;enable〉 {} - } -} diff --git a/cue/testdata/disjunctions/nested.txtar b/cue/testdata/disjunctions/nested.txtar --- a/cue/testdata/disjunctions/nested.txtar +++ b/cue/testdata/disjunctions/nested.txtar @@ -89,80 +89,3 @@ Disjuncts: 32 NumCloseIDs: 19 --- out/compile -- ---- issue3635.cue -{ - issue3635: { - case1: { - Run: { - env: (*{ - [string]: string - }|[ - ...string, - ]) - } - command: (〈0;Run〉 & { - env: 〈import;list〉.Concat([ - [ - "foo", - ], - [ - "bar", - ], - ]) - }) - } - } - issue3635: { - case2: { - out: [ - ...〈1;#Schema〉, - ] - out: [ - (〈1;#Schema〉 & { - name: "x" - }), - ] - #Schema: { - name?: string - container?: { - [string]: (string|〈1;#container〉) - } - #container: (string|{ - env?: 〈1;#env〉 - }) - #env: { - [string]: (bool|string) - } - } - } - } - issue3635: { - reduced: { - out: ({ - 〈1;X〉 - } & 〈0;X〉) - X: { - b: (int|〈0;c〉) - c: (int|{ - e: 〈2;d〉 - }) - } - d: 1 - } - } - issue3635: { - reduced_noshare: { - out: ({ - 〈1;X〉 - } & 〈0;X〉) - X: { - b: (int|〈0;c〉) - c: (int|{ - e: (〈2;d〉 & _|_(no sharing)) - }) - } - d: 1 - } - } -} diff --git a/cue/testdata/disjunctions/operands.txtar b/cue/testdata/disjunctions/operands.txtar --- a/cue/testdata/disjunctions/operands.txtar +++ b/cue/testdata/disjunctions/operands.txtar @@ -52,44 +52,3 @@ Disjuncts: 8 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - list: (*[ - 1, - ]|[ - 2, - ]) - condition: (*true|false) - num: (*1|2) - object: (*{ - a: 1 - }|{ - a: 2 - }) - forLoop: [ - for _, e in 〈1;list〉 { - "count: \(〈1;e〉)" - }, - ] - conditional: { - if 〈1;condition〉 { - a: 3 - } - if (〈1;num〉 < 5) { - b: 3 - } - } - selector: { - a: 〈1;object〉.a - } - index: { - a: 〈1;list〉[0] - } - binOp: { - a: (〈1;num〉 + 4) - } - unaryOp: { - a: -〈1;num〉 - } -} diff --git a/cue/testdata/disjunctions/propagate_err.txtar b/cue/testdata/disjunctions/propagate_err.txtar --- a/cue/testdata/disjunctions/propagate_err.txtar +++ b/cue/testdata/disjunctions/propagate_err.txtar @@ -42,41 +42,3 @@ ./pending.cue:4:5 ./pending.cue:3:5 ./pending.cue:4:9 --- out/compile -- ---- issue4056.cue -{ - issue4056: { - full: { - a: "foo-bar" - a: (_|error("error message 1")) - if 〈import;strings〉.HasPrefix(〈0;a〉, "foo") { - a: (_|error("error message 2")) - } - } - } - issue4056: { - reduced: { - a: "x" - a: (_|error("a")) - if (len(〈0;a〉) > 0) { - a: (_|error("b")) - } - } - } - variant: { - a: "x" - a: (string|int) - if (len(〈0;a〉) > 0) { - a: _ - } - } -} ---- pending.cue -{ - err: { - A: "forty two" - if (〈0;A〉 < 100) { - B: true - } - } -} diff --git a/cue/testdata/disjunctions/resolve.txtar b/cue/testdata/disjunctions/resolve.txtar --- a/cue/testdata/disjunctions/resolve.txtar +++ b/cue/testdata/disjunctions/resolve.txtar @@ -24,37 +24,3 @@ Disjuncts: 12 NumCloseIDs: 6 --- out/compile -- ---- in.cue -{ - resolveAcrossDisjunct: { - t1: { - ({}|{ - #B: 1 - }) - ({ - d: 〈1;#B〉 - }|{}) - #B: int - } - } - resolveAcrossDisjunct: { - nested: { - ({}|{ - a: { - b: { - #B: 1 - } - } - }) - ({ - d: 〈1;a〉.b.#B - }|{}) - a: { - b: { - #B: int - } - } - } - } -} diff --git a/cue/testdata/disjunctions/specdeviation.txtar b/cue/testdata/disjunctions/specdeviation.txtar --- a/cue/testdata/disjunctions/specdeviation.txtar +++ b/cue/testdata/disjunctions/specdeviation.txtar @@ -94,50 +94,3 @@ Disjuncts: 121 NumCloseIDs: 10 --- out/compile -- ---- in.cue -{ - Q: (*1|int) - q: (*〈0;Q〉|int) - P: (*1|int) - P: 2 - p: (*〈0;P〉|int) - r: ((*3|(*1|2)) & (1|2)) - s: ((3|(*1|2)) & (1|2)) - s1: (〈0;#Size〉 & { - min: 5 - }) - #Size: { - max: (>〈0;min〉|*〈0;min〉) - res: (&(int, >=0)|*0) - min: (>〈0;res〉|*(1 + 〈0;res〉)) - } - staged: { - c: (("a"|"b") & (*(*"a"|string)|string)) - d: ((*(*"a"|string)|string) & ("a"|"b")) - } - issue763a: { - #A: { - v: ("a"|"b"|"c") - } - h: { - [string]: 〈1;#A〉 - } - h: { - [=~"^b"]: (〈1;#A〉 & { - v: (*〈2;h〉.a.v|string) - }) - } - h: { - a: { - v: (*"a"|string) - } - } - h: { - baa: _ - } - h: { - boo: _ - } - } -} diff --git a/cue/testdata/eval/basictypes.txtar b/cue/testdata/eval/basictypes.txtar --- a/cue/testdata/eval/basictypes.txtar +++ b/cue/testdata/eval/basictypes.txtar @@ -24,60 +24,6 @@ } -- out/todo.txt -- It doesn't seem like this should be a compile error. --- out/compile -- -comparison.typeComparison.err: invalid operand string ('==' requires concrete value): - ./in.cue:16:23 -comparison.typeComparison.err: invalid operand number ('==' requires concrete value): - ./in.cue:16:33 ---- in.cue -{ - top: { - a: { - _ - } - b: _ - } - scalar: { - a: { - string - } - b: string - c: { - { - { - number - } - } - } - d: number - } - comparison: { - basicEquality: { - t: (42 == 42) - } - typeComparison: { - err: (string == number) - } - structEquality: { - t: ({ - name: "test" - } == { - name: "test" - }) - } - nestedComparison: { - t: ({ - data: { - value: 1 - } - } == { - data: { - value: 1 - } - }) - } - } -} -- out/evalalpha -- comparison.typeComparison.err: invalid operand string ('==' requires concrete value): ./in.cue:16:23 diff --git a/cue/testdata/eval/bounds.txtar b/cue/testdata/eval/bounds.txtar --- a/cue/testdata/eval/bounds.txtar +++ b/cue/testdata/eval/bounds.txtar @@ -514,324 +514,3 @@ Disjuncts: 0 NumCloseIDs: 8 --- out/compile -- ---- binary.cue -{ - simplifyBinary: { - float: { - err1: { - p1: (<1 & >2) - p2: (>2 & <1) - } - err2: { - p1: (>2 & <=1) - p2: (<=1 & >2) - } - err3: { - p1: (>=2 & <2) - p2: (<2 & >=2) - p3: (>2 & <=2) - p4: (<=2 & >2) - } - ok1: { - p1: (>1 & <2) - p2: (<2 & >1) - } - ok2: { - p1: (>=2 & <=2) - p2: (<=2 & >=2) - } - } - } - simplifyBinary: { - integer: { - [_]: { - [_]: int - } - err1: { - p1: (<1 & >2) - p2: (>2 & <1) - } - err2: { - p1: (>2 & <=1) - p2: (<=1 & >2) - } - err3: { - p1: (>=2 & <2) - p2: (<2 & >=2) - p3: (>2 & <=2) - p4: (<=2 & >2) - } - err4: { - p1: (>1 & <2) - p2: (<2 & >1) - } - ok1: { - p1: (>=2 & <=3) - p2: (<=3 & >=2) - } - ok2: { - p1: (>=2 & <=2) - p2: (<=2 & >=2) - } - ok3: { - p1: (>=2 & <3) - p2: (>2 & <=3) - p3: (<3 & >=2) - p4: (<=3 & >2) - } - } - } -} ---- binarystring.cue -{ - simplifyBinary: { - strings: { - err1: { - p1: (<"a" & >"b") - p2: (>"b" & <"a") - } - err2: { - p1: (>"b" & <="a") - p2: (<="a" & >"b") - } - err3: { - p1: (>="b" & <"b") - p2: (<"b" & >="b") - p3: (>"b" & <="b") - p4: (<="b" & >"b") - } - ok1: { - p1: (>"a" & <"b") - p2: (<"b" & >"a") - } - ok2: { - p1: (>"a" & <="b") - p2: (<="b" & >"a") - p3: (>="a" & <"b") - p4: (<"b" & >="a") - } - ok3: { - p1: (>="b" & <="c") - p2: (<="c" & >="b") - } - ok4: { - p1: (>="b" & <="b") - } - } - } - simplifyBinary: { - byte: { - err1: { - p1: (<'a' & >'b') - p2: (>'b' & <'a') - } - err2: { - p1: (>'b' & <='a') - p2: (<='a' & >'b') - } - err3: { - p1: (>='b' & <'b') - p2: (<'b' & >='b') - p3: (>'b' & <='b') - p4: (<='b' & >'b') - } - ok1: { - p1: (>'a' & <'b') - p2: (<'b' & >'a') - } - ok2: { - p1: (>'a' & <='b') - p2: (<='b' & >'a') - p3: (>='a' & <'b') - p4: (<'b' & >='a') - } - ok3: { - p1: (>='b' & <='c') - p2: (<='c' & >='b') - } - ok4: { - p1: (>='b' & <='b') - } - } - } -} ---- equals.cue -{ - equalScalar: { - ok1: ==1 - ok1: 1 - ok2: [ - 1, - 2, - ] - ok2: ==[ - 1, - 2, - ] - err1: ==1 - err1: 2 - err2: [ - 1, - 2, - ] - err2: !=[ - 1, - 2, - ] - } - equalStruct: { - ok1: =={} - ok1: {} - ok2: { - a: 1 - b: 2 - } - ok2: =={ - a: 1 - b: 2 - } - err1: =={} - err1: { - a: 1 - b: 2 - } - err2: { - a: 1 - b: 2 - } - err2: !={ - a: 1 - b: 2 - } - } - nonConcrete: { - ok0: =="foo" - _int: int - iErr1: ==〈0;_int〉 - iErr2: !=〈0;_int〉 - iErr3: ==〈0;_int〉 - iErr3: ==1 - ok4: ==1 - ok4: 〈0;_int〉 - eErr5: =="foo" - eErr5: 〈0;_int〉 - eErr6: ==〈0;_int〉 - eErr6: "foo" - } -} ---- in.cue -{ - x0: 5 - x1: (〈0;b5〉 & 30) - b0: (<〈0;x0〉 & >0) - b1: (〈0;b0〉 & int) - b2: (int & <5.5) - b3: (<10 & <=5) - b4: (>=20 & >20) - b5: (>=21 & >20) - b6: ((int & >5) & <=6) - simplifyExpr: { - less1: <<3 - less2: <<=3 - less3: <=<3 - less4: <=<=3 - less5: >3 - gtr2: >>=3 - gtr3: >=>3 - gtr4: >=>=3 - gtr5: >!=3 - gtr6: >=!=3 - lg1: <>3 - lg2: <>=3 - lg3: <=>3 - lg4: <=>=3 - gl1: ><3 - gl2: ><=3 - gl3: >=<3 - gl4: >=<=3 - ne1: !=!=3 - ne2: !=<3 - ne3: !=<=3 - ne4: !=>3 - ne5: !=>=3 - s: string - n: number - i: int - f: float - b: bytes - basic1: <〈0;i〉 - basic2: >〈0;n〉 - basic3: >=〈0;s〉 - basic4: <=〈0;f〉 - basic5: <=〈0;b〉 - bne1: !=〈0;s〉 - bne2: !=〈0;n〉 - bne3: !=〈0;n〉 - bne4: !=〈0;i〉 - bne5: !=〈0;b〉 - e1: <=~"foo" - e2: >null - } -} ---- issue4142.cue -{ - inDefinitions: { - ok1: { - #X: =={ - name: "X" - } - x: (〈0;#X〉 & { - name: "X" - }) - } - } - inDefinitions: { - ok2: { - x: (〈0;#X〉 & { - name: "Y" - }) - #X: !={ - name: "X" - } - } - } - inDefinitions: { - err1: { - #X: =={ - name: "X" - } - x: (〈0;#X〉 & { - name: "Y" - }) - } - } - inDefinitions: { - err2: { - #X: !={ - name: "X" - } - x: (〈0;#X〉 & { - name: "X" - }) - } - } -} ---- issue4251-panic.cue -{ - issue4251: { - ok: { - a: ((!="c" & =="a") & "a") - b: ((=="b" & !="c") & "b") - c: ((=="x" & >="a") & "x") - d: ((<="z" & =="y") & "y") - } - } - issue4251: { - fail: { - b: ((=="b" & !="b") & "b") - } - } -} diff --git a/cue/testdata/eval/bulk.txtar b/cue/testdata/eval/bulk.txtar --- a/cue/testdata/eval/bulk.txtar +++ b/cue/testdata/eval/bulk.txtar @@ -248,271 +248,6 @@ Notifications: 6 NumCloseIDs: 80 --- out/compile -- ---- in.cue -{ - a: { - foo: { - a: 1 - } - [=~"foo"]: { - b: 1 - name: 〈1;-〉 - } - } - d: (〈0;a〉 & { - foobar: { - c: 2 - } - }) - t1: { - #a: { - [(>"e" & <"z")]: int - } - b: (〈0;#a〉 & { - f: 4 - }) - c: (〈0;#a〉 & { - z: 4 - }) - } - t2: { - #a: { - [("x"|"y")]: int - } - b: (〈0;#a〉 & { - x: 4 - }) - c: (〈0;#a〉 & { - z: 4 - }) - } -} ---- intpattern.cue -{ - issue3670: { - #X: { - [int]: string - } - a: 〈0;#X〉 - a: { - not_int: "c" - } - } - dual: { - _ - [string]: _ - [int]: _ - } -} ---- issue2109.cue -{ - patternCycle: { - issue2109: { - p1: { - countries: [ - "US", - "GB", - "AU", - ] - FlagsURLs: { - [or(〈1;countries〉)]: string - } - 〈0;FlagsURLs〉 - } - } - } - patternCycle: { - issue2109: { - p2: { - FlagsURLs: { - [or(〈1;countries〉)]: string - } - 〈0;FlagsURLs〉 - countries: [ - "US", - "GB", - "AU", - ] - } - } - } - patternCycle: { - issue2109: { - p3: { - 〈0;FlagsURLs〉 - FlagsURLs: { - [or(〈1;countries〉)]: string - } - countries: [ - "US", - "GB", - "AU", - ] - } - } - } - patternCycle: { - t1: { - p1: { - countries: ("US"|"GB"|"AU") - FlagsURLs: { - [〈1;countries〉]: string - } - 〈0;FlagsURLs〉 - } - } - } - patternCycle: { - t1: { - p2: { - 〈0;FlagsURLs〉 - countries: ("US"|"GB"|"AU") - FlagsURLs: { - [〈1;countries〉]: string - } - } - } - } - patternCycle: { - t1: { - p3: { - 〈0;FlagsURLs〉 - FlagsURLs: { - [〈1;countries〉]: string - } - countries: ("US"|"GB"|"AU") - } - } - } -} ---- multi.cue -{ - issue3638: { - full: { - routes: { - default: {} - } - routes: { - [string]: { - spec: [ - { - refs: [ - { - "default" - }, - ] - }, - ] - } - } - #Fields: { - input: _ - output: [ - for _, x in 〈1;input〉 { - 〈1;x〉 - }, - ] - ... - } - #Kubernetes: { - (〈1;#Fields〉 & { - Routes: { - route: { - [_]: { - spec!: 〈5;let HTTPROUTESPEC#1〉.#x - } - } - } - }) - 〈1;#Fields〉 - Routes: _ - input: { - res1: 〈1;Routes〉 - } - } - let HTTPROUTESPEC#1 = { - #x: ([ - ...{ - refs: [ - ...{ - string - }, - ] - }, - ]|*[ - { - other: [] - }, - ]) - } - entrypoint: 〈0;used〉.output - used: (〈0;#Kubernetes〉 & { - Routes: { - route: 〈2;routes〉 - } - }) - } - } - issue3638: { - reduced: { - input: { - k1: { - [string]: { - a: 1 - } - } - } - input: { - k1: { - foo: 〈2;#x〉 - } - } - out: { - for _, x in 〈1;input〉 { - 〈1;x〉 - } - for _, x in 〈1;input〉 { - 〈1;x〉 - } - } - #x: ({ - a: int - }|*{ - b: 2 - }) - } - } - issue3638: { - compare: { - input: { - k1: { - foo: { - a: 1 - } - } - } - input: { - k1: { - foo: 〈2;#x〉 - } - } - out: { - for _, x in 〈1;input〉 { - 〈1;x〉 - } - for _, x in 〈1;input〉 { - 〈1;x〉 - } - } - #x: ({ - a: int - }|*{ - b: 2 - }) - } - } -} -- out/todo.txt -- patternCycle.t1.{p1,p2,p3}: v2 had cyclic pattern constraint errors; v3 resolves correctly. issue3638.full.entrypoint and issue3638.full.#Kubernetes.input.res1: v3 uses structure sharing (~), v2 expands. diff --git a/cue/testdata/eval/closed_disjunction.txtar b/cue/testdata/eval/closed_disjunction.txtar --- a/cue/testdata/eval/closed_disjunction.txtar +++ b/cue/testdata/eval/closed_disjunction.txtar @@ -34,27 +34,5 @@ Disjuncts: 12 NumCloseIDs: 8 --- out/compile -- ---- in.cue -{ - #A: { - b?: int - (*{}|{ - c?: int - }|{ - d?: int - }|{ - e?: int - }) - } - a: (〈0;#A〉 & { - b: 3 - c: 3 - }) - b: (〈0;#A〉 & { - c: 3 - d: 4 - }) -} -- out/todo.txt -- v3 drops e? from b's error result and only shows the two sub-errors without extra positions; v2 showed e? and more error positions including compile-time locations. diff --git a/cue/testdata/eval/closedness.txtar b/cue/testdata/eval/closedness.txtar --- a/cue/testdata/eval/closedness.txtar +++ b/cue/testdata/eval/closedness.txtar @@ -1096,1320 +1096,3 @@ Notifications: 1 NumCloseIDs: 585 --- out/compile -- ---- ellipsis.cue -{ - issue3778: { - full: { - #x: { - a?: string - } - #y: (〈0;#x〉 & { - ... - }) - z: (〈0;#y〉 & { - a: "ok" - b: "something" - }) - } - } - issue3778: { - keepOpen: { - #x: { - a?: string - ... - } - #y: (〈0;#x〉 & { - ... - }) - z: (〈0;#y〉 & { - a: "ok" - b: "something" - }) - } - } - issue1867: { - one: { - #T: close({}) - #T: { - ... - } - x: 〈0;#T〉 - x: { - foo: "foo" - } - } - } - issue1867: { - two: { - #S: {} - #T: { - s: 〈1;#S〉 - } - #T: { - s: { - ... - } - } - x: 〈0;#T〉.s - x: { - foo: "foo" - } - } - } - issue1867: { - three: { - #T: { - s: close({}) - } - #T: { - s: { - ... - } - } - x: 〈0;#T〉.s - x: { - foo: "foo" - } - } - } - issue3924: { - one: { - #Schema: { - ... - { - [string]: 〈2;#SchemaInner〉 - } - } - #SchemaInner: { - allowed?: string - } - out: (〈0;#Schema〉 & { - foo: { - disallowed: "foo" - } - }) - } - } - issue3924: { - two: { - #Schema: { - { - [string]: 〈1;#job〉 - } - #job: (matchN(1, [ - { - other?: string - ... - }, - ]) & close({ - allowed?: string - })) - } - out: (〈0;#Schema〉 & { - foo: { - disallowed: "bar" - } - }) - } - } - issue3924: { - three: { - t1: { - { - foo: (〈1;#job〉 & { - disallowed: "bar" - }) - } - #job: { - other?: string - } - #job: 〈0;#def〉 - #def: { - allowed?: string - } - } - } - } - issue3924: { - three: { - t2: { - { - foo: (〈1;#job〉 & { - disallowed: "bar" - }) - } - #job: { - other?: string - ... - } - #job: 〈0;#def〉 - #def: { - allowed?: string - } - } - } - } - issue3924: { - three: { - t3: { - #job: { - ... - } - #job: 〈0;#def〉 - #def: {} - foo: (〈0;#job〉 & { - disallowed: "bar" - }) - } - } - } - issue3924: { - four: { - A: { - { - foo: 〈2;#B〉 - } - } - #B: { - allowed?: string - } - out: (〈0;A〉 & { - foo: { - disallowed: "foo" - } - }) - } - } -} ---- embed.cue -{ - issue3325: { - ok: { - #Items: { - [string]: { - name: 〈1;-〉 - } - } - #Base: { - name: "base" - type: string - items: 〈1;#Items〉 - } - #Extended: (〈0;#Base〉 & { - type: "extended" - items: { - "my-item": {} - } - }) - broken: { - 〈1;#Base〉 - 〈1;#Extended〉 - } - works: { - 〈1;#Extended〉 - 〈1;#Base〉 - } - } - } - patterns: { - shallow: { - #a: { - [>="k"]: int - } - #b: { - [<="m"]: int - } - #c: { - [>="w"]: int - } - #d: { - [<="y"]: int - } - single: { - X: 〈1;#a〉 - err: 〈0;X〉 - err: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - and: { - p1: { - X: (〈2;#a〉 & 〈2;#b〉) - err: 〈0;X〉 - err: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - } - and: { - p2: { - X: (〈2;#b〉 & 〈2;#a〉) - err: 〈0;X〉 - err: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - } - andEmbed: { - p1: { - X: { - (〈3;#a〉 & 〈3;#b〉) - } - err: 〈0;X〉 - err: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - } - andEmbed: { - p2: { - X: { - (〈3;#b〉 & 〈3;#a〉) - } - err: 〈0;X〉 - err: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - } - orEmbed: { - p1: { - X: { - 〈3;#a〉 - 〈3;#b〉 - } - ok1: 〈0;X〉 - ok1: { - j: 3 - } - ok2: 〈0;X〉 - ok2: { - k: 3 - } - } - } - orEmbed: { - p2: { - X: { - 〈3;#b〉 - 〈3;#a〉 - } - ok1: 〈0;X〉 - ok1: { - j: 3 - } - ok2: 〈0;X〉 - ok2: { - k: 3 - } - } - } - andOrEmbed: { - t1: { - p1: { - X: { - (〈4;#a〉 & 〈4;#b〉) - (〈4;#c〉 & 〈4;#d〉) - } - err1: 〈0;X〉 - err1: { - j: 3 - } - ok1: 〈0;X〉 - ok1: { - k: 3 - } - } - } - } - andOrEmbed: { - t1: { - p2: { - X: { - (〈4;#c〉 & 〈4;#d〉) - (〈4;#a〉 & 〈4;#b〉) - } - err1: 〈0;X〉 - err1: { - j: 3 - } - ok1: 〈0;X〉 - ok1: { - k: 3 - } - } - } - } - andOrEmbed: { - t2: { - X: { - (〈3;#a〉 & 〈3;#b〉) - (〈3;#c〉 & 〈3;#d〉) - ["p"]: int - } - err1: 〈0;X〉 - err1: { - j: 3 - } - ok1: 〈0;X〉 - ok1: { - k: 3 - } - ok2: 〈0;X〉 - ok2: { - p: 3 - } - } - } - indirect: { - a: { - [>="k"]: int - } - #a: 〈0;a〉 - p1: { - X: 〈1;#a〉 - err1: 〈0;X〉 - err1: { - j: 3 - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - p2: { - #a: (〈1;a〉 & _|_(no sharing)) - X: 〈0;#a〉 - err1: 〈0;X〉 - err1: { - j: 3 - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - p3: { - X: (〈1;#a〉 & _|_(no sharing)) - err1: 〈0;X〉 - err1: { - j: 3 - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - p4: { - #a: (〈1;a〉 & _|_(no sharing)) - X: 〈0;#a〉 - X: (〈0;#a〉 & _|_(no sharing)) - err1: 〈0;X〉 - err1: { - j: 3 - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - j: 3 - } - ok: 〈0;X〉 - ok: { - k: 3 - } - } - } - } - } - patterns: { - nested: { - #a: { - x: { - y: { - [>="k"]: int - } - } - } - #b: { - x: { - y: { - [<="m"]: int - } - } - } - #c: { - x: { - y: { - [>="w"]: int - } - } - } - #d: { - x: { - y: { - [<="y"]: int - } - } - } - single: { - X: 〈1;#a〉 - err: 〈0;X〉 - err: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - and: { - p1: { - X: (〈2;#a〉 & 〈2;#b〉) - err: 〈0;X〉 - err: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - } - and: { - p2: { - X: (〈2;#b〉 & 〈2;#a〉) - err: 〈0;X〉 - err: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - } - andEmbed: { - p1: { - X: { - (〈3;#a〉 & 〈3;#b〉) - } - err: 〈0;X〉 - err: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - } - andEmbed: { - p2: { - X: { - (〈3;#b〉 & 〈3;#a〉) - } - err: 〈0;X〉 - err: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - } - orEmbed: { - p1: { - X: { - 〈3;#a〉 - 〈3;#b〉 - } - ok1: 〈0;X〉 - ok1: { - x: { - y: { - j: 3 - } - } - } - ok2: 〈0;X〉 - ok2: { - x: { - y: { - k: 3 - } - } - } - } - } - orEmbed: { - p2: { - X: { - 〈3;#b〉 - 〈3;#a〉 - } - ok1: 〈0;X〉 - ok1: { - x: { - y: { - j: 3 - } - } - } - ok2: 〈0;X〉 - ok2: { - x: { - y: { - k: 3 - } - } - } - } - } - andOrEmbed: { - t1: { - p1: { - X: { - (〈4;#a〉 & 〈4;#b〉) - (〈4;#c〉 & 〈4;#d〉) - } - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - ok1: 〈0;X〉 - ok1: { - x: { - y: { - k: 3 - } - } - } - } - } - } - andOrEmbed: { - t1: { - p2: { - X: { - (〈4;#c〉 & 〈4;#d〉) - (〈4;#a〉 & 〈4;#b〉) - } - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - ok1: 〈0;X〉 - ok1: { - x: { - y: { - k: 3 - } - } - } - } - } - } - andOrEmbed: { - t2: { - X: { - (〈3;#a〉 & 〈3;#b〉) - (〈3;#c〉 & 〈3;#d〉) - ["p"]: int - } - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - ok1: 〈0;X〉 - ok1: { - x: { - y: { - k: 3 - } - } - } - ok2: 〈0;X〉 - ok2: { - x: { - y: { - p: 3 - } - } - } - } - } - indirect: { - a: { - x: { - y: { - [>="k"]: int - } - } - } - #a: 〈0;a〉 - p1: { - X: 〈1;#a〉 - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - p2: { - #a: (〈1;a〉 & _|_(no sharing)) - X: 〈0;#a〉 - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - p3: { - X: (〈1;#a〉 & _|_(no sharing)) - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - p4: { - #a: (〈1;a〉 & _|_(no sharing)) - X: 〈0;#a〉 - X: (〈0;#a〉 & _|_(no sharing)) - err1: 〈0;X〉 - err1: { - x: { - y: { - j: 3 - } - } - } - err2: (〈0;X〉 & _|_(no sharing)) - err2: { - x: { - y: { - j: 3 - } - } - } - ok: 〈0;X〉 - ok: { - x: { - y: { - k: 3 - } - } - } - } - } - } - } - issue2241: { - #close: {} - a: { - x: { - q: 2 - } - 〈1;#close〉 - } - b: 〈0;a〉 - b: { - x: { - r: 4 - } - } - } -} ---- in.cue -{ - #E: { - c: int - } - #A: { - b: int - q: { - 〈2;#E〉 - d: int - } - } - a: (〈0;#A〉 & { - b: 3 - q: { - c: 2 - e: 43 - } - }) - issue852: { - #A: { - [=~"^a-z$"]: string - } - a: 〈0;#A〉 - a: { - Foo: "foo" - } - for k, v in 〈0;a〉 { - b: { - "\(〈2;k〉)": 〈2;v〉 - } - } - } - dynamic: { - #D: { - key: "foo" - 〈0;key〉: int - } - d: (〈0;#D〉 & { - foo: 3 - }) - } - issue4180: { - out: { - if true { - iter: (〈2;#Schema〉 & { - FooOrBar: { - foo: "is foo" - } - }) - } - } - #Foo: { - foo: string - } - #Bar: { - bar: string - } - #Schema: { - FooOrBar: { - ... - } - FooOrBar: (〈1;#Foo〉|〈1;#Bar〉) - } - } -} ---- reroot.cue -{ - issue3330: { - let: { - ok: { - #struct: { - let empty#1 = {} - field: (null|{ - n: int - }) - field: (〈0;let empty#1〉 & { - n: 3 - }) - } - out: 〈import;list〉.Concat([ - [ - 〈2;#struct〉, - ], - ]) - } - } - matthew: { - ok1: { - #struct: { - field: ({ - n: 3 - } & 〈0;g〉) - g: {} - } - out: (〈0;#struct〉 & {}) - } - } - matthew: { - ok2: { - #struct: { - field: ({ - n: 3 - } & 〈0;g〉) - g: {} - } - out: 〈0;#struct〉 - out2: (〈0;out〉 & {}) - } - } - } - issue3331: { - original: { - ok: { - #A: { - let b#2 = {} - c: (〈0;let b#2〉 & { - d: 1 - }) - } - 〈import;list〉.Concat([ - [ - 〈2;#A〉, - ], - ]) - } - } - variant1: { - ok: { - #A: { - let b#3 = {} - c: (〈0;let b#3〉 & { - d: 1 - }) - } - [ - [ - 〈2;#A〉, - ], - ] - } - } - } - indirect: { - embed: { - err1: { - #A: { - x: { - 〈2;#x〉 - 〈2;#y〉 - } - zx: 〈0;x〉.a - } - #x: { - a: { - b: 1 - } - } - #y: { - a: { - c: 2 - } - } - b: 〈0;#A〉 - b1: 〈0;b〉.zx - b1: { - d: 1 - } - } - } - closed: { - err1: { - X: { - a: 〈0;b〉 - b: {} - a: { - e: 1 - } - } - Y: 〈0;X〉 - Y: { - b: 〈0;c〉 - c: 〈1;#X〉 - } - #X: {} - } - } - } - nested: { - ok1: { - #A: { - b: {} - #B: { - c: (〈1;b〉 & { - d: 1 - }) - } - } - x: 〈0;#A〉 - } - } - nested: { - embed: { - ok: { - x: 〈0;#A〉 - #A: { - 〈1;k〉 - } - k: { - d: (〈0;b〉 & { - e: int - }) - b: {} - } - } - } - } - nested: { - err1: { - x: 〈0;#A〉 - #A: { - b: { - f: 1 - } - v: 〈0;#V〉 - #V: { - c: (〈1;b〉 & { - d: 1 - }) - } - } - x: { - b: 〈1;#B〉 - } - #B: { - g: 1 - } - } - } - nested: { - err2: { - #A: { - b: {} - c: (〈0;b〉 & { - d: 1 - }) - } - x: 〈0;#A〉 - x: { - b: { - g: 1 - } - } - } - } - inline: { - #x: { - y: { - z?: { - name: string - } - } - } - err1: ((〈0;#x〉 & { - y: { - z: _ - } - }).y.z & { - name: "a" - age1: 5 - }) - err2: ((〈0;#x〉.y & { - z: _ - }).z & { - name: "a" - age2: 5 - }) - } - mixInDef: { - refInside: { - #x: { - b: { - c: { - d: {} - e: { - f: {} - } - } - } - } - a: 〈0;#x〉 - a: { - b: { - c: { - d: {} - } - } - } - a: { - b: { - c: { - e: 〈1;c〉.d - } - } - } - } - refEdge: { - #x: { - c: { - d: {} - e: { - f: {} - } - } - } - a: 〈0;#x〉 - a: { - c: { - d: {} - } - } - a: { - c: { - e: 〈1;c〉.d - } - } - } - refOutside: { - #x: { - c: { - d: {} - e: { - f: {} - } - } - } - a: 〈0;#x〉 - a: { - c: { - d: {} - } - } - a: { - c: { - e: 〈2;a〉.c.d - } - } - } - } - issue3601: { - original: { - out: { - 〈1;#Transform〉.output - } - #Transform: { - output: (〈1;#Patch〉 & {}).output - } - #Patch: { - target: {} - output: { - foo: { - final: 〈2;target〉 - final: { - version: "v1" - } - } - } - } - } - } - issue3601: { - originalNoShare: { - out: { - 〈1;#Transform〉.output - } - #Transform: { - output: (〈1;#Patch〉 & _|_(no sharing)).output - } - #Patch: { - target: {} - output: { - foo: { - final: 〈2;target〉 - final: { - version: "v1" - } - } - } - } - } - } - issue3601: { - reduced: { - #X: { - a: { - b: { - c: "v1" - } - } - a: { - b: 〈1;empty〉 - } - empty: {} - } - original: { - Y: (〈1;#X〉 & _|_(no sharing)).a - out: (〈0;Y〉 & _|_(no sharing)) - } - moreInlining: { - out: ((〈1;#X〉 & {}).a & {}) - } - noInline: { - Y: (〈1;#X〉 & _|_(no sharing)) - Z: (〈0;Y〉 & _|_(no sharing)) - out: (〈0;Z〉.a & _|_(no sharing)) - } - moreNesting: { - #X: { - a: { - b: { - c: { - d: "v1" - } - } - } - a: { - b: { - c: 〈2;empty〉 - } - } - empty: {} - } - Y: (〈0;#X〉.a & _|_(no sharing)).b - Z: (〈0;Y〉 & _|_(no sharing)) - } - } - } -} ---- validation.cue -{ - issue3332: { - #def: { - field: 〈import;list〉.MinItems(1) - } - use: (〈0;#def〉 & { - field: [ - "value", - ] - }) - } -} diff --git a/cue/testdata/eval/comprehensions.txtar b/cue/testdata/eval/comprehensions.txtar --- a/cue/testdata/eval/comprehensions.txtar +++ b/cue/testdata/eval/comprehensions.txtar @@ -164,177 +164,6 @@ Disjuncts: 0 NumCloseIDs: 48 --- out/compile -- ---- in.cue -{ - a: { - x: 10 - y: 100 - z: 50 - } - b: { - for k, v in 〈1;a〉 if (〈0;v〉 <= 50) { - "\(〈1;k〉)": 〈1;v〉 - } - x: int - if (〈0;x〉 > 3) { - k: 20 - } - k: int - if (〈0;k〉 > 0) { - l: 40 - } - } - c: { - for k, v in 〈1;a〉 let y = (〈0;v〉 + 10) if (〈0;y〉 > 50) { - "\(〈2;k〉)": 〈1;y〉 - } - } - A: { - X: { - run: "dfoo" - } - } - if true { - A: { - X: { - run: string - files: "\(〈import;strings〉.Join([ - 〈1;run〉, - ], "\n"))" - } - } - } - matchOrder: { - a1: { - out: { - [string]: { - Val: 1 - } - } - out: 〈0;in〉.a - in: { - a: { - if true { - b: {} - } - } - } - } - a2: { - out: { - [string]: { - Val: 1 - } - } - in: { - a: { - if true { - b: {} - } - } - } - out: 〈0;in〉.a - } - a3: { - in: { - a: { - if true { - b: {} - } - } - } - out: { - [string]: { - Val: 1 - } - } - out: 〈0;in〉.a - } - a4: { - out: 〈0;in〉.a - out: { - [string]: { - Val: 1 - } - } - in: { - a: { - if true { - b: {} - } - } - } - } - a5: { - out: 〈0;in〉.a - in: { - a: { - if true { - b: {} - } - } - } - out: { - [string]: { - Val: 1 - } - } - } - a6: { - in: { - a: { - if true { - b: {} - } - } - } - out: 〈0;in〉.a - out: { - [string]: { - Val: 1 - } - } - } - } -} ---- issue3691.cue -{ - issue3691: { - original: { - X: { - [string]: string - } - a: { - [string]: 〈1;X〉 - } - a: { - if true { - b: { - c: 1 - } - } - } - } - } - issue3691: { - structuralCycle: { - X: { - [string]: string - } - a: { - [string]: 〈1;X〉 - } - a: { - if true { - b: { - c: 〈3;a〉 - } - } - } - } - } -} -- out/todo.txt -- A.X.files: v3 correctly resolves to "dfoo" (strings.Join(["dfoo"], "\n")); annotated at top level. issue3691.structuralCycle: v3 has different structural cycle representation in error output. diff --git a/cue/testdata/eval/conflicts.txtar b/cue/testdata/eval/conflicts.txtar --- a/cue/testdata/eval/conflicts.txtar +++ b/cue/testdata/eval/conflicts.txtar @@ -53,25 +53,3 @@ Disjuncts: 15 -- out/todo.txt -- v3 reports the argument order differently (string/int vs int/string in v2) and includes an additional error position (5:5) for the assignment in t0.v. --- out/compile -- ---- in.cue -{ - i: int - s: string - t0: { - v: (〈1;i〉 & 〈1;s〉) - } - t1: { - #d1: { - a: { - b: 3 - } - } - #d2: { - a: { - b: 4 - } - } - x: (〈0;#d1〉 & 〈0;#d2〉) - } -} diff --git a/cue/testdata/eval/conjuncts.txtar b/cue/testdata/eval/conjuncts.txtar --- a/cue/testdata/eval/conjuncts.txtar +++ b/cue/testdata/eval/conjuncts.txtar @@ -119,98 +119,6 @@ Notifications: 5 NumCloseIDs: 43 --- out/compile -- ---- in.cue -{ - conjunct: { - t1: ({ - #early: (*"X"|string) - 〈0;#early〉 - } & { - #early: (*"X"|string) - string - }) - } - conjunct: { - t2: { - #early: (*"X"|string) - 〈0;#early〉 - } - } - conjunct: { - t2: { - #early: (*"X"|string) - string - } - } - conjunct: { - t3: (〈1;conjunct〉.t1 & 〈1;conjunct〉.t2) - } - handleComprehensions: { - if false { - subs: (〈1;#sub2〉 & 2) - } - #sub2: 2 - } -} ---- issue2351.cue -{ - issue2351: { - let: { - let _param#1 = "foo" - { - param: (〈1;let _param#1〉 & [ - {}, - ]) - gen: [ - for _, p in 〈1;param〉 { - 〈1;p〉 - }, - ] - }.gen - } - } - issue2351: { - hidden: { - _in1: [ - "foo", - ] - { - in2: 〈1;_in1〉 - out: [ - for _, x in 〈1;in2〉 { - 〈1;x〉 - }, - ] - }.out - } - } -} ---- issue2355.cue -{ - issue2355: { - #GetF1: { - in: _ - out: 〈0;in〉.f1 - } - #PutOut1: { - in: _ - out: { - out1: "\(〈1;in〉)" - } - } - export: { - let data#2 = { - f1: "foo" - } - (〈1;#PutOut1〉 & { - in: (〈2;#GetF1〉 & { - in: 〈2;let data#2〉 - }).out - }).out - } - } -} -- out/todo.txt -- conjunct.t1/t2/t3: complex disjunctions with embedded hidden fields; only @test(eq) checked. issue2355.export: v3 correctly closes it (closing in new evaluator), v2 does not close. diff --git a/cue/testdata/eval/counters.txtar b/cue/testdata/eval/counters.txtar --- a/cue/testdata/eval/counters.txtar +++ b/cue/testdata/eval/counters.txtar @@ -180,155 +180,6 @@ Disjuncts: 36 NumCloseIDs: 60 --- out/compile -- ---- issue3750.cue -{ - issue3750: { - original: { - out: (〈0;#Foo〉 & { - sub: 〈1;#Foo〉 - }) - #Foo: { - sub: (〈1;#Foo〉|〈1;#Bar〉) - meta: { - strs: [ - ...string, - ] - for _, w in 〈import;list〉.FlattenN([ - 〈1;strs〉, - ], 1) {} - } - } - #Bar: { - kind: "bar" - meta: { - strs: [ - ...string, - ] - } - } - } - } - issue3750: { - reduced: { - out: (〈0;Foo〉 & { - sub: 〈1;Foo〉 - }) - Foo: { - sub: (〈1;Foo〉|{ - a: { - b: _ - } - }) - a: { - b: _ - for _, w in 〈import;list〉.FlattenN([ - 〈1;b〉, - ], 1) {} - } - } - } - } -} ---- issue3770.cue -{ - issue3770: { - task: { - m: { - let t#1 = [ - "x", - ] - for _, m in 〈0;let t#1〉 { - 〈1;m〉: { - a: 1 - } - } - x: { - b: 1 - } - } - m: (null|{}) - out: 〈0;m〉.x.a - } - } -} ---- issue3780.cue -{ - issue3780: { - panic1: { - objs: (〈0;#Objects〉 & {}) - param!: bool - if 〈0;param〉 { - objs: { - obj1: { - one: 1 - two: 2 - } - } - } - #Objects: { - [〈import;strings〉.HasPrefix("obj")]: { - kind: "object" - ... - } - } - } - } - issue3780: { - panic2: { - parent: { - objs: (〈0;#Objects〉 & {}) - param?: bool - if (〈0;param〉 != _|_(explicit error (_|_ literal) in source)) { - objs: { - obj1: { - one: 1 - two: 2 - } - } - } - #Objects: { - [〈import;strings〉.HasPrefix("obj")]: { - kind: "object" - ... - } - } - } - } - } -} ---- issue3824.cue -{ - issue3824: { - panic: { - thing: { - spec: { - name: string - } - outputField: string - } - val: string - things: { - [_]: 〈1;thing〉 - } - things: { - [_]: { - spec: (*{ - name: "self-signed" - }|{ - ... - }) - } - } - if true { - things: { - name: {} - } - val: 〈0;things〉["name"].outputField - } - } - } -} -- out/todo.txt -- issue3750.original: v3 has more complex nested disjunction structure in sub field; v2 resolves to concrete value. issue3750.reduced: v3 has different field ordering in disjunction sub-fields compared to v2. diff --git a/cue/testdata/eval/cycles_ref.txtar b/cue/testdata/eval/cycles_ref.txtar --- a/cue/testdata/eval/cycles_ref.txtar +++ b/cue/testdata/eval/cycles_ref.txtar @@ -17,18 +17,3 @@ Unifications: 12 Conjuncts: 24 Disjuncts: 15 --- out/compile -- ---- in.cue -{ - a: (〈0;b〉 + 100) - b: (〈0;a〉 - 100) - a: 200 - c: (〈0;d〉 & { - b: 2 - }) - d: 〈0;e〉 - e: { - a: 1 - } - e: 〈0;c〉 -} diff --git a/cue/testdata/eval/deref.txtar b/cue/testdata/eval/deref.txtar --- a/cue/testdata/eval/deref.txtar +++ b/cue/testdata/eval/deref.txtar @@ -51,53 +51,3 @@ MisalignedConjunct: 4 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - issue4011: { - full: { - let _hugoEnvironments#1 = { - default: "_default" - production: "production" - } - site: { - cls: _ - } - site: { - [_]: { - fs: { - Create: { - for envID, envName in 〈4;let _hugoEnvironments#1〉 let envConfig = 〈3;hugo〉[〈0;envID〉] if (〈0;envConfig〉 != _|_(explicit error (_|_ literal) in source)) { - config: { - Contents: 〈2;envConfig〉 - } - } - } - } - hugo: _ - } - } - site: { - [_]: { - hugo: { - production: {} - } - } - } - } - } - issue4011: { - reduced: { - result: { - for _, envName in [ - "foo", - ] let env = 〈2;envs〉[〈0;envName〉] if (〈0;env〉 != _|_(explicit error (_|_ literal) in source)) { - 〈2;envName〉: true - } - } - envs: { - foo: {} - } - } - } -} diff --git a/cue/testdata/eval/discontinuous.txtar b/cue/testdata/eval/discontinuous.txtar --- a/cue/testdata/eval/discontinuous.txtar +++ b/cue/testdata/eval/discontinuous.txtar @@ -19,36 +19,6 @@ DSpec: {} @test(eq, {D: bar: {}, DSpec: {}}) } --- out/compile -- ---- in.cue -{ - a: [ - for _, c in 〈1;foo〉.bar.baz { - 〈1;c〉 - }, - ] - a: [ - { - name: "http" - }, - ] - foo: { - 〈1;x〉.D - bar: { - baz: [ - { - port: 8080 - }, - ] - } - } - x: { - D: { - bar: 〈1;DSpec〉 - } - DSpec: {} - } -} -- out/eval/stats -- Leaks: 0 Freed: 14 diff --git a/cue/testdata/eval/disjselfcycle.txtar b/cue/testdata/eval/disjselfcycle.txtar --- a/cue/testdata/eval/disjselfcycle.txtar +++ b/cue/testdata/eval/disjselfcycle.txtar @@ -78,100 +78,3 @@ -- out/errors.txt -- [eval] issue4119.reducedNested.x.y.0.f: undefined field: f: ./comprehensions.cue:25:9 --- out/compile -- ---- comprehensions.cue -{ - issue4119: { - reduced: { - x: [ - ..., - ] - x: (_|*[ - { - f: 123 - }, - ]) - x: [ - for _, i in 〈1;x〉 { - f: 〈1;i〉.f - }, - ] - } - } - issue4119: { - reducedNested: { - x: { - y: [ - ..., - ] - } - x: ({ - y: _ - }|*{ - y: [ - { - f: 123 - }, - ] - }) - x: { - y: [ - for _, i in 〈2;x〉 { - f: 〈1;i〉.f - }, - ] - } - } - } - issue4119: { - full: { - _img: { - val: string - accounts: { - groups: (〈2〉.accounts.groups|*[ - { - gid: 65532 - }, - ]) - groups: [ - for _, g in 〈1;groups〉 let _gid = 〈0;g〉.gid { - gid: [ - if (〈2;_gid〉 != _|_(explicit error (_|_ literal) in source)) { - 〈3;_gid〉 - }, - 65532, - ][0] - }, - ] - } - } - art: { - images: { - [string]: 〈2;#Image〉 - } - for k, v in 〈0;images〉 { - images: { - 〈2;k〉: (〈4;_img〉 & 〈2;v〉) - } - } - } - #Image: { - val: string - accounts?: { - groups?: [ - ..., - ] - } - } - art: { - images: { - ko: { - val: "test" - } - } - } - } - } -} ---- in.cue -{} diff --git a/cue/testdata/eval/disjunctioncross.txtar b/cue/testdata/eval/disjunctioncross.txtar --- a/cue/testdata/eval/disjunctioncross.txtar +++ b/cue/testdata/eval/disjunctioncross.txtar @@ -197,134 +197,5 @@ Disjuncts: 80 NumCloseIDs: 96 --- out/compile -- ---- in.cue -{ - #OneOrTwo: (〈0;#One〉|〈0;#Two〉) - #One: { - kind: "one" - one: { - oneField: "value" - } - } - #Two: { - kind: "two" - two: { - optional?: string - } - } - _appDefaults: { - two: { - two: { - optional: (*"optional set"|string) - } - } - } - valueDiscriminator: { - crossing: { - out: (〈0;#Application〉 & { - oneOrTwo: { - kind: "two" - } - }) - #Application: { - oneOrTwo: 〈3;#OneOrTwo〉 - oneOrTwo: (*〈3;_appDefaults〉[〈0;oneOrTwo〉.kind]|_) - } - } - } - valueDiscriminator: { - local: { - out: (〈0;#Application〉 & { - oneOrTwo: { - kind: "two" - } - }) - #Application: { - oneOrTwo: 〈3;#OneOrTwo〉 - oneOrTwo: { - (*〈4;_appDefaults〉[〈1〉.kind]|_) - } - } - } - } - fieldDiscriminator: { - crossing: { - out: (〈0;#Application〉 & { - oneOrTwo: { - two: {} - } - }) - #Application: { - oneOrTwo: 〈3;#OneOrTwo〉 - oneOrTwo: (*〈3;_appDefaults〉[〈0;oneOrTwo〉.kind]|_) - } - } - } - fieldDiscriminator: { - local: { - out: (〈0;#Application〉 & { - oneOrTwo: { - two: {} - } - }) - #Application: { - oneOrTwo: 〈3;#OneOrTwo〉 - oneOrTwo: { - (*〈4;_appDefaults〉[〈1〉.kind]|_) - } - } - } - } - issue3967: { - error: { - nested: { - out: (〈0;#Application〉 & { - oneOrTwo: { - two: {} - } - }) - #Application: { - oneOrTwo: (〈4;#OneOrTwo〉 & { - if (〈2〉.oneOrTwo.kind == "two") { - two: { - if (〈4〉.oneOrTwo.two.optional == _|_(explicit error (_|_ literal) in source)) { - optional: "optional set" - } - } - } - if (〈2〉.oneOrTwo.kind == "never") {} - }) - if (〈1〉.oneOrTwo.kind == "never") {} - } - } - } - } - issue3967: { - error: { - local: { - out: (〈0;#Application〉 & { - oneOrTwo: { - two: {} - } - }) - #Application: { - oneOrTwo: { - (〈5;#OneOrTwo〉 & { - if (〈2〉.kind == "two") { - two: { - if (〈4〉.two.optional == _|_(explicit error (_|_ literal) in source)) { - optional: "optional set" - } - } - } - if (〈2〉.kind == "never") {} - }) - } - } - } - } - } -} -- out/todo.txt -- v3 reports a cycle error for issue3967.error.nested.out (undefined field: kind) and issue3967.error.local.out.oneOrTwo (circular dependency), whereas v2 reported incomplete/cycle errors differently and resolved some fields that v3 does not. diff --git a/cue/testdata/eval/disjunctions.txtar b/cue/testdata/eval/disjunctions.txtar --- a/cue/testdata/eval/disjunctions.txtar +++ b/cue/testdata/eval/disjunctions.txtar @@ -567,572 +567,3 @@ MaxConjunctInfos: 6 MaxReqSets: 7 MaxRedirect: 2 --- out/compile -- ---- dependencies.cue -{ - issue3606: { - data: ({ - notAllowed: true - } & 〈0;#S〉) - #S: (string|{}) - } - issue3672: { - #A: (string|{ - y: true - }) - #B: (〈0;#A〉|{ - a: "append" - }|{ - b: "prepend" - }) - #fn: { - #C: 〈1;#B〉 - #out: { - x: [ - ...〈2;#C〉, - ] - } - } - #def: (〈0;#fn〉 & {}).#out - v: 〈0;#def〉 - v: { - x: [ - { - y: true - }, - ] - } - } - issue3681: { - out: { - one: 〈1;#strDefaultDef〉 - } - out: { - two: "\(〈1;strDefault〉)" - } - strDefault: (*"fallback"|string) - #strDefaultDef: 〈0;strDefault〉 - } - issue3699: { - reduced: { - p1: { - y: { - if 〈1;x〉.z { - 1 - } - } - x: (*{ - z: true - }|{}) - } - } - reduced: { - p2: { - y: { - if 〈1;x〉.z { - 1 - } - } - x: (*{ - z: true - }|{}) - } - } - reduced: { - full: { - _res: { - _fooTrue: ({}|*{ - foo: true - }) - _msgSwitch: [ - if 〈1;_fooTrue〉.foo { - msg: "foo" - }, - { - msg: "bar" - }, - ][0] - out: 〈0;_msgSwitch〉.msg - } - let res#1 = { - out: (〈1;_res〉 & {}).out - } - out: 〈0;let res#1〉.out - } - } - } -} ---- in.cue -{ - a: (*1|int) - aa: (*1|*2|int) - b: ({ - name: "int" - val: int - }|{ - name: "str" - val: string - }) - d: (〈0;b〉 & { - val: 3 - }) - c: (〈0;b〉 & { - name: "int" - val: 3 - }) - e: (〈0;b〉 & { - val: "foo" - }) - f: (〈0;b〉 & { - name: "str" - val: 3 - }) - e1: { - a: (null|{ - bar: 2 - }) - b: (〈0;a〉 & {}).bar - } - d1: { - a: ((null|{ - c: 1 - }) & {}) - b: ({} & (null|{ - c: 1 - })) - } - d2: { - a: (([ - ..., - ]|{ - c: 1 - }) & {}) - b: ({} & ([ - ..., - ]|{ - c: 1 - })) - } - d3: { - a: ((string|{ - c: 1 - }) & {}) - b: ({} & (string|{ - c: 1 - })) - } - d4: { - a: ((string|{ - c: 1 - }) & {}) - b: ({} & (string|{ - c: 1 - })) - } - d5: { - a: ((number|{ - c: 1 - }) & {}) - b: ({} & (number|{ - c: 1 - })) - } - d6: { - a: ((int|{ - c: 1 - }) & {}) - b: ({} & (int|{ - c: 1 - })) - } - t10: { - p1: { - schema: 〈0;test〉 - schema: (string|{ - name: string - }) - #A: { - (string|{ - name: string - }) - } - test: { - name: "Test" - } - test: 〈0;#A〉 - } - } - t10: { - p2: { - schema: (string|{ - name: string - }) - schema: 〈0;test〉 - #A: { - (string|{ - name: string - }) - } - test: { - name: "Test" - } - test: 〈0;#A〉 - } - } - t10: { - p3: { - #A: { - (string|{ - name: string - }) - } - test: { - name: "Test" - } - test: 〈0;#A〉 - schema: (string|{ - name: string - }) - schema: 〈0;test〉 - } - } - t11: { - p1: { - a: 〈0;#A〉 - a: 〈0;b〉 - b: (〈0;#A〉 & [ - "b", - ]) - #A: ([ - ("a"|"b"), - ]|{}) - } - } - t11: { - p2: { - b: (〈0;#A〉 & [ - "b", - ]) - #A: ([ - ("a"|"b"), - ]|{}) - a: 〈0;b〉 - a: 〈0;#A〉 - } - } - cross: { - a: (*"word"|string) - a: (string|*"word") - } - d100: { - i: (null|{ - bar: 2 - }) - j: 〈0;i〉.bar - } - issue641: { - #A: { - type: "a" - x: "" - } - #B: { - type: "b" - x: string - } - #C: { - b: (〈1;#A〉|〈1;#B〉) - } - e: { - [string]: (〈1;#C〉 & { - b: (〈2;#A〉|〈2;#B〉) - }) - } - e: { - foobar: (〈1;#C〉 & { - b: (〈2;#B〉 & { - x: "foobar" - }) - }) - } - } -} ---- indexelim.cue -{ - indexElimination: { - inStruct: { - x: { - a: (*〈1;x〉[0]|0) - }.a - } - inList1: { - x: [ - 〈1;x〉[0], - ][0] - } - inList2: { - x: [ - (*〈1;x〉[0]|0), - ][0] - } - issue3124: { - full: { - x: [ - ...bool, - ] - x: [ - true, - false, - true, - true, - ] - y: [ - for _, v in 〈1;x〉 { - [ - if 〈2;v〉 { - 1 - }, - 0, - ][0] - }, - ] - z: [ - for i, v in 〈1;y〉 { - 〈import;"math/bits"〉.Set((*〈3;z〉[(〈1;i〉 - 1)]|0), ((len(〈3;y〉) - 〈1;i〉) - 1), 〈1;v〉) - }, - ][3] - } - } - } -} ---- issue3406.cue -{ - issue3406: { - out: (〈0;d〉 & { - 〈1;d〉 - }) - d: { - kind: ("foo"|"bar") - } - d: ({ - kind: "foo" - }|{ - kind: "bar" - }) - } -} ---- issue3411.cue -{ - issue3411: { - x: { - y?: [ - ...string, - ] - } - x: ({ - y: [ - "foo", - ] - }|*{ - y: [ - "bar", - ] - }) - } -} ---- issue3434.cue -{ - issue3434: { - t1: { - ({}|{}) - { - ["x"]: 1 - } - { - ["y"]: 2 - } - } - } - issue3434: { - full: { - out: (〈0;#Schema〉 & { - steps: [ - { - run: "example" - }, - ] - }) - #Schema: { - steps: [ - ...{ - run: string - }, - ] - #matrixConfig: (string|[ - ...〈1;#matrixConfig〉, - ]) - matrix?: (({ - ... - }|string) & { - { - [=~"^foo"]: [ - ...{ - [string]: 〈4;#matrixConfig〉 - }, - ] - } - { - [=~"^bar"]: ([ - ...〈3;#matrixConfig〉, - ]|string) - } - }) - } - } - } -} ---- issue3490.cue -{ - issue3490: { - nested: { - p1: { - (("a"|"b")|"b") - ("a"|"b") - } - } - } - issue3490: { - nested: { - p2: { - ("a"|"b") - (("a"|"b")|"b") - } - } - } - issue3490: { - full: { - data: [ - ...〈1;#Schema〉, - ] - data: [ - (〈1;#Schema〉 & {}), - ] - #Schema: { - runs?: ("foo"|([ - 〈1;#D1〉, - ]|[ - 〈1;#D1〉, - 〈1;#D2〉, - ])) - #D1: "d1" - #D2: "d2" - } - } - } -} ---- issue3597.cue -{ - issue3597: { - t1: { - #Schema: { - _ok: bool - ({}|{ - _ok: true - let Ok#2 = 〈0;_ok〉 - ({}|{ - x: 〈1;let Ok#2〉 - }) - }) - } - [string]: 〈0;#Schema〉 - foo: 〈0;bar〉 - bar: {} - } - } - issue3597: { - t2: { - ok: true - X: (_|{ - let Ok#3 = 〈1;ok〉 - (_|{ - x: 〈1;let Ok#3〉 - }) - }) - foo: (〈0;X〉 & { - 〈1;X〉 - }) - } - } -} ---- issue3891.cue -{ - issue3891: { - reduced: { - ({ - x: _ - }|null) - ({ - x: _ - }|null) - x: (*〈0;a〉.y|_) - a: 〈0;b〉 - b: { - y: 1 - } - } - } - issue3891: { - full: { - out: (〈0;#Foo〉|"never") - out: (〈0;#Foo〉|"never") - out: (〈0;_fooTemplate〉 & { - _input: (〈1;_transform〉 & { - in: { - sub1: { - sub2: "bar" - } - } - }).out - }) - _transform: { - in: _ - out: 〈0;in〉 - } - #Foo: { - foo?: _ - } - _fooTemplate: { - _input: _ - foo: (*〈0;_input〉.sub1.sub2|_) - } - } - } -} ---- issue3899.cue -{ - issue3899: { - reduced: { - b: ((〈0;c〉 + "")|string) - c?: string - } - } - issue3899: { - full: { - out: (〈0;#Schema〉 & { - name: "foo" - }) - #Schema: { - _versions: { - foo: "123" - } - spec: { - limits: true - } - name!: string - spec: { - image: (string|*"\(〈1;name〉)") - } - deployImage: 〈0;_versions〉[〈0;spec〉.image] - } - } - } -} diff --git a/cue/testdata/eval/dynamic_field.txtar b/cue/testdata/eval/dynamic_field.txtar --- a/cue/testdata/eval/dynamic_field.txtar +++ b/cue/testdata/eval/dynamic_field.txtar @@ -138,116 +138,6 @@ Disjuncts: 0 NumCloseIDs: 4 --- out/compile -- ---- constraints.cue -{ - constraints: { - t1: "foo" - t2: "bar" - 〈0;t1〉?: { - 〈1;t2〉!: 3 - } - } -} ---- in.cue -{ - a: "foo" - "\(〈0;a〉)": { - b: { - c: { - d: 〈3;e〉 - } - } - } - e: 2 - b: "bar" - "\(〈0;b〉)": { - a: 1 - } - c: 〈0;("\(〈0;b〉)")〉 - withError: { - issue799: ({ - key: &(int, >=-2147483648, <=2147483647) - } & { - "\((1 & 2))": 123 - }) - } - parenExprRefParent: { - a: { - 〈1;x〉: {} - } - x: "foo" - } - parenExprRefEqual: { - 〈0;x〉: {} - x: "foo" - } - chainedResolution: { - x: { - 〈1;x〉.baz: "bar" - 〈1;x〉.foo: "baz" - baz: "foo" - } - } - noCycleError: { - foo: { - [_]: { - #ID: "\(string)" - } - } - foo: { - bar: { - entries: { - 〈3;foo〉.baz.#ID: true - } - } - } - foo: { - baz: {} - } - } -} ---- issue3828.cue -{ - issue3828: { - reduced: { - a: { - b: {} - } - a: { - [_]: { - if true let x = 〈2;str〉 { - 〈1;x〉: true - } - } - } - str: "foobot1" - } - } - issue3828: { - full: { - orgs: { - org1: { - repos: { - repo1: {} - } - } - } - botUser: "bot1" - orgs: { - [_]: { - for repo_name, _ in 〈1〉.repos let orgBotUser = 〈3;botUser〉 { - collaborators: { - 〈3;repo_name〉: { - 〈3;orgBotUser〉: true - } - } - } - } - } - } - } -} -- out/todo.txt -- c: v3 uses structure sharing (~(bar)), v2 expands it. noCycleError: v3 adds extra error message about key value; v2 only reports invalid interpolation. diff --git a/cue/testdata/eval/embed.txtar b/cue/testdata/eval/embed.txtar --- a/cue/testdata/eval/embed.txtar +++ b/cue/testdata/eval/embed.txtar @@ -204,195 +204,6 @@ Disjuncts: 6 NumCloseIDs: 43 --- out/compile -- ---- in.cue -{ - #A: { - 〈1;Common〉 - ... - } - Common: { - a: int - b: int - } - x: 〈0;#A〉 - x: { - c: int - } - #B: { - if true { - a: int - } - ... - } - y: 〈0;#B〉 - y: { - c: int - } -} ---- noclose.cue -{ - double: { - a: { - b?: { - c: { - d: "c" - } - } - } - a: { - { - b: { - { - c: { - e: "member" - } - } - } - } - } - } - doubleAsComprehension: { - a: { - b?: { - c: { - d: "c" - } - } - } - a: { - if true { - b: { - if true { - c: { - e: "member" - } - } - } - } - } - } - fieldNotAllowed: { - t1: { - #X: { - objs: { - extra: { - unused: "foo" - } - ... - } - ... - } - #Y: { - unused: {} - } - addTwo: (〈0;#X〉 & { - 〈1;#Y〉 - objs: { - name: "Two" - } - }) - } - t2: { - #AddObjsExtra: { - objs: { - [string]: { - extra: { - unused: "foo" - } - ... - } - } - ... - } - #EmbedUnused: { - unused: {} - } - #AddTwo: (〈0;#AddObjsExtra〉 & { - 〈1;#EmbedUnused〉 - objs: { - two: { - name: "Two" - labels: { - app: 〈3;objs〉.one.name - } - } - } - }) - out: (〈0;#AddTwo〉 & { - objs: { - one: { - name: "One" - } - } - }) - } - t3: { - x: 〈0;#X〉 - #X: { - y: { - z: { - a: { - [string]: string - } - b: { - E: "1" - } - } - ... - } - } - x1: { - y: 〈1;#Y〉 - } - #Y: { - port?: string - } - x: { - y: { - z: { - b: { - E: string - } - } - port: 〈0;z〉.b.E - z: { - a: { - c?: string - } - } - } - } - if true { - w: (〈1;x〉 & { - y: 〈2;x1〉.y - }) - } - } - } - closednessInversion: { - base: 〈0;#X〉 - base: { - x: 〈1;#Y〉 - } - #X: { - x: { - ... - } - } - #Y: { - y: (string|*"default") - } - out: { - 〈1;base〉.x - a: { - b: { - c: "d" - } - } - } - } -} -- out/todo.txt -- fieldNotAllowed: v3 correctly enforces closedness for cases that evalv2 missed. fieldNotAllowed.t1.addTwo.objs.extra: v3 reports error; evalv2 did not. diff --git a/cue/testdata/eval/errunifiy.txtar b/cue/testdata/eval/errunifiy.txtar --- a/cue/testdata/eval/errunifiy.txtar +++ b/cue/testdata/eval/errunifiy.txtar @@ -20,11 +20,3 @@ Unifications: 4 Conjuncts: 6 Disjuncts: 0 --- out/compile -- ---- in.cue -{ - a: or([]) - a: "t" - b: _|_(explicit error (_|_ literal) in source) - b: "t" -} diff --git a/cue/testdata/eval/expressions.txtar b/cue/testdata/eval/expressions.txtar --- a/cue/testdata/eval/expressions.txtar +++ b/cue/testdata/eval/expressions.txtar @@ -29,38 +29,3 @@ Unifications: 5 Conjuncts: 5 Disjuncts: 5 --- out/compile -- ---- in.cue -{ - a: 1 - b: (1 + 2) - c: (3 - 1) - d: rem(5, 3) - structComparison: { - equalStructs: ({ - a: 1 - b: 2 - } == { - a: 1 - b: 2 - }) - differentStructs: ({ - a: 1 - } == { - a: 2 - }) - emptyStructs: ({} == {}) - } - mixedComparison: { - structVsNumber: ({ - a: 1 - } == 1) - listVsStruct: ([ - 1, - 2, - ] == { - a: 1 - }) - stringVsNumber: ("hello" == 42) - } -} diff --git a/cue/testdata/eval/fields.txtar b/cue/testdata/eval/fields.txtar --- a/cue/testdata/eval/fields.txtar +++ b/cue/testdata/eval/fields.txtar @@ -15,23 +15,6 @@ ./in.cue:4:18 [eval] intField: integer fields not supported: ./in.cue:9:3 --- out/compile -- ---- in.cue -{ - bulkToSelf: { - a: { - foo: { - [string]: int - } - foo: { - bar: "3" - } - } - } - intField: { - 2: string - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/eval/incomplete.txtar b/cue/testdata/eval/incomplete.txtar --- a/cue/testdata/eval/incomplete.txtar +++ b/cue/testdata/eval/incomplete.txtar @@ -121,44 +121,3 @@ ./in.cue:48:14 [incomplete] issue1837.p3.x: undefined field: b: ./in.cue:61:14 --- out/compile -- ---- in.cue -{ - s: string - e1: (〈0;s〉 + 〈0;s〉) - e2: (>"bar" & 〈0;s〉) - e3: (>〈0;s〉 & "foo") - e3b: >〈0;s〉 - e4: (>〈0;e1〉 & 〈0;s〉) - e5: (<〈0;e5〉 & 〈0;s〉) - E: { - a: (〈0;c〉 - 〈0;b〉) - b: (〈0;c〉 - 〈0;a〉) - c: ((〈0;a〉 + 〈0;b〉) & >=5) - } - a: int - okay: ((>10 & <〈0;a〉) + 3) - issue1837: { - p1: { - context: {} - x: 〈0;context〉.b - if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) { - message: "a" - } - } - p2: { - if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) { - message: "a" - } - x: 〈0;context〉.b - context: {} - } - p3: { - if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) { - message: "a" - } - context: {} - x: 〈0;context〉.b - } - } -} diff --git a/cue/testdata/eval/incompleteperm.txtar b/cue/testdata/eval/incompleteperm.txtar --- a/cue/testdata/eval/incompleteperm.txtar +++ b/cue/testdata/eval/incompleteperm.txtar @@ -26,38 +26,6 @@ // applying <= to a bound (>=100) is not valid arithmetic. // https://cuelang.org/issue/405 issue405: >=100 <= 200 --- out/compile -- -permanentlyIncompleteOperands.a: invalid operand string ('+' requires concrete value): - ./in.cue:3:5 -permanentlyIncompleteOperands.a: invalid operand string ('+' requires concrete value): - ./in.cue:3:20 -permanentlyIncompleteOperandsNested.a: invalid operand int ('+' requires concrete value): - ./in.cue:8:6 -permanentlyIncompleteOperandsNested.a: invalid operand int ('+' requires concrete value): - ./in.cue:8:18 -permanentlyIncompleteOperandsDisjunct.a: invalid operand int ('+' requires concrete value): - ./in.cue:12:6 -permanentlyIncompleteOperandsDisjunct.a: invalid operand int ('+' requires concrete value): - ./in.cue:12:18 -issue680: invalid operand >10 ('*' requires concrete value): - ./in.cue:18:12 -issue405: invalid operand >=100 ('<=' requires concrete value): - ./in.cue:23:11 ---- in.cue -{ - permanentlyIncompleteOperands: { - a: ((string + ":") + string) - a: "golang/go:1.13.5" - } - permanentlyIncompleteOperandsNested: { - a: ((int + 1) + (int + 1)) - } - permanentlyIncompleteOperandsDisjunct: { - a: ((int + 1)|(int + 1)) - } - issue680: ((>10 * 2) & 0) - issue405: (>=100 <= 200) -} -- out/evalalpha -- permanentlyIncompleteOperands.a: invalid operand string ('+' requires concrete value): ./in.cue:3:5 diff --git a/cue/testdata/eval/insertion.txtar b/cue/testdata/eval/insertion.txtar --- a/cue/testdata/eval/insertion.txtar +++ b/cue/testdata/eval/insertion.txtar @@ -132,133 +132,3 @@ Unifications: 67 Conjuncts: 163 Disjuncts: 73 --- out/compile -- ---- a.cue -{ - embeddingDirect: { - t1: ({ - #a: _ - _ - } & { - #a: "s" - 〈0;#a〉 - }) - } - embeddingExpr: { - t1: ({ - #a: _ - _ - } & { - #a: "s" - [ - 〈1;#a〉, - ][0] - }) - } - unifiedDirect: { - t1: { - #a: _ - _ - } - t1: { - 〈0;#a〉 - #a: _ - } - t1: { - _ - #a: "s" - } - } - unifiedExpr: { - t1: { - #a: _ - _ - } - t1: { - [ - 〈1;#a〉, - ][0] - #a: _ - } - t1: { - #a: "s" - _ - } - } - cross: { - t1: { - a: { - b: { - v: 1 - a: { - w: 2 - } - } - } - b: { - a: { - x: 2 - b: { - y: 5 - } - } - } - 〈0;a〉 - 〈0;b〉 - } - } -} ---- complex.cue -{ - recursive: { - t1: { - e: {} - c: { - d: { - e: { - f: 1 - } - } - } - 〈0;c〉.d - c: { - d: { - c: { - d: { - e: { - g: 1 - } - } - } - } - } - } - t2: { - 〈0;c〉 - c: { - c: { - g: 1 - } - } - } - } -} ---- issue2169.cue -{ - embeddedFunctionalExpr: { - #fn: ({ - #in: _ - _ - } & { - #in: "str" - (({ - #t: _ - 〈0;#t〉 - } & { - #t: 〈1;#in〉 - _ - }) + "") - }) - 〈0;#fn〉 - } -} diff --git a/cue/testdata/eval/issue1640.txtar b/cue/testdata/eval/issue1640.txtar --- a/cue/testdata/eval/issue1640.txtar +++ b/cue/testdata/eval/issue1640.txtar @@ -27,31 +27,6 @@ lc: string uc: lc } --- out/compile -- ---- a1.cue -{ - y: 〈0;fact2〉.uc - x: 〈0;fact1〉.uc -} ---- a2.cue -{ - x: 〈0;fact1〉.uc - y: 〈0;fact2〉.uc -} ---- x.cue -{ - fact1: (〈0;#MCS〉 & { - lc: 〈1;fact2〉.lc - }) - fact2: (〈0;#MCS〉 & { - lc: "foo" - }) - #MCS: 〈0;#MultiCaseString〉 - #MultiCaseString: { - lc: string - uc: 〈0;lc〉 - } -} -- out/eval/stats -- Leaks: 0 Freed: 15 diff --git a/cue/testdata/eval/issue1886.txtar b/cue/testdata/eval/issue1886.txtar --- a/cue/testdata/eval/issue1886.txtar +++ b/cue/testdata/eval/issue1886.txtar @@ -86,28 +86,3 @@ [incomplete] incompleteTwo._t: invalid interpolation: non-concrete value string (type string): ./in.cue:54:3 ./in.cue:53:7 --- out/compile -- ---- in.cue -{ - cycle: { - x: 200 - x: (〈0;y〉 + 100) - y: (〈0;x〉 - 100) - a: (〈0;b〉 + 100) - b: (〈0;a〉 - 100) - } - incompleteOne: { - _t: { - #p: string - "hello \(〈0;#p〉)" - } - r: "\(〈0;_t〉)" - } - incompleteTwo: { - r: "\(〈0;_t〉)" - _t: { - #p: string - "hello \(〈0;#p〉)" - } - } -} diff --git a/cue/testdata/eval/issue2146.txtar b/cue/testdata/eval/issue2146.txtar --- a/cue/testdata/eval/issue2146.txtar +++ b/cue/testdata/eval/issue2146.txtar @@ -73,56 +73,5 @@ Disjuncts: 12 NumCloseIDs: 38 --- out/compile -- ---- in.cue -{ - p1: { - #A: { - x?: int - y?: int - let list#1 = [ - 〈1;x〉, - 〈1;y〉, - ] - all: [ - for _, v in 〈1;let list#1〉 if (〈0;v〉 != _|_(explicit error (_|_ literal) in source)) { - 〈1;v〉 - }, - ] - (*{ - x?: _|_(explicit error (_|_ literal) in source) - y: 1 - }|_) - } - a: (〈0;#A〉 & { - x: 3 - }) - b: (〈0;#A〉 & 〈0;a〉) - } - p2: { - #A: { - x?: int - y?: int - let list#2 = [ - 〈1;x〉, - 〈1;y〉, - ] - all: [ - for _, v in 〈1;let list#2〉 if (〈0;v〉 != _|_(explicit error (_|_ literal) in source)) { - 〈1;v〉 - }, - ] - (_|*{ - x?: _|_(explicit error (_|_ literal) in source) - y: 1 - }) - } - a: (〈0;#A〉 & { - x: 3 - y: 2 - }) - b: (〈0;#A〉 & 〈0;a〉) - } -} -- out/todo.txt -- p1.b and p2.b: v2 uses structure-shared let (list#1multi/list#2multi), v3 evaluates it per arc. diff --git a/cue/testdata/eval/issue2235.txtar b/cue/testdata/eval/issue2235.txtar --- a/cue/testdata/eval/issue2235.txtar +++ b/cue/testdata/eval/issue2235.txtar @@ -154,138 +154,6 @@ Notifications: 1 NumCloseIDs: 28 --- out/compile -- ---- issue2235.cue -{ - shorewallParams: close({ - [=~"^[A-Z0-9_]+$"]: [ - ...〈import;net〉.IP, - ] - }) - #Cluster: { - clusterName: string - shorewallPrefix: "KUBERNETES_\(〈import;strings〉.ToUpper(〈0;clusterName〉))" - } - clusters: { - [string]: (〈1;#Cluster〉 & { - clusterName: 〈1;-〉 - }) - } - #Cluster: { - globalIngressControllers: { - [string]: 〈2;#GlobalIngressController〉 - } - globalIngressControllers: { - admin: (〈2;#GlobalIngressController〉 & { - class: "admin" - }) - } - for _, c in 〈0;globalIngressControllers〉 { - objects: 〈1;c〉.objects - } - } - for clusterName, cluster in 〈0;clusters〉 { - for class, controller in 〈1;cluster〉.globalIngressControllers { - let svc#1multi = 〈1;controller〉.objects.namespaced.ingress.Service["\(〈1;class〉)-nginx-ingress-controller"] - shorewallParams: { - "\(〈4;cluster〉.shorewallPrefix)_INGRESS_\(〈import;strings〉.ToUpper(〈2;class〉))": 〈1;let svc#1〉.spec.externalIPs - } - } - } - #GlobalIngressController: { - class: string - objects: { - namespaced: { - ingress: { - Service: { - "\(〈4;class〉)-nginx-ingress-controller": { - spec: { - externalIPs: [ - "127.0.0.1", - ] - } - } - } - } - } - } - for kind, objs in 〈0;objects〉.namespaced.ingress { - for name, obj in 〈1;objs〉 { - objects: { - namespaced: { - ingress: { - "\(〈6;kind〉)": { - "\(〈5;name〉)": { - metadata: { - labels: { - "ingress-class": 〈11;class〉 - stack: "ingress" - ... - } - } - } - } - } - } - } - } - } - } - clusters: { - foo: {} - } -} ---- reductions.cue -{ - t1: { - params: 〈0;x〉.y - x: { - y: {} - } - for _, _ in 〈0;x〉 { - if true { - x: { - y: { - a: {} - } - } - } - } - } - t2: { - out: 〈0;let X#2〉.y - let X#2 = 〈0;m〉.x - m: { - x: { - y: {} - } - } - for _, v in 〈0;m〉 { - if true { - m: { - x: { - y: { - z: {} - } - } - } - } - } - } - t3: { - out: 〈0;foo〉.bar - foo: { - bar: {} - } - for _, _ in 〈0;foo〉 { - for name, _ in 〈2;foo〉 { - foo: { - 〈2;name〉: _ - } - } - } - } -} -- out/todo.txt -- v3 uses structure sharing (~) for t1.params, t2.out, t2.let X; v2 expands them. #Cluster.objects and clusters.foo.objects: v3 uses ~(), v2 expands. diff --git a/cue/testdata/eval/issue2337.txtar b/cue/testdata/eval/issue2337.txtar --- a/cue/testdata/eval/issue2337.txtar +++ b/cue/testdata/eval/issue2337.txtar @@ -56,44 +56,6 @@ [eval] simple.x: conflicting values "foo" and "x": ./in.cue:4:7 ./in.cue:9:7 --- out/compile -- ---- in.cue -{ - simple: { - x: "x" - 〈0;x〉: "foo" - } - issue2473: { - one: { - c: { - env: "prod" - env: ("dev"|"prod") - env2: 〈0;env〉 - } - if (〈0;c〉.env2 == "prod") { - { - c: { - env2: string - } - example: 〈0;c〉.env2 - } - } - } - } - issue2473: { - two: { - env: "prod" - env: ("dev"|"prod") - env2: 〈0;env〉 - if (〈0;env2〉 == "prod") { - { - env2: string - example: 〈0;env2〉 - } - } - } - } -} -- out/eval/stats -- Leaks: 2 Freed: 19 diff --git a/cue/testdata/eval/issue2550.txtar b/cue/testdata/eval/issue2550.txtar --- a/cue/testdata/eval/issue2550.txtar +++ b/cue/testdata/eval/issue2550.txtar @@ -15,16 +15,6 @@ -- out/errors.txt -- [eval] undefined field: missing: ./in.cue:4:8 --- out/compile -- ---- in.cue -{ - foo: string - bar: close({}) - if (〈0;bar〉.missing == "x") { - let _bar#1 = 〈1;bar〉 - foo: 〈0;let _bar#1〉 - } -} -- out/eval/stats -- Leaks: 1 Freed: 4 diff --git a/cue/testdata/eval/issue2649.txtar b/cue/testdata/eval/issue2649.txtar --- a/cue/testdata/eval/issue2649.txtar +++ b/cue/testdata/eval/issue2649.txtar @@ -7,11 +7,6 @@ @test(eq:todo, 8) @test(kind=float) // TODO: should this be a float, or can it also be an int? (4 + 8 + 12) / 3 --- out/compile -- ---- in.cue -{ - (((4 + 8) + 12) / 3) -} -- out/eval/stats -- Leaks: 0 Freed: 1 diff --git a/cue/testdata/eval/issue285.txtar b/cue/testdata/eval/issue285.txtar --- a/cue/testdata/eval/issue285.txtar +++ b/cue/testdata/eval/issue285.txtar @@ -29,23 +29,3 @@ Unifications: 10 Conjuncts: 23 Disjuncts: 10 --- out/compile -- ---- in.cue -{ - #TopLevel: { - [string]: { - path: string - content: string - } - } - #Mid: (〈0;#TopLevel〉 & { - myoutput: { - path: "/output" - } - }) - val: ((〈0;#Mid〉 & {}) & { - myoutput: { - content: "foo" - } - }) -} diff --git a/cue/testdata/eval/issue295.txtar b/cue/testdata/eval/issue295.txtar --- a/cue/testdata/eval/issue295.txtar +++ b/cue/testdata/eval/issue295.txtar @@ -9,16 +9,6 @@ "\("f")": _ }) @test(eq, {f: 9}) @test(closed) p: f: 9 --- out/compile -- ---- in.cue -{ - p: close({ - "\("f")": _ - }) - p: { - f: 9 - } -} -- out/eval/stats -- Leaks: 1 Freed: 3 diff --git a/cue/testdata/eval/issue3301.txtar b/cue/testdata/eval/issue3301.txtar --- a/cue/testdata/eval/issue3301.txtar +++ b/cue/testdata/eval/issue3301.txtar @@ -42,28 +42,3 @@ Disjuncts: 18 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - object: (〈0;#Leaf〉 & {}) - #Base: { - extra?: { - ... - } - } - #Mid: { - 〈1;#Base〉 - } - #Leaf: { - 〈1;#Mid〉 - extra?: { - ... - } - more?: int - if (〈0;extra〉.foo != _|_(explicit error (_|_ literal) in source)) { - if (〈1;more〉 != _|_(explicit error (_|_ literal) in source)) { - foo: "bar" - } - } - } -} diff --git a/cue/testdata/eval/issue3330.txtar b/cue/testdata/eval/issue3330.txtar --- a/cue/testdata/eval/issue3330.txtar +++ b/cue/testdata/eval/issue3330.txtar @@ -63,42 +63,3 @@ Unifications: 35 Conjuncts: 69 Disjuncts: 46 --- out/compile -- ---- in.cue -{ - issue3330: { - #A: { - let empty#1 = {} - field: (null|{ - n: int - }) - field: (〈0;let empty#1〉 & { - n: 3 - }) - } - out: 〈import;list〉.Concat([ - [ - 〈2;#A〉, - ], - ]) - } - eliminated: { - #empty: {} - x: (null|{ - n: 3 - }) - x: (〈0;#empty〉 & { - n: 3 - }) - out: len(〈0;x〉) - } - simplified: { - #struct: { - field: ({ - n: 3 - } & 〈0;g〉) - g: {} - } - out: (〈0;#struct〉 & {}) - } -} diff --git a/cue/testdata/eval/issue349.txtar b/cue/testdata/eval/issue349.txtar --- a/cue/testdata/eval/issue349.txtar +++ b/cue/testdata/eval/issue349.txtar @@ -34,17 +34,3 @@ Unifications: 10 Conjuncts: 10 Disjuncts: 10 --- out/compile -- ---- in.cue -{ - ex: { - aaa: "aaa" - list: "list" - zzz: "zzz" - AAA: "AAA" - html: "html" - HTML: "html" - ZZZ: "ZZZ" - Html: "html" - } -} diff --git a/cue/testdata/eval/issue353.txtar b/cue/testdata/eval/issue353.txtar --- a/cue/testdata/eval/issue353.txtar +++ b/cue/testdata/eval/issue353.txtar @@ -30,19 +30,3 @@ Disjuncts: 4 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - e: 〈0;#Example〉 - e: { - a: "hello" - } - #Example: { - a: string - ({ - value?: string - }|{ - externalValue?: string - }) - } -} diff --git a/cue/testdata/eval/issue3672.txtar b/cue/testdata/eval/issue3672.txtar --- a/cue/testdata/eval/issue3672.txtar +++ b/cue/testdata/eval/issue3672.txtar @@ -147,182 +147,6 @@ [incomplete] #orgForConfigTextRules.orgSyntax.elems: invalid interpolation: unresolved disjunction string | {UseSectionName:true} | {Append:string | {UseSectionName:true}} | {Prepend:string | {UseSectionName:true}} | [string | {UseSectionName:true} | {Append:string | {UseSectionName:true}} | {Prepend:string | {UseSectionName:true}},string | {UseSectionName:true} | {Append:string | {UseSectionName:true}} | {Prepend:string | {UseSectionName:true}}] (type (string|list|struct)): ./x.cue:116:5 ./x.cue:114:18 --- out/compile -- ---- x.cue -{ - #FinDefSetElemType: { - #Type!: _ - } - #FinDefSetDefinition: { - #Elem!: 〈1;#FinDefSetElemType〉 - #Alternatives: { - allBut: { - AllBut: [ - ...〈3;#Elem〉.#Type, - ] - } - only: { - Only: [ - ...〈3;#Elem〉.#Type, - ] - } - } - } - #mkFinDefSet: { - #Definition!: 〈1;#FinDefSetDefinition〉 - #Type: or([ - for _, v in 〈1;#Definition〉.#Alternatives { - 〈1;v〉 - }, - ]) - } - #FinDefSetElemType: { - #Type: _ - toString!: { - _input: 〈1;#Type〉 - _output: string - } - } - #FinDefSetDefinition: { - #Elem!: 〈1;#FinDefSetElemType〉 - #Alternatives: { - allBut: { - AllBut: [ - ...〈3;#Elem〉.#Type, - ] - let xs#1 = [ - for _, x in 〈1;AllBut〉 { - (〈5;#Elem〉.toString & { - _input: 〈2;x〉 - })._output - }, - ] - let str#2 = 〈import;strings〉.Join(〈0;let xs#1〉, "\",\"") - orgSyntax: "AllBut [\(〈0;let str#2〉)]" - } - only: { - Only: [ - ...〈3;#Elem〉.#Type, - ] - let xs#3 = [ - for _, x in 〈1;Only〉 { - (〈5;#Elem〉.toString & { - _input: 〈2;x〉 - })._output - }, - ] - let str#4 = 〈import;strings〉.Join(〈0;let xs#3〉, "\",\"") - orgSyntax: "Only [\(〈0;let str#4〉)]" - } - } - } - #ConfigText: (string|{ - UseSectionName: true - }) - #ConfigTextRule: (〈0;#ConfigText〉|{ - Append: 〈1;#ConfigText〉 - }|{ - Prepend: 〈1;#ConfigText〉 - }) - #ConfigTextRules: (〈0;#ConfigTextRule〉|[ - 〈1;#ConfigTextRule〉, - 〈1;#ConfigTextRule〉, - ...〈1;#ConfigTextRule〉, - ]) - #FinDefSetConfigTextElem: 〈0;#FinDefSetElemType〉 - #FinDefSetConfigTextElem: { - #Type: 〈1;#ConfigTextRules〉 - } - #FinDefSetOfConfigText: (〈0;#mkFinDefSet〉 & { - #Definition: { - #Elem: 〈2;#FinDefSetConfigTextElem〉 - } - }).#Type - #FinDefSetConfigTextElem: { - toString: { - _input: 〈2;#ConfigTextRules〉 - _output: (〈2;#orgForConfigTextRules〉 & { - source: 〈1;_input〉 - }).orgSyntax - } - } - #orgForConfigText: { - source: 〈1;#ConfigText〉 - orgSyntax: { - let INS#5 = (〈1;source〉 & string) - let INO#6 = (〈1;source〉 & { - UseSectionName: _ - }) - [ - if (〈1;let INS#5〉 != _|_(explicit error (_|_ literal) in source)) { - 〈import;"encoding/json"〉.Marshal(〈2;let INS#5〉) - }, - if (〈1;let INO#6〉 != _|_(explicit error (_|_ literal) in source)) { - "UseSectionName" - }, - "Impossible", - ][0] - } - } - #orgForConfigTextRule: { - source: 〈1;#ConfigTextRule〉 - orgSyntax: { - let INA#7 = (〈1;source〉 & { - Append: _ - }) - let INP#8 = (〈1;source〉 & { - Prepend: _ - }) - [ - if (〈1;let INA#7〉 != _|_(explicit error (_|_ literal) in source)) { - ("Append " + (〈4;#orgForConfigText〉 & { - source: 〈3;let INA#7〉.Append - }).orgSyntax) - }, - if (〈1;let INP#8〉 != _|_(explicit error (_|_ literal) in source)) { - ("Prepend " + (〈4;#orgForConfigText〉 & { - source: 〈3;let INP#8〉.Prepend - }).orgSyntax) - }, - (〈3;#orgForConfigText〉 & { - source: 〈3;source〉 - }).orgSyntax, - ][0] - } - } - #orgForConfigTextRules: { - source: 〈1;#ConfigTextRules〉 - orgSyntax: { - let INL#9 = (〈1;source〉 & [ - ..., - ]) - [ - if (〈1;let INL#9〉 != _|_(explicit error (_|_ literal) in source)) { - let elems#A = [ - for _, x in 〈4;source〉 { - (〈7;#orgForConfigTextRule〉 & { - source: 〈2;x〉 - }).orgSyntax - }, - ] - let result#B = 〈import;strings〉.Join(〈0;let elems#A〉, "\",\"") - "[\(〈0;let result#B〉)]" - }, - (〈3;#orgForConfigTextRule〉 & { - source: 〈3;source〉 - }).orgSyntax, - ][0] - } - } - value0: 〈0;#FinDefSetOfConfigText〉 - value0: { - Only: [ - { - UseSectionName: true - }, - ] - } -} -- out/eval/stats -- Leaks: 345 Freed: 1738 diff --git a/cue/testdata/eval/issue3688.txtar b/cue/testdata/eval/issue3688.txtar --- a/cue/testdata/eval/issue3688.txtar +++ b/cue/testdata/eval/issue3688.txtar @@ -60,51 +60,3 @@ Disjuncts: 22 NumCloseIDs: 43 --- out/compile -- ---- x.cue -{ - #TypeA: (string|{ - foo: int - }) - #fun1: { - _in(:x): 〈1;#TypeA〉 - out: [ - if ((〈1;_in(:x)〉 & string) != _|_(explicit error (_|_ literal) in source)) { - 〈2;_in(:x)〉 - }, - if (〈1;_in(:x)〉.foo != _|_(explicit error (_|_ literal) in source)) { - "foo" - }, - "impossible", - ][0] - } - examples: { - [string]: { - in: _ - res: (〈2;#fun1〉 & { - _in(:x): 〈1;in〉 - _ - }).out - } - } - examples: { - eg1: { - in: "test" - } - } - examples: { - eg2: { - in: { - foo: 5 - } - } - } - examples: { - eg3: { - in: { - foo: 5 - bar: "test" - } - } - } -} diff --git a/cue/testdata/eval/issue3709.txtar b/cue/testdata/eval/issue3709.txtar --- a/cue/testdata/eval/issue3709.txtar +++ b/cue/testdata/eval/issue3709.txtar @@ -18,13 +18,6 @@ #Foo: bar?: #Bar #Bar: foo?: #Foo --- out/compile -- ---- input.cue -{ - out: { - [string]: 〈import;"foo.test/bar/imported"〉.#Foo - } -} -- out/eval/stats -- Leaks: 0 Freed: 2 diff --git a/cue/testdata/eval/issue3801.txtar b/cue/testdata/eval/issue3801.txtar --- a/cue/testdata/eval/issue3801.txtar +++ b/cue/testdata/eval/issue3801.txtar @@ -191,147 +191,5 @@ Disjuncts: 14 NumCloseIDs: 77 --- out/compile -- ---- nested.cue -{ - issue3801: { - let: { - reduced: { - let F#1 = { - base: { - in: string - let X#2 = { - a: "\(〈1;in〉)" - }.a - out: 〈0;let X#2〉 - } - filled: (〈0;base〉 & { - in: "foo" - }) - } - z: 〈0;let F#1〉.filled.out - } - } - } - issue3801: { - nonRooted: { - reduced: { - #Output: { - output: { - #base: { - val0: string - msgObj: { - a: 〈1;val0〉 - }.a - value: 〈0;msgObj〉 - } - out: (〈0;#base〉 & { - val0: "foo" - }) - } - } - out: (〈0;#Output〉 & {}).output - } - } - } - issue3801: { - let: { - full: { - #Resource: { - someMsg: string - obs: ({}|*{ - missing: true - }) - let pickMsg#4 = [ - if 〈1;obs〉.missing { - msg: "\(〈2;someMsg〉)" - }, - { - msg: "bar" - }, - ][0] - patches: [ - { - op: "add" - path: "/metadata" - value: 〈2;let pickMsg#4〉.msg - }, - ] - } - #Patches: { - [string]: _ - } - #JSONPatch: { - namespace?: string - patch: [ - ...〈2;#JSONOp〉, - ] - output: (〈1;#Patches〉 & { - 〈1;namespace〉: 〈1;patch〉 - }) - } - #JSONOp: ({ - op: "add" - path: string - value: _ - }|{ - op: "remove" - path: string - }) - #Main: { - namespace: string - output: 〈0;let jsonPatch#5〉.output - let jsonPatch#5 = (〈1;#JSONPatch〉 & { - let base#8 = (〈2;#Resource〉 & {}) - let withMsg#9 = (〈0;let base#8〉 & { - someMsg: "foo" - }) - namespace: 〈1;namespace〉 - patch: 〈0;let withMsg#9〉.patches - }) - } - out: (〈0;#Main〉 & { - namespace: "ns1" - }).output - } - } - } - issue3801: { - nonRooted: { - full: { - #Output: { - namespace: string - output: (〈1;#SubOutput〉 & { - namespace: 〈1;namespace〉 - let base2#A = { - let base#B = (〈3;#Base〉 & {}) - output: (〈0;let base#B〉 & { - val0: "foo" - }) - } - patch: 〈0;let base2#A〉.output.value - }).output - } - out: (〈0;#Output〉 & { - namespace: "ns1" - }).output - #SubOutput: { - namespace?: string - patch: _ - output: { - 〈1;namespace〉: 〈1;patch〉 - } - } - #Base: { - val0: string - let msgObj#D = [ - 〈1;val0〉, - ][0] - value: 〈0;let msgObj#D〉 - } - } - } - } -} -- out/todo.txt -- v3 differences in error messages and closedness for nonRooted.reduced.out (#struct vs struct). diff --git a/cue/testdata/eval/issue3805.txtar b/cue/testdata/eval/issue3805.txtar --- a/cue/testdata/eval/issue3805.txtar +++ b/cue/testdata/eval/issue3805.txtar @@ -231,103 +231,6 @@ }] }] }] }) } --- out/compile -- ---- x.cue -{ - #PatientViewSections: { - [string]: 〈1;#PatientViewSection〉 - } - #PatientViewSection: 〈0;#PvSection〉 - #PvSection: { - Section: { - display?: string - entries: 〈2;#PatientViewEntries〉 - } - _json: [ - for k, v in 〈1;Section〉.entries { - 〈1;k〉: 〈1;v〉._json - }, - ] - } - #PatientViewEntries: { - [string]: 〈1;#PatientViewEntry〉 - } - #PatientViewEntry: { - (〈1;#PvSingleForm〉|〈1;#PvLink〉) - } - #PvSingleForm: { - SingleForm: { - formId: string - showNumberOfInstances?: bool - } - _json: [ - { - iDoc: "singleFormIDoc" - "X-FormId": 〈2;SingleForm〉.formId - }, - ] - } - #PvLink: { - Link: { - icon?: string - sections: 〈2;#PatientViewSections〉 - } - _json: [ - for k, v in 〈1;Link〉.sections { - 〈1;k〉: 〈1;v〉._json - }, - ] - } - #TabcatsJson: { - config: { - tabcats: 〈2;#PatientViewSections〉 - ... - } - json: { - tabcats: [ - for k, v in 〈2;config〉.tabcats { - 〈1;k〉: 〈1;v〉._json - }, - ] - } - } - tabcatsExample: 〈0;#TabcatsJson〉 - tabcatsExample: { - _e1: 〈1;#PatientViewEntry〉 - _e1: { - Link: { - sections: { - Formulare: { - Section: { - entries: { - Fotodokumentation: 〈6;_e2〉 - } - } - } - } - } - } - _e2: 〈1;#PatientViewEntry〉 - _e2: { - SingleForm: { - formId: "fotodokumentation" - } - } - _s: 〈1;#PvSection〉 - _s: { - Section: { - entries: { - Dokumentation: 〈3;_e1〉 - } - } - } - config: { - tabcats: { - "02": 〈2;_s〉 - } - } - } -} -- out/eval/stats -- Leaks: 77 Freed: 162 diff --git a/cue/testdata/eval/issue3813.txtar b/cue/testdata/eval/issue3813.txtar --- a/cue/testdata/eval/issue3813.txtar +++ b/cue/testdata/eval/issue3813.txtar @@ -18,23 +18,6 @@ x } y: f: true --- out/compile -- ---- x.cue -{ - x: { - [string]: _ - } - x: 〈0;#d〉 - #d: { - f: _ - } - y: { - 〈1;x〉 - } - y: { - f: true - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/eval/issue3905.txtar b/cue/testdata/eval/issue3905.txtar --- a/cue/testdata/eval/issue3905.txtar +++ b/cue/testdata/eval/issue3905.txtar @@ -104,61 +104,5 @@ Notifications: 2 NumCloseIDs: 13 --- out/compile -- ---- in.cue -{ - issue3905: { - reduced: { - #Schema: { - params: { - name: (string|*"foo") - } - result: { - 〈1;params〉.name: "bar" - } - } - 〈0;#Schema〉.result - } - } - issue3905: { - full: { - #ReferenceGrantBuilder: { - parameters: { - namespace: string - gatewayNamespace: (string|*"foo") - } - referenceGrant: { - 〈1;parameters〉.gatewayNamespace: (〈2;#ReferenceGrant〉 & { - metadata: { - name: 〈3;parameters〉.gatewayNamespace - } - metadata: { - namespace: 〈3;parameters〉.namespace - } - }) - } - } - (〈0;#ReferenceGrantBuilder〉 & { - parameters: { - namespace: "foo" - } - }).referenceGrant - #ReferenceGrant: { - apiVersion: "gateway.networking.k8s.io/v1beta1" - kind: "ReferenceGrant" - metadata!: { - name!: string - namespace!: string - labels?: { - [string]: string - } - annotations?: { - [string]: string - } - } - } - } - } -} -- out/todo.txt -- issue3905.full: v2 evaluates as non-closed struct, v3 as closed (#struct). diff --git a/cue/testdata/eval/issue3919.txtar b/cue/testdata/eval/issue3919.txtar --- a/cue/testdata/eval/issue3919.txtar +++ b/cue/testdata/eval/issue3919.txtar @@ -127,122 +127,5 @@ Disjuncts: 4 NumCloseIDs: 27 --- out/compile -- ---- in.cue -{ - full: { - out: { - env: { - if true { - PORT: 〈import;math〉.Abs(〈3;out〉.port) - } - } - if true { - port: (int|*30080) - } - } - } - reduced: { - if true { - a: 〈import;math〉.Abs(〈1;port〉) - } - port: (int|*30080) - } -} ---- issue3946.cue -{ - issue3946: { - reduced: { - out: [ - for _, v in 〈1;_inputs〉 { - 〈1;v〉 - }, - ] - _inputs: { - [_]: { - doExtra?: bool - if (〈0;doExtra〉 != _|_(explicit error (_|_ literal) in source)) { - if true { - extra: "yes" - } - } - } - } - if true { - _inputs: { - input1: { - name: "input1" - } - } - } - } - } -} ---- let.cue -{ - issue3931: { - full: { - bar: { - [string]: { - spec?: 〈2;let Spec#1〉 - } - } - if true { - foo: { - label: "foo" - } - bar: { - bar1: { - spec: { - selector: 〈3;foo〉 - } - } - } - } - let Spec#1 = { - selector?: 〈1;let Selector#2〉 - } - let Selector#2 = { - label?: string - expr?: [ - ...string, - ] - } - } - } -} ---- secondary.cue -{ - related: { - [string]: { - if true { - shared: { - all_total: 〈3;foo〉.fooData.total - } - } - } - foo: { - fooData: { - total: { - tags: 〈1;_hidden〉 - } - _hidden: { - extra: {} - } - } - } - #Tags: { - [string]: {} - } - bar: { - shared: { - [string]: { - tags: 〈3;#Tags〉 - } - bar_total: 〈2;foo〉.fooData.total - } - } - } -} -- out/todo.txt -- related: v3 uses structure sharing (~) for related.foo.fooData.total.tags and related.foo.shared.all_total, v2 expands them. diff --git a/cue/testdata/eval/issue494.txtar b/cue/testdata/eval/issue494.txtar --- a/cue/testdata/eval/issue494.txtar +++ b/cue/testdata/eval/issue494.txtar @@ -24,56 +24,3 @@ Unifications: 26 Conjuncts: 56 Disjuncts: 28 --- out/compile -- ---- in.cue -{ - _Q: [ - { - pos: 0 - }, - { - pos: 1 - }, - ] - a: { - [string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])] - } - a: { - ben: [ - {}, - ] - } - b: { - [string]: 〈1;_Q〉[0:1] - } - b: { - ben: [ - {}, - ] - } - c: { - [string]: [ - ...{ - l: len(〈3;a〉[〈2;-〉]) - }, - ] - } - c: { - ben: [ - {}, - ] - } - #d: { - [string]: ([ - ...{ - pos: &(int, >=0) - }, - ] & 〈1;_Q〉[0:len(〈1;#d〉[〈0;-〉])]) - } - #d: { - ben: [ - {}, - ] - } - d: 〈0;#d〉 -} diff --git a/cue/testdata/eval/issue500.txtar b/cue/testdata/eval/issue500.txtar --- a/cue/testdata/eval/issue500.txtar +++ b/cue/testdata/eval/issue500.txtar @@ -30,45 +30,3 @@ Unifications: 38 Conjuncts: 45 Disjuncts: 42 --- out/compile -- ---- in.cue -{ - a: 〈import;strings〉.Join(〈import;strings〉.Split("test", "")[1:], "") - b: 〈import;strings〉.Join([ - "t", - "e", - "s", - "t", - ][1:], "") - c: [ - "t", - "e", - "s", - "t", - ][1:] - d: 〈import;strings〉.Join(〈0;c〉, "") - e: 〈import;strings〉.Join(〈import;list〉.Concat([ - [ - "a", - ], - [ - "b", - ], - ]), "") - f: 〈import;list〉.Concat([ - [ - "a", - ], - [ - "b", - ], - ]) - g: 〈import;strings〉.Join(〈0;f〉, "") - h: 〈import;strings〉.Join(〈import;list〉.Repeat([ - "a", - ], 3), "") - i: 〈import;list〉.Repeat([ - "b", - ], 3) - j: 〈import;strings〉.Join(〈0;i〉, "") -} diff --git a/cue/testdata/eval/issue545.txtar b/cue/testdata/eval/issue545.txtar --- a/cue/testdata/eval/issue545.txtar +++ b/cue/testdata/eval/issue545.txtar @@ -85,32 +85,5 @@ Notifications: 3 NumCloseIDs: 22 --- out/compile -- ---- in.cue -{ - t1: { - #Test: { - #HTTP: =~"^http://" - #SSH: !~"^ssh://" - #USER: 〈import;strings〉.MinRunes(3) - source: (〈0;#HTTP〉|〈0;#SSH〉|〈0;#USER〉|〈1;#Test〉) - } - foo: (〈0;#Test〉 & { - source: "http://blablabla" - }) - bar: (〈0;#Test〉 & { - source: 〈1;foo〉 - }) - } - t2: { - str: "foo" - a: =~〈0;str〉 - b: =~"foo" - c: (((〈0;a〉 & 〈0;b〉) & 〈0;a〉) & 〈0;b〉) - d: 〈import;time〉.Time - e: 〈import;time〉.Time() - f: (((〈0;d〉 & 〈0;e〉) & 〈0;d〉) & 〈0;e〉) - } -} -- out/todo.txt -- Reordering of fields in t1.foo and t1.bar between v2 and v3 (source field order differs). diff --git a/cue/testdata/eval/issue599.txtar b/cue/testdata/eval/issue599.txtar --- a/cue/testdata/eval/issue599.txtar +++ b/cue/testdata/eval/issue599.txtar @@ -119,83 +119,5 @@ MaxConjunctInfos: 6 MaxReqSets: 11 MaxRedirect: 2 --- out/compile -- ---- in.cue -{ - a: { - #A: { - n: string - depends_on: [ - ...〈2;#AnyA〉, - ] - } - #AnyA: { - n: string - depends_on: [ - ...〈2;#AnyA〉, - ] - ... - } - #A1: { - 〈1;#A〉 - x: int - y: { - z: string - } - } - #A2: { - 〈1;#A〉 - i: string - } - s: { - [string]: (〈1;#AnyA〉 & { - n: 〈1;-〉 - }) - } - s: { - foo: (〈1;#A1〉 & { - x: 10 - y: { - z: "z" - } - }) - } - s: { - bar: (〈1;#A2〉 & { - i: "hello bar" - depends_on: [ - 〈3;s〉.foo, - ] - }) - } - } - b: { - #A: { - f: { - ... - } - } - #A1: { - 〈1;#A〉 - } - #C: { - d: { - ... - } - } - s: { - [string]: 〈1;#A1〉 - } - s: { - foo: { - f: (〈2;#C〉 & { - d: { - foo: "bar" - } - }) - } - } - } -} -- out/todo.txt -- Reordering of fields between v2 and v3. diff --git a/cue/testdata/eval/issue962.txtar b/cue/testdata/eval/issue962.txtar --- a/cue/testdata/eval/issue962.txtar +++ b/cue/testdata/eval/issue962.txtar @@ -17,13 +17,3 @@ ./in.cue:7:8 [incomplete] _obj: invalid non-ground value string (must be concrete string): ./in.cue:7:8 --- out/compile -- ---- in.cue -{ - foo: { - bar: "something" - } - text: 〈import;"encoding/yaml"〉.Marshal(〈0;_obj〉) - _what: string - _obj: 〈0;foo〉[〈0;_what〉] -} diff --git a/cue/testdata/eval/let.txtar b/cue/testdata/eval/let.txtar --- a/cue/testdata/eval/let.txtar +++ b/cue/testdata/eval/let.txtar @@ -290,205 +290,5 @@ Notifications: 3 NumCloseIDs: 110 --- out/compile -- ---- in.cue -{ - let A#1 = (3 * 3) - let B#2 = (〈0;let A#1〉 + 〈0;let A#1〉) - let C#3 = (〈0;let B#2〉 + 〈0;let B#2〉) - let D#4 = (〈0;let C#3〉 + 〈0;let C#3〉) - let E#5 = (〈0;let D#4〉 + 〈0;let D#4〉) - let F#6 = (〈0;let E#5〉 + 〈0;let E#5〉) - b: { - let G#7 = (〈1;let F#6〉 + 〈1;let F#6〉) - let H#8 = (〈0;let G#7〉 + 〈0;let G#7〉) - let I#9 = (〈0;let H#8〉 + 〈0;let H#8〉) - let J#A = (〈0;let I#9〉 + 〈0;let I#9〉) - let K#B = (〈0;let J#A〉 + 〈0;let J#A〉) - let L#C = (〈0;let K#B〉 + 〈0;let K#B〉) - let M#D = (〈0;let L#C〉 + 〈0;let L#C〉) - let N#E = (〈0;let M#D〉 + 〈0;let M#D〉) - let O#F = (〈0;let N#E〉 + 〈0;let N#E〉) - let P#10 = (〈0;let O#F〉 + 〈0;let O#F〉) - let Q#11 = (〈0;let P#10〉 + 〈0;let P#10〉) - let R#12 = (〈0;let Q#11〉 + 〈0;let Q#11〉) - let S#13 = (〈0;let R#12〉 + 〈0;let R#12〉) - let T#14 = (〈0;let S#13〉 + 〈0;let S#13〉) - a: 〈0;let T#14〉 - b: 〈1;let F#6〉 - } - issue1828: { - volumes: 〈0;let L3#15〉 - let L3#15 = { - for _, v2 in [ - for _, v1 in 〈2;let L2#16〉 {}, - ] {} - } - let L2#16 = 〈0;let L1#17〉 - let L1#17 = [] - } - ignoreErrorInLet: { - let X#18 = (1 & 2) - disjunction: (*〈0;let X#18〉|3) - } -} ---- incomprehension.cue -{ - list: { - l: [ - 1, - 2, - 3, - ] - c: [ - for _, v in 〈1;l〉 { - let X#19 = (〈1;v〉 * 4) - 〈0;let X#19〉 - }, - ] - } - referencesForDirectly: { - l: [ - 1, - 2, - 3, - ] - for k, v in 〈0;l〉 { - let Y#1Amulti = (〈1;v〉 * 4) - "\(〈1;k〉)": 〈0;let Y#1A〉 - } - } - referencesForViaLet: { - l: [ - 1, - 2, - 3, - ] - for k, v in 〈0;l〉 let X = (〈0;v〉 * 4) { - let Y#1Bmulti = 〈1;X〉 - "\(〈2;k〉)": 〈0;let Y#1B〉 - } - } - letClauseReferencesInert: { - x: 2 - l: [ - 1, - 2, - 3, - ] - for k, v in 〈0;l〉 let X = 〈1;x〉 { - let Y#1C = 〈1;X〉 - "\(〈2;k〉)": 〈0;let Y#1C〉 - } - } - indirectReference: { - l: [ - 1, - 2, - 3, - ] - for k, v in 〈0;l〉 { - y: 〈1;v〉 - let X#1D = (〈0;y〉 * 4) - "\(〈1;k〉)": 〈0;let X#1D〉 - } - } - nestedFor: { - for k, y in [ - 4, - 5, - ] { - let X#1Emulti = { - for _, x in [ - 1, - 2, - ] { - let X#1Fmulti = 〈1;x〉 - "\(〈0;let X#1F〉)": 〈0;let X#1F〉 - } - } - "\(〈1;k〉)": 〈0;let X#1E〉 - } - } -} ---- interpolation.cue -{ - issue4022: { - full: { - envScript: [ - for _, v in 〈1;_env〉 let v = 〈2;_env〉["KEY"] { - "\(〈1;v〉)" - }, - ] - _env: { - KEY: (*""|_) - } - } - } -} ---- issue2063.cue -{ - keepDescending: { - t1: { - ec: {} - bs: { - let m#21 = 〈1;ec〉.b - if (〈0;let m#21〉 == _|_(explicit error (_|_ literal) in source)) {} - x: { - y: "" - } - } - } - } - keepDescending: { - t2: { - x: 〈import;"encoding/yaml"〉.Marshal(〈0;bs〉) - ec: {} - bs: { - let m#22 = 〈1;ec〉.b - if (〈0;let m#22〉.b == _|_(explicit error (_|_ literal) in source)) {} - X: { - Y: 〈import;strings〉.Join([], "") - } - } - } - } -} ---- issue2166.cue -{ - letWithDynamicInComprehension: { - _i: { - a: "d" - b: "e" - } - for k, v in 〈0;_i〉 { - let T#23multi = 〈1;v〉 - 〈0;let T#23〉: "1" - } - } -} ---- issue2218.cue -{ - _parent_configs: { - PARENT: true - } - _configs: { - CHILD1: { - property: true - } - CHILD2: { - property: true - parent: "PARENT" - } - } - disabled_parent_test: { - for k, v in 〈1;_configs〉 { - let parent_config#24multi = (*〈3;_parent_configs〉[〈1;v〉.parent]|false) - "\(〈1;k〉)": { - parent_config: 〈1;let parent_config#24〉 - } - } - } -} -- out/todo.txt -- v3 reports extra position info for indirectReference errors and shows letClauseReferencesInert with an unresolved let expression (let Y#1Cmulti = 〈1;X〉) rather than v2's concrete let Y#1C = 2. diff --git a/cue/testdata/eval/letjoin.txtar b/cue/testdata/eval/letjoin.txtar --- a/cue/testdata/eval/letjoin.txtar +++ b/cue/testdata/eval/letjoin.txtar @@ -197,157 +197,5 @@ Disjuncts: 32 NumCloseIDs: 87 --- out/compile -- ---- in.cue -{ - t1: { - x: { - a: int - y: { - let X#1 = { - b: 〈2;a〉 - c: 1 - } - v: 〈0;let X#1〉.c - } - } - x1: 〈0;x〉 - x1: { - a: 1 - } - x2: 〈0;x〉 - x2: { - a: 2 - } - xy: (〈0;x1〉.y & 〈0;x2〉.y) - } - t2: { - x: { - a: {} - y: { - let X#2 = { - b: 〈2;a〉 - c: 1 - } - v: 〈0;let X#2〉.c - } - } - x1: 〈0;x〉 - x1: { - a: { - q: 1 - } - } - x2: 〈0;x〉 - x2: { - a: { - r: 2 - } - } - xy: (〈0;x1〉 & 〈0;x2〉) - } -} ---- issue3590.cue -{ - issue3590: { - reduced: { - result: { - [_]: { - [string]: string - } - } - _input: { - A: { - p: "A" - } - B: { - p: "B" - } - } - for _, v in 〈0;_input〉 { - let Var1#3multi = 〈1;v〉.p - let Var2#4multi = 〈0;let Var1#3〉 - let Items#5 = { - item: 〈1;let Var2#4〉 - } - result: { - "conflicting-\(〈2;v〉.p)": 〈1;let Items#5〉 - } - } - } - } - issue3590: { - full: { - #Result: { - [_]: { - [string]: string - } - } - result: 〈0;#Result〉 - #Input: { - p: ("A"|"B") - } - _input: { - [_]: (〈1;#Input〉 & { - p: 〈1;-〉 - }) - } - _input: { - A: {} - B: {} - } - for _, v in 〈0;_input〉 { - let Var1#6multi = 〈1;v〉.p - let Var2#7multi = 〈0;let Var1#6〉 - let Items#8 = { - item: 〈1;let Var2#7〉 - } - result: { - "conflicting-\(〈2;v〉.p)": 〈1;let Items#8〉 - } - } - } - } - issue3591: { - missing: { - #Result: { - [_]: { - [string]: string - } - } - result: 〈0;#Result〉 - #Input: { - p: ("A"|"B") - } - _input: { - [_]: (〈1;#Input〉 & { - p: 〈1;-〉 - }) - } - _input: { - A: {} - B: {} - } - for _, v in 〈0;_input〉 { - let Var1#9multi = 〈1;v〉.p - let Var2#Amulti = 〈0;let Var1#9〉 - let Items#B = { - item: { - key1: 〈2;let Var2#A〉 - } - } - result: { - "missing-items-\(〈2;v〉.p)": { - for s, attr in 〈2;let Items#B〉 { - if (〈1;attr〉.key1 != _|_(explicit error (_|_ literal) in source)) { - 〈2;s〉: 〈2;attr〉.key1 - } - } - } - } - } - } - } -} -- out/todo.txt -- v3 uses structure sharing (~) for let bindings in t2's x1/x2/xy. v2 incorrectly showed conflicting values errors for issue3590's let Items; v3 correctly handles chained let bindings in for comprehensions. diff --git a/cue/testdata/eval/lists.txtar b/cue/testdata/eval/lists.txtar --- a/cue/testdata/eval/lists.txtar +++ b/cue/testdata/eval/lists.txtar @@ -17,34 +17,3 @@ Unifications: 15 Conjuncts: 29 Disjuncts: 13 --- out/compile -- ---- in.cue -{ - a: [ - ...int, - ] - a: [ - 1, - 2, - 3, - 5, - ] - a: [ - 1, - 2, - 3, - 〈1;d〉, - ] - b: 〈0;a〉[3] - d: 5 - c: [ - for _, x in [ - [ - 1, - 2, - ], - ][0] { - (〈1;x〉 + 〈3;d〉) - }, - ] -} diff --git a/cue/testdata/eval/merge.txtar b/cue/testdata/eval/merge.txtar --- a/cue/testdata/eval/merge.txtar +++ b/cue/testdata/eval/merge.txtar @@ -34,41 +34,3 @@ MisalignedConjunct: 9 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - key: "app01" - manifests: [ - { - deployment: { - #map: { - [string]: { - name: string - image: string - desc: string - } - } - } - deployment: { - #map: { - "\(〈4;key〉)": { - name: "app01" - } - } - } - }, - { - deployment: { - #map: { - app01: { - image: "image01" - } - } - } - }, - ] - results: _ - for _, manifest in 〈0;manifests〉 { - results: 〈1;manifest〉 - } -} diff --git a/cue/testdata/eval/nonrooted.txtar b/cue/testdata/eval/nonrooted.txtar --- a/cue/testdata/eval/nonrooted.txtar +++ b/cue/testdata/eval/nonrooted.txtar @@ -106,67 +106,3 @@ ./in.cue:31:23 x: 2 errors in empty disjunction:: ./in.cue:28:8 --- out/compile -- ---- in.cue -{ - issue3977: { - inlineExpr: { - #NetworkID: 1 - #fn: { - x: 〈1;#NetworkID〉 - out: (〈0;x〉 + 1) - } - err: (〈0;#fn〉 & { - x: 2 - }).out - } - } - issue3977: { - inlineDisj1: { - #NetworkID: ("2"|"3"|"4") - #fn: { - x: 〈1;#NetworkID〉 - out: "value=\(〈0;x〉)" - } - err: (〈0;#fn〉 & { - x: "invalid" - }).out - } - } - issue3977: { - inlineDisj2: { - #NetworkID: 1 - #fn: { - x: 〈1;#NetworkID〉 - out: (〈0;x〉 + 10) - } - err: (〈0;#fn〉 & { - x: (*2|4) - }).out - } - } - issue3977: { - inlineDisj3: { - #NetworkID: 1 - #fn: { - x: 〈1;#NetworkID〉 - out: (〈0;x〉 + 10) - } - ok: (〈0;#fn〉 & { - x: (*2|int) - }).out - } - } - issue3977: { - inlineLet: { - #NetworkID: 1 - let p#1 = ({ - x: 〈1;#NetworkID〉 - out: (〈0;x〉 + 10) - } & { - x: 2 - }) - err: 〈0;let p#1〉.out - } - } -} diff --git a/cue/testdata/eval/notify.txtar b/cue/testdata/eval/notify.txtar --- a/cue/testdata/eval/notify.txtar +++ b/cue/testdata/eval/notify.txtar @@ -99,44 +99,5 @@ Notifications: 5 NumCloseIDs: 241 --- out/compile -- ---- in.cue -{ - t1: { - 〈0;a〉 - a: { - a: (2|1) - } - } - t2: { - d: 〈0;d〉.a - d: { - a: { - a: (2|1) - } - } - } - t3: { - b: 〈0;a〉 - b: ((1|2)|2) - a: (1|2) - } -} ---- issue3437.cue -{ - issue3437: { - r: 〈0〉.a - d: { - a: { - a: { - a: ({ - b: 4 - }|〈3;d〉) - } - } - } - out: (〈0;r〉 & 〈0;d〉) - } -} -- out/todo.txt -- v3 reports error messages with different operand ordering ("conflicting values {a,...} and 1" vs v2's "conflicting values 1 and {a:(2|1)}"). diff --git a/cue/testdata/eval/openinline.txtar b/cue/testdata/eval/openinline.txtar --- a/cue/testdata/eval/openinline.txtar +++ b/cue/testdata/eval/openinline.txtar @@ -113,96 +113,3 @@ Disjuncts: 0 NumCloseIDs: 19 --- out/compile -- ---- in.cue -{ - inlineErr: { - #D: { - a: 1 - } - def: { - x: (〈1;#D〉 & { - b: 2 - }).b - } - } - outerErr: { - _inToOut: { - in: _ - out: 〈0;in〉.foo - } - issue3534: { - #Inner: { - foo: { - minor: 2 - } - } - #Outer: { - version: { - major: 1 - ... - } - } - t1: 〈0;#Outer〉 - t1: { - version: (〈2;_inToOut〉 & { - in: 〈2;#Inner〉 - }).out - } - } - usingClose: { - #Inner: { - foo: close({ - minor: 2 - }) - } - #Outer: { - version: { - major: 1 - ... - } - } - t1: 〈0;#Outer〉 - t1: { - version: (〈2;_inToOut〉 & { - in: 〈2;#Inner〉 - }).out - } - } - extraNesting: { - #Inner: { - foo: { - x: { - minor: 2 - } - } - } - #Outer: { - version: { - x: { - major: 1 - ... - } - } - } - t1: 〈0;#Outer〉 - t1: { - version: (〈2;_inToOut〉 & { - in: 〈2;#Inner〉 - }).out - } - } - } - refFromPkg: 〈import;"foo.com/example"〉.#E.b - refFromLet: { - let X#1 = { - #D: { - a: 2 - } - #E: (〈0;#D〉 & { - b: 1 - }) - } - x: 〈0;let X#1〉.#E.b - } -} diff --git a/cue/testdata/eval/required.txtar b/cue/testdata/eval/required.txtar --- a/cue/testdata/eval/required.txtar +++ b/cue/testdata/eval/required.txtar @@ -143,115 +143,6 @@ ./issue3918.cue:49:8 [incomplete] doNotEscalateError.b.pass: undefined field: self: ./issue3918.cue:49:11 --- out/compile -- ---- in.cue -{ - self: { - t1: { - a?: int - } - } - self: { - t2: { - a!: int - a!: int - } - } - unify: { - t1: { - a!: int - a: int - } - } - unify: { - t2: { - a!: int - a?: int - } - } - #Def: { - t1: { - a!: int - } - } - allowed: { - issue2306: { - #A: { - a!: int - } - #A: 〈0;#B〉 - #B: { - b!: int - } - } - } - reference: { - toWithinDefinition: { - #Foo: { - a!: int - } - b: 〈0;#Foo〉.a - } - toFieldFromDefinition: { - #Foo: { - a!: int - } - b: 〈0;#Foo〉 - c: 〈0;b〉.a - } - toNonDefinition: { - x: { - y!: _ - } - b: 〈0;x〉.y - } - toConcrete: { - a!: 1 - b: (〈0;a〉 + 1) - } - } -} ---- issue3918.cue -{ - issue3918: { - reduced: { - #disjuncts: { - in!: [ - ...string, - ] - out: 〈import;strings〉.Join(〈0;in〉, "|") - } - x: (〈0;#disjuncts〉 & { - in: [ - "foo", - "bar", - ] - }).out - } - noFunction: { - #disjuncts: { - in!: [ - ...string, - ] - out: 〈0;in〉 - } - _foo: (〈0;#disjuncts〉 & {}) - x: 〈0;_foo〉.out - } - } - doNotEscalateError: { - a: { - in: _ - out: 〈0;in〉.self - } - b: { - required!: _ - pass: (〈1;a〉 & { - in: 〈1;required〉 - }).out - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 93 diff --git a/cue/testdata/eval/resolve_basic.txtar b/cue/testdata/eval/resolve_basic.txtar --- a/cue/testdata/eval/resolve_basic.txtar +++ b/cue/testdata/eval/resolve_basic.txtar @@ -22,16 +22,3 @@ Unifications: 9 Conjuncts: 16 Disjuncts: 9 --- out/compile -- ---- in.cue -{ - a: 1 - b: (〈0;a〉 + 1) - d: { - x: _ - y: (〈1;b〉 + 〈0;x〉) - } - e: (〈0;d〉 & { - x: 5 - }) -} diff --git a/cue/testdata/eval/resolve_env.txtar b/cue/testdata/eval/resolve_env.txtar --- a/cue/testdata/eval/resolve_env.txtar +++ b/cue/testdata/eval/resolve_env.txtar @@ -26,30 +26,3 @@ Unifications: 15 Conjuncts: 22 Disjuncts: 15 --- out/compile -- ---- in.cue -{ - a: { - d: int - b: { - c: 〈1;d〉 - } - } - x: { - d: 2 - b: 〈1;a〉.b.c - } - a1: { - y: 5 - } - a1: { - a2: { - a3: { - a4: { - a5: 〈4;a1〉.y - } - } - } - } - b: 〈0;a1〉.a2.a3.a4.a5 -} diff --git a/cue/testdata/eval/selectors.txtar b/cue/testdata/eval/selectors.txtar --- a/cue/testdata/eval/selectors.txtar +++ b/cue/testdata/eval/selectors.txtar @@ -30,30 +30,3 @@ Unifications: 18 Conjuncts: 27 Disjuncts: 18 --- out/compile -- ---- in.cue -{ - a: 1 - b: (〈0;a〉 + 1) - d: { - x: _ - y: (〈1;b〉 + 〈0;x〉) - } - e: (〈0;d〉 & { - x: 5 - }) - f: { - a: { - "foo-bar": 3 - } - b: 〈0;a〉."foo-bar" - } - g: { - a: { - "foo-bar": { - c: 3 - } - } - b: 〈0;a〉."foo-bar".c - } -} diff --git a/cue/testdata/eval/sharing.txtar b/cue/testdata/eval/sharing.txtar --- a/cue/testdata/eval/sharing.txtar +++ b/cue/testdata/eval/sharing.txtar @@ -397,340 +397,3 @@ NumCloseIDs: 105 -- out/todo.txt -- v3 uses structure sharing (~) extensively in issue3641, issue3546, debug, issue3849, issue3903, and pending sections where v2 expanded values inline. v3 also omits shareCycle.t2.Y.x.x structural cycle error and instead reports conflicting values for shareCycle.t2.Y.x with additional position info. --- out/compile -- ---- acrossdisjunction.cue -{ - issue3679: { - b: (null|[ - string, - ]) - b: 〈import;list〉.Repeat([ - for k, v in [ - 0, - ] { - "bar" - }, - ], 1) - } -} ---- dupshare.cue -{ - issue3641: { - simplified: { - t1: { - #Context1: { - ctx: {} - } - Context2: { - ctx: {} - } - #Config1: { - cfg: 〈1;#Context1〉 - } - #Config3: { - cfg: 〈1;#Context1〉 - } - Config2: { - cfg: 〈1;Context2〉 - } - Config: (〈0;#Config1〉 & 〈0;Config2〉) - out: 〈0;Config〉 - out: 〈0;#Config3〉 - } - } - } - issue3641: { - simplified: { - t2: { - #Context1: { - ctx: {} - } - Context2: { - ctx: {} - } - #Config1: { - cfg: 〈1;#Context1〉 - } - #Config3: { - cfg: 〈1;#Context1〉 - } - Config2: { - cfg: 〈1;Context2〉 - } - Config: (〈0;#Config1〉 & 〈0;Config2〉) - out: 〈0;Config〉 - out: 〈0;#Config3〉 - } - } - } - issue3641: { - simplified: { - t3: { - #Context1: { - ctx: {} - } - Context2: { - ctx: {} - } - #Config1: { - cfg: 〈1;#Context1〉 - } - #Config3: { - cfg: 〈1;#Context1〉 - } - Config2: { - cfg: 〈1;Context2〉 - } - Config: (〈0;#Config1〉 & 〈0;Config2〉) - out: _|_(no sharing) - out: 〈0;Config〉 - out: 〈0;#Config3〉 - } - } - } - issue3641: { - full: { - #Context1: { - ctx: {} - } - #Context2: { - ctx: {} - } - #Config1: { - cfg: 〈1;#Context1〉 - } - #Config2: { - cfg: 〈1;#Context2〉 - } - #Schema: { - sch: 〈1;#Config1〉 - } - #Config: (〈0;#Config1〉 & 〈0;#Config2〉) - let config#1 = 〈0;#Config〉 - out: (〈0;#Schema〉 & { - sch: 〈1;let config#1〉 - }) - } - } - issue3546: { - reduced: { - all: [ - "a", - ] - #all: 〈0;all〉 - #Network: { - list: 〈1;#List〉 - } - #List: [ - ...string, - ] - val: 〈0;#Network〉 - val: { - list: 〈1;#all〉 - } - out: 〈0;#Network〉 - out: 〈0;val〉 - } - } -} ---- in.cue -{ - issue3062: { - ok1: { - #S: "a" - #o: { - x: 〈1;#S〉 - } - o: 〈0;#o〉 - o: 〈0;X〉 - X: { - x: 〈1;A〉 - } - A: "a" - } - } - issue3601: { - ok1: { - Y: (〈0;X〉 & _|_(no sharing)).a - X: { - a: { - b: 〈1;a〉.b - } - } - out: (〈0;Y〉 & _|_(no sharing)) - } - } - debug: { - sharingOn: { - a: 〈0;b〉 - b: { - c: 1 - } - } - sharingOff: { - t1: { - a: (〈0;b〉 & _|_(no sharing)) - b: { - c: 1 - } - } - } - sharingOff: { - t2: { - a: 〈0;b〉 - a: _|_(no sharing) - b: { - c: 1 - } - } - } - sharingOff: { - t3: { - a: _|_(no sharing) - a: 〈0;b〉 - b: { - c: 1 - } - } - } - } -} ---- issue3835.cue -{ - issue3835: { - foo: {} - _global: "global value" - [string]: { - if true let orgBotUser = 〈1;_global〉 { - out: ("prefix: " + 〈1;orgBotUser〉) - } - } - } -} ---- let.cue -{ - issue3903: { - full: { - _input: (null|*{ - name: "foo" - }) - let _inputList#2 = 〈import;list〉.FlattenN([ - 〈1;_input〉, - ], 0) - _inputByName: { - for _, input in 〈1;let _inputList#2〉 { - 〈1;input〉.name: 〈1;input〉 - } - } - for name, _input in 〈0;_inputByName〉 { - 〈1;name〉: (〈2;_template〉 & { - input: 〈2;_input〉 - }) - } - _template: { - input: { - name: string - } - result: "result-\(〈0;input〉.name)" - } - } - } - issue3903: { - noshare: { - _input: (null|*{ - name: "foo" - }) - let _inputList#3 = 〈import;list〉.FlattenN([ - 〈1;_input〉, - ], 0) - _inputByName: { - for _, input in (〈1;let _inputList#3〉 & _|_(no sharing)) { - 〈1;input〉.name: 〈1;input〉 - } - } - for name, _input in 〈0;_inputByName〉 { - 〈1;name〉: (〈2;_template〉 & { - input: 〈2;_input〉 - }) - } - _template: { - input: { - name: string - } - result: "result-\(〈0;input〉.name)" - } - } - } -} ---- pendingarcs.cue -{ - pending: { - t1: { - a: 〈0;X〉 - if true { - a: { - b: { - c: { - e: 1 - } - } - } - } - X: { - b: 〈1;Y〉 - } - Y: { - c: { - d: int - } - } - } - } - issue3849: { - dep: (〈0;#Deployment〉 & {}) - if true { - dep: { - metadata: { - name: { - app: "mysql" - } - } - } - } - #Deployment: { - metadata?: 〈1;#ObjectMeta〉 - } - #ObjectMeta: { - name?: { - [string]: string - } - } - } -} ---- sharecycle.cue -{ - shareCycle: { - t1: { - #X: {} - Y: { - x: (〈1;#X〉 & 〈1;Y〉) - } - } - } - shareCycle: { - t2: { - #X: int - Y: { - x: (〈1;#X〉 & 〈1;Y〉) - } - } - } - shareCycle: { - t3: { - #X: {} - Y: { - x: (〈1;Y〉 & 〈1;#X〉) - } - } - } -} diff --git a/cue/testdata/eval/shortcircuit.txtar b/cue/testdata/eval/shortcircuit.txtar --- a/cue/testdata/eval/shortcircuit.txtar +++ b/cue/testdata/eval/shortcircuit.txtar @@ -30,19 +30,3 @@ // No short-circuit: || falls through when left is false. orFalseFalse: false || false @test(eq, false) orFalseTrue: false || true @test(eq, true) --- out/compile -- ---- in.cue -{ - incompleteInt: int - incompleteBool: bool - andFalseBottom: (false && _|_(explicit error (_|_ literal) in source)) - andFalseIncomplete: (false && 〈0;incompleteInt〉) - andFalseTrue: (false && true) - andTrueTrue: (true && true) - andTrueFalse: (true && false) - orTrueBottom: (true || _|_(explicit error (_|_ literal) in source)) - orTrueIncomplete: (true || 〈0;incompleteBool〉) - orTrueTrue: (true || true) - orFalseFalse: (false || false) - orFalseTrue: (false || true) -} diff --git a/cue/testdata/eval/shortcircuit_noexp.txtar b/cue/testdata/eval/shortcircuit_noexp.txtar --- a/cue/testdata/eval/shortcircuit_noexp.txtar +++ b/cue/testdata/eval/shortcircuit_noexp.txtar @@ -13,9 +13,3 @@ ./in.cue:3:20 [user] explicit error (_|_ literal) in source: ./in.cue:4:20 --- out/compile -- ---- in.cue -{ - noExpAnd: (false && _|_(explicit error (_|_ literal) in source)) - noExpOr: (true || _|_(explicit error (_|_ literal) in source)) -} diff --git a/cue/testdata/eval/structs.txtar b/cue/testdata/eval/structs.txtar --- a/cue/testdata/eval/structs.txtar +++ b/cue/testdata/eval/structs.txtar @@ -12,10 +12,3 @@ Unifications: 4 Conjuncts: 7 Disjuncts: 4 --- out/compile -- ---- in.cue -{ - v: { - a: (〈import;struct〉.MaxFields(2) & {}) - }.a -} diff --git a/cue/testdata/eval/unify.txtar b/cue/testdata/eval/unify.txtar --- a/cue/testdata/eval/unify.txtar +++ b/cue/testdata/eval/unify.txtar @@ -22,28 +22,3 @@ Unifications: 8 Conjuncts: 19 Disjuncts: 9 --- out/compile -- ---- in.cue -{ - a: { - d: { - 〈2;#base〉 - #info: { - ... - } - Y: 〈0;#info〉.X - } - } - #base: { - #info: { - ... - } - } - a: { - [string]: { - #info: { - X: "foo" - } - } - } -} diff --git a/cue/testdata/eval/v0.7.txtar b/cue/testdata/eval/v0.7.txtar --- a/cue/testdata/eval/v0.7.txtar +++ b/cue/testdata/eval/v0.7.txtar @@ -354,510 +354,3 @@ NumCloseIDs: 86 -- out/todo.txt -- v3 uses structure sharing (~) for dynamic.t2.ok.foo/\#X and mutual.t4.ok's y.c fields. v3 reports fewer error positions for definition.t0.err and definition.t1.err (missing some context positions). --- out/compile -- ---- builtins.cue -{ - mutualBuiltin: { - t1: { - ok: { - s3: 〈import;strings〉.ContainsAny(〈0;s4〉) - s4: 〈import;strings〉.ContainsAny(〈0;s3〉) - s4: "dd" - } - } - } - mutualBuiltin: { - t2: { - ok: { - s3: 〈import;strings〉.ContainsAny(〈0;s5〉, "dd") - s5: 〈0;s6〉 - s6: "dd" - } - } - } -} ---- chained.cue -{ - issue3925: { - reduced: { - out: 〈import;"encoding/yaml"〉.Marshal(〈0;in〉.b.actual) - in: { - a: "actual" - a: ("actual"|"other") - b: { - 〈1;a〉: { - c: "str" - } - } - } - } - } - issue3925: { - full: { - for name, _ in 〈0;_inputs〉 { - out: { - 〈2;name〉: { - early: "early value" - } - } - } - _inputs: { - input1: { - name: "actual" - config: { - 〈1;name〉: { - one: "one value" - } - } - } - } - _inputs: { - [_]: { - name: ("actual"|"other") - } - } - for name, input in 〈0;_inputs〉 { - out: { - 〈2;name〉: { - lateYAML: 〈import;"encoding/yaml"〉.Marshal(〈3;input〉.config[〈3;input〉.name]) - } - } - } - } - } -} ---- comprehensions.cue -{ - comprehensions: { - t1: { - ok: { - src: [ - "foo", - ] - for _, v in 〈0;src〉 { - "\(〈1;v〉)": 〈1;v〉 - } - } - } - } -} ---- definition.cue -{ - definition: { - t0: { - err: { - #D1: { - env: {} - } - d1: { - env: { - c: "C" - } - } - d1: 〈0;#D1〉 - } - } - } - definition: { - t1: { - err: { - a: 〈0;#A〉 - a: { - c: 1 - } - #A: {} - } - } - } - definition: { - t2: { - ok: { - p1: { - #A: { - ... - { - a: int - } - } - x: (〈0;#A〉 & { - c: int - }) - } - } - } - } - definition: { - t2: { - ok: { - p2: { - #A: { - { - a: int - } - ... - } - x: (〈0;#A〉 & { - c: int - }) - } - } - } - } - definition: { - t2: { - ok: { - p3: { - x: (〈0;#A〉 & { - c: int - }) - #A: { - ... - { - a: int - } - } - } - } - } - } - definition: { - t2: { - ok: { - p4: { - x: (〈0;#A〉 & { - c: int - }) - #A: { - { - a: int - } - ... - } - } - } - } - } -} ---- dynamic.cue -{ - dynamic: { - t1: { - ok: { - [string]: { - name: 〈1;-〉 - } - 〈0;x〉.y: {} - x: { - y: "foo" - } - } - } - } - dynamic: { - t2: { - ok: { - foo: 〈0;#X〉 - #X: { - a: { - b: { - C: 1 - } - } - for _, _ in 〈0;a〉 { - a: { - "b": { - D: 2 - } - } - } - } - } - } - } -} ---- equality.cue -{ - issue3194: { - reduced: { - A: (*0|>10) - A: (*0|>10) - { - out: close({ - b: 〈2;A〉 - }) - out: { - b: 〈2;A〉 - } - }.out - } - } -} ---- expr.cue -{ - expr: { - t1: { - ok: { - a: 〈0;X〉 - X: 5.0 - X: (〈0;Y〉 / 2) - Y: (〈0;a〉 * 2) - } - } - } - expr: { - t2: { - ok: { - A: (〈0;X〉 + 2) - X: 5 - X: (〈0;A〉 - 2) - } - } - } - expr: { - t3: { - ok: { - p1: { - a0: 〈0;X〉 - X: 5.0 - X: (〈0;a0〉 * 1) - } - } - } - } - expr: { - t3: { - ok: { - p2: { - b: (〈0;Y〉 * 1) - Y: (〈0;b〉 * 1) - Y: 5.0 - } - } - } - } - expr: { - t4: { - ok: { - a0: 〈0;X〉 - b0: 〈0;a1〉 - a1: (〈0;a0〉 + 2) - b1: (〈0;b0〉 - 2) - a0: 〈0;X〉 - X: 〈0;b1〉 - X: 5.0 - } - } - } -} ---- in.cue -{ - mutual: { - t0: { - ok: { - c: (〈0;e〉 & { - b: 2 - }) - e: { - a: 1 - } - e: 〈0;c〉 - } - } - } - mutual: { - t1: { - ok: { - a: { - 〈0;b〉 - b: { - b: { - f: 1 - } - } - } - a: 〈0;a〉.b - a: { - b: { - b: { - f: 1 - } - } - } - } - } - } - mutual: { - t2: { - ok: { - x: { - a: { - a: { - f: 1 - } - } - } - x: 〈0;y〉.a - y: { - a: { - a: { - e: 1 - } - } - } - y: 〈0;x〉.a - } - } - } - mutual: { - t3: { - ok: { - d: { - e: { - f: 1 - } - } - 〈0;d〉 - d: { - d: { - e: { - g: 1 - } - } - } - } - } - } - mutual: { - t4: { - ok: { - p0: { - z: 〈0;x〉.b - x: { - b: 〈1;y〉.c - } - x: { - b: { - d: { - b: 2 - } - } - } - y: { - c: 〈1;z〉.d - } - z: { - d: { - a: 1 - } - } - } - p1: { - x: { - b: 〈1;y〉.c - } - z: 〈0;x〉.b - x: { - b: { - d: { - b: 2 - } - } - } - y: { - c: 〈1;z〉.d - } - z: { - d: { - a: 1 - } - } - } - p2: { - x: { - b: 〈1;y〉.c - } - x: { - b: { - d: { - b: 2 - } - } - } - y: { - c: 〈1;z〉.d - } - z: 〈0;x〉.b - z: { - d: { - a: 1 - } - } - } - p3: { - x: { - b: { - d: { - b: 2 - } - } - } - y: { - c: 〈1;z〉.d - } - z: 〈0;x〉.b - x: { - b: 〈1;y〉.c - } - z: { - d: { - a: 1 - } - } - } - p4: { - z: 〈0;x〉.b - x: { - b: { - d: { - b: 2 - } - } - } - y: { - c: 〈1;z〉.d - } - x: { - b: 〈1;y〉.c - } - z: { - d: { - a: 1 - } - } - } - p5: { - x: { - b: { - d: { - b: 2 - } - } - } - y: { - c: 〈1;z〉.d - } - x: { - b: 〈1;y〉.c - } - z: 〈0;x〉.b - z: { - d: { - a: 1 - } - } - } - check: ((((〈0;p1〉 & 〈0;p2〉) & 〈0;p3〉) & 〈0;p4〉) & 〈0;p5〉) - } - } - } -} diff --git a/cue/testdata/eval/v0.7errorprop.txtar b/cue/testdata/eval/v0.7errorprop.txtar --- a/cue/testdata/eval/v0.7errorprop.txtar +++ b/cue/testdata/eval/v0.7errorprop.txtar @@ -19,15 +19,6 @@ Unifications: 4 Conjuncts: 6 Disjuncts: 5 --- out/compile -- ---- in.cue -{ - a: 〈0;#A〉 - a: { - c: 1 - } - #A: {} -} -- out/todo.txt -- v2 reports additional error positions (in.cue:1:4 and in.cue:3:5) for the "field not allowed" error on a.c. v3 only reports the direct field definition position diff --git a/cue/testdata/export/000.txtar b/cue/testdata/export/000.txtar --- a/cue/testdata/export/000.txtar +++ b/cue/testdata/export/000.txtar @@ -1,11 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- "hello" --- out/compile -- ---- in.cue -{ - "hello" -} -- out/eval/stats -- Leaks: 0 Freed: 1 diff --git a/cue/testdata/export/001.txtar b/cue/testdata/export/001.txtar --- a/cue/testdata/export/001.txtar +++ b/cue/testdata/export/001.txtar @@ -1,11 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- 'hello' --- out/compile -- ---- in.cue -{ - 'hello' -} -- out/eval/stats -- Leaks: 0 Freed: 1 diff --git a/cue/testdata/export/002.txtar b/cue/testdata/export/002.txtar --- a/cue/testdata/export/002.txtar +++ b/cue/testdata/export/002.txtar @@ -1,11 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- 'hello\nworld' --- out/compile -- ---- in.cue -{ - 'hello\nworld' -} -- out/eval/stats -- Leaks: 0 Freed: 1 diff --git a/cue/testdata/export/003.txtar b/cue/testdata/export/003.txtar --- a/cue/testdata/export/003.txtar +++ b/cue/testdata/export/003.txtar @@ -1,11 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- "hello\nworld" --- out/compile -- ---- in.cue -{ - "hello\nworld" -} -- out/eval/stats -- Leaks: 0 Freed: 1 diff --git a/cue/testdata/export/004.txtar b/cue/testdata/export/004.txtar --- a/cue/testdata/export/004.txtar +++ b/cue/testdata/export/004.txtar @@ -6,16 +6,6 @@ "_foo": int _bar: int } --- out/compile -- ---- in.cue -{ - { - $type: 3 - "_": int - "_foo": int - _bar: int - } -} -- out/eval/stats -- Leaks: 0 Freed: 5 diff --git a/cue/testdata/export/005.txtar b/cue/testdata/export/005.txtar --- a/cue/testdata/export/005.txtar +++ b/cue/testdata/export/005.txtar @@ -1,18 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: 1, b: a + 2, c: null, d: true, e: _, f: string} --- out/compile -- ---- in.cue -{ - { - a: 1 - b: (〈0;a〉 + 2) - c: null - d: true - e: _ - f: string - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/export/006.txtar b/cue/testdata/export/006.txtar --- a/cue/testdata/export/006.txtar +++ b/cue/testdata/export/006.txtar @@ -1,20 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: {b: 2.0, s: "abc"}, b: a.b, c: a.c, d: a["d"], e: a.t[2:3]} --- out/compile -- ---- in.cue -{ - { - a: { - b: 2.0 - s: "abc" - } - b: 〈0;a〉.b - c: 〈0;a〉.c - d: 〈0;a〉["d"] - e: 〈0;a〉.t[2:3] - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/export/007.txtar b/cue/testdata/export/007.txtar --- a/cue/testdata/export/007.txtar +++ b/cue/testdata/export/007.txtar @@ -7,20 +7,6 @@ d: #a["d"] e: #a.t[2:3] } --- out/compile -- ---- in.cue -{ - { - #a: { - b: 2.0 - s: "abc" - } - b: 〈0;#a〉.b - c: 〈0;#a〉.c - d: 〈0;#a〉["d"] - e: 〈0;#a〉.t[2:3] - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/export/008.txtar b/cue/testdata/export/008.txtar --- a/cue/testdata/export/008.txtar +++ b/cue/testdata/export/008.txtar @@ -1,15 +1,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: [ 3 & 4]} --- out/compile -- ---- in.cue -{ - { - a: [ - (3 & 4), - ] - } -} -- out/eval/stats -- Leaks: 0 Freed: 3 diff --git a/cue/testdata/export/009.txtar b/cue/testdata/export/009.txtar --- a/cue/testdata/export/009.txtar +++ b/cue/testdata/export/009.txtar @@ -9,33 +9,6 @@ e: [1, 2, ...] f: [1, 2, ...] } --- out/compile -- ---- in.cue -{ - { - a: 〈import;list〉.Repeat([ - int, - ], 5) - a: [ - 1, - 2, - ..., - ] - e: [ - ...int, - ] - e: [ - 1, - 2, - ..., - ] - f: [ - 1, - 2, - ..., - ] - } -} -- out/eval/stats -- Leaks: 0 Freed: 15 diff --git a/cue/testdata/export/010.txtar b/cue/testdata/export/010.txtar --- a/cue/testdata/export/010.txtar +++ b/cue/testdata/export/010.txtar @@ -10,33 +10,6 @@ e: [1, 2, ...] f: [1, 2, ...] } --- out/compile -- ---- in.cue -{ - { - a: 〈import;list〉.Repeat([ - int, - ], 5) - a: [ - 1, - 2, - ..., - ] - e: [ - ...int, - ] - e: [ - 1, - 2, - ..., - ] - f: [ - 1, - 2, - ..., - ] - } -} -- out/eval/stats -- Leaks: 0 Freed: 15 diff --git a/cue/testdata/export/011.txtar b/cue/testdata/export/011.txtar --- a/cue/testdata/export/011.txtar +++ b/cue/testdata/export/011.txtar @@ -2,17 +2,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: {b: []}, c: a.b, d: a["b"]} --- out/compile -- ---- in.cue -{ - { - a: { - b: [] - } - c: 〈0;a〉.b - d: 〈0;a〉["b"] - } -} -- out/eval/stats -- Leaks: 0 Freed: 5 diff --git a/cue/testdata/export/012.txtar b/cue/testdata/export/012.txtar --- a/cue/testdata/export/012.txtar +++ b/cue/testdata/export/012.txtar @@ -2,14 +2,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: *"foo" | *"bar" | *string | int, b: a[2:3]} --- out/compile -- ---- in.cue -{ - { - a: (*"foo"|*"bar"|*string|int) - b: 〈0;a〉[2:3] - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/export/013.txtar b/cue/testdata/export/013.txtar --- a/cue/testdata/export/013.txtar +++ b/cue/testdata/export/013.txtar @@ -3,13 +3,6 @@ { a: >=0 & <=10 & !=1 } --- out/compile -- ---- in.cue -{ - { - a: ((>=0 & <=10) & !=1) - } -} -- out/eval/stats -- Leaks: 0 Freed: 2 diff --git a/cue/testdata/export/014.txtar b/cue/testdata/export/014.txtar --- a/cue/testdata/export/014.txtar +++ b/cue/testdata/export/014.txtar @@ -4,13 +4,6 @@ { a: >=0 & <=10 & !=1 } --- out/compile -- ---- in.cue -{ - { - a: ((>=0 & <=10) & !=1) - } -} -- out/eval/stats -- Leaks: 0 Freed: 2 diff --git a/cue/testdata/export/015.txtar b/cue/testdata/export/015.txtar --- a/cue/testdata/export/015.txtar +++ b/cue/testdata/export/015.txtar @@ -6,16 +6,6 @@ a: (*1 | 2) & (1 | *2) b: [(*1 | 2) & (1 | *2)] } --- out/compile -- ---- in.cue -{ - { - a: ((*1|2) & (1|*2)) - b: [ - ((*1|2) & (1|*2)), - ] - } -} -- out/eval/stats -- Leaks: 0 Freed: 16 diff --git a/cue/testdata/export/016.txtar b/cue/testdata/export/016.txtar --- a/cue/testdata/export/016.txtar +++ b/cue/testdata/export/016.txtar @@ -17,25 +17,6 @@ f64: float64 fi: float64 & int } --- out/compile -- ---- in.cue -{ - { - u16: ((int & >=0) & <=65535) - u32: &(int, >=0, <=4294967295) - u64: &(int, >=0, <=18446744073709551615) - u128: &(int, >=0, <=340282366920938463463374607431768211455) - u8: &(int, >=0, <=255) - ua: (&(int, >=0, <=65535) & >0) - us: ((>=0 & <10000) & int) - i16: ((>=-32768 & int) & <=32767) - i32: (&(int, >=-2147483648, <=2147483647) & >0) - i64: &(int, >=-9223372036854775808, <=9223372036854775807) - i128: &(int, >=-170141183460469231731687303715884105728, <=170141183460469231731687303715884105727) - f64: &(>=-1.797693134862315708145274237317043567981E+308, <=1.797693134862315708145274237317043567981E+308) - fi: (&(>=-1.797693134862315708145274237317043567981E+308, <=1.797693134862315708145274237317043567981E+308) & int) - } -} -- out/eval/stats -- Leaks: 0 Freed: 14 diff --git a/cue/testdata/export/017.txtar b/cue/testdata/export/017.txtar --- a/cue/testdata/export/017.txtar +++ b/cue/testdata/export/017.txtar @@ -2,21 +2,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: [1, 2], b: {for k, v in a if v > 1 {"\(k)": v}}} --- out/compile -- ---- in.cue -{ - { - a: [ - 1, - 2, - ] - b: { - for k, v in 〈1;a〉 if (〈0;v〉 > 1) { - "\(〈1;k〉)": 〈1;v〉 - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 6 diff --git a/cue/testdata/export/018.txtar b/cue/testdata/export/018.txtar --- a/cue/testdata/export/018.txtar +++ b/cue/testdata/export/018.txtar @@ -2,21 +2,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: [1, 2], b: [for k, v in a {v}]} --- out/compile -- ---- in.cue -{ - { - a: [ - 1, - 2, - ] - b: [ - for k, v in 〈1;a〉 { - 〈1;v〉 - }, - ] - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/export/019.txtar b/cue/testdata/export/019.txtar --- a/cue/testdata/export/019.txtar +++ b/cue/testdata/export/019.txtar @@ -2,14 +2,6 @@ #inlinetest:exclude skip — tests export format, not evaluator semantics -- in.cue -- {a: >=0 & <=10, b: "Count: \(a) times"} --- out/compile -- ---- in.cue -{ - { - a: (>=0 & <=10) - b: "Count: \(〈0;a〉) times" - } -} -- out/eval/stats -- Leaks: 0 Freed: 3 diff --git a/cue/testdata/export/020.txtar b/cue/testdata/export/020.txtar --- a/cue/testdata/export/020.txtar +++ b/cue/testdata/export/020.txtar @@ -19,11 +19,3 @@ a: (string){ "" } b: (int){ 0 } } --- out/compile -- ---- in.cue -{ - { - a: "" - b: len(〈0;a〉) - } -} diff --git a/cue/testdata/export/021.txtar b/cue/testdata/export/021.txtar --- a/cue/testdata/export/021.txtar +++ b/cue/testdata/export/021.txtar @@ -10,24 +10,6 @@ b: a: b: 4 a: b: 3 } --- out/compile -- ---- in.cue -{ - { - b: { - idx: 〈1;a〉[〈0;str〉] - str: string - } - b: { - a: { - b: 4 - } - } - a: { - b: 3 - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/export/022.txtar b/cue/testdata/export/022.txtar --- a/cue/testdata/export/022.txtar +++ b/cue/testdata/export/022.txtar @@ -17,30 +17,6 @@ replicas: 2 } } --- out/compile -- ---- in.cue -{ - { - job: { - [_]: { - name: 〈1;-〉 - replicas: (&(int, >=0)|*1) - command: string - } - } - job: { - list: { - command: "ls" - } - } - job: { - nginx: { - command: "nginx" - replicas: 2 - } - } - } -} -- out/eval/stats -- Leaks: 1 Freed: 13 diff --git a/cue/testdata/export/023.txtar b/cue/testdata/export/023.txtar --- a/cue/testdata/export/023.txtar +++ b/cue/testdata/export/023.txtar @@ -23,35 +23,6 @@ {[_]: <300} } } --- out/compile -- ---- in.cue -{ - { - #emb: { - a: 1 - sub: { - f: 3 - } - } - #def: { - 〈1;#emb〉 - b: 2 - } - #f: { - a: 10 - } - #e: { - 〈1;#f〉 - b: int - { - [_]: <100 - } - { - [_]: <300 - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 15 diff --git a/cue/testdata/export/024.txtar b/cue/testdata/export/024.txtar --- a/cue/testdata/export/024.txtar +++ b/cue/testdata/export/024.txtar @@ -16,29 +16,6 @@ } val2: #def2 } --- out/compile -- ---- in.cue -{ - { - reg: { - foo: 1 - bar: { - baz: 3 - } - } - #def: { - a: 1 - sub: 〈1;reg〉 - } - val: 〈0;#def〉 - #def2: { - a: { - b: int - } - } - val2: 〈0;#def2〉 - } -} -- out/eval/stats -- Leaks: 0 Freed: 16 diff --git a/cue/testdata/export/025.txtar b/cue/testdata/export/025.txtar --- a/cue/testdata/export/025.txtar +++ b/cue/testdata/export/025.txtar @@ -12,24 +12,6 @@ a: int c: *1 | 2 } --- out/compile -- ---- in.cue -{ - { - b: [ - { - { - [_]: int - } - if (〈2;a〉 > 4) { - f: 4 - } - }, - ][〈0;a〉] - a: int - c: (*1|2) - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/export/026.txtar b/cue/testdata/export/026.txtar --- a/cue/testdata/export/026.txtar +++ b/cue/testdata/export/026.txtar @@ -6,19 +6,6 @@ {a: 1} | {b: 1} } } --- out/compile -- ---- in.cue -{ - { - if false { - ({ - a: 1 - }|{ - b: 1 - }) - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 1 diff --git a/cue/testdata/export/027.txtar b/cue/testdata/export/027.txtar --- a/cue/testdata/export/027.txtar +++ b/cue/testdata/export/027.txtar @@ -11,15 +11,6 @@ #Bar: #Foo | string } } --- out/compile -- ---- in.cue -{ - { - #Foo: { - #Bar: (〈1;#Foo〉|string) - } - } -} -- out/eval/stats -- Leaks: 1 Freed: 4 diff --git a/cue/testdata/export/028.txtar b/cue/testdata/export/028.txtar --- a/cue/testdata/export/028.txtar +++ b/cue/testdata/export/028.txtar @@ -8,22 +8,6 @@ } a: [...string] } --- out/compile -- ---- in.cue -{ - { - #FindInMap: { - #: { - "Fn::FindInMap": [ - (string|〈3;#FindInMap〉), - ] - } - } - a: [ - ...string, - ] - } -} -- out/eval/stats -- Leaks: 1 Freed: 7 diff --git a/cue/testdata/export/029.txtar b/cue/testdata/export/029.txtar --- a/cue/testdata/export/029.txtar +++ b/cue/testdata/export/029.txtar @@ -11,26 +11,6 @@ #: "Fn::And": [_] } } --- out/compile -- ---- in.cue -{ - { - #And: { - #: { - "Fn::And": [ - ...(3|〈3;#And〉), - ] - } - } - #Ands: (〈0;#And〉 & { - #: { - "Fn::And": [ - _, - ] - } - }) - } -} -- out/eval/stats -- Leaks: 0 Freed: 12 diff --git a/cue/testdata/export/030.txtar b/cue/testdata/export/030.txtar --- a/cue/testdata/export/030.txtar +++ b/cue/testdata/export/030.txtar @@ -17,25 +17,6 @@ } #Bar: string } --- out/compile -- ---- in.cue -{ - { - #Foo: { - sgl: 〈1;#Bar〉 - ref: (null|〈1;#Foo〉) - ext: (〈1;#Bar〉|null) - ref: (null|〈1;#Foo〉) - ref2: (null|〈1;#Foo〉.sgl) - ... - } - #Foo: { - "#Foo": 2 - ... - } - #Bar: string - } -} -- out/eval/stats -- Leaks: 1 Freed: 22 diff --git a/cue/testdata/export/031.txtar b/cue/testdata/export/031.txtar --- a/cue/testdata/export/031.txtar +++ b/cue/testdata/export/031.txtar @@ -6,20 +6,6 @@ A: [uint] B: A & ([10] | [192]) } --- out/compile -- ---- in.cue -{ - { - A: [ - &(int, >=0), - ] - B: (〈0;A〉 & ([ - 10, - ]|[ - 192, - ])) - } -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/export/032.txtar b/cue/testdata/export/032.txtar --- a/cue/testdata/export/032.txtar +++ b/cue/testdata/export/032.txtar @@ -4,14 +4,6 @@ [string]: _ foo: 3 } --- out/compile -- ---- in.cue -{ - { - [string]: _ - foo: 3 - } -} -- out/eval/stats -- Leaks: 0 Freed: 2 diff --git a/cue/testdata/export/issue2119.txtar b/cue/testdata/export/issue2119.txtar --- a/cue/testdata/export/issue2119.txtar +++ b/cue/testdata/export/issue2119.txtar @@ -71,39 +71,3 @@ Disjuncts: 0 NumCloseIDs: 14 --- out/compile -- ---- in.cue -{ - simplified: { - x: { - d: { - ".*" - [ - (〈2〉 + ""), - ][0] - } - } - out: 〈import;"encoding/yaml"〉.Marshal(〈0;x〉) - } - original: { - #testableRegexp: { - string - #test: close({ - in: string - out: 〈import;regexp〉.FindSubmatch((("^" + 〈2〉) + "$"), 〈0;in〉)[1] - }) - } - rule: { - #patterns: { - bar: (〈2;#testableRegexp〉 & { - "(.*)" - #test: { - in: "testcontent" - out: "testcontent" - } - }) - } - } - out: 〈import;"encoding/yaml"〉.Marshal(〈0;rule〉) - } -} diff --git a/cue/testdata/export/issue2244.txtar b/cue/testdata/export/issue2244.txtar --- a/cue/testdata/export/issue2244.txtar +++ b/cue/testdata/export/issue2244.txtar @@ -65,27 +65,3 @@ [incomplete] error in call to strings.HasSuffix: non-concrete value string: ./in.cue:11:6 ./in.cue:8:12 --- out/compile -- ---- in.cue -{ - _#matchPattern(:x): { - #pattern: string - [ - if 〈import;strings〉.HasSuffix(〈1;#pattern〉, "*") { - let prefix#1 = 〈import;strings〉.TrimSuffix(〈2;#pattern〉, "*") - 〈0;let prefix#1〉 - }, - "'\(〈1;#pattern〉)'", - ][0] - } - _#isReleaseTag(:x): (〈0;_#matchPattern(:x)〉 & { - #pattern: "refs/tags/v*" - _ - }) - #step: { - if: (number|string) - } - m: (〈0;#step〉 & { - if: 〈1;_#isReleaseTag(:x)〉 - }) -} diff --git a/cue/testdata/export/issue854.txtar b/cue/testdata/export/issue854.txtar --- a/cue/testdata/export/issue854.txtar +++ b/cue/testdata/export/issue854.txtar @@ -22,11 +22,6 @@ -- out/errors.txt -- [incomplete] b: undefined field: c: ./b/b.cue:5:6 --- out/compile -- ---- a.cue -{ - theb: 〈import;"mod.test/b"〉.name -} -- out/eval/stats -- Leaks: 5 Freed: 2 @@ -38,4 +33,4 @@ Conjuncts: 8 Disjuncts: 0 -NumCloseIDs: 1 \ No newline at end of file +NumCloseIDs: 1 diff --git a/cue/testdata/fulleval/000_detect_conflicting_value.txtar b/cue/testdata/fulleval/000_detect_conflicting_value.txtar --- a/cue/testdata/fulleval/000_detect_conflicting_value.txtar +++ b/cue/testdata/fulleval/000_detect_conflicting_value.txtar @@ -23,9 +23,3 @@ Unifications: 2 Conjuncts: 5 Disjuncts: 4 --- out/compile -- ---- in.cue -{ - a: 8000.9 - a: (7080|int) -} diff --git a/cue/testdata/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar b/cue/testdata/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar --- a/cue/testdata/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar +++ b/cue/testdata/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar @@ -10,19 +10,6 @@ } | { b?: 4, a: 2 }) --- out/compile -- ---- in.cue -{ - d: ({ - a: 1 - b?: 3 - }|{ - a: 2 - }) - c: (〈0;d〉 & { - b?: 4 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 15 diff --git a/cue/testdata/fulleval/002_resolve_all_disjunctions.txtar b/cue/testdata/fulleval/002_resolve_all_disjunctions.txtar --- a/cue/testdata/fulleval/002_resolve_all_disjunctions.txtar +++ b/cue/testdata/fulleval/002_resolve_all_disjunctions.txtar @@ -15,29 +15,6 @@ name: "foobar" port: *7080 | int }) --- out/compile -- ---- in.cue -{ - service: { - [string]: { - name: (string|*〈1;-〉) - port: (int|*7080) - } - } - service: { - foo: _ - } - service: { - bar: { - port: 8000 - } - } - service: { - baz: { - name: "foobar" - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 23 diff --git a/cue/testdata/fulleval/003_field_templates.txtar b/cue/testdata/fulleval/003_field_templates.txtar --- a/cue/testdata/fulleval/003_field_templates.txtar +++ b/cue/testdata/fulleval/003_field_templates.txtar @@ -15,41 +15,6 @@ foo: {} @test(eq, {name: "foo", y: 1}) bar: _ @test(eq, {name: "bar", y: 1}) } --- out/compile -- ---- in.cue -{ - a: { - { - [_]: int - } - k: 1 - } - b: { - { - [_]: { - x: 0 - y: (*1|int) - } - } - v: {} - w: { - y: 0 - } - } - b: { - [_]: {} - } - c: { - { - [_]: { - name: 〈1;-〉 - y: 1 - } - } - foo: {} - bar: _ - } -} -- out/eval/stats -- Leaks: 0 Freed: 21 diff --git a/cue/testdata/fulleval/004_field_comprehension.txtar b/cue/testdata/fulleval/004_field_comprehension.txtar --- a/cue/testdata/fulleval/004_field_comprehension.txtar +++ b/cue/testdata/fulleval/004_field_comprehension.txtar @@ -21,26 +21,6 @@ } @test(eq, {b: 2, c: 3}) } --- out/compile -- ---- in.cue -{ - a: { - for k, v in 〈1;b〉 if (〈0;k〉 < "d") if (〈0;v〉 > 〈2;b〉.a) { - "\(〈1;k〉)": 〈1;v〉 - } - } - b: { - a: 1 - b: 2 - c: 3 - d: 4 - } - c: { - for k, v in 〈1;b〉 if (〈0;k〉 < "d") if (〈0;v〉 > 〈2;b〉.a) { - "\(〈1;k〉)": 〈1;v〉 - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 12 diff --git a/cue/testdata/fulleval/005_conditional_field.txtar b/cue/testdata/fulleval/005_conditional_field.txtar --- a/cue/testdata/fulleval/005_conditional_field.txtar +++ b/cue/testdata/fulleval/005_conditional_field.txtar @@ -27,28 +27,6 @@ [incomplete] d: non-concrete value int in operand to >: ./in.cue:20:5 ./in.cue:19:5 --- out/compile -- ---- in.cue -{ - a: { - if 〈0;b〉 { - a: "foo" - } - b: true - } - c: { - a: 3 - if (〈0;a〉 > 1) { - a: 3 - } - } - d: { - a: int - if (〈0;a〉 > 1) { - a: 3 - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/fulleval/006_referencing_field_in_field_comprehension.txtar b/cue/testdata/fulleval/006_referencing_field_in_field_comprehension.txtar --- a/cue/testdata/fulleval/006_referencing_field_in_field_comprehension.txtar +++ b/cue/testdata/fulleval/006_referencing_field_in_field_comprehension.txtar @@ -7,23 +7,6 @@ "\(k)": v } } --- out/compile -- ---- in.cue -{ - a: { - b: { - c: 4 - } - } - a: { - b: { - d: 5 - } - for k, v in 〈0;b〉 { - "\(〈1;k〉)": 〈1;v〉 - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/fulleval/007_different_labels_for_templates.txtar b/cue/testdata/fulleval/007_different_labels_for_templates.txtar --- a/cue/testdata/fulleval/007_different_labels_for_templates.txtar +++ b/cue/testdata/fulleval/007_different_labels_for_templates.txtar @@ -2,23 +2,6 @@ a: [X=string]: {name: X} a: [Name=string]: {name: Name} a: foo: {} @test(eq, {name: "foo"}) --- out/compile -- ---- in.cue -{ - a: { - [string]: { - name: 〈1;-〉 - } - } - a: { - [string]: { - name: 〈1;-〉 - } - } - a: { - foo: {} - } -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/fulleval/008_nested_templates_in_one_field.txtar b/cue/testdata/fulleval/008_nested_templates_in_one_field.txtar --- a/cue/testdata/fulleval/008_nested_templates_in_one_field.txtar +++ b/cue/testdata/fulleval/008_nested_templates_in_one_field.txtar @@ -10,43 +10,6 @@ name: "EE" kind: "FF" }) --- out/compile -- ---- in.cue -{ - a: { - [string]: { - b: { - [string]: { - name: 〈3;-〉 - kind: 〈1;-〉 - } - } - } - } - a: { - A: { - b: { - B: _ - } - } - } - a: { - C: { - b: { - D: _ - } - } - } - a: { - EE: { - b: { - FF: { - c: "bar" - } - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 18 diff --git a/cue/testdata/fulleval/009_template_unification_within_one_struct.txtar b/cue/testdata/fulleval/009_template_unification_within_one_struct.txtar --- a/cue/testdata/fulleval/009_template_unification_within_one_struct.txtar +++ b/cue/testdata/fulleval/009_template_unification_within_one_struct.txtar @@ -12,33 +12,6 @@ name: "E" kind: "E" }) --- out/compile -- ---- in.cue -{ - a: { - { - [string]: { - name: 〈1;-〉 - } - } - { - [string]: { - kind: 〈1;-〉 - } - } - } - a: { - A: _ - } - a: { - C: _ - } - a: { - E: { - c: "bar" - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 12 diff --git a/cue/testdata/fulleval/010_field_comprehensions_with_multiple_keys.txtar b/cue/testdata/fulleval/010_field_comprehensions_with_multiple_keys.txtar --- a/cue/testdata/fulleval/010_field_comprehensions_with_multiple_keys.txtar +++ b/cue/testdata/fulleval/010_field_comprehensions_with_multiple_keys.txtar @@ -26,50 +26,6 @@ C: D: {a: "C", b: "D"} E: F: {a: "E", b: "F"} }) --- out/compile -- ---- in.cue -{ - for _, x in [ - { - a: "A" - b: "B" - }, - { - a: "C" - b: "D" - }, - { - a: "E" - b: "F" - }, - ] { - a: { - "\(〈2;x〉.a)": { - b: { - "\(〈4;x〉.b)": 〈4;x〉 - } - } - } - } - for _, x in [ - { - a: "A" - b: "B" - }, - { - a: "C" - b: "D" - }, - { - a: "E" - b: "F" - }, - ] { - "\(〈1;x〉.a)": { - "\(〈2;x〉.b)": 〈2;x〉 - } - } -} -- out/eval/stats -- Leaks: 20 Freed: 29 diff --git a/cue/testdata/fulleval/011_field_comprehensions_with_templates.txtar b/cue/testdata/fulleval/011_field_comprehensions_with_templates.txtar --- a/cue/testdata/fulleval/011_field_comprehensions_with_templates.txtar +++ b/cue/testdata/fulleval/011_field_comprehensions_with_templates.txtar @@ -15,28 +15,6 @@ } }) a: b: c: d: "bar" --- out/compile -- ---- in.cue -{ - num: 1 - a: { - if (〈1;num〉 < 5) { - [string]: { - [string]: { - name: 〈2;-〉 - kind: 〈1;-〉 - } - } - } - } - a: { - b: { - c: { - d: "bar" - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/fulleval/012_disjunctions_of_lists.txtar b/cue/testdata/fulleval/012_disjunctions_of_lists.txtar --- a/cue/testdata/fulleval/012_disjunctions_of_lists.txtar +++ b/cue/testdata/fulleval/012_disjunctions_of_lists.txtar @@ -5,23 +5,6 @@ l & ["c", "d"] @test(eq, ["c", "d"]) } --- out/compile -- ---- in.cue -{ - l: (*[ - int, - int, - ]|[ - string, - string, - ]) - t1: { - (〈1;l〉 & [ - "c", - "d", - ]) - } -} -- out/eval/stats -- Leaks: 0 Freed: 18 diff --git a/cue/testdata/fulleval/013_normalization.txtar b/cue/testdata/fulleval/013_normalization.txtar --- a/cue/testdata/fulleval/013_normalization.txtar +++ b/cue/testdata/fulleval/013_normalization.txtar @@ -6,13 +6,6 @@ a: string | string @test(eq, string) b: *1 | *int @test(eq, *1 | *int) c: *1.0 | *float @test(eq, *1.0 | *float) --- out/compile -- ---- in.cue -{ - a: (string|string) - b: (*1|*int) - c: (*1.0|*float) -} -- out/eval/stats -- Leaks: 0 Freed: 10 diff --git a/cue/testdata/fulleval/014_default_disambiguation_and_elimination.txtar b/cue/testdata/fulleval/014_default_disambiguation_and_elimination.txtar --- a/cue/testdata/fulleval/014_default_disambiguation_and_elimination.txtar +++ b/cue/testdata/fulleval/014_default_disambiguation_and_elimination.txtar @@ -10,17 +10,6 @@ @test(eq, 1 | 3 | int) } --- out/compile -- ---- in.cue -{ - a: (*1|int) - b: (*3|int) - e: (*1|*1) - c: (〈0;a〉 & 〈0;b〉) - d: { - (〈1;b〉 & 〈1;a〉) - } -} -- out/eval/stats -- Leaks: 0 Freed: 24 diff --git a/cue/testdata/fulleval/016_struct_comprehension_with_template.txtar b/cue/testdata/fulleval/016_struct_comprehension_with_template.txtar --- a/cue/testdata/fulleval/016_struct_comprehension_with_template.txtar +++ b/cue/testdata/fulleval/016_struct_comprehension_with_template.txtar @@ -33,35 +33,6 @@ type: "service" port: *7080 | int }) --- out/compile -- ---- in.cue -{ - result: [ - for _, v in 〈1;service〉 { - 〈1;v〉 - }, - ] - service: { - [string]: { - name: (*〈1;-〉|string) - type: "service" - port: (*7080|int) - } - } - service: { - foo: {} - } - service: { - bar: { - port: 8000 - } - } - service: { - baz: { - name: "foobar" - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 51 diff --git a/cue/testdata/fulleval/017_resolutions_in_struct_comprehension_keys.txtar b/cue/testdata/fulleval/017_resolutions_in_struct_comprehension_keys.txtar --- a/cue/testdata/fulleval/017_resolutions_in_struct_comprehension_keys.txtar +++ b/cue/testdata/fulleval/017_resolutions_in_struct_comprehension_keys.txtar @@ -1,16 +1,5 @@ -- in.cue -- a: {for _, b in ["c"] {"\(b+".")": "a"}} @test(eq, {"c.": "a"}) --- out/compile -- ---- in.cue -{ - a: { - for _, b in [ - "c", - ] { - "\((〈1;b〉 + "."))": "a" - } - } -} -- out/eval/stats -- Leaks: 2 Freed: 3 diff --git a/cue/testdata/fulleval/018_recursive_evaluation_within_list.txtar b/cue/testdata/fulleval/018_recursive_evaluation_within_list.txtar --- a/cue/testdata/fulleval/018_recursive_evaluation_within_list.txtar +++ b/cue/testdata/fulleval/018_recursive_evaluation_within_list.txtar @@ -17,30 +17,6 @@ [incomplete] b1.d: non-concrete value string in operand to +: ./in.cue:10:5 ./in.cue:11:5 --- out/compile -- ---- in.cue -{ - l: [ - 〈1;a〉, - ] - a: (〈0;b〉 & { - c: "t" - }) - b: { - d: 〈0;c〉 - c: string - } - l1: [ - 〈1;a1〉, - ] - a1: (〈0;b1〉 & { - c: "t" - }) - b1: { - d: ("s" + 〈0;c〉) - c: string - } -} -- out/eval/stats -- Leaks: 0 Freed: 21 diff --git a/cue/testdata/fulleval/020_complex_interaction_of_groundness.txtar b/cue/testdata/fulleval/020_complex_interaction_of_groundness.txtar --- a/cue/testdata/fulleval/020_complex_interaction_of_groundness.txtar +++ b/cue/testdata/fulleval/020_complex_interaction_of_groundness.txtar @@ -16,37 +16,6 @@ ./in.cue:4:34 ./in.cue:4:23 ./in.cue:5:13 --- out/compile -- ---- in.cue -{ - res: [ - for _, x in 〈1;a〉 for _, y in 〈0;x〉 { - (〈1;y〉 & { - d: "b" - }) - }, - ] - res: [ - (〈1;a〉.b.c & { - d: "b" - }), - ] - a: { - b: { - [string]: { - d: string - s: ("a" + 〈0;d〉) - } - } - } - a: { - b: { - c: { - d: string - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 10 diff --git a/cue/testdata/fulleval/021_complex_groundness_2.txtar b/cue/testdata/fulleval/021_complex_groundness_2.txtar --- a/cue/testdata/fulleval/021_complex_groundness_2.txtar +++ b/cue/testdata/fulleval/021_complex_groundness_2.txtar @@ -45,42 +45,6 @@ ./in.cue:15:14 ./in.cue:20:23 ./in.cue:21:13 --- out/compile -- ---- in.cue -{ - r1: (〈0;f1〉 & { - y: "c" - }) - f1: { - y: string - res: (〈1;a〉.b.c & { - d: 〈1;y〉 - }) - } - a: { - b: { - c: { - d: string - s: ("a" + 〈0;d〉) - } - } - } - a: { - b: { - [string]: { - d: string - s: ("a" + 〈0;d〉) - } - } - } - a: { - b: { - c: { - d: string - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 16 diff --git a/cue/testdata/fulleval/022_references_from_template_to_concrete.txtar b/cue/testdata/fulleval/022_references_from_template_to_concrete.txtar --- a/cue/testdata/fulleval/022_references_from_template_to_concrete.txtar +++ b/cue/testdata/fulleval/022_references_from_template_to_concrete.txtar @@ -19,24 +19,3 @@ Unifications: 14 Conjuncts: 21 Disjuncts: 15 --- out/compile -- ---- in.cue -{ - res: [ - 〈1;t〉, - ] - t: { - [string]: { - a: (〈0;c〉 + 〈0;b〉.str) - b: { - str: string - } - c: "X" - } - x: { - b: { - str: "DDDD" - } - } - } -} diff --git a/cue/testdata/fulleval/024_Issue_#23.txtar b/cue/testdata/fulleval/024_Issue_#23.txtar --- a/cue/testdata/fulleval/024_Issue_#23.txtar +++ b/cue/testdata/fulleval/024_Issue_#23.txtar @@ -25,15 +25,3 @@ Unifications: 7 Conjuncts: 15 Disjuncts: 11 --- out/compile -- ---- in.cue -{ - x: ({ - a: 1 - }|{ - a: 2 - }) - y: (〈0;x〉 & { - a: 3 - }) -} diff --git a/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar b/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar --- a/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar +++ b/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar @@ -58,27 +58,6 @@ ./in.cue:20:6 -- out/todo.txt -- n1.min and n1.max: v2 reports "cycle error" without position details; v3 reports the full cycle with positions. --- out/compile -- ---- in.cue -{ - n1: { - min: <〈0;max〉 - max: >〈0;min〉 - } - n2: -〈0;num〉 - n3: +〈0;num〉 - n4: (〈0;num〉 + 〈0;num〉) - n5: (〈0;num〉 - 〈0;num〉) - n6: (〈0;num〉 * 〈0;num〉) - n7: (〈0;num〉 / 〈0;num〉) - b1: !〈0;is〉 - s1: "\(〈0;str〉)" - s2: 〈import;strings〉.ContainsAny("dd") - s3: 〈import;strings〉.ContainsAny(〈0;str〉, "dd") - str: string - num: <4 - is: bool -} -- out/eval/stats -- Leaks: 0 Freed: 17 diff --git a/cue/testdata/fulleval/027_len_of_incomplete_types.txtar b/cue/testdata/fulleval/027_len_of_incomplete_types.txtar --- a/cue/testdata/fulleval/027_len_of_incomplete_types.txtar +++ b/cue/testdata/fulleval/027_len_of_incomplete_types.txtar @@ -29,36 +29,3 @@ Unifications: 27 Conjuncts: 37 Disjuncts: 10 --- out/compile -- ---- in.cue -{ - args: (*[]|[ - ...string, - ]) - v1: len(〈0;args〉) - v2: len([]) - v3: len({}) - v4: len({ - a: 3 - }) - v5: len(({ - a: 3 - }|{ - a: 4 - })) - v6: len(('sf'|'dd')) - v7: len(([ - 2, - ]|*[ - 1, - 2, - ])) - v8: len(([ - 2, - ]|[ - 1, - 2, - ])) - v9: len("😂") - v10: len("") -} diff --git a/cue/testdata/fulleval/028_slice_rewrite_bug.txtar b/cue/testdata/fulleval/028_slice_rewrite_bug.txtar --- a/cue/testdata/fulleval/028_slice_rewrite_bug.txtar +++ b/cue/testdata/fulleval/028_slice_rewrite_bug.txtar @@ -16,25 +16,6 @@ } }) } --- out/compile -- ---- in.cue -{ - t1: { - fn: { - arg: ([ - ...int, - ] & [ - 1, - ]) - out: 〈0;arg〉[1:] - } - fn1: (〈0;fn〉 & { - arg: [ - 1, - ] - }) - } -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/fulleval/029_Issue_#94.txtar b/cue/testdata/fulleval/029_Issue_#94.txtar --- a/cue/testdata/fulleval/029_Issue_#94.txtar +++ b/cue/testdata/fulleval/029_Issue_#94.txtar @@ -48,33 +48,3 @@ MisalignedConjunct: 1 NumCloseIDs: 1 --- out/compile -- ---- in.cue -{ - foo: { - opt?: 1 - txt: 2 - #def: 3 - regular: 4 - _hidden: 5 - } - comp: { - for k, v in 〈1;foo〉 { - "\(〈1;k〉)": 〈1;v〉 - } - } - select: { - opt: 〈1;foo〉.opt - txt: 〈1;foo〉.txt - #def: 〈1;foo〉.#def - regular: 〈1;foo〉.regular - _hidden: 〈1;foo〉._hidden - } - index: { - opt: 〈1;foo〉["opt"] - txt: 〈1;foo〉["txt"] - #def: 〈1;foo〉["#def"] - regular: 〈1;foo〉["regular"] - _hidden: 〈1;foo〉["_hidden"] - } -} diff --git a/cue/testdata/fulleval/030_retain_references_with_interleaved_embedding.txtar b/cue/testdata/fulleval/030_retain_references_with_interleaved_embedding.txtar --- a/cue/testdata/fulleval/030_retain_references_with_interleaved_embedding.txtar +++ b/cue/testdata/fulleval/030_retain_references_with_interleaved_embedding.txtar @@ -17,31 +17,6 @@ a: [Name=string]: {#info: { X: "foo" }} --- out/compile -- ---- in.cue -{ - a: { - d: { - 〈2;#base〉 - #info: { - ... - } - Y: 〈0;#info〉.X - } - } - #base: { - #info: { - ... - } - } - a: { - [string]: { - #info: { - X: "foo" - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/fulleval/031_comparison_against_bottom.txtar b/cue/testdata/fulleval/031_comparison_against_bottom.txtar --- a/cue/testdata/fulleval/031_comparison_against_bottom.txtar +++ b/cue/testdata/fulleval/031_comparison_against_bottom.txtar @@ -34,33 +34,3 @@ Unifications: 21 Conjuncts: 28 Disjuncts: 21 --- out/compile -- ---- in.cue -{ - a: (_|_(explicit error (_|_ literal) in source) == _|_(explicit error (_|_ literal) in source)) - b: ((〈0;err〉 == 1) & 2) - c: (〈0;err〉 == _|_(explicit error (_|_ literal) in source)) - d: (〈0;err〉 != _|_(explicit error (_|_ literal) in source)) - e: ((〈0;err〉 != 1) & 3) - f: (({ - a: 1 - } & { - a: 2 - }) == _|_(explicit error (_|_ literal) in source)) - g: (({ - a: 1 - } & { - b: 2 - }) == _|_(explicit error (_|_ literal) in source)) - h: (_|_(explicit error (_|_ literal) in source) == ({ - a: 1 - } & { - a: 2 - })) - i: (_|_(explicit error (_|_ literal) in source) == ({ - a: 1 - } & { - b: 2 - })) - err: (1 & 2) -} diff --git a/cue/testdata/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar b/cue/testdata/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar --- a/cue/testdata/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar +++ b/cue/testdata/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar @@ -21,25 +21,6 @@ -- out/errors.txt -- [incomplete] #Workflow.#JobID: error in call to or: empty list in call to or: ./in.cue:6:10 --- out/compile -- ---- in.cue -{ - #Workflow: { - jobs: { - [string]: {} - } - #JobID: or([ - for k, _ in 〈1;jobs〉 { - 〈1;k〉 - }, - ]) - } - foo: (〈0;#Workflow〉 & { - jobs: { - foo: {} - } - }) -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/fulleval/034_label_and_field_aliases.txtar b/cue/testdata/fulleval/034_label_and_field_aliases.txtar --- a/cue/testdata/fulleval/034_label_and_field_aliases.txtar +++ b/cue/testdata/fulleval/034_label_and_field_aliases.txtar @@ -27,25 +27,6 @@ str: (int){ 5 } } """) --- out/compile -- ---- in.cue -{ - p: { - [string]: { - name: 〈1;-〉 - } - } - p: { - q: _ - } - "foo=bar": "str" - a: 〈0;"foo=bar"〉 - bb: 4 - b1: 〈0;bb〉 - b1: 〈0;bb〉 - "\(〈0;a〉)": 5 - c: 〈0;("\(〈0;a〉)")〉 -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/fulleval/035_optionals_with_label_filters.txtar b/cue/testdata/fulleval/035_optionals_with_label_filters.txtar --- a/cue/testdata/fulleval/035_optionals_with_label_filters.txtar +++ b/cue/testdata/fulleval/035_optionals_with_label_filters.txtar @@ -43,54 +43,6 @@ ./in.cue:25:8 -- out/todo.txt -- v2 reports additional error positions for jobs1.foo1 and jobs3.fooTest1 (extra positions for pattern/optional constraints); v3 only reports the direct definition position. --- out/compile -- ---- in.cue -{ - #JobID: =~"^[a-zA-Z]*$" - #Job: { - name: string - cmd: string - } - #Jobs: { - { - [〈2;#JobID〉]: 〈2;#Job〉 - } - { - [=~"Test$"]: { - name: =~"^test" - } - } - } - jobs: { - foo: { - name: "allGood" - } - } - jobs: { - foo: { - name: "allGood" - } - } - jobs1: 〈0;#Jobs〉 - jobs1: { - foo1: {} - } - jobs2: 〈0;#Jobs〉 - jobs2: { - fooTest: { - name: "badName" - } - } - jobs3: 〈0;#Jobs〉 - jobs3: { - [string]: 〈1;#Job〉 - } - jobs3: { - fooTest1: { - name: "badName" - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 19 diff --git a/cue/testdata/fulleval/040.txtar b/cue/testdata/fulleval/040.txtar --- a/cue/testdata/fulleval/040.txtar +++ b/cue/testdata/fulleval/040.txtar @@ -23,24 +23,6 @@ tagExpr: "latestdd" tagInString: "latest" }) --- out/compile -- ---- in.cue -{ - #Task: { - ({ - op: "pull" - tag: (*"latest"|string) - refToTag: 〈0;tag〉 - tagExpr: (〈0;tag〉 + "dd") - tagInString: "\(〈0;tag〉)" - }|{ - op: "scratch" - }) - } - foo: (〈0;#Task〉 & { - op: "pull" - }) -} -- out/eval/stats -- Leaks: 8 Freed: 16 diff --git a/cue/testdata/fulleval/041.txtar b/cue/testdata/fulleval/041.txtar --- a/cue/testdata/fulleval/041.txtar +++ b/cue/testdata/fulleval/041.txtar @@ -24,16 +24,3 @@ MisalignedConjunct: 1 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - t: { - #ok: (*true|bool) - if 〈0;#ok〉 { - x: int - } - } - s: (〈0;t〉 & { - #ok: false - }) -} diff --git a/cue/testdata/fulleval/042_cross-dependent_comprehension.txtar b/cue/testdata/fulleval/042_cross-dependent_comprehension.txtar --- a/cue/testdata/fulleval/042_cross-dependent_comprehension.txtar +++ b/cue/testdata/fulleval/042_cross-dependent_comprehension.txtar @@ -26,19 +26,3 @@ Disjuncts: 12 NumCloseIDs: 3 --- out/compile -- ---- in.cue -{ - #a: { - if 〈0;b〉 { - c: 4 - } - b: bool - } - x: ((〈0;#a〉 & { - b: true - }) & { - c: 4 - }) - y: 〈0;x〉 -} diff --git a/cue/testdata/fulleval/043_optional_expanded_before_lookup.txtar b/cue/testdata/fulleval/043_optional_expanded_before_lookup.txtar --- a/cue/testdata/fulleval/043_optional_expanded_before_lookup.txtar +++ b/cue/testdata/fulleval/043_optional_expanded_before_lookup.txtar @@ -15,22 +15,6 @@ field2: "2" name: "A" }) --- out/compile -- ---- in.cue -{ - test: { - [_]: { - name: 〈1;-〉 - } - } - test: { - A: { - field1: "1" - field2: "2" - } - } - B: (〈0;test〉.A & {}) -} -- out/eval/stats -- Leaks: 0 Freed: 10 diff --git a/cue/testdata/fulleval/044_Issue_#178.txtar b/cue/testdata/fulleval/044_Issue_#178.txtar --- a/cue/testdata/fulleval/044_Issue_#178.txtar +++ b/cue/testdata/fulleval/044_Issue_#178.txtar @@ -32,11 +32,3 @@ Unifications: 5 Conjuncts: 13 Disjuncts: 10 --- out/compile -- ---- in.cue -{ - foo: 〈import;"encoding/csv"〉.Decode(〈0;data〉) - data: bytes - len: int - bar: 〈import;"encoding/hex"〉.EncodedLen(〈0;len〉) -} diff --git a/cue/testdata/fulleval/046_non-structural_direct_cycles.txtar b/cue/testdata/fulleval/046_non-structural_direct_cycles.txtar --- a/cue/testdata/fulleval/046_non-structural_direct_cycles.txtar +++ b/cue/testdata/fulleval/046_non-structural_direct_cycles.txtar @@ -26,15 +26,3 @@ Unifications: 7 Conjuncts: 10 Disjuncts: 8 --- out/compile -- ---- in.cue -{ - c1: ({ - bar: { - baz: 2 - } - } & 〈0;c1〉.bar) - c2: ({ - bar: 1 - } & 〈0;c2〉.bar) -} diff --git a/cue/testdata/fulleval/047_dont_bind_to_string_labels.txtar b/cue/testdata/fulleval/047_dont_bind_to_string_labels.txtar --- a/cue/testdata/fulleval/047_dont_bind_to_string_labels.txtar +++ b/cue/testdata/fulleval/047_dont_bind_to_string_labels.txtar @@ -5,15 +5,6 @@ "x": 2 z: x @test(eq, 1) } --- out/compile -- ---- in.cue -{ - x: 1 - y: { - x: 2 - z: 〈1;x〉 - } -} -- out/eval/stats -- Leaks: 0 Freed: 5 diff --git a/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar b/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar --- a/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar +++ b/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar @@ -18,9 +18,3 @@ Unifications: 3 Conjuncts: 3 Disjuncts: 0 --- out/compile -- ---- in.cue -{ - input: string - foo: 〈import;"encoding/json"〉.Marshal(〈0;input〉) -} diff --git a/cue/testdata/fulleval/049_alias_reuse_in_nested_scope.txtar b/cue/testdata/fulleval/049_alias_reuse_in_nested_scope.txtar --- a/cue/testdata/fulleval/049_alias_reuse_in_nested_scope.txtar +++ b/cue/testdata/fulleval/049_alias_reuse_in_nested_scope.txtar @@ -34,38 +34,3 @@ Unifications: 29 Conjuncts: 40 Disjuncts: 29 --- out/compile -- ---- in.cue -{ - #Foo: { - let X#1 = or([ - for k, _ in {} { - 〈1;k〉 - }, - ]) - connection: { - [〈1;let X#1〉]: 〈1;let X#1〉 - } - } - #A: { - foo: "key" - let X#2 = 〈0;foo〉 - a: { - foo: { - [〈2;let X#2〉]: 〈2;let X#2〉 - } - } - } - #B: { - foo: string - let X#3 = 〈0;foo〉 - a: { - foo: { - [〈2;let X#3〉]: 〈2;let X#3〉 - } - } - } - b: (〈0;#B〉 & { - foo: "key" - }) -} diff --git a/cue/testdata/fulleval/050_json_Marshaling_detects_incomplete.txtar b/cue/testdata/fulleval/050_json_Marshaling_detects_incomplete.txtar --- a/cue/testdata/fulleval/050_json_Marshaling_detects_incomplete.txtar +++ b/cue/testdata/fulleval/050_json_Marshaling_detects_incomplete.txtar @@ -29,15 +29,3 @@ Unifications: 16 Conjuncts: 24 Disjuncts: 21 --- out/compile -- ---- in.cue -{ - a: 〈import;"encoding/json"〉.Marshal({ - a: string - }) - foo: { - a: 3 - b: 〈1;foo〉.c - } - b: 〈import;"encoding/json"〉.Marshal(〈0;foo〉) -} diff --git a/cue/testdata/fulleval/051_detectIncompleteYAML.txtar b/cue/testdata/fulleval/051_detectIncompleteYAML.txtar --- a/cue/testdata/fulleval/051_detectIncompleteYAML.txtar +++ b/cue/testdata/fulleval/051_detectIncompleteYAML.txtar @@ -42,24 +42,3 @@ Unifications: 17 Conjuncts: 32 Disjuncts: 17 --- out/compile -- ---- in.cue -{ - #Spec: { - _vars(:foobar): { - something: string - } - data: { - #foo: { - use: 〈2;_vars(:foobar)〉.something - } - baz: 〈import;"encoding/yaml"〉.Marshal(〈1;_vars(:foobar)〉.something) - foobar: 〈import;"encoding/yaml"〉.Marshal(〈0;#foo〉) - } - } - Val: (〈0;#Spec〉 & { - _vars(:foobar): { - something: "var-string" - } - }) -} diff --git a/cue/testdata/fulleval/052_detectIncompleteJSON.txtar b/cue/testdata/fulleval/052_detectIncompleteJSON.txtar --- a/cue/testdata/fulleval/052_detectIncompleteJSON.txtar +++ b/cue/testdata/fulleval/052_detectIncompleteJSON.txtar @@ -41,24 +41,3 @@ Unifications: 17 Conjuncts: 32 Disjuncts: 17 --- out/compile -- ---- in.cue -{ - #Spec: { - _vars(:foobar): { - something: string - } - data: { - #foo: { - use: 〈2;_vars(:foobar)〉.something - } - baz: 〈import;"encoding/json"〉.Marshal(〈1;_vars(:foobar)〉.something) - foobar: 〈import;"encoding/json"〉.Marshal(〈0;#foo〉) - } - } - Val: (〈0;#Spec〉 & { - _vars(:foobar): { - something: "var-string" - } - }) -} diff --git a/cue/testdata/fulleval/053_issue312.txtar b/cue/testdata/fulleval/053_issue312.txtar --- a/cue/testdata/fulleval/053_issue312.txtar +++ b/cue/testdata/fulleval/053_issue312.txtar @@ -11,17 +11,6 @@ } @test(eq, *{} | {}) --- out/compile -- ---- in.cue -{ - for _, x in [ - 1, - ] { - (*close({})|{ - [_]: null - }) - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/fulleval/054_issue312.txtar b/cue/testdata/fulleval/054_issue312.txtar --- a/cue/testdata/fulleval/054_issue312.txtar +++ b/cue/testdata/fulleval/054_issue312.txtar @@ -6,20 +6,6 @@ a: 2 y: *1 | { a: 2 } }) --- out/compile -- ---- in.cue -{ - x: { - y: (*1|{ - a: 2 - }) - for _, x in [ - 1, - ] { - 〈2;y〉 - } - } -} -- out/eval/stats -- Leaks: 1 Freed: 8 diff --git a/cue/testdata/fulleval/055_issue318.txtar b/cue/testdata/fulleval/055_issue318.txtar --- a/cue/testdata/fulleval/055_issue318.txtar +++ b/cue/testdata/fulleval/055_issue318.txtar @@ -23,19 +23,6 @@ ./in.cue:6:15 [eval] #T.vy: undefined field: y: ./in.cue:8:12 --- out/compile -- ---- in.cue -{ - #T: { - arg: { - x: string - } - out1: "\(〈0;arg〉.x) \(〈0;arg〉.y)" - out2: "\(〈0;arg〉.y)" - vx: 〈0;arg〉.x - vy: 〈0;arg〉.y - } -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/inlinetest/closedness.txtar b/cue/testdata/inlinetest/closedness.txtar --- a/cue/testdata/inlinetest/closedness.txtar +++ b/cue/testdata/inlinetest/closedness.txtar @@ -32,42 +32,3 @@ t4: _ @test(closed) t4: _ @test(allows, "string") // quoted: literal field named string t4: _ @test(allows=false, string) // unquoted: any-string pattern not present --- out/compile -- ---- in.cue -{ - t1: close({ - b: {} - }) - t1: _ - t1: { - b: _ - } - t1: _ - t1: _ - #X: { - [=~"^Q*$"]: int - } - #X: _ - #X: _ - #X: _ - #X: _ - t2: 〈0;#X〉 - t2: _ - t2: _ - t2: _ - t2: _ - #Y: { - ... - } - t3: 〈0;#Y〉 - t3: _ - t3: _ - t3: _ - t3: _ - t4: close({ - string: 1 - }) - t4: _ - t4: _ - t4: _ -} diff --git a/cue/testdata/inlinetest/debug.txtar b/cue/testdata/inlinetest/debug.txtar --- a/cue/testdata/inlinetest/debug.txtar +++ b/cue/testdata/inlinetest/debug.txtar @@ -48,19 +48,3 @@ """) z: 99 } --- out/compile -- ---- in.cue -{ - debugCheckScalar: 42 - debugCheckStruct: { - a: 1 - b: 2 - } - debugCheckComputed: { - x: 10 - y: (〈0;x〉 * 2) - } - debugCheckVersioned: { - z: 99 - } -} diff --git a/cue/testdata/inlinetest/decl_eq.txtar b/cue/testdata/inlinetest/decl_eq.txtar --- a/cue/testdata/inlinetest/decl_eq.txtar +++ b/cue/testdata/inlinetest/decl_eq.txtar @@ -17,13 +17,3 @@ y: 2 } }) --- out/compile -- ---- in.cue -{ - a: 1 - b: (〈0;a〉 + 1) - c: { - x: "hello" - y: 〈1;b〉 - } -} diff --git a/cue/testdata/inlinetest/decl_eq_mixed.txtar b/cue/testdata/inlinetest/decl_eq_mixed.txtar --- a/cue/testdata/inlinetest/decl_eq_mixed.txtar +++ b/cue/testdata/inlinetest/decl_eq_mixed.txtar @@ -6,9 +6,3 @@ x: 1 @test(eq, 1) y: x + 1 @test(eq, {x: 1, y: 2}) --- out/compile -- ---- in.cue -{ - x: 1 - y: (〈0;x〉 + 1) -} diff --git a/cue/testdata/inlinetest/decl_eq_pattern.txtar b/cue/testdata/inlinetest/decl_eq_pattern.txtar --- a/cue/testdata/inlinetest/decl_eq_pattern.txtar +++ b/cue/testdata/inlinetest/decl_eq_pattern.txtar @@ -5,13 +5,3 @@ {[X=string]: baz: X} bar: {} @test(eq, {bar: baz: "bar"}) --- out/compile -- ---- in.cue -{ - { - [string]: { - baz: 〈1;-〉 - } - } - bar: {} -} diff --git a/cue/testdata/inlinetest/hidden_fields.txtar b/cue/testdata/inlinetest/hidden_fields.txtar --- a/cue/testdata/inlinetest/hidden_fields.txtar +++ b/cue/testdata/inlinetest/hidden_fields.txtar @@ -31,25 +31,3 @@ // No hidden fields on either side: passes trivially. noHidden: {a: 1, b: 2} @test(eq, {a: 1, b: 2}) --- out/compile -- ---- in.cue -{ - hiddenInBoth: { - _secret(:foo): 42 - a: (〈0;_secret(:foo)〉 + 1) - } - hiddenDeclForm: { - _secret(:foo): "x" - b: (〈0;_secret(:foo)〉 + 〈0;_secret(:foo)〉) - } - hiddenDefInBoth: { - _#Meta(:foo): { - info: "internal" - } - a: 1 - } - noHidden: { - a: 1 - b: 2 - } -} diff --git a/cue/testdata/inlinetest/permute.txtar b/cue/testdata/inlinetest/permute.txtar --- a/cue/testdata/inlinetest/permute.txtar +++ b/cue/testdata/inlinetest/permute.txtar @@ -69,33 +69,3 @@ } }) } --- out/compile -- ---- in.cue -{ - threeFieldPermute: { - a: (〈0;b〉 + 〈0;c〉) - b: 1 - c: 2 - } - twoFieldPermute: { - x: (〈0;y〉 + 1) - y: 5 - } - inDeclPermute: { - p: (〈0;q〉 + 〈0;r〉) - q: 3 - r: 7 - } - concretePermute: { - x: { - alpha: 1 - beta: 2 - gamma: 3 - } - y: { - alpha: 1 - beta: 2 - gamma: 3 - } - } -} diff --git a/cue/testdata/inlinetest/struct_eq.txtar b/cue/testdata/inlinetest/struct_eq.txtar --- a/cue/testdata/inlinetest/struct_eq.txtar +++ b/cue/testdata/inlinetest/struct_eq.txtar @@ -4,11 +4,3 @@ a: 1 b: a + 1 } --- out/compile -- ---- in.cue -{ - myStruct: { - a: 1 - b: (〈0;a〉 + 1) - } -} diff --git a/cue/testdata/inlinetest/structural.txtar b/cue/testdata/inlinetest/structural.txtar --- a/cue/testdata/inlinetest/structural.txtar +++ b/cue/testdata/inlinetest/structural.txtar @@ -50,31 +50,3 @@ [eval] errWithCode: conflicting values string and 1 (mismatched types string and int): ./in.cue:7:14 ./in.cue:7:23 --- out/compile -- ---- in.cue -{ - errOnly: (1 & 2) - errWithCode: (string & 1) - eqBasic: { - a: 1 - b: 2 - } - eqComputed: { - x: 10 - y: (〈0;x〉 * 2) - } - skippedTest: { - a: 1 - } - descTest: { - v: "ok" - } - versionOverride: { - x: 1 - } - plainFixture: { - x: 42 - } - refsFixture: 〈0;plainFixture〉.x - mixedInline: 42 -} diff --git a/cue/testdata/inlinetest/validators.txtar b/cue/testdata/inlinetest/validators.txtar --- a/cue/testdata/inlinetest/validators.txtar +++ b/cue/testdata/inlinetest/validators.txtar @@ -11,13 +11,3 @@ intMixDirect: int & <=1 @test(eq, <=1 & int) intMixEmbed: {int & <=1} @test(eq, {<=1 & int}) --- out/compile -- ---- in.cue -{ - rawMax: 〈import;struct〉.MaxFields(2) - rawMin: 〈import;struct〉.MinFields(3) - intMixDirect: (int & <=1) - intMixEmbed: { - (int & <=1) - } -} diff --git a/cue/testdata/interpolation/041_interpolation.txtar b/cue/testdata/interpolation/041_interpolation.txtar --- a/cue/testdata/interpolation/041_interpolation.txtar +++ b/cue/testdata/interpolation/041_interpolation.txtar @@ -15,17 +15,6 @@ [eval] e: invalid interpolation: cannot use [] (type list) as type (bool|string|bytes|number): ./in.cue:7:4 ./in.cue:7:7 --- out/compile -- ---- in.cue -{ - a: "\(4)" - b: "one \(〈0;a〉) two \((〈0;a〉 + 〈0;c〉))" - c: "one" - d: "\(〈0;r〉)" - u: "\(_)" - r: _ - e: "\([])" -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/interpolation/042_multiline_interpolation.txtar b/cue/testdata/interpolation/042_multiline_interpolation.txtar --- a/cue/testdata/interpolation/042_multiline_interpolation.txtar +++ b/cue/testdata/interpolation/042_multiline_interpolation.txtar @@ -44,34 +44,6 @@ 4) """ @test(eq, "\n4\n") --- out/compile -- ---- in.cue -{ - a1: "before - \(4) - after" - a2: "before - \(4) - " - a3: " - \(4) - after" - a4: " - \(4) - " - m1: "before - \(4) - after" - m2: "before - \(4) - " - m3: " - \(4) - after" - m4: " - \(4) - " -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/interpolation/incomplete.txtar b/cue/testdata/interpolation/incomplete.txtar --- a/cue/testdata/interpolation/incomplete.txtar +++ b/cue/testdata/interpolation/incomplete.txtar @@ -28,19 +28,3 @@ Unifications: 7 Conjuncts: 11 Disjuncts: 7 --- out/compile -- ---- in.cue -{ - a: "foo" - b: "boo" - commands: { - #c: { - help: "help!" - } - } - out: "a is \(〈0;a〉) - b is \(〈0;b〉) - - c is \(〈0;commands〉.#c.help) - d is \(〈0;commands〉.#d.help)" -} diff --git a/cue/testdata/interpolation/issue487.txtar b/cue/testdata/interpolation/issue487.txtar --- a/cue/testdata/interpolation/issue487.txtar +++ b/cue/testdata/interpolation/issue487.txtar @@ -36,25 +36,3 @@ Unifications: 15 Conjuncts: 29 Disjuncts: 15 --- out/compile -- ---- in.cue -{ - t1: { - #R: { - pos: &(int, >=0) - name: "hello_\(〈0;pos〉)" - } - a: (〈0;#R〉 & { - pos: 67 - }) - } - t2: { - #R: { - pos: string - name: "hello_\(〈0;pos〉)" - } - a: (〈0;#R〉 & { - pos: "a" - }) - } -} diff --git a/cue/testdata/interpolation/scalars.txtar b/cue/testdata/interpolation/scalars.txtar --- a/cue/testdata/interpolation/scalars.txtar +++ b/cue/testdata/interpolation/scalars.txtar @@ -28,21 +28,6 @@ Unifications: 11 Conjuncts: 12 Disjuncts: 0 --- out/compile -- ---- in.cue -{ - bool1: "1+1=2: \(true)" - bool1: "1+1=2: \(true)" - bool2: "1+1=1: \(false)" - b1: 'a\xed\x95a' - bytes1s: "\(〈0;b1〉)" - bytes1b: '\(〈0;b1〉)' - b2: 'a\x80\x95a' - bytes2s: "\(〈0;b2〉)" - bytes2b: '\(〈0;b2〉)' - n1: "\(1) \(2.00)" - n2: "\(1E+2)" -} -- out/diff-v2-v3.txt -- v2 produces two replacement characters for bytes2s ("a\uFFFD\uFFFDa"); v3 produces one ("a\uFFFDa"). Reason: V2 implements Go conversions standard, which diff --git a/cue/testdata/lists/019_list_types.txtar b/cue/testdata/lists/019_list_types.txtar --- a/cue/testdata/lists/019_list_types.txtar +++ b/cue/testdata/lists/019_list_types.txtar @@ -27,74 +27,6 @@ e1: [...float] @test(eq, []) -- out/errors.txt -- [eval] e0: incompatible list lengths (1 and 2) --- out/compile -- ---- in.cue -{ - l0: 〈import;list〉.Repeat([ - int, - ], 3) - l0: [ - 1, - 2, - 3, - ] - l2: [ - ...{ - a: int - }, - ] - l2: [ - { - a: 1 - }, - { - a: 2 - b: 3 - }, - ] - s1: 〈import;list〉.Repeat([ - int, - ], 6)[2:3] - s2: [ - 0, - 2, - 3, - ][1:2] - i1: 〈import;list〉.Repeat([ - int, - ], 6)[2] - i2: [ - 0, - 2, - 3, - ][2] - t0: [ - ...{ - a: 8 - }, - ] - t0: [ - {}, - ] - t1: [ - ..., - ] - t1: [ - ...int, - ] - e0: 〈import;list〉.Repeat([ - {}, - ], 2) - e0: [ - {}, - ] - e1: [ - ...int, - ] - e1: [ - ...float, - ] -} -- out/eval/stats -- Leaks: 0 Freed: 41 diff --git a/cue/testdata/lists/020_list_compilefail.txtar b/cue/testdata/lists/020_list_compilefail.txtar --- a/cue/testdata/lists/020_list_compilefail.txtar +++ b/cue/testdata/lists/020_list_compilefail.txtar @@ -12,53 +12,6 @@ c: [1, 2, ...] d: >=2 * [int] d: [1, 2, ...] --- out/compile -- -l3: invalid operand <=2 ('*' requires concrete value): - ./in.cue:1:5 -l4: invalid operand <=2 ('*' requires concrete value): - ./in.cue:2:5 -l5: invalid operand <=2 ('*' requires concrete value): - ./in.cue:3:5 -l5: invalid operand int ('*' requires concrete value): - ./in.cue:3:12 -b: invalid operand <=5 ('*' requires concrete value): - ./in.cue:4:5 -d: invalid operand >=2 ('*' requires concrete value): - ./in.cue:8:4 ---- in.cue -{ - l3: (<=2 * []) - l4: (<=2 * [ - int, - ]) - l5: (<=2 * (int * [ - int, - ])) - b: (<=5 * [ - int, - ]) - b: [ - 1, - 2, - ..., - ] - c: ((>=3 & <=5) * [ - int, - ]) - c: [ - 1, - 2, - ..., - ] - d: (>=2 * [ - int, - ]) - d: [ - 1, - 2, - ..., - ] -} -- out/evalalpha -- l3: invalid operand <=2 ('*' requires concrete value): ./in.cue:1:5 diff --git a/cue/testdata/lists/021_list_equality.txtar b/cue/testdata/lists/021_list_equality.txtar --- a/cue/testdata/lists/021_list_equality.txtar +++ b/cue/testdata/lists/021_list_equality.txtar @@ -67,285 +67,6 @@ ./in.cue:61:16 [incomplete] neIncomplete1: invalid right-hand value to '!=' (type list): 0: incomplete value string: ./in.cue:63:16 --- out/compile -- ---- in.cue -{ - eq0: ([] == []) - eq1: ([ - ..., - ] == []) - eq2: ([] == [ - ..., - ]) - eq3: ([ - ..., - ] == [ - ..., - ]) - eq4: ([ - 1, - ] == [ - 1, - ]) - eq5: ([ - 1, - ..., - ] == [ - 1, - ]) - eq6: ([ - 1, - ] == [ - 1, - ..., - ]) - eq7: ([ - 1, - ..., - ] == [ - 1, - ..., - ]) - eq8: ([ - 1, - 2, - ] == [ - 1, - 2, - ]) - eq9: ([ - 1, - 2, - ..., - ] == [ - 1, - 2, - ]) - eq10: ([ - 1, - 2, - ] == [ - 1, - 2, - ..., - ]) - eq11: ([ - 1, - 2, - ..., - ] == [ - 1, - 2, - ..., - ]) - ne0: ([] != []) - ne1: ([ - ..., - ] != []) - ne2: ([] != [ - ..., - ]) - ne3: ([ - ..., - ] != [ - ..., - ]) - ne4: ([ - 1, - ] != [ - 1, - ]) - ne5: ([ - 1, - ..., - ] != [ - 1, - ]) - ne6: ([ - 1, - ] != [ - 1, - ..., - ]) - ne7: ([ - 1, - ..., - ] != [ - 1, - ..., - ]) - ne8: ([ - 1, - 2, - ] != [ - 1, - 2, - ]) - ne9: ([ - 1, - 2, - ..., - ] != [ - 1, - 2, - ]) - ne10: ([ - 1, - 2, - ] != [ - 1, - 2, - ..., - ]) - ne11: ([ - 1, - 2, - ..., - ] != [ - 1, - 2, - ..., - ]) - feq0: ([] == [ - 1, - ]) - feq1: ([ - ..., - ] == [ - 1, - ]) - feq2: ([] == [ - 1, - ..., - ]) - feq3: ([ - ..., - ] == [ - 1, - ..., - ]) - feq4: ([ - 1, - ] == []) - feq5: ([ - 1, - ..., - ] == []) - feq6: ([ - 1, - ] == [ - ..., - ]) - feq7: ([ - 1, - ..., - ] == [ - ..., - ]) - feq8: ([ - 1, - 2, - ] == [ - 1, - ]) - feq9: ([ - 1, - ..., - ] == [ - 1, - 2, - ]) - feq10: ([ - 1, - 2, - ] == [ - 1, - ..., - ]) - feq11: ([ - 1, - ..., - ] == [ - 1, - 2, - ..., - ]) - fne0: ([] != [ - 1, - ]) - fne1: ([ - ..., - ] != [ - 1, - ]) - fne2: ([] != [ - 1, - ..., - ]) - fne3: ([ - 1, - ..., - ] != [ - 1, - ..., - ]) - fne4: ([ - 1, - ] != []) - fne5: ([ - 1, - ..., - ] != []) - fne6: ([ - 1, - ] != [ - ..., - ]) - fne7: ([ - 1, - ..., - ] != [ - ..., - ]) - fne8: ([ - 1, - 2, - ] != [ - 1, - ]) - fne9: ([ - 1, - ..., - ] != [ - 1, - 2, - ]) - fne10: ([ - 1, - 2, - ] != [ - 1, - ..., - ]) - fne11: ([ - 1, - ..., - ] != [ - 1, - 2, - ..., - ]) - eqIncomplete1: ([ - 1, - ] == [ - string, - ]) - neIncomplete1: ([ - 1, - ] != [ - string, - ]) -} -- out/eval/stats -- Leaks: 0 Freed: 244 diff --git a/cue/testdata/packages/builtin.txtar b/cue/testdata/packages/builtin.txtar --- a/cue/testdata/packages/builtin.txtar +++ b/cue/testdata/packages/builtin.txtar @@ -9,10 +9,3 @@ -- out/evalalpha -- builtin package "x/y" undefined: ./x.cue:1:8 --- out/compile -- ---- x.cue -{ - foo: [ - 〈import;"x/y"〉, - ] -} diff --git a/cue/testdata/packages/embed.txtar b/cue/testdata/packages/embed.txtar --- a/cue/testdata/packages/embed.txtar +++ b/cue/testdata/packages/embed.txtar @@ -38,9 +38,3 @@ Notifications: 1 NumCloseIDs: 9 --- out/compile -- ---- in.cue -{ - 〈import;"mod.test/pkg:bar"〉 - z: 3 -} diff --git a/cue/testdata/packages/issue398.txtar b/cue/testdata/packages/issue398.txtar --- a/cue/testdata/packages/issue398.txtar +++ b/cue/testdata/packages/issue398.txtar @@ -38,9 +38,3 @@ NumCloseIDs: 4 -- out/todo.txt -- Reordering --- out/compile -- ---- foo.cue -{ - 〈import;"mod.test/pkg:bar"〉 - zz: 3 -} diff --git a/cue/testdata/packages/sub.txtar b/cue/testdata/packages/sub.txtar --- a/cue/testdata/packages/sub.txtar +++ b/cue/testdata/packages/sub.txtar @@ -28,9 +28,3 @@ Disjuncts: 0 NumCloseIDs: 2 --- out/compile -- ---- in.cue -{ - #pkg1: 〈import;"mod.test/foo/pkg1"〉.Object - "Hello \(〈0;#pkg1〉)!" -} diff --git a/cue/testdata/references/alias.txtar b/cue/testdata/references/alias.txtar --- a/cue/testdata/references/alias.txtar +++ b/cue/testdata/references/alias.txtar @@ -216,154 +216,3 @@ ./in.cue:120:8 [incomplete] opt.b: cannot reference optional field: opt: ./in.cue:131:5 --- out/compile -- ---- in.cue -{ - a1: { - foo: 1 - } - b1: (〈0;a1〉.foo + 2) - a1p: { - foo: 1 - } - b1p: (〈0;a1p〉.foo + 2) - a2: { - name: "a2" - val: 〈1;a2〉.foo - } - a2: { - foo: 42 - } - a3: { - foo: 1 - } - b3: "a3" - a4: { - foo: 1 - } - b4: (〈0;a4〉.foo + 2) - "dyn": { - foo: 1 - } - b5: (〈0;("dyn")〉.foo + 10) - "dyn2": { - name: 〈1;-〉 - val: 〈1;("dyn2")〉.foo - } - dyn2: { - foo: 100 - } - pattern: { - [string]: { - labelRef: 〈1;-〉 - } - foo: {} - } - pattern2: { - [string]: { - labelVal: 〈1;-〉 - fieldVal: 〈1;(〈0;-〉)〉.data - } - foo: { - data: 1 - } - bar: { - data: 2 - } - } - nested: { - inner: { - a: 1 - } - b: (〈0;inner〉.a + 〈1;nested〉.inner.a) - } - result1: 〈0;nested〉.b - multi: { - a: 1 - b: (〈0;a〉 + 2) - c: (〈0;b〉 + 3) - } - comp: { - items: [ - 1, - 2, - 3, - ] - for i, v in 〈0;items〉 { - "\(〈1;i〉)": { - index: 〈2;i〉 - value: 〈2;v〉 - double: (〈1;("\(〈1;i〉)")〉.value * 2) - } - } - } - constrained?: { - required: true - } - test1: 〈0;constrained〉.required - "\("inter")": { - foo: 1 - } - b6: (〈0;("\("inter")")〉.foo + 5) - opt?: { - a: 1 - b: 〈1;opt〉 - } - def: ({ - b: 2 - c: 〈1;def〉.b - }|{ - b: 3 - }) - pattern3: { - [string]: { - labelName: 〈1;-〉 - } - test: {} - } - pattern4: { - [string]: { - fieldRef: 〈1;(〈0;-〉)〉.x - } - test: { - x: 99 - } - } - same: { - a: 1 - b: 2 - c: (〈0;a〉 + 〈0;b〉) - } - chain: { - a: 1 - } - chain2: { - ref: 〈1;chain〉.a - } - result2: 〈0;chain2〉.ref - list: [ - 1, - 2, - 3, - ] - b7: (〈0;list〉[0] + 〈0;list〉[1]) - disj: (1|2|3) - b8: 〈0;disj〉 - deep: { - [string]: { - [string]: { - outer: 〈2;-〉 - inner: 〈1;-〉 - value: 〈1;(〈0;-〉)〉.x - } - foo: { - x: 1 - } - } - bar: {} - } - #Def: { - field: 42 - } - usedef: 〈0;#Def〉.field -} diff --git a/cue/testdata/references/alias_err.txtar b/cue/testdata/references/alias_err.txtar --- a/cue/testdata/references/alias_err.txtar +++ b/cue/testdata/references/alias_err.txtar @@ -38,36 +38,3 @@ ./old.cue:9:2 issue2094: cyclic reference in field alias: ./old.cue:9:5 --- out/compile -- -issue2527: cyclic reference in field alias: - ./new.cue:6:3 -issue2094: cyclic reference in field alias: - ./new.cue:11:3 -issue2094: unreferenced alias or let clause Y: - ./new.cue:11:5 -issue2527: cyclic reference in field alias: - ./old.cue:4:5 -issue2094: unreferenced alias or let clause Y: - ./old.cue:9:2 -issue2094: cyclic reference in field alias: - ./old.cue:9:5 ---- new.cue -{ - issue2527: { - 〈0;(_|_(cyclic reference in field alias))〉: 3 - } - issue2094: { - 〈0;("foo")〉: string - "foo": "bar" - } -} ---- old.cue -{ - issue2527: { - 〈0;(_|_(cyclic reference in field alias))〉: 3 - } - issue2094: { - 〈0;("foo")〉: string - "foo": "bar" - } -} diff --git a/cue/testdata/references/embed_self.txtar b/cue/testdata/references/embed_self.txtar --- a/cue/testdata/references/embed_self.txtar +++ b/cue/testdata/references/embed_self.txtar @@ -12,9 +12,3 @@ Unifications: 2 Conjuncts: 4 Disjuncts: 3 --- out/compile -- ---- in.cue -{ - Foo: {} - 〈0;Foo〉 -} diff --git a/cue/testdata/references/errors.txtar b/cue/testdata/references/errors.txtar --- a/cue/testdata/references/errors.txtar +++ b/cue/testdata/references/errors.txtar @@ -55,28 +55,3 @@ Unifications: 17 Conjuncts: 17 Disjuncts: 0 --- out/compile -- ---- references.cue -{ - missingField: { - a: {} - r: 〈0;a〉.b - } - missingFieldClosed: { - #a: {} - r: 〈0;#a〉.b - } - missingFieldNested: { - a: {} - r: 〈0;a〉.b.c - } - missingFieldNestedClosed: { - #a: {} - r: 〈0;#a〉.d.c - } - missingFieldNestedInInterpolation: { - a: {} - r1: "\(〈0;a〉.b.c)" - r2: "\(〈0;a〉.d.c)" - } -} diff --git a/cue/testdata/references/incomplete.txtar b/cue/testdata/references/incomplete.txtar --- a/cue/testdata/references/incomplete.txtar +++ b/cue/testdata/references/incomplete.txtar @@ -55,36 +55,3 @@ Disjuncts: 0 NumCloseIDs: 4 --- out/compile -- ---- in.cue -{ - comprehensions: { - a: {} - b: { - if 〈1;a〉.b {} - } - c: { - for _, x in 〈1;a〉.b { - 〈1;x〉 - } - } - } - openStruct: { - a: {} - b: 〈0;a〉.c - } - selectFromTop: { - top: _ - a: 〈0;top〉.foo - } - indexOnTop: { - top: _ - a: 〈0;top〉[2] - } - incompleteIndex: { - top: _ - a: [ - 1, - ][〈0;top〉] - } -} diff --git a/cue/testdata/references/index.txtar b/cue/testdata/references/index.txtar --- a/cue/testdata/references/index.txtar +++ b/cue/testdata/references/index.txtar @@ -72,60 +72,3 @@ Disjuncts: 8 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - intIndex: [ - 2, - ][0] - stringIndex: { - foo: "bar" - }["foo"] - stringOfNumberIndex: { - "3": 3 - }["3"] - indexToDefault: (*[ - 0, - ]|{})[0] - outOfBoundsDisjunction: (*[]|{})[1] - indexDoesNotDistribute: (*[]|[ - 1, - ])[0] - doesNotDistributeType: { - l: [] - a: (*〈0;l〉|{ - "3": 3 - })["3"] - } - stringIndexToList: [ - 2, - ][""] - indexOutOfBounds2: 2[2] - booleanIndex: [][true] - indexOutOfBounds3: [ - 1, - 2, - 3, - ][4] - negativeIndex: [ - 1, - 2, - 3, - ][-1] - varIndexTooLarge: { - n: 3 - a: [ - 1, - 2, - 3, - ][〈0;n〉] - } - varNegativeIndex: { - n: -1 - a: [ - 1, - 2, - 3, - ][〈0;n〉] - } -} diff --git a/cue/testdata/references/labels.txtar b/cue/testdata/references/labels.txtar --- a/cue/testdata/references/labels.txtar +++ b/cue/testdata/references/labels.txtar @@ -134,155 +134,3 @@ Disjuncts: 2 NumCloseIDs: 9 --- out/compile -- ---- in.cue -{ - a: { - [string]: 〈0;-〉 - } - a: { - bar: _ - } - b: { - [string]: { - 〈1;-〉 - } - } - b: { - bar: _ - } - c: { - [string]: 〈0;-〉 - } - c: { - [string]: { - { - { - 〈3;-〉 - } - } - } - } - c: { - bar: _ - } - d: { - [string]: { - name: 〈1;-〉 - } - } - d: { - bar: {} - } - e: { - [string]: { - [string]: (〈1;-〉 + 〈0;-〉) - } - } - e: { - foo: { - bar: _ - } - } - patternField: { - t1: { - [string]: { - b: (〈1;(〈0;-〉)〉|null) - } - a: { - r: 0 - } - } - } - patternField: { - t2: { - a: { - r: 0 - } - [string]: { - z: 1 - b: 〈1;(〈0;-〉)〉.z - } - } - } - bar: 3 - f1: { - "foo\(〈1;bar〉)": { - name: "xx" - foo: 〈1;("foo\(〈1;bar〉)")〉.name - } - } - f1: { - "foo\(〈1;bar〉)": { - "foo\(〈2;bar〉)baz": { - name: "xx" - a: 〈2;("foo\(〈1;bar〉)")〉["foo\(〈3;bar〉)baz"].name - b: 〈1;("foo\(〈2;bar〉)baz")〉.name - } - } - } - c1: { - "foo\(〈1;bar〉)": { - [string]: { - name: 〈1;-〉 - foo: 〈2;("foo\(〈1;bar〉)")〉.x.name - } - } - } - c1: { - foo3: { - x: _ - } - } - emptyLabel: { - "": 1 - a: 〈1;emptyLabel〉[""] - } - underscore: { - a: { - foo: 〈0;#Foo〉 - foo: { - "_": "bar" - } - #Foo: { - [=~""]: string - } - } - } - underscore: { - c: { - foo: { - "_": "any" - } - foo: { - [=~""]: string - } - } - } - underscore: { - d: { - bar: { - "_": "any" - } - #bar: { - [string]: string - } - bar: 〈0;#bar〉 - } - } - underscore: { - e: { - baz: { - "_h": "any" - } - #baz: { - [=~"_"]: string - } - baz: 〈0;#baz〉 - } - } - invalidPattern: { - [(=~"BAD)" & =~"x")]: string - y: 123 - } -} diff --git a/cue/testdata/references/labelstop.txtar b/cue/testdata/references/labelstop.txtar --- a/cue/testdata/references/labelstop.txtar +++ b/cue/testdata/references/labelstop.txtar @@ -14,13 +14,3 @@ Unifications: 3 Conjuncts: 5 Disjuncts: 3 --- out/compile -- ---- in.cue -{ - { - [string]: { - baz: 〈1;-〉 - } - } - bar: {} -} diff --git a/cue/testdata/references/let.txtar b/cue/testdata/references/let.txtar --- a/cue/testdata/references/let.txtar +++ b/cue/testdata/references/let.txtar @@ -139,188 +139,3 @@ Notifications: 2 NumCloseIDs: 45 --- out/compile -- ---- in.cue -{ - a1list: [ - { - 1 - }, - ] - let A1#1 = 〈0;a1list〉 - a1: ((100 * 〈0;let A1#1〉[0]) + 〈0;let A1#1〉[0]) - a2list: [ - { - 2 - }, - ] - let A2#2 = 〈0;a2list〉 - a2: { - b: ((100 * 〈1;let A2#2〉[0]) + 〈1;let A2#2〉[0]) - } - a3list: [ - { - 3 - }, - ] - let A3#3 = 〈0;a3list〉 - a3: { - b: { - c: ((100 * 〈2;let A3#3〉[0]) + 〈2;let A3#3〉[0]) - } - } - a4list: [ - { - 4 - }, - ] - let A4#4 = 〈0;a4list〉 - a4: [ - for _, x in 〈1;let A4#4〉 { - v: 404 - }, - ] - a5list: [ - { - 5 - }, - ] - let A5#5 = 〈0;a5list〉 - a5: { - b: [ - for _, x in 〈2;let A5#5〉 { - v: 505 - }, - ] - } - a6list: [ - { - 6 - }, - ] - let A6#6 = 〈0;a6list〉 - a6: { - b: { - c: [ - for _, x in 〈3;let A6#6〉 { - v: 606 - }, - ] - } - } - a7list: [ - { - 7 - }, - ] - let A7#7 = 〈0;a7list〉 - a7: { - for _, x in 〈1;let A7#7〉 { - v: 707 - } - } - a8list: [ - { - 8 - }, - ] - let A8#8 = 〈0;a8list〉 - a8: { - b: { - for _, x in 〈2;let A8#8〉 { - v: 808 - } - } - } - a9list: [ - { - 9 - }, - ] - let A9#9 = 〈0;a9list〉 - a9: { - b: { - c: { - for _, x in 〈3;let A9#9〉 { - v: 909 - } - } - } - } - incompleteLet: { - input: [ - 1, - 2, - 3, - 4, - 5, - ] - last: { - min: 〈import;list〉.Min(〈1;input〉) - max: 〈import;list〉.Max(〈1;input〉) - } - bar: { - let mn#A = 〈1;last〉.min - let mx#B = 〈import;list〉.max - min: 〈0;let mn#A〉 - max: 〈0;let mx#B〉 - } - x: { - if (〈import;list〉.max < 0) {} - } - } - scalarReference: { - inScalar: { - p0: { - 5 - let x#C = 6 - #b: 〈0;let x#C〉 - } - } - inScalar: { - p1: { - #b: 〈0;let x#D〉 - let x#D = 6 - 5 - } - } - inList: { - p0: { - let x#E = { - a: 1 - } - [ - 〈1;let x#E〉, - ] - } - } - inList: { - p1: { - [ - 〈1;let x#F〉, - ] - let x#F = { - a: 1 - } - } - } - } - issue1116: { - a: { - #a: [ - "a", - "b", - ] - let List#10 = 〈0;#a〉 - 〈0;let List#10〉[(len(〈0;let List#10〉) - 1)] - } - b: { - let List#11 = 〈0;#a〉 - 〈0;let List#11〉[(len(〈0;let List#11〉) - 1)] - #a: [ - "a", - "b", - ] - } - } -} diff --git a/cue/testdata/references/letcycle.txtar b/cue/testdata/references/letcycle.txtar --- a/cue/testdata/references/letcycle.txtar +++ b/cue/testdata/references/letcycle.txtar @@ -53,117 +53,6 @@ v2: cycles.a.let[].c.c, v3: cycles.a.let[].c v2: cycles.b.let[].c.c, v3: cycles.b.let[].c v2: cycles.issue1042.#Add16.let[].for[].c.for[].for[].c, v3: cycles.issue1042.#Add16.let[].for[].c --- out/compile -- -cycles.a.let[].c: cyclic references in let clause or alias: - ./in.cue:5:15 -cycles.b.let[].c: cyclic references in let clause or alias: - ./in.cue:11:15 -cycles.issue1042.#Add16.let[].for[].c: cyclic references in let clause or alias: - ./in.cue:34:45 ---- in.cue -{ - cycles: { - a: { - let A#1 = { - c: 〈1;let B#2〉=>〈0;let A#1〉=>{ - c: 〈1;let B#2〉=>_|_(cyclic references in let clause or alias) - } - } - let B#2 = 〈0;let A#1〉=>{ - c: 〈1;let B#2〉=>_|_(cyclic references in let clause or alias) - } - out: 〈0;let A#1〉=>{ - c: 〈1;let B#2〉=>_|_(cyclic references in let clause or alias) - } - } - b: { - let A#3 = { - c: 〈1;let B#4〉=>{ - 〈1;let A#3〉=>{ - c: 〈1;let B#4〉=>_|_(cyclic references in let clause or alias) - }.c - } - } - let B#4 = { - 〈1;let A#3〉=>{ - c: 〈1;let B#4〉=>_|_(cyclic references in let clause or alias) - }.c - } - out: 〈0;let A#3〉=>{ - c: 〈1;let B#4〉=>_|_(cyclic references in let clause or alias) - } - } - issue1042: { - #FullAdder: { - a: bool - b: bool - c: bool - sum: bool - carry: bool - } - #Add16: { - a: ([ - bool, - ] * 16) - b: ([ - bool, - ] * 16) - out: ([ - bool, - ] * 16) - let fulladders#5 = [ - for _, i in 〈import;list〉.Range(0, 4, 1) { - (〈4;#FullAdder〉 & { - a: 〈4;a〉[〈2;i〉] - b: 〈4;b〉[〈2;i〉] - c: 〈4;let carries#6〉=>[ - false, - for _, i in 〈import;list〉.Range(0, 4, 1) { - 〈3;let fulladders#5〉=>[ - for _, i in 〈import;list〉.Range(0, 4, 1) { - (〈4;#FullAdder〉 & { - a: 〈4;a〉[〈2;i〉] - b: 〈4;b〉[〈2;i〉] - c: 〈4;let carries#6〉=>_|_(cyclic references in let clause or alias)[〈2;i〉] - }) - }, - ][〈1;i〉].carry - }, - ][〈2;i〉] - }) - }, - ] - let carries#6 = [ - false, - for _, i in 〈import;list〉.Range(0, 4, 1) { - 〈3;let fulladders#5〉=>[ - for _, i in 〈import;list〉.Range(0, 4, 1) { - (〈4;#FullAdder〉 & { - a: 〈4;a〉[〈2;i〉] - b: 〈4;b〉[〈2;i〉] - c: 〈4;let carries#6〉=>_|_(cyclic references in let clause or alias)[〈2;i〉] - }) - }, - ][〈1;i〉].carry - }, - ] - out: [ - for _, i in 〈import;list〉.Range(0, 4, 1) { - 〈3;let fulladders#5〉=>[ - for _, i in 〈import;list〉.Range(0, 4, 1) { - (〈4;#FullAdder〉 & { - a: 〈4;a〉[〈2;i〉] - b: 〈4;b〉[〈2;i〉] - c: 〈4;let carries#6〉=>_|_(cyclic references in let clause or alias)[〈2;i〉] - }) - }, - ][〈1;i〉].sum - }, - ] - } - } - } -} -- out/evalalpha -- cycles.a.let[].c: cyclic references in let clause or alias: ./in.cue:5:15 diff --git a/cue/testdata/references/optional.txtar b/cue/testdata/references/optional.txtar --- a/cue/testdata/references/optional.txtar +++ b/cue/testdata/references/optional.txtar @@ -24,19 +24,3 @@ Unifications: 9 Conjuncts: 9 Disjuncts: 10 --- out/compile -- ---- in.cue -{ - t1: { - a: { - foo?: int - b: 〈0;foo〉 - } - } - t2: { - a: { - b: 〈0;foo〉 - foo?: int - } - } -} diff --git a/cue/testdata/references/package.txtar b/cue/testdata/references/package.txtar --- a/cue/testdata/references/package.txtar +++ b/cue/testdata/references/package.txtar @@ -34,9 +34,3 @@ Unifications: 5 Conjuncts: 6 Disjuncts: 6 --- out/compile -- ---- in.cue -{ - a: 1 - incomplete: 〈import;"foo.com/example"〉.Settings -} diff --git a/cue/testdata/references/self.txtar b/cue/testdata/references/self.txtar --- a/cue/testdata/references/self.txtar +++ b/cue/testdata/references/self.txtar @@ -257,104 +257,3 @@ ./validator.cue:19:12 ./validator.cue:18:12 ./validator.cue:19:19 --- out/compile -- ---- in.cue -{ - a: 〈1〉.b - b: "hello" - x: { - y: 〈1〉.z - z: "world" - } - foo: { - bar: 〈1〉.baz - } - foo: { - baz: "greeting" - } - nested: { - level1: { - field: 〈1〉.value - value: "level1 value" - } - } - listTest: { - items: [ - 1, - 2, - 〈1〉[0], - 〈1〉[1], - ] - first: 1 - second: 2 - } - computed: { - key: "test" - value: 〈1〉["key"] - } - cycle: 〈1〉.cycle -} ---- list.cue -{ - #IntStrings: { - 〈import;list〉.Repeat([ - int, - string, - ], div(len(〈1〉), 2)) - } - listCheck: { - ok1: 〈1;#IntStrings〉 - } - listCheck: { - ok1: [ - 1, - "foo", - 2, - "bar", - ] - } - listCheck: { - err: 〈1;#IntStrings〉 - } - listCheck: { - err: [ - 1, - "foo", - "bar", - 2, - ] - } -} ---- validator.cue -{ - validator: { - err1: { - { - { - { - ==(〈1〉 + 1) - } - } - } - } - err1: 2 - err2: { - ==(〈1〉 + 1) - } - err2: 2 - } - cyclicErr: { - err3: ==(〈1〉 + 1) - err3: 4 - } -} ---- withlet.cue -{ - withLet: { - let X#1 = 〈1〉 - foo: 1 - bar: { - baz: 〈1;let X#1〉.foo - } - } -} diff --git a/cue/testdata/references/value.txtar b/cue/testdata/references/value.txtar --- a/cue/testdata/references/value.txtar +++ b/cue/testdata/references/value.txtar @@ -65,32 +65,3 @@ 2: (int){ 1 } } } --- out/compile -- ---- err.cue -{ - cycleErr: { - err3: ==(〈1〉 + 1) - err3: 4 - } -} ---- in.cue -{ - structShorthand: { - b: 3 - c: 〈1〉.b - } - fieldAndValue: { - foo: { - 3 - #sum: (〈1;foo〉 + 〈1〉) - } - } - valueCycle: { - b: (3 + 〈0〉) - } - listValueAlias: [ - 1, - 2, - 〈1〉[0], - ] -} diff --git a/cue/testdata/resolve/000_convert___to_top.txtar b/cue/testdata/resolve/000_convert___to_top.txtar --- a/cue/testdata/resolve/000_convert___to_top.txtar +++ b/cue/testdata/resolve/000_convert___to_top.txtar @@ -2,13 +2,6 @@ # an open struct without any concrete fields. -- in.cue -- a: {[_]: _} @test(eq, {}) --- out/compile -- ---- in.cue -{ - a: { - [_]: _ - } -} -- out/eval/stats -- Leaks: 0 Freed: 2 diff --git a/cue/testdata/resolve/001.txtar b/cue/testdata/resolve/001.txtar --- a/cue/testdata/resolve/001.txtar +++ b/cue/testdata/resolve/001.txtar @@ -3,22 +3,6 @@ b: {c: {d: 3}} c: {c: d.d} @test(eq, {c: 2}) d: {d: 2} --- out/compile -- ---- in.cue -{ - a: 〈0;b〉.c.d - b: { - c: { - d: 3 - } - } - c: { - c: 〈1;d〉.d - } - d: { - d: 2 - } -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/resolve/004.txtar b/cue/testdata/resolve/004.txtar --- a/cue/testdata/resolve/004.txtar +++ b/cue/testdata/resolve/004.txtar @@ -3,17 +3,6 @@ b: a @test(eq, {d: 1}) @test(shareID=ba) a: {d: 1, d: _} @test(eq, {d: 1}) @test(shareID=ba) b: _ --- out/compile -- ---- in.cue -{ - a: _ - b: 〈0;a〉 - a: { - d: 1 - d: _ - } - b: _ -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/resolve/005_JSON.txtar b/cue/testdata/resolve/005_JSON.txtar --- a/cue/testdata/resolve/005_JSON.txtar +++ b/cue/testdata/resolve/005_JSON.txtar @@ -4,16 +4,6 @@ b: a @test(eq, 3) o: {"a\nb": 2} @test(eq, {"a\nb": 2}) c: o["a\nb"] @test(eq, 2) --- out/compile -- ---- in.cue -{ - a: 3 - b: 〈0;a〉 - o: { - "a\nb": 2 - } - c: 〈0;o〉["a\nb"] -} -- out/eval/stats -- Leaks: 0 Freed: 6 diff --git a/cue/testdata/resolve/006_arithmetic.txtar b/cue/testdata/resolve/006_arithmetic.txtar --- a/cue/testdata/resolve/006_arithmetic.txtar +++ b/cue/testdata/resolve/006_arithmetic.txtar @@ -11,16 +11,6 @@ [eval] e2: conflicting values int and 2.0 (mismatched types int and float): ./in.cue:6:5 ./in.cue:6:11 --- out/compile -- ---- in.cue -{ - v1: (1000000000000 / 2.0) - v2: (2.0 == 2) - n1: 1 - v5: (2.0 / 〈0;n1〉) - v6: (1.0 / 1.0) - e2: (int & (4.0 / 2.0)) -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/cue/testdata/resolve/007_inequality.txtar b/cue/testdata/resolve/007_inequality.txtar --- a/cue/testdata/resolve/007_inequality.txtar +++ b/cue/testdata/resolve/007_inequality.txtar @@ -5,16 +5,6 @@ d: null != {} @test(eq, true) e: null == [] @test(eq, false) f: 0 == 0.0 @test(eq, true) // types are unified first TODO: make this consistent --- out/compile -- ---- in.cue -{ - a: (1 != 2) - b: (1 != null) - c: (true == null) - d: (null != {}) - e: (null == []) - f: (0 == 0.0) -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/resolve/008_attributes.txtar b/cue/testdata/resolve/008_attributes.txtar --- a/cue/testdata/resolve/008_attributes.txtar +++ b/cue/testdata/resolve/008_attributes.txtar @@ -4,20 +4,6 @@ c: a & b @test(eq, {foo: 1 @foo() @baz(1) @bar()}) e: a & {foo: 1 @foo(other)} @test(eq, {foo: 1 @foo(other) @foo() @baz(1)}) --- out/compile -- ---- in.cue -{ - a: { - foo: 1 - } - b: { - foo: 1 - } - c: (〈0;a〉 & 〈0;b〉) - e: (〈0;a〉 & { - foo: 1 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/resolve/009_optional_field_unification.txtar b/cue/testdata/resolve/009_optional_field_unification.txtar --- a/cue/testdata/resolve/009_optional_field_unification.txtar +++ b/cue/testdata/resolve/009_optional_field_unification.txtar @@ -10,25 +10,6 @@ "g\(2)"?: 2 @test(eq, {g1: 1, g2?: 2}) } --- out/compile -- ---- in.cue -{ - a: { - foo?: string - } - b: { - foo: "foo" - } - c: (〈0;a〉 & 〈0;b〉) - d: (〈0;a〉 & { - foo?: "bar" - }) - e: { - g1: 1 - "g\(1)"?: 1 - "g\(2)"?: 2 - } -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/resolve/010_optional_field_resolves_to_incomplete.txtar b/cue/testdata/resolve/010_optional_field_resolves_to_incomplete.txtar --- a/cue/testdata/resolve/010_optional_field_resolves_to_incomplete.txtar +++ b/cue/testdata/resolve/010_optional_field_resolves_to_incomplete.txtar @@ -9,15 +9,6 @@ ./in.cue:3:6 [incomplete] r.c: cannot reference optional field: a: ./in.cue:4:8 --- out/compile -- ---- in.cue -{ - r: { - a?: 3 - b: 〈0;a〉 - c: 〈1;r〉["a"] - } -} -- out/eval/stats -- Leaks: 0 Freed: 5 diff --git a/cue/testdata/resolve/011_bounds.txtar b/cue/testdata/resolve/011_bounds.txtar --- a/cue/testdata/resolve/011_bounds.txtar +++ b/cue/testdata/resolve/011_bounds.txtar @@ -97,61 +97,6 @@ [eval] e9: conflicting values >"a" and <1 (mismatched types string and number): ./in.cue:64:5 ./in.cue:64:12 --- out/compile -- ---- in.cue -{ - i1: (>1 & 5) - i2: ((>=0 & <=10) & 5) - i3: (!=null & []) - i4: (!=2 & !=4) - s1: ((>=0 & <=10) & !=1) - s2: ((>=0 & <=10) & !=11) - s3: (>5 & !=5) - s4: (<10 & !=10) - s5: (!=2 & !=2) - s6: (!=2 & >=2) - s7: (>=2 & !=2) - s8: (!=5 & >5) - s10: (((>=0 & <=10) & <12) & >1) - s11: (((>0 & >=0) & <=12) & <12) - s20: (>=10 & <=10) - s22: (>5 & <=6) - s22a: (>5 & (<=6 & int)) - s22b: ((int & >5) & <=6) - s22c: (>=5 & (<6 & int)) - s22d: ((int & >=5) & <6) - s22e: ((>=5 & <6) & int) - s22f: (int & (>=5 & <6)) - s23: (>0 & <2) - s23a: ((>0 & <2) & int) - s23b: (int & (>0 & <2)) - s23c: ((int & >0) & <2) - s23d: (>0 & (int & <2)) - s23e: (>0.0 & <2.0) - s30: (>0 & int) - floats: { - [string]: float - f1: (<10.0 & <=5.0) - f2: (<=10.0 & <5.0) - f3: (<1.1 & <=1.1) - f4: (<=1.1 & <=1.1) - f5: (>1.1 & >=1.1) - f6: (>=1.1 & >1.1) - f7: (>=1.1 & <=1.1) - issue1310: (>=2.1 & <=1.0) - fe2: (>2.1 & <=2.1) - fe3: ((float & >2) & <=3) - } - e1: (null & !=null) - e2: (!=null & null) - e3: (>1 & 1) - e4: (<0 & 0) - e5: (>1 & <0) - e6: (>11 & <11) - e7: (>=11 & <11) - e8: (>11 & <=11) - e9: (>"a" & <1) -} -- out/eval/stats -- Leaks: 0 Freed: 50 diff --git a/cue/testdata/resolve/012_bound_conversions.txtar b/cue/testdata/resolve/012_bound_conversions.txtar --- a/cue/testdata/resolve/012_bound_conversions.txtar +++ b/cue/testdata/resolve/012_bound_conversions.txtar @@ -23,21 +23,6 @@ [eval] c4: conflicting values 1.2 and int (mismatched types float and int): ./in.cue:14:5 ./in.cue:14:23 --- out/compile -- ---- in.cue -{ - r0: ((int & >0.1) & <=1.9) - r1: ((int & >0.1) & <1.9) - r2: ((int & >=0.1) & <1.9) - r3: ((int & >=-1.9) & <=-0.1) - r4: ((int & >-1.9) & <=-0.1) - r5: (>=1.1 & <=1.1) - r6: (〈0;r5〉 & 1.1) - c1: ((1.2 & >1.3) & <2) - c2: (1.2 & (>1.3 & <2)) - c3: (1.2 & (>=1 & <2)) - c4: (1.2 & ((>=1 & <2) & int)) -} -- out/eval/stats -- Leaks: 0 Freed: 12 diff --git a/cue/testdata/resolve/013_custom_validators.txtar b/cue/testdata/resolve/013_custom_validators.txtar --- a/cue/testdata/resolve/013_custom_validators.txtar +++ b/cue/testdata/resolve/013_custom_validators.txtar @@ -14,16 +14,6 @@ ./in.cue:6:4 ./in.cue:6:24 ./in.cue:7:4 --- out/compile -- ---- in.cue -{ - a: 〈import;strings〉.ContainsAny("ab") - a: "after" - b: 〈import;strings〉.ContainsAny("c") - b: "dog" - c: (〈import;strings〉.ContainsAny("d") & 〈import;strings〉.ContainsAny("g")) - c: "dog" -} -- out/eval/stats -- Leaks: 0 Freed: 4 diff --git a/cue/testdata/resolve/014_null_coalescing.txtar b/cue/testdata/resolve/014_null_coalescing.txtar --- a/cue/testdata/resolve/014_null_coalescing.txtar +++ b/cue/testdata/resolve/014_null_coalescing.txtar @@ -2,13 +2,6 @@ a: null @test(eq, null) b: a.x | "b" @test(eq, "b") c: a["x"] | "c" @test(eq, "c") --- out/compile -- ---- in.cue -{ - a: null - b: (〈0;a〉.x|"b") - c: (〈0;a〉["x"]|"c") -} -- out/eval/stats -- Leaks: 0 Freed: 8 diff --git a/cue/testdata/resolve/016_index.txtar b/cue/testdata/resolve/016_index.txtar --- a/cue/testdata/resolve/016_index.txtar +++ b/cue/testdata/resolve/016_index.txtar @@ -48,55 +48,6 @@ ./in.cue:15:16 [incomplete] e10: undefined field: b: ./in.cue:21:10 --- out/compile -- ---- in.cue -{ - a: [ - 2, - ][0] - b: { - foo: "bar" - }["foo"] - c: (*〈0;l〉|{ - "3": 3 - })["3"] - d: (*[]|[ - 1, - ])[0] - l: [] - e1: [ - 2, - ][""] - e2: 2[2] - e3: [][true] - e4: [ - 1, - 2, - 3, - ][3] - e5: [ - 1, - 2, - 3, - ][-1] - e6: (*[]|{})[1] - e7: [ - 1, - 2, - 3, - ][3] - e8: [ - 1, - 2, - 3, - ][-1] - e9: (*[]|{})[1] - def: { - a: 1 - #b: 3 - } - e10: 〈0;def〉["b"] -} -- out/eval/stats -- Leaks: 0 Freed: 55 diff --git a/cue/testdata/resolve/017_disjunctions_of_lists.txtar b/cue/testdata/resolve/017_disjunctions_of_lists.txtar --- a/cue/testdata/resolve/017_disjunctions_of_lists.txtar +++ b/cue/testdata/resolve/017_disjunctions_of_lists.txtar @@ -3,25 +3,6 @@ l1: ["a", "b"] @test(eq, ["a", "b"]) l2: l & ["c", "d"] @test(eq, ["c", "d"]) --- out/compile -- ---- in.cue -{ - l: ([ - int, - int, - ]|[ - string, - string, - ]) - l1: [ - "a", - "b", - ] - l2: (〈0;l〉 & [ - "c", - "d", - ]) -} -- out/eval/stats -- Leaks: 0 Freed: 18 diff --git a/cue/testdata/resolve/018_slice.txtar b/cue/testdata/resolve/018_slice.txtar --- a/cue/testdata/resolve/018_slice.txtar +++ b/cue/testdata/resolve/018_slice.txtar @@ -25,33 +25,6 @@ [eval] e7: cannot use "9" (type string) as type int in slice index: ./in.cue:9:5 ./in.cue:9:10 --- out/compile -- ---- in.cue -{ - a: [ - 2, - ][0:0] - b: [ - 0, - ][1:1] - e1: [][1:1] - e2: [ - 0, - ][-1:0] - e3: [ - 0, - ][1:0] - e4: [ - 0, - ][1:2] - e5: 4[1:2] - e6: [ - 2, - ]["":] - e7: [ - 2, - ][:"9"] -} -- out/eval/stats -- Leaks: 0 Freed: 25 diff --git a/cue/testdata/resolve/022_list_unification.txtar b/cue/testdata/resolve/022_list_unification.txtar --- a/cue/testdata/resolve/022_list_unification.txtar +++ b/cue/testdata/resolve/022_list_unification.txtar @@ -1,23 +1,6 @@ -- in.cue -- a: {l: ["foo", v], v: l[1]} @test(eq, {l: ["foo", _], v: _}) b: a & {l: [_, "bar"]} @test(eq, {l: ["foo", "bar"], v: "bar"}) --- out/compile -- ---- in.cue -{ - a: { - l: [ - "foo", - 〈1;v〉, - ] - v: 〈0;l〉[1] - } - b: (〈0;a〉 & { - l: [ - _, - "bar", - ] - }) -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/resolve/023_correct_error_messages.txtar b/cue/testdata/resolve/023_correct_error_messages.txtar --- a/cue/testdata/resolve/023_correct_error_messages.txtar +++ b/cue/testdata/resolve/023_correct_error_messages.txtar @@ -5,11 +5,6 @@ [eval] a: conflicting values "a" and 1 (mismatched types string and int): ./in.cue:1:4 ./in.cue:1:10 --- out/compile -- ---- in.cue -{ - a: ("a" & 1) -} -- out/eval/stats -- Leaks: 0 Freed: 2 diff --git a/cue/testdata/resolve/024_structs.txtar b/cue/testdata/resolve/024_structs.txtar --- a/cue/testdata/resolve/024_structs.txtar +++ b/cue/testdata/resolve/024_structs.txtar @@ -17,23 +17,6 @@ ./in.cue:5:5 ./in.cue:4:5 ./in.cue:7:13 --- out/compile -- ---- in.cue -{ - a: (〈0;t〉 & { - c: 5 - }) - b: (〈0;ti〉 & { - c: 7 - }) - t: { - c: number - d: (〈0;c〉 * 3) - } - ti: (〈0;t〉 & { - c: int - }) -} -- out/eval/stats -- Leaks: 0 Freed: 13 diff --git a/cue/testdata/resolve/025_definitions.txtar b/cue/testdata/resolve/025_definitions.txtar --- a/cue/testdata/resolve/025_definitions.txtar +++ b/cue/testdata/resolve/025_definitions.txtar @@ -44,51 +44,6 @@ ./in.cue:16:7 [eval] foo1.recursive.feild: field not allowed: ./in.cue:22:3 --- out/compile -- ---- in.cue -{ - #Foo: { - field: int - recursive: { - field: string - } - } - #Foo1: { - field: int - } - #Foo1: { - field2: string - } - foo: 〈0;#Foo〉 - foo: { - feild: 2 - } - foo1: 〈0;#Foo〉 - foo1: { - field: 2 - recursive: { - feild: 2 - } - } - #Bar: { - field: int - { - [_]: int - } - } - bar: 〈0;#Bar〉 - bar: { - feild: 2 - } - #Mixed: string - Mixed: string - mixedRec: { - #Mixed: string - } - mixedRec: { - Mixed: string - } -} -- out/eval/stats -- Leaks: 0 Freed: 28 diff --git a/cue/testdata/resolve/027_new-style_definitions.txtar b/cue/testdata/resolve/027_new-style_definitions.txtar --- a/cue/testdata/resolve/027_new-style_definitions.txtar +++ b/cue/testdata/resolve/027_new-style_definitions.txtar @@ -10,24 +10,6 @@ _hid: 3 a: "foo" } @test(eq, {#def: 4, _hid: 3, a: "foo"}) --- out/compile -- ---- in.cue -{ - #Foo: { - a: 1 - b: int - } - "#Foo": (〈0;#Foo〉 & { - b: 1 - }) - bulk: ({ - [string]: string - } & { - #def: 4 - _hid: 3 - a: "foo" - }) -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar b/cue/testdata/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar --- a/cue/testdata/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar +++ b/cue/testdata/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar @@ -29,50 +29,6 @@ ./in.cue:11:6 [eval] c.w.0.d: field not allowed: ./in.cue:22:7 --- out/compile -- ---- in.cue -{ - #S: { - [string]: { - a: int - } - } - a: (〈0;#S〉 & { - v: { - b: int - } - }) - #Q: { - [string]: ({ - a: int - }|{ - b: int - }) - } - b: (〈0;#Q〉 & { - w: { - c: int - } - }) - #R: { - [string]: [ - { - a: int - }, - { - b: int - }, - ] - } - c: (〈0;#R〉 & { - w: [ - { - d: int - }, - ..., - ] - }) -} -- out/eval/stats -- Leaks: 0 Freed: 24 diff --git a/cue/testdata/resolve/030_definitions_with_disjunctions.txtar b/cue/testdata/resolve/030_definitions_with_disjunctions.txtar --- a/cue/testdata/resolve/030_definitions_with_disjunctions.txtar +++ b/cue/testdata/resolve/030_definitions_with_disjunctions.txtar @@ -17,30 +17,6 @@ -- out/errors.txt -- [eval] bar.c: field not allowed: ./in.cue:12:7 --- out/compile -- ---- in.cue -{ - #Foo: { - field: int - ({ - a: 1 - }|{ - b: 2 - }) - } - foo: 〈0;#Foo〉 - foo: { - a: 1 - } - bar: 〈0;#Foo〉 - bar: { - c: 2 - } - baz: 〈0;#Foo〉 - baz: { - b: 2 - } -} -- out/eval/stats -- Leaks: 6 Freed: 34 diff --git a/cue/testdata/resolve/031_definitions_with_disjunctions_recurisive.txtar b/cue/testdata/resolve/031_definitions_with_disjunctions_recurisive.txtar --- a/cue/testdata/resolve/031_definitions_with_disjunctions_recurisive.txtar +++ b/cue/testdata/resolve/031_definitions_with_disjunctions_recurisive.txtar @@ -10,23 +10,6 @@ } @test(eq, { x: {field: int, c: 3, a: 1} | {field: int, c: 3, b: 2} }) --- out/compile -- ---- in.cue -{ - #Foo: { - x: { - field: int - ({ - a: 1 - }|{ - b: 2 - }) - } - x: { - c: 3 - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 13 diff --git a/cue/testdata/resolve/033_top-level_definition_with_struct_and_disjunction.txtar b/cue/testdata/resolve/033_top-level_definition_with_struct_and_disjunction.txtar --- a/cue/testdata/resolve/033_top-level_definition_with_struct_and_disjunction.txtar +++ b/cue/testdata/resolve/033_top-level_definition_with_struct_and_disjunction.txtar @@ -12,22 +12,6 @@ Type: "A" Size: 1 } @test(eq, {Type: "B", Text: string, Size: 0} | {Type: "A", Text: string, Size: 1}) --- out/compile -- ---- in.cue -{ - #def: { - Type: string - Text: string - Size: int - } - #def: ({ - Type: "B" - Size: 0 - }|{ - Type: "A" - Size: 1 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 13 diff --git a/cue/testdata/resolve/034_closing_structs.txtar b/cue/testdata/resolve/034_closing_structs.txtar --- a/cue/testdata/resolve/034_closing_structs.txtar +++ b/cue/testdata/resolve/034_closing_structs.txtar @@ -17,37 +17,6 @@ cpct: cp & ct @test(eq, {x: int}) @test(closed) @test(allows, string) @test(allows:todo=false, string) ctcp: ct & cp @test(eq, {x: int}) @test(closed) @test(allows, string) @test(allows:todo=false, string) ctct: ct & ct @test(eq, {x: int}) @test(closed) @test(shareID=ctct) @test(allows, string) --- out/compile -- ---- in.cue -{ - op: { - x: int - } - ot: { - x: int - ... - } - cp: close({ - x: int - }) - ct: close({ - x: int - ... - }) - opot: (〈0;op〉 & 〈0;ot〉) - otop: (〈0;ot〉 & 〈0;op〉) - opcp: (〈0;op〉 & 〈0;cp〉) - cpop: (〈0;cp〉 & 〈0;op〉) - opct: (〈0;op〉 & 〈0;ct〉) - ctop: (〈0;ct〉 & 〈0;op〉) - otcp: (〈0;ot〉 & 〈0;cp〉) - cpot: (〈0;cp〉 & 〈0;ot〉) - otct: (〈0;ot〉 & 〈0;ct〉) - ctot: (〈0;ct〉 & 〈0;ot〉) - cpct: (〈0;cp〉 & 〈0;ct〉) - ctcp: (〈0;ct〉 & 〈0;cp〉) - ctct: (〈0;ct〉 & 〈0;ct〉) -} -- out/eval/stats -- Leaks: 0 Freed: 90 diff --git a/cue/testdata/resolve/035_excluded_embedding_from_closing.txtar b/cue/testdata/resolve/035_excluded_embedding_from_closing.txtar --- a/cue/testdata/resolve/035_excluded_embedding_from_closing.txtar +++ b/cue/testdata/resolve/035_excluded_embedding_from_closing.txtar @@ -22,32 +22,6 @@ ./in.cue:14:5 [eval] V.b.extra: field not allowed: ./in.cue:15:5 --- out/compile -- ---- in.cue -{ - #S: { - a: { - c: int - } - { - c: { - d: int - } - } - let B#1 = { - open: int - } - b: 〈0;let B#1〉 - } - V: (〈0;#S〉 & { - c: { - e: int - } - b: { - extra: int - } - }) -} -- out/eval/stats -- Leaks: 1 Freed: 21 diff --git a/cue/testdata/resolve/038_incomplete_comprehensions.txtar b/cue/testdata/resolve/038_incomplete_comprehensions.txtar --- a/cue/testdata/resolve/038_incomplete_comprehensions.txtar +++ b/cue/testdata/resolve/038_incomplete_comprehensions.txtar @@ -20,25 +20,6 @@ -- out/errors.txt -- [incomplete] A: cannot range over src (incomplete type _): ./in.cue:2:11 --- out/compile -- ---- in.cue -{ - A: { - for _, v in 〈0;src〉 { - "\(〈1;v〉)": 〈1;v〉 - } - src: _ - if true { - baz: "baz" - } - } - B: (〈0;A〉 & { - src: [ - "foo", - "bar", - ] - }) -} -- out/eval/stats -- Leaks: 0 Freed: 11 diff --git a/cue/testdata/resolve/039_reference_to_root.txtar b/cue/testdata/resolve/039_reference_to_root.txtar --- a/cue/testdata/resolve/039_reference_to_root.txtar +++ b/cue/testdata/resolve/039_reference_to_root.txtar @@ -34,34 +34,6 @@ [incomplete] wp.c: non-concrete value int in operand to +: ./in.cue:15:5 ./in.cue:14:5 --- out/compile -- ---- in.cue -{ - a: { - b: int - } - c: (〈0;a〉 & { - b: 100 - d: (〈1;a〉.b + 3) - }) - x: { - b: int - c: (〈0;b〉 + 5) - } - y: (〈0;x〉 & { - b: 100 - }) - v: { - b: int - c: (〈1;v〉.b + 5) - } - w: (〈0;v〉 & { - b: 100 - }) - wp: (〈0;v〉 & { - b: 100 - }) -} -- out/eval/stats -- Leaks: 0 Freed: 21 diff --git a/cue/testdata/resolve/040_references_from_template_to_concrete.txtar b/cue/testdata/resolve/040_references_from_template_to_concrete.txtar --- a/cue/testdata/resolve/040_references_from_template_to_concrete.txtar +++ b/cue/testdata/resolve/040_references_from_template_to_concrete.txtar @@ -15,29 +15,6 @@ } t: x: {b: str: "DDDD"} @test(eq, {b: {str: "DDDD"}, a: "XDDDD", c: "X"}) --- out/compile -- ---- in.cue -{ - res: [ - 〈1;t〉, - ] - t: { - [string]: { - a: (〈0;c〉 + 〈0;b〉.str) - b: { - str: string - } - c: "X" - } - } - t: { - x: { - b: { - str: "DDDD" - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/resolve/043_diamond-shaped_constraints.txtar b/cue/testdata/resolve/043_diamond-shaped_constraints.txtar --- a/cue/testdata/resolve/043_diamond-shaped_constraints.txtar +++ b/cue/testdata/resolve/043_diamond-shaped_constraints.txtar @@ -18,26 +18,6 @@ } @test(eq, {A: {c: 3, a: 1}, B: {d: 4, b: 2, c: 3, a: 1}}) -- out/todo.txt -- Reordering --- out/compile -- ---- in.cue -{ - S: { - A: { - a: 1 - } - B: (〈0;A〉 & { - b: 2 - }) - } - T: (〈0;S〉 & { - A: { - c: 3 - } - B: { - d: 4 - } - }) -} -- out/eval/stats -- Leaks: 0 Freed: 16 diff --git a/cue/testdata/resolve/044_field_templates.txtar b/cue/testdata/resolve/044_field_templates.txtar --- a/cue/testdata/resolve/044_field_templates.txtar +++ b/cue/testdata/resolve/044_field_templates.txtar @@ -20,41 +20,6 @@ foo: {name: "foo", y: 1} bar: {name: "bar", y: 1} }) --- out/compile -- ---- in.cue -{ - a: { - { - [_]: int - } - k: 1 - } - b: { - { - [_]: { - x: 0 - y: (*1|int) - } - } - v: {} - w: { - x: 0 - } - } - b: { - [_]: {} - } - c: { - { - [_]: { - name: 〈1;-〉 - y: 1 - } - } - foo: {} - bar: _ - } -} -- out/eval/stats -- Leaks: 0 Freed: 21 diff --git a/cue/testdata/resolve/045_range_unification.txtar b/cue/testdata/resolve/045_range_unification.txtar --- a/cue/testdata/resolve/045_range_unification.txtar +++ b/cue/testdata/resolve/045_range_unification.txtar @@ -72,45 +72,6 @@ [eval] n2: incompatible integer bounds <=1.3 and >=1.1: ./in.cue:42:19 ./in.cue:42:11 --- out/compile -- ---- in.cue -{ - a1: ((>=1 & <=5) & 3) - a2: ((>=1 & <=5) & 1) - a3: ((>=1 & <=5) & 5) - a4: ((>=1 & <=5) & 6) - a5: ((>=1 & <=5) & 0) - a6: ((3 & >=1) & <=5) - a7: ((1 & >=1) & <=5) - a8: ((5 & >=1) & <=5) - a9: ((6 & >=1) & <=5) - a10: ((0 & >=1) & <=5) - b1: (((>=1 & <=5) & >=1) & <=5) - b2: (((>=1 & <=5) & >=1) & <=1) - b3: (((>=1 & <=5) & >=5) & <=5) - b4: (((>=1 & <=5) & >=2) & <=3) - b5: (((>=1 & <=5) & >=3) & <=9) - b6: (((>=1 & <=5) & >=5) & <=9) - b7: (((>=1 & <=5) & >=6) & <=9) - b8: (((>=1 & <=5) & >=1) & <=5) - b9: (((>=1 & <=1) & >=1) & <=5) - b10: (((>=5 & <=5) & >=1) & <=5) - b11: (((>=2 & <=3) & >=1) & <=5) - b12: (((>=3 & <=9) & >=1) & <=5) - b13: (((>=5 & <=9) & >=1) & <=5) - b14: (((>=6 & <=9) & >=1) & <=5) - c1: ((int & >=1) & <=5) - c2: ((>=1 & <=5) & int) - c3: ((string & >=1) & <=5) - c4: ((>=1 & <=5) & string) - s1: ((>="d" & <="z") & "e") - s2: ((>="d" & <="z") & "ee") - n1: ((number & >=1) & <=2) - n2: ((int & >=1.1) & <=1.3) - n3: ((>=1.0 & <=3.0) & 2) - n4: ((>=0.0 & <=0.1) & 0.09999) - n5: ((>=1 & <=5) & 2.5) -} -- out/eval/stats -- Leaks: 0 Freed: 36 diff --git a/cue/testdata/resolve/046_predefined_ranges.txtar b/cue/testdata/resolve/046_predefined_ranges.txtar --- a/cue/testdata/resolve/046_predefined_ranges.txtar +++ b/cue/testdata/resolve/046_predefined_ranges.txtar @@ -19,15 +19,3 @@ s3: (number){ &(>=-340282346638528859811704183484516925440, <=340282346638528859811704183484516925440) } s4: (int){ &(>=0, int) } } --- out/compile -- ---- in.cue -{ - k1: &(int, >=-128, <=127) - k1: 44 - k2: &(int, >=-9223372036854775808, <=9223372036854775807) - k2: -8000000000 - s1: &(int, >=-128, <=127) - s2: &(int, >=0, <=65535) - s3: &(>=-340282346638528859811704183484516925440, <=340282346638528859811704183484516925440) - s4: &(int, >=0) -} diff --git a/cue/testdata/resolve/046_predefined_ranges_error.txtar b/cue/testdata/resolve/046_predefined_ranges_error.txtar --- a/cue/testdata/resolve/046_predefined_ranges_error.txtar +++ b/cue/testdata/resolve/046_predefined_ranges_error.txtar @@ -4,9 +4,3 @@ -- out/errors.txt -- [eval] e1: invalid value 100000 (out of bound <=32767): ./in.cue:2:5 --- out/compile -- ---- in.cue -{ - e1: &(int, >=-32768, <=32767) - e1: 100000 -} diff --git a/cue/testdata/resolve/047_struct_comprehensions.txtar b/cue/testdata/resolve/047_struct_comprehensions.txtar --- a/cue/testdata/resolve/047_struct_comprehensions.txtar +++ b/cue/testdata/resolve/047_struct_comprehensions.txtar @@ -20,33 +20,6 @@ reg: 4 }) --- out/compile -- ---- in.cue -{ - obj: { - foo: { - a: "bar" - } - } - obj: { - [string]: { - a: (*"dummy"|string) - if true { - sub: { - as: 〈2;a〉 - } - } - } - } - for k, v in { - #def: 1 - opt?: 2 - _hid: 3 - reg: 4 - } { - "\(〈1;k〉)": 〈1;v〉 - } -} -- out/eval/stats -- Leaks: 2 Freed: 12 diff --git a/cue/testdata/resolve/048_builtins.txtar b/cue/testdata/resolve/048_builtins.txtar --- a/cue/testdata/resolve/048_builtins.txtar +++ b/cue/testdata/resolve/048_builtins.txtar @@ -134,106 +134,6 @@ [incomplete] decimalListErrors.b.result: error in call to list.Avg: non-concrete value int for element 0 of number list argument 0: ./in.cue:62:11 ./in.cue:61:7 --- out/compile -- ---- in.cue -{ - a1: { - a: and([ - 〈1;b〉, - 〈1;c〉, - ]) - b: =~"oo" - c: =~"fo" - } - a2: (〈0;a1〉 & { - a: "foo" - }) - a3: (〈0;a1〉 & { - a: "bar" - }) - o1: { - a: or([ - 〈1;b〉, - 〈1;c〉, - ]) - b: string - c: "bar" - } - o2: (〈0;o1〉 & { - a: "foo" - }) - o3: (〈0;o1〉 & { - a: "foo" - b: "baz" - }) - stringListErrors: { - a: { - x: [ - string, - ...string, - ] - result: 〈import;strings〉.Join(〈0;x〉, " ") - } - b: { - x: [ - int, - ...string, - ] - result: 〈import;strings〉.Join(〈0;x〉, " ") - } - c: { - x: [] - result: 〈import;strings〉.Join(〈0;x〉, int) - } - } - decimalListErrors: { - a: { - x: [ - string, - ] - result: 〈import;list〉.Avg(〈0;x〉) - } - b: { - x: [ - int, - ...string, - ] - result: 〈import;list〉.Avg(〈0;x〉) - } - } -} ---- issue3648.cue -{ - issue3648: { - reduced: { - [string]: { - a: 〈import;list〉.Concat([ - 〈1;b〉, - ]) - b: [ - {}, - ] - } - foo: {} - } - } - issue3648: { - full: { - #Redirect: { - path?: string - } - [string]: { - allRedirects: 〈import;list〉.Concat([ - 〈1;redirects〉, - ]) - redirects: [ - ...〈2;#Redirect〉, - ] - } - foo: {} - } - } -} -- out/eval/stats -- Leaks: 1 Freed: 86 diff --git a/cue/testdata/scalars/embed.txtar b/cue/testdata/scalars/embed.txtar --- a/cue/testdata/scalars/embed.txtar +++ b/cue/testdata/scalars/embed.txtar @@ -194,168 +194,6 @@ [incomplete] arithmetic.sum: non-concrete value int in operand to +: ./in.cue:79:3 ./in.cue:80:7 --- out/compile -- ---- in.cue -{ - intEmbed: { - a1: { - 2 - } - a2: { - v: { - 3 - #foo: (〈2;a2〉.v + 1) - } - w: 〈0;v〉 - x: 〈0;v〉.#foo - } - a3: (〈0;a1〉 + 〈0;a2〉.v) - } - listEmbed: { - a1: { - 2 - } - b3: { - [ - 1, - 2, - ] - #foo: 1 - } - b4: 〈import;list〉.Concat([ - 〈1;b3〉, - 〈1;b3〉, - ]) - b5: 〈0;b3〉[1] - b6: 〈0;b3〉[5] - b7: 〈0;b4〉[〈0;a1〉] - } - stringEmbed: { - s1: { - "foo" - #bar: "bar" - } - s2: [ - 〈1;s1〉, - { - 〈2;s1〉.#bar - #baz: 4 - }, - ] - s3: 〈import;strings〉.Join(〈0;s2〉, "--") - } - outPattern: { - sum: { - out: (〈0;#a〉 + 〈0;#b〉) - #a: int - #b: int - } - used: { - (〈1;sum〉 & { - #a: 1 - #b: 3 - }) - } - } - arithmetic: { - sum: { - (〈0;#a〉 + 〈0;#b〉) - #a: int - #b: int - } - a1: ((〈0;sum〉 & { - _ - #a: 1 - #b: 3 - }) + 2) - a2: (2 + (〈0;sum〉 & { - _ - #a: 1 - #b: 3 - })) - a3: (2 + (2 + (〈0;sum〉 & { - _ - #a: 1 - #b: 3 - }))) - } - defCheck: { - a: { - #def: 1 - } - b: 〈0;a〉.#def - } - optionalExists: { - (string|{ - value?: string - if (〈0;value〉 != _|_(explicit error (_|_ literal) in source)) { - other: int - } - }) - } - optionalCheck: { - thing: (string|{ - value?: string - if (〈0;value〉 != _|_(explicit error (_|_ literal) in source)) { - other: int - } - }) - thing: { - value: "some string" - other: 3 - } - } - hidden: { - issue794: { - _foo: "foo" - [ - 〈1;_foo〉, - ] - } - } -} ---- issue2113.cue -{ - merged: { - t1: { - #fn: { - #in2: _ - _ - } - #fn: { - #in2: { - c1: string - } - 〈0;#in2〉.c1 - } - x: (〈0;#fn〉 & { - #in2: { - c1: "V 1" - } - _ - }) - } - } -} ---- issue2163.cue -{ - selfRefInEmbed: { - t1: { - #Func: { - #in: _ - _ - } - #fn: 〈0;#Func〉 - #fn: { - #in: _ - ((〈1;#Func〉 & { - _foo: 〈1;#in〉 - "buzz" - }) + "fiz") - } - } - } -} -- out/eval/stats -- Leaks: 4 Freed: 132 diff --git a/cue/testdata/scalars/embed_bound.txtar b/cue/testdata/scalars/embed_bound.txtar --- a/cue/testdata/scalars/embed_bound.txtar +++ b/cue/testdata/scalars/embed_bound.txtar @@ -14,15 +14,3 @@ !=null x: 1 } @test(eq, {x: 1}) --- out/compile -- ---- in.cue -{ - a: { - !=null - } - b: !=null - c: { - !=null - x: 1 - } -} diff --git a/cue/testdata/scalars/emptystruct.txtar b/cue/testdata/scalars/emptystruct.txtar --- a/cue/testdata/scalars/emptystruct.txtar +++ b/cue/testdata/scalars/emptystruct.txtar @@ -139,69 +139,3 @@ Disjuncts: 6 NumCloseIDs: 56 --- out/compile -- ---- in.cue -{ - elipsis: { - test1: { - string - #foo: "bar" - } - #Def: { - ... - #foo: string - _ - } - check: (〈0;test1〉 & 〈0;#Def〉) - } - bulk: { - test1: { - string - #foo: "bar" - } - #Def: { - [string]: int - #foo: string - _ - } - check: (〈0;test1〉 & 〈0;#Def〉) - } - optional: { - test1: { - string - #foo: "bar" - } - #Def: { - bar?: int - #foo: string - _ - } - check: (〈0;test1〉 & 〈0;#Def〉) - } - issue783: { - test1: { - string - #foo: "bar" - } - test2: { - hello: "world" - #foo: "bar" - } - #Def1: ({ - ... - #foo: string - }|{ - string - #foo: string - }) - check1a: (〈0;test1〉 & 〈0;#Def1〉) - check1b: (〈0;test2〉 & 〈0;#Def1〉) - #Def2: { - ... - #foo: string - _ - } - check2a: (〈0;test1〉 & 〈0;#Def2〉) - check2b: (〈0;test2〉 & 〈0;#Def2〉) - } -} diff --git a/cue/testdata/scalars/yield.txtar b/cue/testdata/scalars/yield.txtar --- a/cue/testdata/scalars/yield.txtar +++ b/cue/testdata/scalars/yield.txtar @@ -32,33 +32,6 @@ ./in.cue:14:2 ./in.cue:14:13 ./in.cue:16:2 --- out/compile -- ---- in.cue -{ - ifScalar: { - _#cond: true - if 〈0;_#cond〉 { - 5 - } - } - ifScalarConflict: { - _#cond: true - if 〈0;_#cond〉 { - 5 - } - "soo" - } - ifScalarNested: { - _#cond: true - if 〈0;_#cond〉 { - { - { - 5 - } - } - } - } -} -- out/eval/stats -- Leaks: 0 Freed: 7 diff --git a/internal/core/compile/compile_test.go b/internal/core/compile/compile_test.go --- a/internal/core/compile/compile_test.go +++ b/internal/core/compile/compile_test.go @@ -15,8 +15,11 @@ package compile_test import ( + "bytes" "flag" "fmt" + "os" + "path/filepath" "strings" "testing" @@ -25,7 +28,9 @@ "cuelang.org/go/internal/core/compile" "cuelang.org/go/internal/core/debug" "cuelang.org/go/internal/core/runtime" + "cuelang.org/go/internal/cuetest" "cuelang.org/go/internal/cuetxtar" + "golang.org/x/tools/txtar" ) var ( @@ -33,8 +38,12 @@ ) func TestCompile(t *testing.T) { + if cuetest.UpdateGoldenFiles { + syncTestdataInputsCUE(t) + } + test := cuetxtar.TxTarTest{ - Root: "../../../cue/testdata/", + Root: "testdata", Name: "compile", } @@ -69,6 +78,49 @@ })) } }) +} + +func syncTestdataInputsCUE(t *testing.T) { + t.Helper() + + const srcRoot = "../../../cue/testdata" + const dstRoot = "testdata/sync" + + if err := os.RemoveAll(dstRoot); err != nil { + t.Fatal(err) + } + + err := filepath.WalkDir(srcRoot, func(srcPath string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + if entry.IsDir() || filepath.Ext(srcPath) != ".txtar" { + return nil + } + srcArchive, err := txtar.ParseFile(srcPath) + if err != nil { + return err + } + rel, err := filepath.Rel(srcRoot, srcPath) + if err != nil { + return err + } + dstPath := filepath.Join(dstRoot, rel) + + archive := &txtar.Archive{Comment: bytes.Clone(srcArchive.Comment)} + for _, f := range srcArchive.Files { + if strings.HasSuffix(f.Name, ".cue") { + archive.Files = append(archive.Files, txtar.File{Name: f.Name, Data: bytes.Clone(f.Data)}) + } + } + if err := os.MkdirAll(filepath.Dir(dstPath), 0777); err != nil { + return err + } + return os.WriteFile(dstPath, txtar.Format(archive), 0666) + }) + if err != nil { + t.Fatal(err) + } } // TestX is for debugging. Do not delete. diff --git a/cue/testdata/basicrewrite/aliases/aliases.txtar b/cue/testdata/basicrewrite/aliases/aliases.txtar --- a/cue/testdata/basicrewrite/aliases/aliases.txtar +++ b/cue/testdata/basicrewrite/aliases/aliases.txtar @@ -18,20 +18,6 @@ let b = 3 d: 3 }) --- out/compile -- ---- in.cue -{ - t0: { - _a: _ - let _b#1 = 〈0;_a〉 - _out: 〈0;let _b#1〉 - } - t1: { - _a: 〈0;let b#2〉 - let b#2 = 〈0;d〉 - d: 3 - } -} -- out/eval/stats -- Leaks: 0 Freed: 9 diff --git a/cue/testdata/builtins/list/issue332.txtar b/cue/testdata/builtins/list/issue332.txtar --- a/cue/testdata/builtins/list/issue332.txtar +++ b/cue/testdata/builtins/list/issue332.txtar @@ -28,22 +28,3 @@ Disjuncts: 0 NumCloseIDs: 15 --- out/compile -- ---- in.cue -{ - #d: { - #x: string - result: [ - 〈1;#x〉, - ] - } - #foo: { - #x: _ - y: 〈import;list〉.FlattenN((〈1;#d〉 & { - #x: 〈1;#x〉 - }).result, 1) - } - r: (〈0;#foo〉 & { - #x: "hello" - }) -} diff --git a/cue/testdata/builtins/list/sort.txtar b/cue/testdata/builtins/list/sort.txtar --- a/cue/testdata/builtins/list/sort.txtar +++ b/cue/testdata/builtins/list/sort.txtar @@ -14,17 +14,3 @@ Disjuncts: 0 NumCloseIDs: 5 --- out/compile -- ---- in.cue -{ - a: 〈import;list〉.Sort([ - 2, - 3, - 1, - 4, - ], { - x: _ - y: _ - less: (〈0;x〉 < 〈0;y〉) - }) -} diff --git a/internal/core/compile/testdata/README.md b/internal/core/compile/testdata/README.md new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/README.md @@ -0,0 +1,13 @@ +# Compile Testdata + +The `sync` directory is generated from `cue/testdata` when running: + +```sh +CUE_UPDATE=1 go test ./internal/core/compile +``` + +Do not edit files under `sync` directly. The update run deletes and recreates +that directory, then regenerates the compile output sections. + +Compile-specific test archives that should not be synced from `cue/testdata` +belong outside `sync`, for example under `local/`. diff --git a/internal/core/compile/testdata/sync/basicrewrite/000_errors.txtar b/internal/core/compile/testdata/sync/basicrewrite/000_errors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/000_errors.txtar @@ -0,0 +1,19 @@ +-- in.cue -- +a: _|_ & _|_ @test(err, code=user) +b: null & _|_ @test(err, code=user) +c: b.a == _|_ @test(eq, true) +d: _|_ != b.a @test(eq, false) +e: _|_ == _|_ @test(eq, true) +f: ({} & false) == _|_ @test(eq, true) +g: _|_ != ({} & false) @test(eq, false) +-- out/compile -- +--- in.cue +{ + a: (_|_(explicit error (_|_ literal) in source) & _|_(explicit error (_|_ literal) in source)) + b: (null & _|_(explicit error (_|_ literal) in source)) + c: (〈0;b〉.a == _|_(explicit error (_|_ literal) in source)) + d: (_|_(explicit error (_|_ literal) in source) != 〈0;b〉.a) + e: (_|_(explicit error (_|_ literal) in source) == _|_(explicit error (_|_ literal) in source)) + f: (({} & false) == _|_(explicit error (_|_ literal) in source)) + g: (_|_(explicit error (_|_ literal) in source) != ({} & false)) +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/001_regexp.txtar b/internal/core/compile/testdata/sync/basicrewrite/001_regexp.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/001_regexp.txtar @@ -0,0 +1,49 @@ +-- in.cue -- +c1: "a" =~ "a" @test(eq, true) +c2: "foo" =~ "[a-z]{3}" @test(eq, true) +c3: "foo" =~ "[a-z]{4}" @test(eq, false) +c4: "foo" !~ "[a-z]{4}" @test(eq, true) + +b1: =~"a" @test(eq, "a") +b1: "a" +b2: =~"[a-z]{3}" @test(eq, "foo") +b2: "foo" +b3: =~"[a-z]{4}" @test(err, code=eval, contains="out of bound", pos=[0:5, 1:5]) +b3: "foo" +b4: !~"[a-z]{4}" @test(eq, "foo") +b4: "foo" + +s1: !="b" & =~"c" @test(eq, =~"c") +s2: =~"c" & !="b" @test(eq, =~"c") +s3: !="b" & =~"[a-z]" @test(eq, !="b" & =~"[a-z]") +s4: =~"[a-z]" & !="b" @test(eq, =~"[a-z]" & !="b") // TODO: allow different order + +e1: "foo" =~ 1 @test(err, code=eval, + contains="cannot use 1", pos=[0:5, 0:14]) +e2: "foo" !~ true @test(err, code=eval, + contains="cannot use true", pos=[0:5, 0:14]) +e3: !="a" & <5 @test(err, code=eval, + contains="conflicting values", pos=[0:5, 0:13]) +-- out/compile -- +--- in.cue +{ + c1: ("a" =~ "a") + c2: ("foo" =~ "[a-z]{3}") + c3: ("foo" =~ "[a-z]{4}") + c4: ("foo" !~ "[a-z]{4}") + b1: =~"a" + b1: "a" + b2: =~"[a-z]{3}" + b2: "foo" + b3: =~"[a-z]{4}" + b3: "foo" + b4: !~"[a-z]{4}" + b4: "foo" + s1: (!="b" & =~"c") + s2: (=~"c" & !="b") + s3: (!="b" & =~"[a-z]") + s4: (=~"[a-z]" & !="b") + e1: ("foo" =~ 1) + e2: ("foo" !~ true) + e3: (!="a" & <5) +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/002_arithmetic.txtar b/internal/core/compile/testdata/sync/basicrewrite/002_arithmetic.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/002_arithmetic.txtar @@ -0,0 +1,56 @@ +-- in.cue -- +i1: 1 & int @test(eq, 1) +i2: 2 & int @test(eq, 2) + +sum: -1 + +2 @test(eq, 1) +div1: 2.0 / 3 * 6 @test(eq, 4.0) @test(kind=float) +div2: 2 / 3 * 6 @test(eq, 4.0) @test(kind=float, + hint="we may consider this to be int in the future") +div3: 1.00 / 1.00 @test(eq, 1.0) @test(kind=float) +divZero: 1.0 / 0 @test(err, code=eval, contains="division by zero", pos=[0:10]) +div00: 0 / 0 @test(err, code=eval, contains="division undefined", pos=[0:10]) +b: 1 != 4 @test(eq, true) +add: div1 + 1.0 @test(eq, 5.0) + +idiv00: div(0, 0) @test(err, code=eval, contains="division by zero", pos=[0:9]) +imod00: mod(0, 0) @test(err, code=eval, contains="division by zero", pos=[0:9]) +iquo00: quo(0, 0) @test(err, code=eval, contains="division by zero", pos=[0:9]) +irem00: rem(0, 0) @test(err, code=eval, contains="division by zero", pos=[0:9]) + +v1: 1.0T / 2.0 @test(eq, 5.0E+11) +v2: 2.0 == 2 @test(eq, true) +v3: 2.0 / 3.0 @test(eq, 0.6666666666666666666666666666666667) +v5: div(i1, i2) @test(eq, 0) + +e0: 2 + "a" @test(err, code=eval, contains="invalid operands", pos=[0:5, 0:9]) +e5: div(1.0, 2) @test(err, code=eval, contains="cannot use", pos=[0:9]) +e6: rem(2, 2.0) @test(err, code=eval, contains="cannot use", pos=[0:12]) +e7: quo(2, 2.0) @test(err, code=eval, contains="cannot use", pos=[0:12]) +e8: mod(1.0, 1) @test(err, code=eval, contains="cannot use", pos=[0:9]) +-- out/compile -- +--- in.cue +{ + i1: (1 & int) + i2: (2 & int) + sum: (-1 + +2) + div1: ((2.0 / 3) * 6) + div2: ((2 / 3) * 6) + div3: (1.00 / 1.00) + divZero: (1.0 / 0) + div00: (0 / 0) + b: (1 != 4) + add: (〈0;div1〉 + 1.0) + idiv00: div(0, 0) + imod00: mod(0, 0) + iquo00: quo(0, 0) + irem00: rem(0, 0) + v1: (1000000000000 / 2.0) + v2: (2.0 == 2) + v3: (2.0 / 3.0) + v5: div(〈0;i1〉, 〈0;i2〉) + e0: (2 + "a") + e5: div(1.0, 2) + e6: rem(2, 2.0) + e7: quo(2, 2.0) + e8: mod(1.0, 1) +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/003_integer-specific_arithmetic.txtar b/internal/core/compile/testdata/sync/basicrewrite/003_integer-specific_arithmetic.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/003_integer-specific_arithmetic.txtar @@ -0,0 +1,56 @@ +-- in.cue -- +q1: quo(5, 2) @test(eq, 2) +q2: quo(5, -2) @test(eq, -2) +q3: quo(-5, 2) @test(eq, -2) +q4: quo(-5, -2) @test(eq, 2) +qe1: quo(2.0, 1) @test(err, code=eval, pos=[0:10], contains="cannot use") +qe2: quo(2, 1.0) @test(err, code=eval, pos=[0:13], contains="cannot use") + +r1: rem(5, 2) @test(eq, 1) +r2: rem(5, -2) @test(eq, 1) +r3: rem(-5, 2) @test(eq, -1) +r4: rem(-5, -2) @test(eq, -1) +re1: rem(2.0, 1) @test(err, code=eval, pos=[0:10], contains="cannot use") +re2: rem(2, 1.0) @test(err, code=eval, pos=[0:13], contains="cannot use") + +d1: div(5, 2) @test(eq, 2) +d2: div(5, -2) @test(eq, -2) +d3: div(-5, 2) @test(eq, -3) +d4: div(-5, -2) @test(eq, 3) +de1: div(2.0, 1) @test(err, code=eval, pos=[0:10], contains="cannot use") +de2: div(2, 1.0) @test(err, code=eval, pos=[0:13], contains="cannot use") + +m1: mod(5, 2) @test(eq, 1) +m2: mod(5, -2) @test(eq, 1) +m3: mod(-5, 2) @test(eq, 1) +m4: mod(-5, -2) @test(eq, 1) +me1: mod(2.0, 1) @test(err, code=eval, pos=[0:10], contains="cannot use") +me2: mod(2, 1.0) @test(err, code=eval, pos=[0:13], contains="cannot use") +-- out/compile -- +--- in.cue +{ + q1: quo(5, 2) + q2: quo(5, -2) + q3: quo(-5, 2) + q4: quo(-5, -2) + qe1: quo(2.0, 1) + qe2: quo(2, 1.0) + r1: rem(5, 2) + r2: rem(5, -2) + r3: rem(-5, 2) + r4: rem(-5, -2) + re1: rem(2.0, 1) + re2: rem(2, 1.0) + d1: div(5, 2) + d2: div(5, -2) + d3: div(-5, 2) + d4: div(-5, -2) + de1: div(2.0, 1) + de2: div(2, 1.0) + m1: mod(5, 2) + m2: mod(5, -2) + m3: mod(-5, 2) + m4: mod(-5, -2) + me1: mod(2.0, 1) + me2: mod(2, 1.0) +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/004_booleans.txtar b/internal/core/compile/testdata/sync/basicrewrite/004_booleans.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/004_booleans.txtar @@ -0,0 +1,17 @@ +-- in.cue -- +t: true @test(eq, true) +t: !false +f: false @test(eq, false) +f: !t +e: true @test(err, code=eval, pos=[0:4, 1:4], contains="conflicting values") +e: !true +-- out/compile -- +--- in.cue +{ + t: true + t: !false + f: false + f: !〈0;t〉 + e: true + e: !true +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/005_boolean_arithmetic.txtar b/internal/core/compile/testdata/sync/basicrewrite/005_boolean_arithmetic.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/005_boolean_arithmetic.txtar @@ -0,0 +1,17 @@ +-- in.cue -- +a: true && true @test(eq, true) +b: true || false @test(eq, true) +c: false == true @test(eq, false) +d: false != true @test(eq, true) +e: true & true @test(eq, true) +f: true & false @test(err, code=eval, pos=[0:4, 0:11]) +-- out/compile -- +--- in.cue +{ + a: (true && true) + b: (true || false) + c: (false == true) + d: (false != true) + e: (true & true) + f: (true & false) +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/006_basic_type.txtar b/internal/core/compile/testdata/sync/basicrewrite/006_basic_type.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/006_basic_type.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +a: 1 & int @test(eq, 1) +b: number & 1 @test(eq, 1) +c: 1.0 @test(eq, 1.0) +c: float +d: int & float @test(err, code=eval, pos=[0:4, 0:10]) +e: "4" & string @test(eq, "4") +f: true @test(eq, true) +f: bool +-- out/compile -- +--- in.cue +{ + a: (1 & int) + b: (number & 1) + c: 1.0 + c: float + d: (int & float) + e: ("4" & string) + f: true + f: bool +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/007_strings_and_bytes.txtar b/internal/core/compile/testdata/sync/basicrewrite/007_strings_and_bytes.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/007_strings_and_bytes.txtar @@ -0,0 +1,24 @@ +-- in.cue -- +s0: "foo" + "bar" @test(eq, "foobar") +s1: 3 * "abc" @test(eq, "abcabcabc") +s2: "abc" * 2 @test(eq, "abcabc") + +b0: 'foo' + 'bar' @test(eq, 'foobar') +b1: 3 * 'abc' @test(eq, 'abcabcabc') +b2: 'abc' * 2 @test(eq, 'abcabc') + +// TODO: consider the semantics of this and perhaps allow this. +e0: "a" + '' @test(err, code=eval) +e1: 'b' + "c" @test(err, code=eval) +-- out/compile -- +--- in.cue +{ + s0: ("foo" + "bar") + s1: (3 * "abc") + s2: ("abc" * 2) + b0: ('foo' + 'bar') + b1: (3 * 'abc') + b2: ('abc' * 2) + e0: ("a" + '') + e1: ('b' + "c") +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/008_escaping.txtar b/internal/core/compile/testdata/sync/basicrewrite/008_escaping.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/008_escaping.txtar @@ -0,0 +1,11 @@ +-- in.cue -- +a: "foo\nbar" @test(eq, "foo\nbar") +b: a @test(eq, "foo\nbar") + +// TODO: mimic http://exploringjs.com/es6/ch_template-literals.html#sec_introduction-template-literals +-- out/compile -- +--- in.cue +{ + a: "foo\nbar" + b: 〈0;a〉 +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/009_reference.txtar b/internal/core/compile/testdata/sync/basicrewrite/009_reference.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/009_reference.txtar @@ -0,0 +1,37 @@ +-- in.cue -- +a: b @test(eq, 2) +b: 2 +d: { + d: 3 + e: d @test(eq, 3) +} @test(eq, {d: 3, e: 3}) +e: { + @test(eq, { + e: {v: 1} + f: {v: 1} + }) + e: { + v: 1 + } + f: { + v: e.v + } +} +-- out/compile -- +--- in.cue +{ + a: 〈0;b〉 + b: 2 + d: { + d: 3 + e: 〈0;d〉 + } + e: { + e: { + v: 1 + } + f: { + v: 〈1;e〉.v + } + } +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/010_lists.txtar b/internal/core/compile/testdata/sync/basicrewrite/010_lists.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/010_lists.txtar @@ -0,0 +1,61 @@ +-- in.cue -- +list: [1, 2, 3] @test(eq, [1, 2, 3]) +index: [1, 2, 3][1] @test(eq, 2) +unify: [1, 2, 3] & [_, 2, 3] @test(eq, [1, 2, 3]) +e: [] & 4 @test(err, code=eval, pos=[0:8, 0:13], contains="conflicting values", args=[list, int]) + +// No "contains" as message may vary by implementation. +e2: [3]["d"] @test(err, code=eval, pos=[0:12]) +e3: [3][-1] @test(err, code=eval, pos=[0:8, 0:12], contains="invalid index", args=[-1]) +e4: [1, 2, ...>=4 & <=5] & [1, 2, 4, 8] @test(err, code=eval, pos=[0:24, 0:41], contains="invalid value", args=[8, <=5]) +e5: [1, 2, 4, 8] & [1, 2, ...>=4 & <=5] @test(err, code=eval, pos=[0:39, 0:18], contains="invalid value", args=[8, <=5]) +-- out/compile -- +--- in.cue +{ + list: [ + 1, + 2, + 3, + ] + index: [ + 1, + 2, + 3, + ][1] + unify: ([ + 1, + 2, + 3, + ] & [ + _, + 2, + 3, + ]) + e: ([] & 4) + e2: [ + 3, + ]["d"] + e3: [ + 3, + ][-1] + e4: ([ + 1, + 2, + ...(>=4 & <=5), + ] & [ + 1, + 2, + 4, + 8, + ]) + e5: ([ + 1, + 2, + 4, + 8, + ] & [ + 1, + 2, + ...(>=4 & <=5), + ]) +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/012_selecting.txtar b/internal/core/compile/testdata/sync/basicrewrite/012_selecting.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/012_selecting.txtar @@ -0,0 +1,39 @@ +-- in.cue -- +obj: {a: 1, b: 2} @test(eq, {a: 1, b: 2}) +index: {a: 1, b: 2}["b"] @test(eq, 2) +mulidx: {a: 1, b: {a: 1, b: 3}}["b"]["b"] @test(eq, 3) +e: {a: 1}[4] @test(err, code=eval, pos=[0:16]) +f: {a: 1}.b @test(err, code=incomplete, pos=[0:16]) +g: {a: 1}["b"] @test(err, code=incomplete, pos=[0:16]) +h: [3].b @test(err, code=eval, pos=[0:13]) +-- out/compile -- +--- in.cue +{ + obj: { + a: 1 + b: 2 + } + index: { + a: 1 + b: 2 + }["b"] + mulidx: { + a: 1 + b: { + a: 1 + b: 3 + } + }["b"]["b"] + e: { + a: 1 + }[4] + f: { + a: 1 + }.b + g: { + a: 1 + }["b"] + h: [ + 3, + ].b +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/013_obj_unify.txtar b/internal/core/compile/testdata/sync/basicrewrite/013_obj_unify.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/013_obj_unify.txtar @@ -0,0 +1,52 @@ +-- in.cue -- +o1: {a: 1} & {b: 2} @test(eq, {a: 1, b: 2}) +o2: {a: 1, b: 2} & {b: 2} @test(eq, {a: 1, b: 2}) +o3: {a: 1} & {a: 1, b: 2} @test(eq, {a: 1, b: 2}) +o4: {a: 1} & {b: 2} +o4: {a: 1, b: 2} & {b: 2} +o4: {a: 1} & {a: 1, b: 2} @test(eq, {a: 1, b: 2}) + +e: 1 @test(err, code=eval, pos=[0:4, 1:4], contains="conflicting values") +e: {a: 3} +-- out/compile -- +--- in.cue +{ + o1: ({ + a: 1 + } & { + b: 2 + }) + o2: ({ + a: 1 + b: 2 + } & { + b: 2 + }) + o3: ({ + a: 1 + } & { + a: 1 + b: 2 + }) + o4: ({ + a: 1 + } & { + b: 2 + }) + o4: ({ + a: 1 + b: 2 + } & { + b: 2 + }) + o4: ({ + a: 1 + } & { + a: 1 + b: 2 + }) + e: 1 + e: { + a: 3 + } +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/014_disjunctions.txtar b/internal/core/compile/testdata/sync/basicrewrite/014_disjunctions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/014_disjunctions.txtar @@ -0,0 +1,54 @@ +-- in.cue -- +o1: 1 | 2 | 3 @test(eq, 1 | 2 | 3) +o2: (1 | 2 | 3) & 1 @test(eq, 1) +o3: 2 & (1 | *2 | 3) @test(eq, 2) +o4: (1 | *2 | 3) & (1 | 2 | *3) @test(eq, 1 | 2 | 3) +o5: (1 | *2 | 3) & (3 | *2 | 1) @test(eq, *2 | 1 | 3) +o6: (1 | 2 | 3) & (3 | 1 | 2) @test(eq, 1 | 2 | 3) +o7: (1 | 2 | 3) & (2 | 3) @test(eq, 2 | 3) +o8: (1 | 2 | 3) & (3 | 2) @test(eq, 2 | 3) +o9: (2 | 3) & (1 | 2 | 3) @test(eq, 2 | 3) +o10: (3 | 2) & (1 | *2 | 3) @test(eq, *2 | 3) + +m1: (1 | (*2 | 3)) & (>=2 & <=3) @test(eq, *2 | 3) +m2: (1 | (*2 | 3)) & (2 | 3) @test(eq, *2 | 3) +m3: (*1 | *(*2 | 3)) & (2 | 3) @test(eq, *2 | 3) +m4: (2 | 3) & (*2 | 3) @test(eq, *2 | 3) +m5: (*2 | 3) & (2 | 3) @test(eq, *2 | 3) + +// 2&(*2 | 3) | 3&(*2 | 3) +// (*1 | (*2 | 3)) & (2 | 3) +// *1& (2 | 3) | (*2 | 3)&(2 | 3) +// *2&(2 | 3) | 3&(2 | 3) + +// (2 | 3)&(*1 | (*2 | 3)) +// 2&(*1 | (*2 | 3)) | 3&(*1 | (*2 | 3)) +// *1&2 | (*2 | 3)&2 | *1&3 | (*2 | 3)&3 +// (*2 | 3)&2 | (*2 | 3)&3 +// *2 | 3 + +// All errors are treated the same as per the unification model. +i1: [1, 2][3] | "c" @test(eq, "c") +-- out/compile -- +--- in.cue +{ + o1: (1|2|3) + o2: ((1|2|3) & 1) + o3: (2 & (1|*2|3)) + o4: ((1|*2|3) & (1|2|*3)) + o5: ((1|*2|3) & (3|*2|1)) + o6: ((1|2|3) & (3|1|2)) + o7: ((1|2|3) & (2|3)) + o8: ((1|2|3) & (3|2)) + o9: ((2|3) & (1|2|3)) + o10: ((3|2) & (1|*2|3)) + m1: ((1|(*2|3)) & (>=2 & <=3)) + m2: ((1|(*2|3)) & (2|3)) + m3: ((*1|*(*2|3)) & (2|3)) + m4: ((2|3) & (*2|3)) + m5: ((*2|3) & (2|3)) + i1: ([ + 1, + 2, + ][3]|"c") +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/015_types.txtar b/internal/core/compile/testdata/sync/basicrewrite/015_types.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/015_types.txtar @@ -0,0 +1,23 @@ +-- in.cue -- +i: int @test(eq, int) +j: int & 3 @test(eq, 3) +s: string @test(eq, string) +t: "s" & string @test(eq, "s") +e: int & string @test(err, code=eval, contains="conflicting values") +e2: 1 & string @test(err, code=eval, contains="conflicting values") +b: !int @test(err, code=eval, pos=[0:6], contains="invalid operand") +p: +true @test(err, code=eval, pos=[0:5], contains="invalid operation") +m: -false @test(err, code=eval, pos=[0:5], contains="invalid operation") +-- out/compile -- +--- in.cue +{ + i: int + j: (int & 3) + s: string + t: ("s" & string) + e: (int & string) + e2: (1 & string) + b: !int + p: +true + m: -false +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/016_comparison.txtar b/internal/core/compile/testdata/sync/basicrewrite/016_comparison.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/016_comparison.txtar @@ -0,0 +1,792 @@ +#name: comparison +#evalPartial +-- cue.mod/module.cue -- +module: "x.test" +language: version: "v0.14.0" +-- in.cue -- +// Explanation of error markers: +// t: true +// f: false +// e: permanent error +// i: incomplete error +numbers: { + tLss: 1 < 2 @test(eq, true) + tLeq: 1 <= 1.0 @test(eq, true) + tLeq: 2.0 <= 3 @test(eq, true) + tEql: 1 == 1.0 @test(eq, true) + tNeq: 1.0 == 1 @test(eq, true) + tGeq: 2.0 >= 2 @test(eq, true) + tGtr: !(2 > 3) @test(eq, true) + tExpr: "a"+"b" == "ab" @test(eq, true) +} +-- lists.cue -- +lists: { + // Equal lists + t1: [] == [] @test(eq, true) + t2: [1, 2, 3] == [1, 2, 3] @test(eq, true) + t3: [1, "foo", true] == [1, "foo", true] @test(eq, true) + t4: [[1, 2], [3, 4]] == [[1, 2], [3, 4]] @test(eq, true) + t5: ([1, ...int] & [1, 2, 3]) == [1, 2, 3] @test(eq, true) + t6: [1] == ([...1] & [_]) @test(eq, true) + t7: [{a: 1}] == ([...{a: 1}] & [_]) @test(eq, true) + t8: [{a: 1}] != [...{a: 1}] @test(eq, true) // true as it is not equal + t9: [...int] == [...string] @test(eq, true) // additional types are irrelevant. + + // Non-equal lists + f1: [1, 2, 3] == [1, 2, 4] @test(eq, false) + f2: [1, 2, 3] == [1, 2] @test(eq, false) + f3: [1, 2, 3] == [1, 3, 2] @test(eq, false) // different order + f4: [] == [1] @test(eq, false) + f5: [1, 2] == [1, "2"] @test(eq, false) // different types + f6: [*1 | 2 | 3] == [*2 | 3 | 4] @test(eq, false) + + + // TODO: types can never match. This could be a permanent error. + // This was V2 behavior. + eIncompat: [int] == [string] @test(err, code=incomplete|eval, pos=[0:13]) @test(err:todo, code=eval, pos=[0:13]) + + // Error cases + eErrPassthrough: [1/0] == [1] @test(err, code=eval, contains="invalid", pos=[0:19]) + + // incomplete passtrhough + _e3l: {} + eErrPassthrough: [_e3l.b] == [1] @test(err, code=eval, + suberr=(code=eval, contains="division by zero", pos=[-4:19]), + suberr=(code=eval, contains="conflicting values", pos=[6:19]), + ) + + // error reported as part of combined eErrPassthrough error + eErrPassthrough: [1, 2] == [1, int & string] + + // Inequality tests + tNeq1: [1, 2] != [1, 3] @test(eq, true) + fNeq2: [1, 2] != [1, 2] @test(eq, false) +} +-- structs.cue -- +@experiment(structcmp) + +structs: eq: { + // Equal structs + t1: {} == {} @test(eq, true) + t2: {a: 1, b: "foo"} == {a: 1, b: "foo"} @test(eq, true) + t3: {a: 1, b: 2} == {b: 2, a: 1} @test(eq, true) // different order + t4: {a: {x: 1, y: 2}} == {a: {x: 1, y: 2}} @test(eq, true) // nested structs + t5: ({a: 1, b: 2, c: 3} & {d: 4}) == {a: 1, b: 2, c: 3, d: 4} @test(eq, true) // unification + t6: {{{{a: 1}}}} == {{a: 1}} @test(eq, true) // embedding + t7: {[string]: int} == {[string]: string} @test(eq, true) + _t8l: *1 | 2 | 3 + t8: {a: _t8l} == {a: 3| *1} @test(eq, true) + + // Non-equal structs + f1: {a: 1, b: "foo"} == {a: 2, b: "foo"} @test(eq, false) + f2: {a: 1, b: "foo"} == {a: 1, c: "foo"} @test(eq, false) + f3: {a: {x: 1}} == {a: {x: 2}} @test(eq, false) + f4: {a: 1, b: 2} == {a: 1} @test(eq, false) + f5: {} == {a: 1} @test(eq, false) + f6: {a: 1} == 1 @test(eq, false) + f7: {a: 1, b?: 2} == {a: 1, b: 2} @test(eq, false) // optional field does not exist + f8: {{{{a: 1}}}} == {{a: 1, b: 2}} @test(eq, false) // embedding + _f9r: *2 | 3 | 4 + f9: {a: *1 | 2 | 3} == {a: _f9r} @test(eq, false) + + // Only test some versions of != recognizing the same code paths are + // followed for ==. + tNe1: {a: 1} != {a: 2} @test(eq, true) + fNe1: {a: 2} != {a: 2} @test(eq, false) +} +ignore: { + t0: {_hidden: 1} == {_hidden: 2} @test(eq, true) + t1: {_hidden: 1} == {} @test(eq, true) + t1: {} == {_hidden: 1} @test(eq, true) + t2: {#def: 1} == {#def: 2} @test(eq, true) + t3: {#def: 1} == {} @test(eq, true) + t4: {} == {#def: 1} @test(eq, true) + t5: {_#hiddenDef: 1} == {_#hiddenDef: 2} @test(eq, true) + t6: {_#hiddenDef: 1} == {} @test(eq, true) + t7: {} == {_#hiddenDef: 1} @test(eq, true) + + f0: {_hidden: 1} != {_hidden: 2} @test(eq, false) + f1: {_hidden: 1} != {} @test(eq, false) + f1: {} != {_hidden: 1} @test(eq, false) + f2: {#def: 1} != {#def: 2} @test(eq, false) + f3: {#def: 1} != {} @test(eq, false) + f4: {} != {#def: 1} @test(eq, false) + f5: {_#hiddenDef: 1} != {_#hiddenDef: 2} @test(eq, false) + f6: {_#hiddenDef: 1} != {} @test(eq, false) + f7: {} != {_#hiddenDef: 1} @test(eq, false) +} +embeddedScalars: { + _one: 1 + _two: 2 + + t1: 1 == {1} @test(eq, true) + t2: [1] == [{1}] @test(eq, true) + t3: {a: 1} == {a: {1}} @test(eq, true) + t4: [_one] == [{_one}] @test(eq, true) + + f1: _one == [{_two}] @test(eq, false) + f2: {a: _two} == {a: {_one}} @test(eq, false) + f3: _one == {_two} @test(eq, false) + f4: [_two] == [{_one}] @test(eq, false) +} + +// Error cases +incomplete: { + _int: int + _string: string + + iErr1: {a!: _int} == {a!: _int} @test(err, code=incomplete, contains="field is required but not present", pos=[0:9]) + iErr2: {a!: _int} == {a!: 1} @test(err, code=incomplete, contains="field is required but not present", pos=[0:9]) + eErr3: {a: _int} == {a: _string} @test(err, code=incomplete|eval, contains="incomplete value int", pos=[0:9]) @test(err:todo, code=eval) + eErr4: {a: 1/0} == {a: 1} @test(err, code=eval, contains="failed arithmetic", pos=[0:9]) // Error passthrough + + eErr5: {a: 1} == {a: _int & _string} @test(err, code=eval, contains="conflicting values", pos=[0:9]) // Error passthrough + iErr6: {a!: 1} == {a: 1} @test(err, code=incomplete, contains="field is required but not present", pos=[0:9]) + eErr7: {a: 1} == {a!: 2} @test(err, code=incomplete, contains="field is required but not present", pos=[0:9]) @test(err:todo, code=eval) // Required cannot match even when concrete. + + // Only test some versions of != recognizing the same code paths are + // followed for ==. + tNe1: {a: 1} != {a: 2} @test(eq, true) + fNe1: {a: 2} != {a: 2} @test(eq, false) +} +-- typediff.cue -- +@experiment(structcmp) + +diffTypes: { + // Right now, all these tests are expected to report a type error. The + // result indicators are assuming, however, that we define equality to be + // total for all concrete values. This means that those marked as false (or + // true for !=) are permanent errors. + + // Tests with different types. + fScalar1: 2 == "s" @test(eq, false) + fScalar2: "s" == 2 @test(eq, false) + fScalar3: true == 2 @test(eq, false) + + fStruct1: {a: 1} == "s" @test(eq, false) + + fList1: 5 == [5] @test(eq, false) + fList2: "ab" == ["a", "b"] @test(eq, false) + fList3: true == [true] @test(eq, false) + fList4: {a: 1} == [{a: 1}] @test(eq, false) + fList5: [1, 2] == 3 @test(eq, false) + fList6: [1, 2] == "ab" @test(eq, false) + fList7: [true] == false @test(eq, false) + fList8: [1, 2] == {a: 1} @test(eq, false) + fList9: [1, 2] == null @test(eq, false) + + // Negated comparisons + tNeList1: [1, 2] != 3 @test(eq, true) + tNeList2: [1, 2] != "ab" @test(eq, true) + + _int: int + _string: string + + // Lists with incompatible element types + iRecursive1: [_int] == [_int] @test(err, code=incomplete, contains="incomplete value int", pos=[0:15]) // can still match, but not concrete + eRecursive2: [_int] == [_string] @test(err, code=incomplete, contains="incomplete value int", pos=[0:15]) @test(err:todo, code=eval) // can never match + fRecursive3: [1, 2] == [1, "2"] @test(eq, false) + tRecursive4: [...int] == [...string] @test(eq, true) + fRecursive5: [1, "a"] == [1, 2] @test(eq, false) + + eNe1: [1, 2] != [_int] @test(err, code=incomplete, contains="incomplete value int", pos=[0:8]) @test(err:todo, code=eval) // length can never match + iNe2: [_int] != [1] @test(err, code=incomplete, contains="incomplete value int", pos=[0:8]) + iNe3: {a: 1} != {a: _int} @test(err, code=incomplete, contains="incomplete value int", pos=[0:8]) + iNe4: {a: _int} != {a: 1} @test(err, code=incomplete, contains="incomplete value int", pos=[0:8]) +} +-- out/compile -- +--- in.cue +{ + numbers: { + tLss: (1 < 2) + tLeq: (1 <= 1.0) + tLeq: (2.0 <= 3) + tEql: (1 == 1.0) + tNeq: (1.0 == 1) + tGeq: (2.0 >= 2) + tGtr: !(2 > 3) + tExpr: (("a" + "b") == "ab") + } +} +--- lists.cue +{ + lists: { + t1: ([] == []) + t2: ([ + 1, + 2, + 3, + ] == [ + 1, + 2, + 3, + ]) + t3: ([ + 1, + "foo", + true, + ] == [ + 1, + "foo", + true, + ]) + t4: ([ + [ + 1, + 2, + ], + [ + 3, + 4, + ], + ] == [ + [ + 1, + 2, + ], + [ + 3, + 4, + ], + ]) + t5: (([ + 1, + ...int, + ] & [ + 1, + 2, + 3, + ]) == [ + 1, + 2, + 3, + ]) + t6: ([ + 1, + ] == ([ + ...1, + ] & [ + _, + ])) + t7: ([ + { + a: 1 + }, + ] == ([ + ...{ + a: 1 + }, + ] & [ + _, + ])) + t8: ([ + { + a: 1 + }, + ] != [ + ...{ + a: 1 + }, + ]) + t9: ([ + ...int, + ] == [ + ...string, + ]) + f1: ([ + 1, + 2, + 3, + ] == [ + 1, + 2, + 4, + ]) + f2: ([ + 1, + 2, + 3, + ] == [ + 1, + 2, + ]) + f3: ([ + 1, + 2, + 3, + ] == [ + 1, + 3, + 2, + ]) + f4: ([] == [ + 1, + ]) + f5: ([ + 1, + 2, + ] == [ + 1, + "2", + ]) + f6: ([ + (*1|2|3), + ] == [ + (*2|3|4), + ]) + eIncompat: ([ + int, + ] == [ + string, + ]) + eErrPassthrough: ([ + (1 / 0), + ] == [ + 1, + ]) + _e3l: {} + eErrPassthrough: ([ + 〈1;_e3l〉.b, + ] == [ + 1, + ]) + eErrPassthrough: ([ + 1, + 2, + ] == [ + 1, + (int & string), + ]) + tNeq1: ([ + 1, + 2, + ] != [ + 1, + 3, + ]) + fNeq2: ([ + 1, + 2, + ] != [ + 1, + 2, + ]) + } +} +--- structs.cue +{ + structs: { + eq: { + t1: ({} == {}) + t2: ({ + a: 1 + b: "foo" + } == { + a: 1 + b: "foo" + }) + t3: ({ + a: 1 + b: 2 + } == { + b: 2 + a: 1 + }) + t4: ({ + a: { + x: 1 + y: 2 + } + } == { + a: { + x: 1 + y: 2 + } + }) + t5: (({ + a: 1 + b: 2 + c: 3 + } & { + d: 4 + }) == { + a: 1 + b: 2 + c: 3 + d: 4 + }) + t6: ({ + { + { + { + a: 1 + } + } + } + } == { + { + a: 1 + } + }) + t7: ({ + [string]: int + } == { + [string]: string + }) + _t8l: (*1|2|3) + t8: ({ + a: 〈1;_t8l〉 + } == { + a: (3|*1) + }) + f1: ({ + a: 1 + b: "foo" + } == { + a: 2 + b: "foo" + }) + f2: ({ + a: 1 + b: "foo" + } == { + a: 1 + c: "foo" + }) + f3: ({ + a: { + x: 1 + } + } == { + a: { + x: 2 + } + }) + f4: ({ + a: 1 + b: 2 + } == { + a: 1 + }) + f5: ({} == { + a: 1 + }) + f6: ({ + a: 1 + } == 1) + f7: ({ + a: 1 + b?: 2 + } == { + a: 1 + b: 2 + }) + f8: ({ + { + { + { + a: 1 + } + } + } + } == { + { + a: 1 + b: 2 + } + }) + _f9r: (*2|3|4) + f9: ({ + a: (*1|2|3) + } == { + a: 〈1;_f9r〉 + }) + tNe1: ({ + a: 1 + } != { + a: 2 + }) + fNe1: ({ + a: 2 + } != { + a: 2 + }) + } + } + ignore: { + t0: ({ + _hidden: 1 + } == { + _hidden: 2 + }) + t1: ({ + _hidden: 1 + } == {}) + t1: ({} == { + _hidden: 1 + }) + t2: ({ + #def: 1 + } == { + #def: 2 + }) + t3: ({ + #def: 1 + } == {}) + t4: ({} == { + #def: 1 + }) + t5: ({ + _#hiddenDef: 1 + } == { + _#hiddenDef: 2 + }) + t6: ({ + _#hiddenDef: 1 + } == {}) + t7: ({} == { + _#hiddenDef: 1 + }) + f0: ({ + _hidden: 1 + } != { + _hidden: 2 + }) + f1: ({ + _hidden: 1 + } != {}) + f1: ({} != { + _hidden: 1 + }) + f2: ({ + #def: 1 + } != { + #def: 2 + }) + f3: ({ + #def: 1 + } != {}) + f4: ({} != { + #def: 1 + }) + f5: ({ + _#hiddenDef: 1 + } != { + _#hiddenDef: 2 + }) + f6: ({ + _#hiddenDef: 1 + } != {}) + f7: ({} != { + _#hiddenDef: 1 + }) + } + embeddedScalars: { + _one: 1 + _two: 2 + t1: (1 == { + 1 + }) + t2: ([ + 1, + ] == [ + { + 1 + }, + ]) + t3: ({ + a: 1 + } == { + a: { + 1 + } + }) + t4: ([ + 〈1;_one〉, + ] == [ + { + 〈2;_one〉 + }, + ]) + f1: (〈0;_one〉 == [ + { + 〈2;_two〉 + }, + ]) + f2: ({ + a: 〈1;_two〉 + } == { + a: { + 〈2;_one〉 + } + }) + f3: (〈0;_one〉 == { + 〈1;_two〉 + }) + f4: ([ + 〈1;_two〉, + ] == [ + { + 〈2;_one〉 + }, + ]) + } + incomplete: { + _int: int + _string: string + iErr1: ({ + a!: 〈1;_int〉 + } == { + a!: 〈1;_int〉 + }) + iErr2: ({ + a!: 〈1;_int〉 + } == { + a!: 1 + }) + eErr3: ({ + a: 〈1;_int〉 + } == { + a: 〈1;_string〉 + }) + eErr4: ({ + a: (1 / 0) + } == { + a: 1 + }) + eErr5: ({ + a: 1 + } == { + a: (〈1;_int〉 & 〈1;_string〉) + }) + iErr6: ({ + a!: 1 + } == { + a: 1 + }) + eErr7: ({ + a: 1 + } == { + a!: 2 + }) + tNe1: ({ + a: 1 + } != { + a: 2 + }) + fNe1: ({ + a: 2 + } != { + a: 2 + }) + } +} +--- typediff.cue +{ + diffTypes: { + fScalar1: (2 == "s") + fScalar2: ("s" == 2) + fScalar3: (true == 2) + fStruct1: ({ + a: 1 + } == "s") + fList1: (5 == [ + 5, + ]) + fList2: ("ab" == [ + "a", + "b", + ]) + fList3: (true == [ + true, + ]) + fList4: ({ + a: 1 + } == [ + { + a: 1 + }, + ]) + fList5: ([ + 1, + 2, + ] == 3) + fList6: ([ + 1, + 2, + ] == "ab") + fList7: ([ + true, + ] == false) + fList8: ([ + 1, + 2, + ] == { + a: 1 + }) + fList9: ([ + 1, + 2, + ] == null) + tNeList1: ([ + 1, + 2, + ] != 3) + tNeList2: ([ + 1, + 2, + ] != "ab") + _int: int + _string: string + iRecursive1: ([ + 〈1;_int〉, + ] == [ + 〈1;_int〉, + ]) + eRecursive2: ([ + 〈1;_int〉, + ] == [ + 〈1;_string〉, + ]) + fRecursive3: ([ + 1, + 2, + ] == [ + 1, + "2", + ]) + tRecursive4: ([ + ...int, + ] == [ + ...string, + ]) + fRecursive5: ([ + 1, + "a", + ] == [ + 1, + 2, + ]) + eNe1: ([ + 1, + 2, + ] != [ + 〈1;_int〉, + ]) + iNe2: ([ + 〈1;_int〉, + ] != [ + 1, + ]) + iNe3: ({ + a: 1 + } != { + a: 〈1;_int〉 + }) + iNe4: ({ + a: 〈1;_int〉 + } != { + a: 1 + }) + } +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/017_null.txtar b/internal/core/compile/testdata/sync/basicrewrite/017_null.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/017_null.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +eql: null == null @test(eq, true) +neq: null != null @test(eq, false) +unf: null & null @test(eq, null) + +// errors +eq1: null == 1 @test(eq, false) +eq2: 1 == null @test(eq, false) +ne1: "s" != null @test(eq, true) +call: null() @test(err, code=eval, pos=[0:7], contains="cannot call non-function") +-- out/compile -- +--- in.cue +{ + eql: (null == null) + neq: (null != null) + unf: (null & null) + eq1: (null == 1) + eq2: (1 == null) + ne1: ("s" != null) + call: null() +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/018_self-reference_cycles.txtar b/internal/core/compile/testdata/sync/basicrewrite/018_self-reference_cycles.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/018_self-reference_cycles.txtar @@ -0,0 +1,184 @@ +-- in.cue -- +a: b - 100 @test(err, code=cycle) +b: a + 100 @test(err, code=cycle) + +c: [c[1], c[0]] @test(eq, [_, _]) + +d: e - 1 @test(eq, 1) +e: 1 + d +e: *2 | 0 @test(eq, *2 | 0) +-- disjunction.cue -- +oneway: { + t1: { + a: *1 | int + a: b + 1 + b: "b" and (>"b" & string) get equated when at least the task has + // completed. + #a + #a: <"a" | >"b" | string + #a: <"a" | >"b" | string // conjuncts 127 disjuncts 120 + #a: <"a" | >"b" | string // conjuncts 219 disjuncts 210 (+92; +90) + #a: <"a" | >"b" | string // conjuncts 311 disjuncts 300 (+92; +90) + #a: <"a" | >"b" | string // conjuncts 403 disjuncts 390 (+92; +90) + #a: <"a" | >"b" | string // conjuncts 495 disjuncts 480 (+92; +90) +} +@test(eq, at=issue3610, { + <"a" + #a: <"a" | >"b" | string +} | { + >"b" + #a: <"a" | >"b" | string +} | { + string + #a: <"a" | >"b" | string +}) + +-- out/compile -- +--- in.cue +{ + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + pat: ({ + [string]: 1 + }|{ + a: 2 + }) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + list: ([ + 1, + ]|[ + 2, + ]|[ + 3, + ]|[ + 4, + ]) + issue3610: { + 〈0;#a〉 + #a: (<"a"|>"b"|string) + #a: (<"a"|>"b"|string) + #a: (<"a"|>"b"|string) + #a: (<"a"|>"b"|string) + #a: (<"a"|>"b"|string) + #a: (<"a"|>"b"|string) + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/disjunction.txtar b/internal/core/compile/testdata/sync/benchmarks/disjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/disjunction.txtar @@ -0,0 +1,139 @@ +// Triggering recomputation of disjunctions on each branch results +// in exponential run time. Ensure this does not happen. +-- in.cue -- +x: a0: {} +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int +x: [_]: f: *1 | int + +x: { + a0: {} + @test(eq, {a0: {f: *1 | int}}) +} +-- out/compile -- +--- in.cue +{ + x: { + a0: {} + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + [_]: { + f: (*1|int) + } + } + x: { + a0: {} + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/inlinedisjunction.txtar b/internal/core/compile/testdata/sync/benchmarks/inlinedisjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/inlinedisjunction.txtar @@ -0,0 +1,60 @@ +-- in.cue -- +#def: { + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {c: string} + {} | {a: string} +} +x: #def +x: c: "foo" + +@test(eq, { + #def: {} | {a: string} | {c: string} | {c: string, a: string} + x: {c: "foo"} | {c: "foo", a: string} +}) +-- out/compile -- +--- in.cue +{ + #def: { + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + c: string + }) + ({}|{ + a: string + }) + } + x: 〈0;#def〉 + x: { + c: "foo" + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue1684.txtar b/internal/core/compile/testdata/sync/benchmarks/issue1684.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue1684.txtar @@ -0,0 +1,165 @@ +# Tests that recursive secret/nested-map structures (#secrets) unify correctly +# without exponential conjunct expansion. Performance regression originally +# caused quadratic growth when #secrets disjunctions were repeatedly applied. +# https://cuelang.org/issue/1684 + +// TODO: significantly reduce the number of counts in this evaluation. +-- in.cue -- +#Secret: { + $secret: id: string +} +#secrets: #Secret | {[string]: #secrets} + +out: #secrets & { + FOO: $secret: id: "100" + ONE: TWO: THREE: $secret: id: "123" +} + +#Secret: { + $secret: _id: string +} +#secrets: #Secret | {[string]: #secrets} + +out: #secrets & { + FOO: $secret: _id: "100" + ONE: TWO: THREE: $secret: _id: "123" +} @test(eq, { + FOO: $secret: {id: "100", _id: "100"} + ONE: TWO: THREE: $secret: {id: "123", _id: "123"} +}) + +-- perf.cue -- +nestedCross: closed: { + #D: {id: string} | {[string]: #D} + #D: {id: string} | {[string]: #D} + #D: {id: string} | {[string]: #D} +} @test(eq, {#D: {id: string} | {}}) + +nestedCross: open: { + D: {id: string} | {[string]: D} + D: {id: string} | {[string]: D} + D: {id: string} | {[string]: D} +} @test(eq, {D: {id: string} | {}}) + +// TODO(perf): support this case. This is currently exponential, although the +// tight bound on the detection of structural cycles mitigates the situation. +// +// An additional improvement would be to stop processing disjunctions if we see +// there are more than two solutions. +nestedClosed: passing: { + D: {id: {}} | {[string]: D} + D: {id: {}} | {[string]: D} + D: {id: {}} | {[string]: D} +} @test(eq, {D: {id: {}} | {}}) +-- out/compile -- +--- in.cue +{ + #Secret: { + $secret: { + id: string + } + } + #secrets: (〈0;#Secret〉|{ + [string]: 〈1;#secrets〉 + }) + out: (〈0;#secrets〉 & { + FOO: { + $secret: { + id: "100" + } + } + ONE: { + TWO: { + THREE: { + $secret: { + id: "123" + } + } + } + } + }) + #Secret: { + $secret: { + _id: string + } + } + #secrets: (〈0;#Secret〉|{ + [string]: 〈1;#secrets〉 + }) + out: (〈0;#secrets〉 & { + FOO: { + $secret: { + _id: "100" + } + } + ONE: { + TWO: { + THREE: { + $secret: { + _id: "123" + } + } + } + } + }) +} +--- perf.cue +{ + nestedCross: { + closed: { + #D: ({ + id: string + }|{ + [string]: 〈1;#D〉 + }) + #D: ({ + id: string + }|{ + [string]: 〈1;#D〉 + }) + #D: ({ + id: string + }|{ + [string]: 〈1;#D〉 + }) + } + } + nestedCross: { + open: { + D: ({ + id: string + }|{ + [string]: 〈1;D〉 + }) + D: ({ + id: string + }|{ + [string]: 〈1;D〉 + }) + D: ({ + id: string + }|{ + [string]: 〈1;D〉 + }) + } + } + nestedClosed: { + passing: { + D: ({ + id: {} + }|{ + [string]: 〈1;D〉 + }) + D: ({ + id: {} + }|{ + [string]: 〈1;D〉 + }) + D: ({ + id: {} + }|{ + [string]: 〈1;D〉 + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue2176.txtar b/internal/core/compile/testdata/sync/benchmarks/issue2176.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue2176.txtar @@ -0,0 +1,108 @@ +# Tests that a sliding-window computation over string characters (finding unique +# character combinations of a given length) evaluates efficiently. The nested +# let-bindings and list comprehensions triggered performance regressions between +# CUE versions. +# https://cuelang.org/issue/2176 +-- in.cue -- +import ( + "strings" + "list" +) + +#Datastream: { + message: string + message: strings.MinRunes(4) + + marker: { + length: int + position: { + let characters = strings.Split(message, "") + let unique_combinations = { + // begin computation once we have more than x number of characters. + for i, _ in characters if i >= length-1 { + // this line is causing an increased evaluation time between cue versions. + // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + let combination = list.Slice(characters, i-length+1, i+1) + + // last x number of characters are not unique. + if list.UniqueItems(list.Slice(characters, i-length+1, i+1)) { + "\(i+1)": combination + } + } + } + [for i, _ in unique_combinations {i}][0] + } + } +} + +input_short: """ + mjqjpqmgbljsphdztnvjfqwrcgsmlb + """ +input_long: """ + qfmfhmhjmjggwbbvdvwvlvrrtsrsccwsslvlffjrrtprprjjvmmclmmghhddpvddclctcqtccgbgdbgdgsdgghqhtqtvvptvppwrwprpvrrrhpphththvhhrnnhnlnslnlhnhnhgnhnpnqqsmsgsllprlprrlzzqzffmzztctbtnbtthlttqvqcqmcmpcpbbczzbqbgghcghchhvwvllfrfnnbssfzsszpsplpglpprnpnfnbnhbnbtbzzvbvpbbhjjlzzbtbvbppczppbwppqwwnwlwccglgvgrgmmdwmwrmrppnfnhhhhqthqthqqrhrshhhqbhqqjgjvjllzvzbzhbbpttjsszvzqqtzzmbmddpldpdcdnccrmcrmmpwprplrrqssvddmpdmmwfwwlrljrrdsssmhsspnpffjggqllnzlnlhnnmddfrfpfbbvssjsrrznngcghgchcmhmrrrtzztjzzhchssslsmlmvvpwpqpjqjdddmsdmmtgtmgtglttfbbgrrcprrqffmmjnjttcmczzgbzggthhsttpggrmmgwwnpnqnqvnqvqppmlpmlpmpjpljljmmtpptfppfrppfdpfdppddmdttgzgzzdbzdzhzhnnsqssvmvbbpjjzwwvnwvvzmvzmzpmpttvrvccqddpgdppgmmthmthtggsfsbbvfbvfvhfvhvvpwpddqrqgqhghnnfmfbbwrbrgbgbvgbbdttffrddqbqpqzzmttlhhsqhsqhsqhhlplttpnpsstpthhpfhpfplprrgfrgffjppghgppghgdggjmmcgmccjvvsrvsrrwgrgmrrngrgttvbtbltthrthrttmfffjpfpssncnrngrrltrltlggjgcgllrzzllhwwjwrwgrgsrgrhrphrhhqwqsqmqlmqlmqmqrmrnnwnhwnhwhzwzjwwgbghhsjspszsznzfztfzfpzzlczztctsstctqtfqfqcfqqjrjccttmqqfpfdfnfwnffqbfbblpbpfpcfcwfccblbwwmqwqrrgprpccngnhghpppwmpplcppfrfjjgmmbzbhbcbzzgdgsdsvvqllzlppnfnlnlslsljlppcscqqfjjjwzwppfgfjjsvvsggjbjljpjpzjzrzjrzzfnfpnfpnfpnfnsnggmpggdllpmmrhhdqqppttgqqcsqsjsbjsjrsrqrbqqmbmcbmcbmbfmfvfqqdbdppmrprnrggmjjhnhbhdhbbfcbbcjjdhhwjwmjmssjswscswcwzccbgbqqmqgmmsdsjsbsdbsddvttjpppcqpcqcgqqslqsssczszrzvvrtvvjppswwhnnwlwtwhhwwzfwwpfpddlvvnvnnvlnntjtqjqjzzjttvvbqbhqbhbbbwnwhnwnppdbpdpvddrqdqjjlvlqqdfdhdjhdjdcjcrcjjggfmfvvfllvfvgglzllmhmzmdddfwddqjjqjfqfcfrrstrssptsstllrflfwwgswslwlbwbwjjvhvfvhfhffhsslwsllbnbblccbwwjqwqqdllrdrnrnffcbbqqpnqqdmdndtntvvrjvvsvmvgvnnmjlwgnjcwljgwnrwpqlztwrpmpgqtwlhrcwsrrhqhjhznrtpqfdnzbfqrzwslptdbdcnqvcllpjsfdvmzqwvzbpnmfcfcjnbmhtwhttjgtnczwctpdthhwmzvzrrgsnmbflgmszgsbvghbzgcmcmszgsbfmlmpbdspqlftmqrcjtmvgcrzznlfwjcbmddplsqrfflqnqfsldwhnncczdmfrrrsbjjqsdzrsgbdbwjbslfcqglsqfddhdsrcdrgqfqthgmfjvnfdfgdncfzpvqcpscnpmfgvqbfwszwzgmqvmcrdrwplfshdgqrchmccpqfznbmfvlhdpctlqgjslrwhjfjlmqfblgjrdlnzdtwlpwhnrhrcrpfwqpmjlgrdbgpbljntmbqlblqqqpgrnjtmjqvjpzvsqdpgtchmmwbhtmgcjqdplrtptqcvdjjpqdzsrcjhcwvdcghlwrdhtdfctmqfcjcqhcvvbzgsvlggcrdgqbtznwwmnbgsfrjprqgcmlswftlwpqqqvshdprldrsghmhrqvmqmvglbvzpvtrjbhcvhqmvdtcvsllznqzjmhpnlbhmlzthbwwhhvdtcdfdcdzhnbsrnqqjvzzsvfjhbsdlsbdlqjnlpnhfcjtdppzmphghltztzcdvzwbftbvwhvgmrllqfzrpbltptdtjjqtfwjfmczzgdvclqbsbftgtlhnhrrvbpvdltstdnhqvpvtjhmghptvsfnlspslmfsftzdrwljrgblgmcbmlszmhnlfdtmsrnjqwrfmsnfgpcqgzmlwppffrmbvhnlstfpgzw + """ + +input: *input_short | input_long + +datastream: #Datastream & {message: input} + +output: [string]: string +output: { + "1": (datastream & {marker: length: 4}).marker.position + "2": (datastream & {marker: length: 14}).marker.position +} @test(eq, {"1": {"7"}, "2": {"19"}}) +// NOTE: output contains lots of expanded lets. Use @test(debug) to view. + +@test(eq,at=datastream, { + message: *"mjqjpqmgbljsphdztnvjfqwrcgsmlb" | "qfmfhmhjmjggwbbvdvwvlvrrtsrsccwsslvlffjrrtprprjjvmmclmmghhddpvddclctcqtccgbgdbgdgsdgghqhtqtvvptvppwrwprpvrrrhpphththvhhrnnhnlnslnlhnhnhgnhnpnqqsmsgsllprlprrlzzqzffmzztctbtnbtthlttqvqcqmcmpcpbbczzbqbgghcghchhvwvllfrfnnbssfzsszpsplpglpprnpnfnbnhbnbtbzzvbvpbbhjjlzzbtbvbppczppbwppqwwnwlwccglgvgrgmmdwmwrmrppnfnhhhhqthqthqqrhrshhhqbhqqjgjvjllzvzbzhbbpttjsszvzqqtzzmbmddpldpdcdnccrmcrmmpwprplrrqssvddmpdmmwfwwlrljrrdsssmhsspnpffjggqllnzlnlhnnmddfrfpfbbvssjsrrznngcghgchcmhmrrrtzztjzzhchssslsmlmvvpwpqpjqjdddmsdmmtgtmgtglttfbbgrrcprrqffmmjnjttcmczzgbzggthhsttpggrmmgwwnpnqnqvnqvqppmlpmlpmpjpljljmmtpptfppfrppfdpfdppddmdttgzgzzdbzdzhzhnnsqssvmvbbpjjzwwvnwvvzmvzmzpmpttvrvccqddpgdppgmmthmthtggsfsbbvfbvfvhfvhvvpwpddqrqgqhghnnfmfbbwrbrgbgbvgbbdttffrddqbqpqzzmttlhhsqhsqhsqhhlplttpnpsstpthhpfhpfplprrgfrgffjppghgppghgdggjmmcgmccjvvsrvsrrwgrgmrrngrgttvbtbltthrthrttmfffjpfpssncnrngrrltrltlggjgcgllrzzllhwwjwrwgrgsrgrhrphrhhqwqsqmqlmqlmqmqrmrnnwnhwnhwhzwzjwwgbghhsjspszsznzfztfzfpzzlczztctsstctqtfqfqcfqqjrjccttmqqfpfdfnfwnffqbfbblpbpfpcfcwfccblbwwmqwqrrgprpccngnhghpppwmpplcppfrfjjgmmbzbhbcbzzgdgsdsvvqllzlppnfnlnlslsljlppcscqqfjjjwzwppfgfjjsvvsggjbjljpjpzjzrzjrzzfnfpnfpnfpnfnsnggmpggdllpmmrhhdqqppttgqqcsqsjsbjsjrsrqrbqqmbmcbmcbmbfmfvfqqdbdppmrprnrggmjjhnhbhdhbbfcbbcjjdhhwjwmjmssjswscswcwzccbgbqqmqgmmsdsjsbsdbsddvttjpppcqpcqcgqqslqsssczszrzvvrtvvjppswwhnnwlwtwhhwwzfwwpfpddlvvnvnnvlnntjtqjqjzzjttvvbqbhqbhbbbwnwhnwnppdbpdpvddrqdqjjlvlqqdfdhdjhdjdcjcrcjjggfmfvvfllvfvgglzllmhmzmdddfwddqjjqjfqfcfrrstrssptsstllrflfwwgswslwlbwbwjjvhvfvhfhffhsslwsllbnbblccbwwjqwqqdllrdrnrnffcbbqqpnqqdmdndtntvvrjvvsvmvgvnnmjlwgnjcwljgwnrwpqlztwrpmpgqtwlhrcwsrrhqhjhznrtpqfdnzbfqrzwslptdbdcnqvcllpjsfdvmzqwvzbpnmfcfcjnbmhtwhttjgtnczwctpdthhwmzvzrrgsnmbflgmszgsbvghbzgcmcmszgsbfmlmpbdspqlftmqrcjtmvgcrzznlfwjcbmddplsqrfflqnqfsldwhnncczdmfrrrsbjjqsdzrsgbdbwjbslfcqglsqfddhdsrcdrgqfqthgmfjvnfdfgdncfzpvqcpscnpmfgvqbfwszwzgmqvmcrdrwplfshdgqrchmccpqfznbmfvlhdpctlqgjslrwhjfjlmqfblgjrdlnzdtwlpwhnrhrcrpfwqpmjlgrdbgpbljntmbqlblqqqpgrnjtmjqvjpzvsqdpgtchmmwbhtmgcjqdplrtptqcvdjjpqdzsrcjhcwvdcghlwrdhtdfctmqfcjcqhcvvbzgsvlggcrdgqbtznwwmnbgsfrjprqgcmlswftlwpqqqvshdprldrsghmhrqvmqmvglbvzpvtrjbhcvhqmvdtcvsllznqzjmhpnlbhmlzthbwwhhvdtcdfdcdzhnbsrnqqjvzzsvfjhbsdlsbdlqjnlpnhfcjtdppzmphghltztzcdvzwbftbvwhvgmrllqfzrpbltptdtjjqtfwjfmczzgdvclqbsbftgtlhnhrrvbpvdltstdnhqvpvtjhmghptvsfnlspslmfsftzdrwljrgblgmcbmlszmhnlfdtmsrnjqwrfmsnfgpcqgzmlwppffrmbvhnlstfpgzw" + marker: {length: int, position: {_|_}} +}) + +-- out/compile -- +--- in.cue +{ + #Datastream: { + message: string + message: 〈import;strings〉.MinRunes(4) + marker: { + length: int + position: { + let characters#1 = 〈import;strings〉.Split(〈2;message〉, "") + let unique_combinations#2multi = { + for i, _ in 〈1;let characters#1〉 if (〈0;i〉 >= (〈3;length〉 - 1)) { + let combination#3multi = 〈import;list〉.Slice(〈3;let characters#1〉, ((〈1;i〉 - 〈4;length〉) + 1), (〈1;i〉 + 1)) + if 〈import;list〉.UniqueItems(〈import;list〉.Slice(〈3;let characters#1〉, ((〈1;i〉 - 〈4;length〉) + 1), (〈1;i〉 + 1))) { + "\((〈2;i〉 + 1))": 〈1;let combination#3〉 + } + } + } + [ + for i, _ in 〈1;let unique_combinations#2〉 { + 〈1;i〉 + }, + ][0] + } + } + } + input_short: "mjqjpqmgbljsphdztnvjfqwrcgsmlb" + input_long: "qfmfhmhjmjggwbbvdvwvlvrrtsrsccwsslvlffjrrtprprjjvmmclmmghhddpvddclctcqtccgbgdbgdgsdgghqhtqtvvptvppwrwprpvrrrhpphththvhhrnnhnlnslnlhnhnhgnhnpnqqsmsgsllprlprrlzzqzffmzztctbtnbtthlttqvqcqmcmpcpbbczzbqbgghcghchhvwvllfrfnnbssfzsszpsplpglpprnpnfnbnhbnbtbzzvbvpbbhjjlzzbtbvbppczppbwppqwwnwlwccglgvgrgmmdwmwrmrppnfnhhhhqthqthqqrhrshhhqbhqqjgjvjllzvzbzhbbpttjsszvzqqtzzmbmddpldpdcdnccrmcrmmpwprplrrqssvddmpdmmwfwwlrljrrdsssmhsspnpffjggqllnzlnlhnnmddfrfpfbbvssjsrrznngcghgchcmhmrrrtzztjzzhchssslsmlmvvpwpqpjqjdddmsdmmtgtmgtglttfbbgrrcprrqffmmjnjttcmczzgbzggthhsttpggrmmgwwnpnqnqvnqvqppmlpmlpmpjpljljmmtpptfppfrppfdpfdppddmdttgzgzzdbzdzhzhnnsqssvmvbbpjjzwwvnwvvzmvzmzpmpttvrvccqddpgdppgmmthmthtggsfsbbvfbvfvhfvhvvpwpddqrqgqhghnnfmfbbwrbrgbgbvgbbdttffrddqbqpqzzmttlhhsqhsqhsqhhlplttpnpsstpthhpfhpfplprrgfrgffjppghgppghgdggjmmcgmccjvvsrvsrrwgrgmrrngrgttvbtbltthrthrttmfffjpfpssncnrngrrltrltlggjgcgllrzzllhwwjwrwgrgsrgrhrphrhhqwqsqmqlmqlmqmqrmrnnwnhwnhwhzwzjwwgbghhsjspszsznzfztfzfpzzlczztctsstctqtfqfqcfqqjrjccttmqqfpfdfnfwnffqbfbblpbpfpcfcwfccblbwwmqwqrrgprpccngnhghpppwmpplcppfrfjjgmmbzbhbcbzzgdgsdsvvqllzlppnfnlnlslsljlppcscqqfjjjwzwppfgfjjsvvsggjbjljpjpzjzrzjrzzfnfpnfpnfpnfnsnggmpggdllpmmrhhdqqppttgqqcsqsjsbjsjrsrqrbqqmbmcbmcbmbfmfvfqqdbdppmrprnrggmjjhnhbhdhbbfcbbcjjdhhwjwmjmssjswscswcwzccbgbqqmqgmmsdsjsbsdbsddvttjpppcqpcqcgqqslqsssczszrzvvrtvvjppswwhnnwlwtwhhwwzfwwpfpddlvvnvnnvlnntjtqjqjzzjttvvbqbhqbhbbbwnwhnwnppdbpdpvddrqdqjjlvlqqdfdhdjhdjdcjcrcjjggfmfvvfllvfvgglzllmhmzmdddfwddqjjqjfqfcfrrstrssptsstllrflfwwgswslwlbwbwjjvhvfvhfhffhsslwsllbnbblccbwwjqwqqdllrdrnrnffcbbqqpnqqdmdndtntvvrjvvsvmvgvnnmjlwgnjcwljgwnrwpqlztwrpmpgqtwlhrcwsrrhqhjhznrtpqfdnzbfqrzwslptdbdcnqvcllpjsfdvmzqwvzbpnmfcfcjnbmhtwhttjgtnczwctpdthhwmzvzrrgsnmbflgmszgsbvghbzgcmcmszgsbfmlmpbdspqlftmqrcjtmvgcrzznlfwjcbmddplsqrfflqnqfsldwhnncczdmfrrrsbjjqsdzrsgbdbwjbslfcqglsqfddhdsrcdrgqfqthgmfjvnfdfgdncfzpvqcpscnpmfgvqbfwszwzgmqvmcrdrwplfshdgqrchmccpqfznbmfvlhdpctlqgjslrwhjfjlmqfblgjrdlnzdtwlpwhnrhrcrpfwqpmjlgrdbgpbljntmbqlblqqqpgrnjtmjqvjpzvsqdpgtchmmwbhtmgcjqdplrtptqcvdjjpqdzsrcjhcwvdcghlwrdhtdfctmqfcjcqhcvvbzgsvlggcrdgqbtznwwmnbgsfrjprqgcmlswftlwpqqqvshdprldrsghmhrqvmqmvglbvzpvtrjbhcvhqmvdtcvsllznqzjmhpnlbhmlzthbwwhhvdtcdfdcdzhnbsrnqqjvzzsvfjhbsdlsbdlqjnlpnhfcjtdppzmphghltztzcdvzwbftbvwhvgmrllqfzrpbltptdtjjqtfwjfmczzgdvclqbsbftgtlhnhrrvbpvdltstdnhqvpvtjhmghptvsfnlspslmfsftzdrwljrgblgmcbmlszmhnlfdtmsrnjqwrfmsnfgpcqgzmlwppffrmbvhnlstfpgzw" + input: (*〈0;input_short〉|〈0;input_long〉) + datastream: (〈0;#Datastream〉 & { + message: 〈1;input〉 + }) + output: { + [string]: string + } + output: { + "1": (〈1;datastream〉 & { + marker: { + length: 4 + } + }).marker.position + "2": (〈1;datastream〉 & { + marker: { + length: 14 + } + }).marker.position + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue3307.txtar b/internal/core/compile/testdata/sync/benchmarks/issue3307.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue3307.txtar @@ -0,0 +1,57 @@ +# Tests that a large `if` guard on an incomplete bool does not trigger +# O(n) work per field inside the conditional block. Each field in the +# guarded struct should not independently re-evaluate the condition. +# https://cuelang.org/issue/3307 +-- in.cue -- +@test(err, code=incomplete, contains="incomplete bool") +if _request.enabled { + r1: { + k1: 0 + k2: 0 + k3: 0 + k4: 0 + k5: 0 + k6: 0 + k7: 0 + k8: 0 + k9: 0 + k10: 0 + k11: 0 + k12: 0 + k13: 0 + k14: 0 + k15: 0 + k16: 0 + k17: 0 + } +} + +_request: enabled: _ +-- out/compile -- +--- in.cue +{ + if 〈0;_request〉.enabled { + r1: { + k1: 0 + k2: 0 + k3: 0 + k4: 0 + k5: 0 + k6: 0 + k7: 0 + k8: 0 + k9: 0 + k10: 0 + k11: 0 + k12: 0 + k13: 0 + k14: 0 + k15: 0 + k16: 0 + k17: 0 + } + } + _request: { + enabled: _ + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue3334.txtar b/internal/core/compile/testdata/sync/benchmarks/issue3334.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue3334.txtar @@ -0,0 +1,319 @@ +# Tests that a single top-level disjunction (null | Schema) applied to a deeply +# nested struct does not cause exponential evaluation. Schema is a recursive +# JSON-Schema-like definition with many optional disjunctive fields. +# https://cuelang.org/issue/3334 +-- in.cue -- +// Single disjunction at the top. +x?: null | Schema +x: properties: { + disableSelfServiceScrape: {} + dnsConfig: { + properties: { + nameservers: {} + } + } + podDisruptionBudget: { + properties: { + maxUnavailable: {} + minAvailable: { + anyOf: [{}, {}] + } + labels: {} + } + } +} + +Schema: { + title?: string + $ref?: null | string + enum?: [...] + required?: [...string] + items?: null | _ + anyOf?: [...Schema] + allOf?: [...Schema] + oneOf?: [...Schema] + not?: null | Schema + properties?: [string]: Schema + additionalProperties?: null | _ + patternProperties?: [string]: Schema + dependencies?: [string]: _ + additionalItems?: null | _ + definitions?: [string]: _ + externalDocs?: null | { + description?: string + url?: string + } + example?: null | _ + nullable?: bool +} + +@test(eq, at=x, { + properties: { + disableSelfServiceScrape: { + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + dnsConfig: { + properties: { + nameservers: { + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + } + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + podDisruptionBudget: { + properties: { + maxUnavailable: { + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + minAvailable: { + anyOf: [{ + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + }, + { + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + }] + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + labels: { + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + properties?: {} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + } + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool + } + } + title?: string + $ref?: null | string + enum?: [] + required?: [] + items?: null | _ + anyOf?: [] + allOf?: [] + oneOf?: [] + not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null | {title?: string, $ref?: null | string, enum?: [], required?: [], items?: null | _, anyOf?: [], allOf?: [], oneOf?: [], not?: null, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool}, properties?: {}, additionalProperties?: null | _, patternProperties?: {}, dependencies?: {}, additionalItems?: null | _, definitions?: {}, externalDocs?: null | {description?: string, url?: string}, example?: null | _, nullable?: bool} + additionalProperties?: null | _ + patternProperties?: {} + dependencies?: {} + additionalItems?: null | _ + definitions?: {} + externalDocs?: null | {description?: string, url?: string} + example?: null | _ + nullable?: bool +}) +-- out/compile -- +--- in.cue +{ + x?: (null|〈0;Schema〉) + x: { + properties: { + disableSelfServiceScrape: {} + dnsConfig: { + properties: { + nameservers: {} + } + } + podDisruptionBudget: { + properties: { + maxUnavailable: {} + minAvailable: { + anyOf: [ + {}, + {}, + ] + } + labels: {} + } + } + } + } + Schema: { + title?: string + $ref?: (null|string) + enum?: [ + ..., + ] + required?: [ + ...string, + ] + items?: (null|_) + anyOf?: [ + ...〈2;Schema〉, + ] + allOf?: [ + ...〈2;Schema〉, + ] + oneOf?: [ + ...〈2;Schema〉, + ] + not?: (null|〈1;Schema〉) + properties?: { + [string]: 〈2;Schema〉 + } + additionalProperties?: (null|_) + patternProperties?: { + [string]: 〈2;Schema〉 + } + dependencies?: { + [string]: _ + } + additionalItems?: (null|_) + definitions?: { + [string]: _ + } + externalDocs?: (null|{ + description?: string + url?: string + }) + example?: (null|_) + nullable?: bool + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue3514.txtar b/internal/core/compile/testdata/sync/benchmarks/issue3514.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue3514.txtar @@ -0,0 +1,93 @@ +# Tests that matching a data value against a large matchIf schema (with many +# nested disjunctions and required fields) completes in bounded time. The +# schema models a Dependabot config; the original issue caused a hang. +# https://cuelang.org/issue/3514 +-- in.cue -- +import "list" + +_schema & _data +_data: { + "updates": [ + { + "schedule": { + "interval": "daily" + } + } + ], +} + +_schema: { + matchIf( + null | bool | number | string | [...] | {"enable-beta-ecosystems"!: true}, + _, + null | bool | number | string | [...] | { + "updates"?: null | bool | number | string | [...null | bool | number | string | [...] | {...}] | {...} + ... + } + ) & { + "updates"!: [...#update] + } + + #update: { + "schedule"!: { + "timezone"?: #timezone + ... + } + ... + } + + // This was originally a list of 571 explicit time zones. + #timezone: or([for i in list.Range(0, 571, 1) {"\(i)"}]) +} + +@test(eq, at=_data, { updates: [{schedule: {interval: "daily"}}] }) +-- out/compile -- +--- in.cue +{ + (〈0;_schema〉 & 〈0;_data〉) + _data: { + updates: [ + { + schedule: { + interval: "daily" + } + }, + ] + } + _schema: { + (matchIf((null|bool|number|string|[ + ..., + ]|{ + "enable-beta-ecosystems"!: true + }), _, (null|bool|number|string|[ + ..., + ]|{ + updates?: (null|bool|number|string|[ + ...(null|bool|number|string|[ + ..., + ]|{ + ... + }), + ]|{ + ... + }) + ... + })) & { + updates!: [ + ...〈2;#update〉, + ] + }) + #update: { + schedule!: { + timezone?: 〈2;#timezone〉 + ... + } + ... + } + #timezone: or([ + for _, i in 〈import;list〉.Range(0, 571, 1) { + "\(〈1;i〉)" + }, + ]) + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue3517.txtar b/internal/core/compile/testdata/sync/benchmarks/issue3517.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue3517.txtar @@ -0,0 +1,132 @@ +# Tests that cyclic arithmetic constraints (#TimeSpan: start = end - duration +# etc.) within a task set unify and report errors correctly. The original +# issue involved a hang or very slow evaluation with interdependent tasks. +# https://cuelang.org/issue/3517 +-- main.cue -- +package p + +#TimeSpan: { + start: float + duration: float + end: float + + start: end - duration + duration: end - start + end: start + duration + + start: <=end +} + +#Task: { + action: string + timeSpan: #TimeSpan +} + +#TaskSet: { + action: string + #tasks: [string]: #Task + tasks: [for _, v in #tasks {v}] + tasks: [...#Task] + timeSpan?: #TimeSpan +} + +#T1: #Task & { + action: "Task 1" + timeSpan: #TimeSpan & { + duration: 4.2 + } +} + +#T2: #Task & { + action: "Task 2" + timeSpan: #TimeSpan & { + duration: 120.0 + } +} + +ts: #TaskSet +ts: this={ + action: "Task 1 and Task 2" + #tasks: { + t1: #T1 & { + timeSpan: end: this.#tasks.t2.timeSpan.start + } + t2: #T2 & { + timeSpan: end: 119 // this.timeSpan.end + } + } + timeSpan: start: this.#tasks.t1.timeSpan.start +} +@test(err, at=ts.#tasks.t1, code=eval, path=ts.#tasks.t2.timeSpan.end, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[119, float, int, float], + pos=[-49:12, -18:12, -6:7, -5:19], +) +@test(err, at=ts.#tasks.t2, code=eval, path=ts.#tasks.t2.timeSpan.end, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[119, float, int, float], + pos=[-54:12, -23:12, -11:7, -10:19], +) +-- out/compile -- +--- main.cue +{ + #TimeSpan: { + start: float + duration: float + end: float + start: (〈0;end〉 - 〈0;duration〉) + duration: (〈0;end〉 - 〈0;start〉) + end: (〈0;start〉 + 〈0;duration〉) + start: <=〈0;end〉 + } + #Task: { + action: string + timeSpan: 〈1;#TimeSpan〉 + } + #TaskSet: { + action: string + #tasks: { + [string]: 〈2;#Task〉 + } + tasks: [ + for _, v in 〈1;#tasks〉 { + 〈1;v〉 + }, + ] + tasks: [ + ...〈2;#Task〉, + ] + timeSpan?: 〈1;#TimeSpan〉 + } + #T1: (〈0;#Task〉 & { + action: "Task 1" + timeSpan: (〈1;#TimeSpan〉 & { + duration: 4.2 + }) + }) + #T2: (〈0;#Task〉 & { + action: "Task 2" + timeSpan: (〈1;#TimeSpan〉 & { + duration: 120.0 + }) + }) + ts: 〈0;#TaskSet〉 + ts: { + action: "Task 1 and Task 2" + #tasks: { + t1: (〈2;#T1〉 & { + timeSpan: { + end: 〈4〉.#tasks.t2.timeSpan.start + } + }) + t2: (〈2;#T2〉 & { + timeSpan: { + end: 119 + } + }) + } + timeSpan: { + start: 〈2〉.#tasks.t1.timeSpan.start + } + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue3633.txtar b/internal/core/compile/testdata/sync/benchmarks/issue3633.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue3633.txtar @@ -0,0 +1,257 @@ +# Tests that recursive schema definitions with many optional fields (e.g. a +# JSON-Schema-like #Schema with properties/required) do not cause exponential +# conjunct blowup when embedded or unified. The `reduced` case validates basic +# self-embedding; `full` validates a realistic JSON-Schema-style structure. +# https://cuelang.org/issue/3633 +-- in.cue -- +reduced: { + #Schema: { + a?: null | bool | string | int | #Schema + b?: null | bool | string | int | #Schema + c?: null | bool | string | int | #Schema + d?: null | bool | string | int | #Schema + e?: null | bool | string | int | #Schema + f?: null | bool | string | int | #Schema + } + + out: #Schema & { #Schema } +} +full: { + #Schema: { + required?: [...string] + properties?: [string]: null | bool | string | [...int] | #Schema + + foo00?: null | bool | string | [...int] | {string: int32} + foo01?: null | bool | string | [...int] | {string: int32} + foo02?: null | bool | string | [...int] | {string: int32} + foo03?: null | bool | string | [...int] | {string: int32} + foo04?: null | bool | string | [...int] | {string: int32} + foo05?: null | bool | string | [...int] | {string: int32} + foo06?: null | bool | string | [...int] | {string: int32} + foo07?: null | bool | string | [...int] | {string: int32} + foo08?: null | bool | string | [...int] | {string: int32} + foo09?: null | bool | string | [...int] | {string: int32} + foo10?: null | bool | string | [...int] | {string: int32} + foo11?: null | bool | string | [...int] | {string: int32} + foo12?: null | bool | string | [...int] | {string: int32} + foo13?: null | bool | string | [...int] | {string: int32} + foo14?: null | bool | string | [...int] | {string: int32} + foo15?: null | bool | string | [...int] | {string: int32} + foo16?: null | bool | string | [...int] | {string: int32} + foo17?: null | bool | string | [...int] | {string: int32} + foo18?: null | bool | string | [...int] | {string: int32} + foo19?: null | bool | string | [...int] | {string: int32} + } + + out: [...#Schema] & [{ + #Schema + properties: foo: required: ["bar", "baz"] + }] +} + +// TODO(inline): +// 1) format better +// 2) identify repeated elements +// 3) leave at= flag at begginning when generating. +@test(eq, at=full.out, [{ + properties: { + foo: { + required: ["bar", "baz"] + properties?: {} + foo00?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo01?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo02?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo03?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo04?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo05?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo06?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo07?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo08?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo09?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo10?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo11?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo12?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo13?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo14?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo15?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo16?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo17?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo18?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo19?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + } + } + required?: [] + foo00?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo01?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo02?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo03?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo04?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo05?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo06?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo07?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo08?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo09?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo10?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo11?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo12?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo13?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo14?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo15?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo16?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo17?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo18?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} + foo19?: null | bool | string | [] | {string: >=-2147483648 & <=2147483647 & int} +}]) +@test(eq, { + a?: null | bool | string | int | {a?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, b?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, c?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, d?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, e?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, f?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}} + b?: null | bool | string | int | {a?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, b?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, c?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, d?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, e?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, f?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}} + c?: null | bool | string | int | {a?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, b?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, c?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, d?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, e?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, f?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}} + d?: null | bool | string | int | {a?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, b?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, c?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, d?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, e?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, f?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}} + e?: null | bool | string | int | {a?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, b?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, c?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, d?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, e?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, f?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}} + f?: null | bool | string | int | {a?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, b?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, c?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, d?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, e?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}, f?: null | bool | string | int | {a?: null | bool | string | int, b?: null | bool | string | int, c?: null | bool | string | int, d?: null | bool | string | int, e?: null | bool | string | int, f?: null | bool | string | int}} +}, at=reduced.out) + +-- out/compile -- +--- in.cue +{ + reduced: { + #Schema: { + a?: (null|bool|string|int|〈1;#Schema〉) + b?: (null|bool|string|int|〈1;#Schema〉) + c?: (null|bool|string|int|〈1;#Schema〉) + d?: (null|bool|string|int|〈1;#Schema〉) + e?: (null|bool|string|int|〈1;#Schema〉) + f?: (null|bool|string|int|〈1;#Schema〉) + } + out: (〈0;#Schema〉 & { + 〈1;#Schema〉 + }) + } + full: { + #Schema: { + required?: [ + ...string, + ] + properties?: { + [string]: (null|bool|string|[ + ...int, + ]|〈2;#Schema〉) + } + foo00?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo01?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo02?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo03?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo04?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo05?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo06?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo07?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo08?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo09?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo10?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo11?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo12?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo13?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo14?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo15?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo16?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo17?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo18?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + foo19?: (null|bool|string|[ + ...int, + ]|{ + string: &(int, >=-2147483648, <=2147483647) + }) + } + out: ([ + ...〈1;#Schema〉, + ] & [ + { + 〈2;#Schema〉 + properties: { + foo: { + required: [ + "bar", + "baz", + ] + } + } + }, + ]) + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/issue572.txtar b/internal/core/compile/testdata/sync/benchmarks/issue572.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/issue572.txtar @@ -0,0 +1,36 @@ +# Tests that a large comprehension-generated struct (1500 entries) evaluates +# in linear time rather than exhibiting quadratic or worse blowup from +# repeated unification of the accumulating result. +# https://cuelang.org/issue/572 +-- in.cue -- +package p + +import "list" + +_entries: [for i in list.Range(1, 1500, 1) {i}] +unified: { + for entry in _entries { + "\(entry)": true + } +} + +// TODO(inline): _entries$p and [0] don't work here. +// @test(eq, at=_entries$p[0], 1) +// @test(eq, at=_entries$[1498], 1499) +@test(eq, at=unified."1", true) +@test(eq, at=unified."1499", true) + +-- out/compile -- +--- in.cue +{ + _entries(:p): [ + for _, i in 〈import;list〉.Range(1, 1500, 1) { + 〈1;i〉 + }, + ] + unified: { + for _, entry in 〈1;_entries(:p)〉 { + "\(〈1;entry〉)": true + } + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/listdedup.txtar b/internal/core/compile/testdata/sync/benchmarks/listdedup.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/listdedup.txtar @@ -0,0 +1,161 @@ +# Tests that repeated references to the same type in a struct (e.g. #ref twice, +# _ | {} twice) do not cause exponential blowup in conjuncts/disjuncts. +# https://cuelang.org/issue/758 +# https://cuelang.org/issue/1044 + +// TODO(perf): reduce number of conjunctions and disjunctions. +-- in.cue -- +A: #Task +B: #steps: #Script & {mount: [A]} +C: #steps: #Script & {mount: [B]} + +#Script: {mount: [...#Task]} @test(eq, {mount: []}) + +#Task: { + // Without the proper constructs, repeating the below results + // in exponential runtime. + #ref + #ref + _ | {} + _ | {} + #steps: #Script + ... +} + +#ref: {a: 1} | {b: 2} @test(eq, {a: 1} | {b: 2}) + +@test(eq, { + A: {#steps: {mount: []}, a: 1} | {#steps: {mount: []}, b: 2} + B: { + #steps: { + mount: [{#steps: {mount: []}, a: 1} | {#steps: {mount: []}, b: 2}] + } + } + C: { + #steps: { + mount: [{#steps: { + mount: [{#steps: {mount: []}, a: 1} | {#steps: {mount: []}, b: 2}] +}, a: 1} | {#steps: { + mount: [{#steps: {mount: []}, a: 1} | {#steps: {mount: []}, b: 2}] +}, b: 2}] + } + } + #Script: {mount: []} + #Task: {#steps: {mount: []}, a: 1} | {#steps: {mount: []}, b: 2} + #ref: {a: 1} | {b: 2} +}) +// TODO(inline): replace @test(debug) with @test(shareID=...) once the +// framework supports asserting sharing inside disjunction members. All +// ~(#Script) occurrences here are inside disjunct arms (A, #Task, +// B.#steps.mount[0]) — the CUE API creates a fresh vertex when projecting +// a field through a disjunction boundary, so pointer-identity checks fail. +@test(debug, """ + (struct){ + A: (#struct){ |((#struct){ + #steps: ~(#Script) + a: (int){ 1 } + }, (#struct){ + #steps: ~(#Script) + b: (int){ 2 } + }) } + B: (struct){ + #steps: (#struct){ + mount: (#list){ + 0: (#struct){ |((#struct){ + #steps: ~(#Script) + a: (int){ 1 } + }, (#struct){ + #steps: ~(#Script) + b: (int){ 2 } + }) } + } + } + } + C: (struct){ + #steps: (#struct){ + mount: (#list){ + 0: (#struct){ |((#struct){ + #steps: (#struct){ + mount: (#list){ + 0: (#struct){ |((#struct){ + #steps: ~(#Script) + a: (int){ 1 } + }, (#struct){ + #steps: ~(#Script) + b: (int){ 2 } + }) } + } + } + a: (int){ 1 } + }, (#struct){ + #steps: (#struct){ + mount: (#list){ + 0: (#struct){ |((#struct){ + #steps: ~(#Script) + a: (int){ 1 } + }, (#struct){ + #steps: ~(#Script) + b: (int){ 2 } + }) } + } + } + b: (int){ 2 } + }) } + } + } + } + #Script: (#struct){ + mount: (list){ + } + } + #Task: (#struct){ |((#struct){ + #steps: ~(#Script) + a: (int){ 1 } + }, (#struct){ + #steps: ~(#Script) + b: (int){ 2 } + }) } + #ref: (#struct){ |((#struct){ + a: (int){ 1 } + }, (#struct){ + b: (int){ 2 } + }) } + } + """) +-- out/compile -- +--- in.cue +{ + A: 〈0;#Task〉 + B: { + #steps: (〈1;#Script〉 & { + mount: [ + 〈3;A〉, + ] + }) + } + C: { + #steps: (〈1;#Script〉 & { + mount: [ + 〈3;B〉, + ] + }) + } + #Script: { + mount: [ + ...〈2;#Task〉, + ] + } + #Task: { + 〈1;#ref〉 + 〈1;#ref〉 + (_|{}) + (_|{}) + #steps: 〈1;#Script〉 + ... + } + #ref: ({ + a: 1 + }|{ + b: 2 + }) +} diff --git a/internal/core/compile/testdata/sync/benchmarks/listdisj.txtar b/internal/core/compile/testdata/sync/benchmarks/listdisj.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/listdisj.txtar @@ -0,0 +1,47 @@ +# Tests that a recursive list-typed disjunction (#T) shared across multiple +# fields does not cause exponential blowup. x and y both reference #T and +# should share the same vertex rather than being independently expanded. +# https://cuelang.org/issue/1940 +-- in.cue -- +#T: + ["a", #T] | + ["b", #T] | + ["c", #T] | + ["d", ...#T] @test(shareID=T) + +x: #T @test(shareID=T) +y: #T @test(shareID=T) +z: #T @test(shareID=T) +v: #T @test(shareID=T) + +#X: x @test(shareID=T) +#X: y +#X: z +#X: v +#X: #T +-- out/compile -- +--- in.cue +{ + #T: ([ + "a", + 〈1;#T〉, + ]|[ + "b", + 〈1;#T〉, + ]|[ + "c", + 〈1;#T〉, + ]|[ + "d", + ...〈1;#T〉, + ]) + x: 〈0;#T〉 + y: 〈0;#T〉 + z: 〈0;#T〉 + v: 〈0;#T〉 + #X: 〈0;x〉 + #X: 〈0;y〉 + #X: 〈0;z〉 + #X: 〈0;v〉 + #X: 〈0;#T〉 +} diff --git a/internal/core/compile/testdata/sync/benchmarks/mergeddisjunction.txtar b/internal/core/compile/testdata/sync/benchmarks/mergeddisjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/mergeddisjunction.txtar @@ -0,0 +1,87 @@ +// Here one comprehension creates a number of distinct values, each of which +// with a disjunction, then another comprehension maps them back to the +// same value, creating a large number of disjunctions. +// +// The disjunctions cannot be identified as equal in the general case. If no +// care is taken, disjunction elimination will be exponential, causing over +// a billion disjuncts to process in the below example. With the proper +// optimizations, there is a small, constant number of disjunction ops per +// disjunct. +// +// Issue #651 +-- in.cue -- +list: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, +] + +a: [X=string]: text: *"default" | string +a: { + for i in list { + "\(i)": text: string + } +} + +b: { + for x in a { + "\(x.text)": {text: x.text} + } +} @test(eq, {default: {text: *"default" | string}}) +-- out/compile -- +--- in.cue +{ + list: [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + ] + a: { + [string]: { + text: (*"default"|string) + } + } + a: { + for _, i in 〈1;list〉 { + "\(〈1;i〉)": { + text: string + } + } + } + b: { + for _, x in 〈1;a〉 { + "\(〈1;x〉.text)": { + text: 〈2;x〉.text + } + } + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/share.txtar b/internal/core/compile/testdata/sync/benchmarks/share.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/share.txtar @@ -0,0 +1,48 @@ +See https://en.wikipedia.org/wiki/Billion_lauHs_attack. +-- in.cue -- +f: [g, g, g, g, g, g, g] @test(shareID=G, at=0) @test(shareID=G, at=3) @test(shareID=G, at=6) +g: [h, h, h, h, h, h, h] @test(shareID=G) @test(shareID=H, at=0) @test(shareID=H, at=3) @test(shareID=H, at=6) +h: [i, i, i, i, i, i, i] @test(shareID=H) @test(shareID=I, at=0) @test(shareID=I, at=3) @test(shareID=I, at=6) +i: [j, j, j, j, j, j, j] @test(shareID=I) +j: 1 +-- out/compile -- +--- in.cue +{ + f: [ + 〈1;g〉, + 〈1;g〉, + 〈1;g〉, + 〈1;g〉, + 〈1;g〉, + 〈1;g〉, + 〈1;g〉, + ] + g: [ + 〈1;h〉, + 〈1;h〉, + 〈1;h〉, + 〈1;h〉, + 〈1;h〉, + 〈1;h〉, + 〈1;h〉, + ] + h: [ + 〈1;i〉, + 〈1;i〉, + 〈1;i〉, + 〈1;i〉, + 〈1;i〉, + 〈1;i〉, + 〈1;i〉, + ] + i: [ + 〈1;j〉, + 〈1;j〉, + 〈1;j〉, + 〈1;j〉, + 〈1;j〉, + 〈1;j〉, + 〈1;j〉, + ] + j: 1 +} diff --git a/internal/core/compile/testdata/sync/benchmarks/sharefg.txtar b/internal/core/compile/testdata/sync/benchmarks/sharefg.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/sharefg.txtar @@ -0,0 +1,434 @@ +# This file has fine-grained sharing tests. +-- in.cue -- +// In each case, the number of output nodes should be linear in the input size. +// +// This means that in each case, the next line should not retrigger the +// computation of the previous field. + +// 26 Nodes computed: +// f1: 5 +// f2+: +3 each +binexpr: { + f1: { out: x: 2 } + f2: { out: x: f1.out.x + 1 } + f3: { out: x: f2.out.x + 1 } + f4: { out: x: f3.out.x + 1 } + f5: { out: x: f4.out.x + 1 } + f6: { out: x: f5.out.x + 1 } + f7: { out: x: f6.out.x + 1 } + f8: { out: x: f7.out.x + 1 } @test(eq, {out: {x: 9}}) +} + +// 26 Nodes computed: +// f1: 5 +// f2+: +3 each +parenthesized: { + f1: { out: x: 2 } + f2: { out: x: (f1.out).x + 1 } + f3: { out: x: (f2.out).x + 1 } + f4: { out: x: (f3.out).x + 1 } + f5: { out: x: (f4.out).x + 1 } + f6: { out: x: (f5.out).x + 1 } + f7: { out: x: (f6.out).x + 1 } + f8: { out: x: (f7.out).x + 1 } @test(eq, {out: {x: 9}}) +} + +// TODO(perf): fix +// 82 Nodes computed [O(n^2)]: +// f1: 5 +// fn: +(n*2 + 1) +// SHOULD BE: +// 26 Nodes computed: +// f1: 5 +// f2+: +3 each +embedded: { + f1: { out: x: 2 } + f2: { out: x: {f1.out}.x + 1 } + f3: { out: x: {f2.out}.x + 1 } + f4: { out: x: {f3.out}.x + 1 } + f5: { out: x: {f4.out}.x + 1 } + f6: { out: x: {f5.out}.x + 1 } + f7: { out: x: {f6.out}.x + 1 } + f8: { out: x: {f7.out}.x + 1 } @test(eq, {out: {x: 9}}) +} + +// TODO(perf): fix +// 82 Nodes computed [O(n^2)]: +// f1: 5 +// fn: +(n*2 + 1) each +// SHOULD BE: +// 26 Nodes computed: +// f1: 5 +// f2+: +3 each +embeddedWithEmpty: { + f1: { out: x: 2 } + f2: { out: x: {f1.out & {}}.x + 1 } + f3: { out: x: {f2.out & {}}.x + 1 } + f4: { out: x: {f3.out & {}}.x + 1 } + f5: { out: x: {f4.out & {}}.x + 1 } + f6: { out: x: {f5.out & {}}.x + 1 } + f7: { out: x: {f6.out & {}}.x + 1 } + f8: { out: x: {f7.out & {}}.x + 1 } @test(eq, {out: {x: 9}}) +} + +// TODO(perf): fix +// This will visualize O(n^2) output size unless CUE allows for a bit more +// sophisticated sharing. +weave: { + f: X={ + out: in + 1 + in: X.ref.out + 1 + ref: _ & {} + } + f8: f&{ ref: f7 } + f7: f&{ ref: f6 } + f6: f&{ ref: f5 } + f5: f&{ ref: f4 } + f4: f&{ ref: f3 } + f3: f&{ ref: f2 } @test(eq, {ref: {ref: {out: 2}, out: 4, in: 3}, out: 6, in: 5 }) + f2: f&{ ref: f1 } @test(eq, {ref: {out: 2}, out: 4, in: 3}) + f1: { out: 2 } @test(eq, {out: 2}) +} +@test(eq, at=weave.f8, { + ref: { + ref: { + ref: { + ref: { + ref: { + ref: {ref: {out: 2}, out: 4, in: 3} + out: 6 + in: 5 + } + out: 8 + in: 7 + } + out: 10 + in: 9 + } + out: 12 + in: 11 + } + out: 14 + in: 13 + } + out: 16 + in: 15 +}) + +// TODO(perf): fix +// This will visualize O(n^2) output size unless CUE supports fine-grained +// sharing. +weaveExtraField: { + f: X={ + out: in + 1 + in: X.ref.out + 1 + ref: {y: 4} // Cannot share because of this, but sub arcs still can be. + } + f8: f&{ ref: f7 } @test(eq, 16, at=out) + f7: f&{ ref: f6 } + f6: f&{ ref: f5 } + f5: f&{ ref: f4 } + f4: f&{ ref: f3 } + f3: f&{ ref: f2 } + f2: f&{ ref: f1 } @test(eq, {ref: {y: 4, out: 2}, out: 4, in: 3}) + f1: { out: 2 } @test(eq, {out: 2}) +} + @test(eq, at=weaveExtraField.f8, { + ref: { + y: 4 + ref: { + y: 4 + ref: { + y: 4 + ref: { + y: 4 + ref: { + y: 4 + ref: { + y: 4 + ref: {y: 4, out: 2} + out: 4 + in: 3 + } + out: 6 + in: 5 + } + out: 8 + in: 7 + } + out: 10 + in: 9 + } + out: 12 + in: 11 + } + out: 14 + in: 13 + } + out: 16 + in: 15 +}) +-- out/compile -- +--- in.cue +{ + binexpr: { + f1: { + out: { + x: 2 + } + } + f2: { + out: { + x: (〈2;f1〉.out.x + 1) + } + } + f3: { + out: { + x: (〈2;f2〉.out.x + 1) + } + } + f4: { + out: { + x: (〈2;f3〉.out.x + 1) + } + } + f5: { + out: { + x: (〈2;f4〉.out.x + 1) + } + } + f6: { + out: { + x: (〈2;f5〉.out.x + 1) + } + } + f7: { + out: { + x: (〈2;f6〉.out.x + 1) + } + } + f8: { + out: { + x: (〈2;f7〉.out.x + 1) + } + } + } + parenthesized: { + f1: { + out: { + x: 2 + } + } + f2: { + out: { + x: (〈2;f1〉.out.x + 1) + } + } + f3: { + out: { + x: (〈2;f2〉.out.x + 1) + } + } + f4: { + out: { + x: (〈2;f3〉.out.x + 1) + } + } + f5: { + out: { + x: (〈2;f4〉.out.x + 1) + } + } + f6: { + out: { + x: (〈2;f5〉.out.x + 1) + } + } + f7: { + out: { + x: (〈2;f6〉.out.x + 1) + } + } + f8: { + out: { + x: (〈2;f7〉.out.x + 1) + } + } + } + embedded: { + f1: { + out: { + x: 2 + } + } + f2: { + out: { + x: ({ + 〈3;f1〉.out + }.x + 1) + } + } + f3: { + out: { + x: ({ + 〈3;f2〉.out + }.x + 1) + } + } + f4: { + out: { + x: ({ + 〈3;f3〉.out + }.x + 1) + } + } + f5: { + out: { + x: ({ + 〈3;f4〉.out + }.x + 1) + } + } + f6: { + out: { + x: ({ + 〈3;f5〉.out + }.x + 1) + } + } + f7: { + out: { + x: ({ + 〈3;f6〉.out + }.x + 1) + } + } + f8: { + out: { + x: ({ + 〈3;f7〉.out + }.x + 1) + } + } + } + embeddedWithEmpty: { + f1: { + out: { + x: 2 + } + } + f2: { + out: { + x: ({ + (〈3;f1〉.out & {}) + }.x + 1) + } + } + f3: { + out: { + x: ({ + (〈3;f2〉.out & {}) + }.x + 1) + } + } + f4: { + out: { + x: ({ + (〈3;f3〉.out & {}) + }.x + 1) + } + } + f5: { + out: { + x: ({ + (〈3;f4〉.out & {}) + }.x + 1) + } + } + f6: { + out: { + x: ({ + (〈3;f5〉.out & {}) + }.x + 1) + } + } + f7: { + out: { + x: ({ + (〈3;f6〉.out & {}) + }.x + 1) + } + } + f8: { + out: { + x: ({ + (〈3;f7〉.out & {}) + }.x + 1) + } + } + } + weave: { + f: { + out: (〈0;in〉 + 1) + in: (〈1〉.ref.out + 1) + ref: (_ & {}) + } + f8: (〈0;f〉 & { + ref: 〈1;f7〉 + }) + f7: (〈0;f〉 & { + ref: 〈1;f6〉 + }) + f6: (〈0;f〉 & { + ref: 〈1;f5〉 + }) + f5: (〈0;f〉 & { + ref: 〈1;f4〉 + }) + f4: (〈0;f〉 & { + ref: 〈1;f3〉 + }) + f3: (〈0;f〉 & { + ref: 〈1;f2〉 + }) + f2: (〈0;f〉 & { + ref: 〈1;f1〉 + }) + f1: { + out: 2 + } + } + weaveExtraField: { + f: { + out: (〈0;in〉 + 1) + in: (〈1〉.ref.out + 1) + ref: { + y: 4 + } + } + f8: (〈0;f〉 & { + ref: 〈1;f7〉 + }) + f7: (〈0;f〉 & { + ref: 〈1;f6〉 + }) + f6: (〈0;f〉 & { + ref: 〈1;f5〉 + }) + f5: (〈0;f〉 & { + ref: 〈1;f4〉 + }) + f4: (〈0;f〉 & { + ref: 〈1;f3〉 + }) + f3: (〈0;f〉 & { + ref: 〈1;f2〉 + }) + f2: (〈0;f〉 & { + ref: 〈1;f1〉 + }) + f1: { + out: 2 + } + } +} diff --git a/internal/core/compile/testdata/sync/benchmarks/sort.txtar b/internal/core/compile/testdata/sync/benchmarks/sort.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/sort.txtar @@ -0,0 +1,76 @@ +// NOTE: the performance of Sort is not measured by counters. The issues +// of https://cuelang.org/issues/745 were mostly related to poor memory +// management. +-- in.cue -- +import "list" + +_a: [{name: 1}, {name: 3}, {name: 4}, {name: 5}, {name: 6}, {name: 7}, {name: 8}, {name: 9}, {name: 0}] +_b: [_a, _a, _a, _a, _a, _a, _a, _a, _a, _a] +_c: [_b, _b, _b, _b, _b, _b, _b, _b, _b, _b] + +out: list.Sort(list.FlattenN(_c, 4), {x: _, y: _, less: x.name < y.name}) + +@test(eq, at=out.0, {name: 0}) +@test(eq, at=out.899, {name: 9}) +-- out/compile -- +--- in.cue +{ + _a: [ + { + name: 1 + }, + { + name: 3 + }, + { + name: 4 + }, + { + name: 5 + }, + { + name: 6 + }, + { + name: 7 + }, + { + name: 8 + }, + { + name: 9 + }, + { + name: 0 + }, + ] + _b: [ + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + 〈1;_a〉, + ] + _c: [ + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + 〈1;_b〉, + ] + out: 〈import;list〉.Sort(〈import;list〉.FlattenN(〈0;_c〉, 4), { + x: _ + y: _ + less: (〈0;x〉.name < 〈0;y〉.name) + }) +} diff --git a/internal/core/compile/testdata/sync/benchmarks/typocheck.txtar b/internal/core/compile/testdata/sync/benchmarks/typocheck.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/benchmarks/typocheck.txtar @@ -0,0 +1,57 @@ +// Issue #3881 +-- in.cue -- +import "list" + +out: #Output & {#input: _input} + +_input: { + for n in list.Range(1, 100, 1) { + "A\(n)": "B\(n)": name: "name\(n)" + } +} +#Embed: [string]: string +#Output: { + #Embed + #input: _ + + for _, lvlA in #input { + for nameB, lvlB in lvlA { + (nameB): lvlB.name + } + } +} + +_checkB1: out.B1 @test(eq, "name1") +_checkB50: out.B50 @test(eq, "name50") +_checkB99: out.B99 @test(eq, "name99") +-- out/compile -- +--- in.cue +{ + out: (〈0;#Output〉 & { + #input: 〈1;_input〉 + }) + _input: { + for _, n in 〈import;list〉.Range(1, 100, 1) { + "A\(〈1;n〉)": { + "B\(〈2;n〉)": { + name: "name\(〈3;n〉)" + } + } + } + } + #Embed: { + [string]: string + } + #Output: { + 〈1;#Embed〉 + #input: _ + for _, lvlA in 〈0;#input〉 { + for nameB, lvlB in 〈1;lvlA〉 { + 〈1;nameB〉: 〈1;lvlB〉.name + } + } + } + _checkB1: 〈0;out〉.B1 + _checkB50: 〈0;out〉.B50 + _checkB99: 〈0;out〉.B99 +} diff --git a/internal/core/compile/testdata/sync/builtins/056_issue314.txtar b/internal/core/compile/testdata/sync/builtins/056_issue314.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/056_issue314.txtar @@ -0,0 +1,62 @@ +# Tests that builtin encoding/template functions (text/template.Execute, +# encoding/json.Marshal, encoding/yaml.Marshal) correctly produce [incomplete] +# errors rather than panicking when called with abstract (non-concrete) values. +# https://cuelang.org/issue/314 +-- in.cue -- +import ( + "text/template" + "encoding/yaml" + "encoding/json" +) + +x: { + s: "myname" + #T + @test(eq, {s: "myname", out: "myname"}) +} + +#T: { + s: string + out: template.Execute("{{.s}}", { + "s": s + }) @test(err, code=incomplete, + contains="error in call to text/template.Execute: cannot convert non-concrete value string", pos=[0:7, -1:2]) +} + +#V: { + s: string + out: json.Marshal({"s": s}) @test(err, code=incomplete, + contains="cannot convert incomplete value", pos=[0:7, -1:7]) +} + +#U: { + s: string + out: yaml.Marshal({"s": s}) @test(err, code=incomplete, + contains="incomplete value string", pos=[0:7, -1:7, 0:26]) +} +-- out/compile -- +--- in.cue +{ + x: { + s: "myname" + 〈1;#T〉 + } + #T: { + s: string + out: 〈import;"text/template"〉.Execute("{{.s}}", { + s: 〈1;s〉 + }) + } + #V: { + s: string + out: 〈import;"encoding/json"〉.Marshal({ + s: 〈1;s〉 + }) + } + #U: { + s: string + out: 〈import;"encoding/yaml"〉.Marshal({ + s: 〈1;s〉 + }) + } +} diff --git a/internal/core/compile/testdata/sync/builtins/all.txtar b/internal/core/compile/testdata/sync/builtins/all.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/all.txtar @@ -0,0 +1,77 @@ +-- in.cue -- +fatalArg: { + x: len("eee" + 'eee') @test(err, code=eval, + contains="invalid operands", + args= ["eee", 'eee', string, bytes], pos=[0:9, 0:17]) +} + +// don't call builtin for a permanent error of a child node +fatalChild: { + #b: {} + x: and([{a: #b.c}]) @test(err, at=a, code=eval, contains="undefined field: c", pos=[0:17]) +} + +// allow incomplete child values. The error will persist after `and` is +// evaluated down the line. This allows the and-ing of templates that may +// complete later. +okIncompleteChild: { + b: {} + x: and([{a: b.c}, {b: 1}]) @test(eq, { + a: _|_ @test(err, code=incomplete, contains="undefined field: c") + b: 1 + }) +} +-- issue3412.cue -- +// Tests that using and() in a pattern constraint with a definition +// reference defined after its use does not crash (nil pointer +// dereference in matchPatternValue). Issue: evalv3 panicked when +// #constraints appeared after its usage in the pattern key. +// https://cuelang.org/issue/3412 +andInPattern: { + out: { + [and(#constraints)]: _ + someKey: {} + } @test(eq, { + [=~"^.*$"]: _ + someKey: {} + }) + #constraints: [=~"^.*$"] @test(eq, [=~"^.*$"]) +} +-- out/compile -- +--- in.cue +{ + fatalArg: { + x: len(("eee" + 'eee')) + } + fatalChild: { + #b: {} + x: and([ + { + a: 〈2;#b〉.c + }, + ]) + } + okIncompleteChild: { + b: {} + x: and([ + { + a: 〈2;b〉.c + }, + { + b: 1 + }, + ]) + } +} +--- issue3412.cue +{ + andInPattern: { + out: { + [and(〈1;#constraints〉)]: _ + someKey: {} + } + #constraints: [ + =~"^.*$", + ] + } +} diff --git a/internal/core/compile/testdata/sync/builtins/and.txtar b/internal/core/compile/testdata/sync/builtins/and.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/and.txtar @@ -0,0 +1,60 @@ +-- in.cue -- +merge: and([1, 1]) @test(eq, 1) + +// ensure definitions along embedded scalars are preserved. +embed: and([{2, #x: 1}, {2, #x: 2}]) @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[0:13, 0:21, 0:25, 0:33]) + +// issue3719: and() with a comprehension over an incomplete field failed in +// evalv3 while the equivalent expression without and() worked correctly. +// https://cuelang.org/issue/3719 +issue3719: { + #openStruct: {...} + _filledLater: #openStruct.foo @test(err, code=incomplete, contains="undefined field: foo", pos=[0:28]) + + // The comprehension below should work regardless of whether it's wrapped in "and". + + withoutAnd: { + for k, v in _filledLater.bar { + (k): v + } + } @test(err, code=incomplete, contains="undefined field: foo", pos=[in.cue:11:28]) + withAnd: and([ + for k, v in _filledLater.bar { + (k): v + } + ]) @test(err, code=incomplete, contains="undefined field: foo", pos=[in.cue:11:28]) +} +-- out/compile -- +--- in.cue +{ + merge: and([ + 1, + 1, + ]) + embed: and([ + { + 2 + #x: 1 + }, + { + 2 + #x: 2 + }, + ]) + issue3719: { + #openStruct: { + ... + } + _filledLater: 〈0;#openStruct〉.foo + withoutAnd: { + for k, v in 〈1;_filledLater〉.bar { + 〈1;k〉: 〈1;v〉 + } + } + withAnd: and([ + for k, v in 〈1;_filledLater〉.bar { + 〈1;k〉: 〈1;v〉 + }, + ]) + } +} diff --git a/internal/core/compile/testdata/sync/builtins/args.txtar b/internal/core/compile/testdata/sync/builtins/args.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/args.txtar @@ -0,0 +1,46 @@ +-- in.cue -- +import ( + "math" + "strings" +) + +// issue3584: builtin functions with default-valued disjunction arguments +// (e.g. *1 | 2) caused an "error in call" panic in evalv3. +// https://cuelang.org/issue/3584 +issue3584: reduced: t1: { + ref: out + trigger: *1 | 2 + out: strings.SliceRunes("ABC", 0, trigger) + @test(eq, { + ref: "A" + trigger: *1 | 2 + out: "A" + }) +} + +issue3584: reduced: t2: { + x: math.Abs(y) + y: *6 | 5 + @test(eq, {x: 6, y: *6 | 5}) +} +-- out/compile -- +--- in.cue +{ + issue3584: { + reduced: { + t1: { + ref: 〈0;out〉 + trigger: (*1|2) + out: 〈import;strings〉.SliceRunes("ABC", 0, 〈0;trigger〉) + } + } + } + issue3584: { + reduced: { + t2: { + x: 〈import;math〉.Abs(〈0;y〉) + y: (*6|5) + } + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/closeall.txtar b/internal/core/compile/testdata/sync/builtins/closeall.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/closeall.txtar @@ -0,0 +1,97 @@ +-- in.cue -- +@experiment(explicitopen) + +// Basic usage of __closeAll - makes structs recursively closed +a: __closeAll({ + field1: 1 + nested: { + field2: "hello" + } +}) @test(eq, {field1: 1, nested: {field2: "hello"}}) + +// Test that extra fields are not allowed (should error) +b: { + err: a & {extra: "not allowed"} + @test(err, at=err.extra, code=eval, contains="field not allowed", pos=[1:12]) +} + +// Test that nested extra fields are not allowed (should error) +c: { + err: a & { + field1: 1 + nested: { + field2: "hello" + extra: "not allowed" + } + } + @test(err, at=err.nested.extra, code=eval, contains="field not allowed", pos=[5:4]) +} + +// Test with non-struct should error +d: { + err: __closeAll("not a struct") @test(err, code=eval, contains="argument must be a struct or list literal", pos=[0:7]) +} + +// Test with empty struct +e: __closeAll({}) @test(eq, {}) +f: { + err: e & {extra: "not allowed"} // should error + @test(err, at=err.extra, code=eval, contains="field not allowed", pos=[1:12]) +} + + +#A: a: int +g: { + err: __closeAll(#A) @test(err, code=eval, contains="argument must be a struct or list literal", pos=[0:7]) +} +-- old.cue -- +// May not be used if explicitopen is not set. +h: { + err: __closeAll({}) @test(err, code=eval, contains="__closeAll may only be used when explicitopen is enabled", pos=[0:7]) +} + +-- out/compile -- +--- in.cue +{ + a: __closeAll({ + field1: 1 + nested: { + field2: "hello" + } + }) + b: { + err: (〈1;a〉 & { + extra: "not allowed" + }) + } + c: { + err: (〈1;a〉 & { + field1: 1 + nested: { + field2: "hello" + extra: "not allowed" + } + }) + } + d: { + err: __closeAll("not a struct") + } + e: __closeAll({}) + f: { + err: (〈1;e〉 & { + extra: "not allowed" + }) + } + #A: { + a: int + } + g: { + err: __closeAll(〈1;#A〉) + } +} +--- old.cue +{ + h: { + err: __closeAll({}) + } +} diff --git a/internal/core/compile/testdata/sync/builtins/closed.txtar b/internal/core/compile/testdata/sync/builtins/closed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/closed.txtar @@ -0,0 +1,415 @@ +-- in.cue -- +a: close({ + a: b: int +}) + +b: a & {x: int} @test(err, code=eval, at=x, contains="field not allowed", pos=[0:9]) // err +c: a & {a: c: int} @test(eq, {a: {c: int, b: int}}) // okay (non-recursive close) + +inDisjunctions: { + x: [string]: #Def + #Def: [string]: { + a: b: true + let X = a + close({uint: a: b: X.b}) | close({string: a: b: true}) + } + x: socket: string: {} + x: syslog: x.socket + x: syslog: xxx: {} + + @test(eq, { + x: { + socket: string: { + a: b: true + uint: a: b: true + } | { + a: b: true + string: a: b: true + } + syslog: { + string: { + a: b: true + uint: a: b: true + } | { + a: b: true + string: a: b: true + } + xxx: { + a: b: true + uint: a: b: true + } | { + a: b: true + string: a: b: true + } + } + } + #Def: {} + }) +} + +// issue642: Tests that close() with merged struct patterns (concrete fields and +// bulk optional) correctly allows subfields. https://cuelang.org/issue/642 +issue642: { + test: close({ + a: _ + b: x: _ + } & { + [string]: y: _ + }) @test(closed) + + test: a: x: _ + test: b: x: _ + + @test(eq, { + test: { + [string]: y: _ + a: { + y: _ + x: _ + } + b: { + x: _ + y: _ + } + } + }) +} + +// Issue 642 +withSubfields: { + test: close({ + a: _ + b: x: _ + [string]: y: _ + }) + + test: a: x: _ + test: b: x: _ + + @test(eq, { + test: { + [string]: y: _ + a: { + y: _ + x: _ + } + b: { + x: _ + y: _ + } + } + }) +} + +// issue3572: Tests that close({...}) allows additional fields when unified +// with an open struct. https://cuelang.org/issue/3572 +issue3572: { + t1: close({...}) & {a: 5} @test(eq, {a: 5}) @test(closed) + + e: close({...}) @test(closed) // TODO: @test(allows=expr) + + t2: e & {a: 5} @test(eq, {a: 5}) @test(closed) +} + +// issue3580: Tests that close() does not panic when a field inside the closed +// struct references another field of the same struct. https://cuelang.org/issue/3580 +issue3580: { + x: close({ + a: _ + b: x.a + }) @test(closed) +} +-- embed.cue -- +nestedEmbedded: base: { + close({ foo?: close({ foo?: _ }) }) + foo: allowed: 5 + + @test(eq, { foo: { allowed: 5, foo?: _ } }) +} +nestedEmbedded: t1: { + { close({ foo?: close({ foo?: _ }) }) } + foo: allowed: 5 + + @test(eq, { foo: { allowed: 5, foo?: _ } }) +} +nestedEmbedded: t2: { + {{ close({ foo?: close({ foo?: _ }) }) }} + foo: allowed: 5 + + @test(eq, { foo: { allowed: 5, foo?: _ } }) +} +unified: base: { + x: close({ foo?: close({ foo?: _ }) }) + x: foo: disallowed: 5 @test(err, code=eval, contains="field not allowed", pos=[0:10]) +} +unified: t1: { + x: { close({ foo?: close({ foo?: _ }) }) } + x: foo: disallowed: 5 @test(err, code=eval, contains="field not allowed", pos=[0:10]) +} +unified: t2: { + x: {{ close({ foo?: close({ foo?: _ }) }) }} + x: foo: disallowed: 5 @test(err, code=eval, contains="field not allowed", pos=[0:10]) +} +nestedWithSelfReference: t1: { + _schema: close({ + foo?: _schema + }) @test(shareID=S) + // TODO(inline): make work for hidden fields. + // @test(err, at=_schema.foo, code=structural_cycle) + // @test(shareID=S, at=x.foo.foo) + + x: {_schema} + x: foo: disallowed: 5 @test(err, code=eval, contains="field not allowed", pos=[0:10]) +} +nestedWithSelfReference: t2: { + _schema: close({ + foo?: _schema + }) + // TODO(inline): make work for hidden fields. + // @test(err, at=foo, code=structural_cycle) + x: {{_schema}} + x: foo: disallowed: 5 @test(err, code=eval, contains="field not allowed", pos=[0:10]) +} +-- out/compile -- +--- embed.cue +{ + nestedEmbedded: { + base: { + close({ + foo?: close({ + foo?: _ + }) + }) + foo: { + allowed: 5 + } + } + } + nestedEmbedded: { + t1: { + { + close({ + foo?: close({ + foo?: _ + }) + }) + } + foo: { + allowed: 5 + } + } + } + nestedEmbedded: { + t2: { + { + { + close({ + foo?: close({ + foo?: _ + }) + }) + } + } + foo: { + allowed: 5 + } + } + } + unified: { + base: { + x: close({ + foo?: close({ + foo?: _ + }) + }) + x: { + foo: { + disallowed: 5 + } + } + } + } + unified: { + t1: { + x: { + close({ + foo?: close({ + foo?: _ + }) + }) + } + x: { + foo: { + disallowed: 5 + } + } + } + } + unified: { + t2: { + x: { + { + close({ + foo?: close({ + foo?: _ + }) + }) + } + } + x: { + foo: { + disallowed: 5 + } + } + } + } + nestedWithSelfReference: { + t1: { + _schema: close({ + foo?: 〈1;_schema〉 + }) + x: { + 〈1;_schema〉 + } + x: { + foo: { + disallowed: 5 + } + } + } + } + nestedWithSelfReference: { + t2: { + _schema: close({ + foo?: 〈1;_schema〉 + }) + x: { + { + 〈2;_schema〉 + } + } + x: { + foo: { + disallowed: 5 + } + } + } + } +} +--- in.cue +{ + a: close({ + a: { + b: int + } + }) + b: (〈0;a〉 & { + x: int + }) + c: (〈0;a〉 & { + a: { + c: int + } + }) + inDisjunctions: { + x: { + [string]: 〈1;#Def〉 + } + #Def: { + [string]: { + a: { + b: true + } + let X#1 = 〈0;a〉 + (close({ + uint: { + a: { + b: 〈3;let X#1〉.b + } + } + })|close({ + string: { + a: { + b: true + } + } + })) + } + } + x: { + socket: { + string: {} + } + } + x: { + syslog: 〈1;x〉.socket + } + x: { + syslog: { + xxx: {} + } + } + } + issue642: { + test: close(({ + a: _ + b: { + x: _ + } + } & { + [string]: { + y: _ + } + })) + test: { + a: { + x: _ + } + } + test: { + b: { + x: _ + } + } + } + withSubfields: { + test: close({ + a: _ + b: { + x: _ + } + [string]: { + y: _ + } + }) + test: { + a: { + x: _ + } + } + test: { + b: { + x: _ + } + } + } + issue3572: { + t1: (close({ + ... + }) & { + a: 5 + }) + e: close({ + ... + }) + t2: (〈0;e〉 & { + a: 5 + }) + } + issue3580: { + x: close({ + a: _ + b: 〈1;x〉.a + }) + } +} diff --git a/internal/core/compile/testdata/sync/builtins/default.txtar b/internal/core/compile/testdata/sync/builtins/default.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/default.txtar @@ -0,0 +1,31 @@ +-- in.cue -- +Len: len(*[1, 2, 3] | 0) @test(eq, 3) +Close: close(*{} | 0) @test(eq, {}) @test(closed) +And: and(*[1, 1] | int) @test(eq, 1) +Or: or(*[1, 1] | int) @test(eq, 1) +Div: div(*5 | string, 2) @test(eq, 2) +Mod: mod(*5 | string, 2) @test(eq, 1) +Quo: quo(*5 | string, 2) @test(eq, 2) +Rem: rem(*5 | string, 2) @test(eq, 1) +-- out/compile -- +--- in.cue +{ + Len: len((*[ + 1, + 2, + 3, + ]|0)) + Close: close((*{}|0)) + And: and((*[ + 1, + 1, + ]|int)) + Or: or((*[ + 1, + 1, + ]|int)) + Div: div((*5|string), 2) + Mod: mod((*5|string), 2) + Quo: quo((*5|string), 2) + Rem: rem((*5|string), 2) +} diff --git a/internal/core/compile/testdata/sync/builtins/error.txtar b/internal/core/compile/testdata/sync/builtins/error.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/error.txtar @@ -0,0 +1,163 @@ +-- cue.mod/module.cue -- +module: "cuelang.org/error" +language: version: "v0.15.0" +-- in.cue -- +selection: { + dropError: 1 | error("drop me") @test(eq, 1) + + useCustomError: 1&2 | error("use me") @test(err, code=eval, contains="use me", pos=[0:24, 0:18, 0:20]) + + twoCustomErrors: 1&2 | error("error one") | error("error two") @test(err, code=eval, contains="empty disjunction", + suberr=(code=eval, contains="error one", pos=[0:25]), + suberr=(code=eval, contains="error two", pos=[0:46]), + ) + + x: int + dropIncomplete: x + 1 | error("user msg: x + 1 failed") @test(err, code=incomplete, contains="user msg: x + 1 failed", pos=[0:26, -1:5]) +} + +interpolation: { + a: {b: int} + world: "world" @test(eq, "world") + + substituteAll: a.notExist | error("hello \(world)") @test(err, code=incomplete, contains="hello world", pos=[0:30]) + + substituteFail: a.b + 1 | a.notExist | error("reference failed: \(a.b) | \(a.notExist)") @test(err, code=incomplete, contains="reference failed:", pos=[0:41, -5:9, 0:77]) + + // When the error() message itself contains an error, + // the custom error should not be thrown away. + // For comparison, without interpolation: + errorNoInterpolation: "a" | "b" | error("custom") + errorNoInterpolation: "c" @test(err, code=eval, contains="custom", pos=[-1:36, -1:24, 0:24]) + + // When the struct interpolation fails, the custom error should + // still be shown rather than being replaced by the interpolation error. + errorStructInterpolation: "a" | "b" | error("custom: \({x: 1})") + errorStructInterpolation: "c" @test(err, code=eval, contains="custom: {x:1}", pos=[-1:40, -1:28, -1:57, 0:28]) + + // When the interpolation always results in an error, the custom + // error should still be shown. + errorBottomInterpolation: "a" | "b" | error("custom: \(1 & 2)") + errorBottomInterpolation: "c" @test(err, code=eval, contains="custom: (1 & 2)", pos=[-1:40, -1:28, -1:57, 0:28]) +} +indirect: { + x: error @test(eq, error) + y: x("msg") @test(err, code=user, contains="msg", pos=[0:5]) +} +-- incomplete.cue -- +import "struct" + +// The custom error should not alter the type of error. +minFields: struct.MinFields(2) | error("should remain incomplete") @test(eq, struct.MinFields(2)) +maxFields: a: 1 @test(eq, 1) + +multi: struct.MinFields(2) | error("should remain incomplete") | error("second") @test(err, code=incomplete, + pos=[0:8, 0:25, 4:8], + suberr=(code=eval, contains="should remain incomplete", pos=[0:30]), + suberr=(code=eval, contains="second", pos=[0:66])) +multi: a: 1 + +-- self.cue -- +@experiment(aliasv2) + +// When error() interpolates "self" which is the enclosing struct +// containing the error value itself (a cycle), the custom error +// should still be shown. +errorSelf: { + v: "x" | "y" | error("bad: \(self)") + v: "z" + @test(err, code=eval, contains="bad:", pos=[1:17, 0:12, 1:5, 2:5]) +} +-- issues.cue -- +// issue4001: Tests that error() text is shown correctly when the message uses +// string concatenation with interpolation. https://cuelang.org/issue/4001 +issue4001: { + a: "b" + a: int | error("error: "+"a='\(a)'") @test(err, code=eval, contains="error: a='b'", pos=[0:11, -1:5, 0:5]) +} +// issue3983: Tests that multiple error() disjunctions aggregate all user-defined +// error messages correctly. https://cuelang.org/issue/3983 +issue3983: { + x: int | error("I wanted an integer") + x: >10 | error("I wanted more than 10") + x: <20 | error("I wanted less than 20") + + x: 3 + @test(err, code=eval, contains="2 errors in empty disjunction", pos=[2:5, 5:5], + suberr=(code=eval, contains="I wanted an integer", hint="this could be dropped"), + suberr=(code=eval, contains="I wanted more than 10"), + hint="we could also include the third condition, if we want to be consistent.", + ) +} +// issue3984: Tests that error() shows all relevant source locations when the +// error builtin is used in a disjunction. https://cuelang.org/issue/3984 +issue3984: { + v: "a" | error("must be a") + v: "b" @test(err, code=eval, contains="must be a", pos=[-1:11, -1:5, 0:5]) +} +-- out/compile -- +--- in.cue +{ + selection: { + dropError: (1|error("drop me")) + useCustomError: ((1 & 2)|error("use me")) + twoCustomErrors: ((1 & 2)|error("error one")|error("error two")) + x: int + dropIncomplete: ((〈0;x〉 + 1)|error("user msg: x + 1 failed")) + } + interpolation: { + a: { + b: int + } + world: "world" + substituteAll: (〈0;a〉.notExist|error("hello \(〈0;world〉)")) + substituteFail: ((〈0;a〉.b + 1)|〈0;a〉.notExist|error("reference failed: \(〈0;a〉.b) | \(〈0;a〉.notExist)")) + errorNoInterpolation: ("a"|"b"|error("custom")) + errorNoInterpolation: "c" + errorStructInterpolation: ("a"|"b"|error("custom: \({ + x: 1 + })")) + errorStructInterpolation: "c" + errorBottomInterpolation: ("a"|"b"|error("custom: \((1 & 2))")) + errorBottomInterpolation: "c" + } + indirect: { + x: error + y: 〈0;x〉("msg") + } +} +--- incomplete.cue +{ + minFields: (〈import;struct〉.MinFields(2)|error("should remain incomplete")) + maxFields: { + a: 1 + } + multi: (〈import;struct〉.MinFields(2)|error("should remain incomplete")|error("second")) + multi: { + a: 1 + } +} +--- issues.cue +{ + issue4001: { + a: "b" + a: (int|error(("error: " + "a='\(〈0;a〉)'"))) + } + issue3983: { + x: (int|error("I wanted an integer")) + x: (>10|error("I wanted more than 10")) + x: (<20|error("I wanted less than 20")) + x: 3 + } + issue3984: { + v: ("a"|error("must be a")) + v: "b" + } +} +--- self.cue +{ + errorSelf: { + v: ("x"|"y"|error("bad: \(〈1〉)")) + v: "z" + } +} diff --git a/internal/core/compile/testdata/sync/builtins/export.txtar b/internal/core/compile/testdata/sync/builtins/export.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/export.txtar @@ -0,0 +1,60 @@ +-- in.cue -- +import "encoding/yaml" + +// issue3972: Tests that yaml.Marshal with list comprehensions over conditionally +// defined fields works correctly in evalv3. https://cuelang.org/issue/3972 +issue3972: { + // yaml uses Syntax to convert CUE to YAML. Ensure that unresolved values + // are properly handled. + // TODO(inline): the inline testing framework indicated that this field + // was not used in the computation of the test result. That seems correct. + // But maybe this test is then not testing what it is supposed to do. + // Investigate against the original issue. + output: out0: "static" @test(eq, "static") // has to go first + + input: inputStatic: "static" + if false { + input: inputNever: "never" + } + + derived: derivedStatic: "static" + if false { + derived: derivedNever: input.inputNever + } + + _out1: [for svc, _ in derived {svc}] + output: out1: yaml.Marshal(_out1) @test(eq, "- derivedStatic\n") +} +-- out/compile -- +--- in.cue +{ + issue3972: { + output: { + out0: "static" + } + input: { + inputStatic: "static" + } + if false { + input: { + inputNever: "never" + } + } + derived: { + derivedStatic: "static" + } + if false { + derived: { + derivedNever: 〈2;input〉.inputNever + } + } + _out1: [ + for svc, _ in 〈1;derived〉 { + 〈1;svc〉 + }, + ] + output: { + out1: 〈import;"encoding/yaml"〉.Marshal(〈1;_out1〉) + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/incomplete.txtar b/internal/core/compile/testdata/sync/builtins/incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/incomplete.txtar @@ -0,0 +1,208 @@ +-- in.cue -- +import ( + "list" + "strings" + "text/template" +) + +list1: { + // Note that Top is not incomplete, only its first element is. + // We allow FlattenN to proceed and pass on the incomplete values. + Out1: list.FlattenN(Top, 1) @test(err, at=0, code=incomplete, contains="undefined field: b", pos=[in.cue:19:10]) + Out2: [...] & list.FlattenN(Top, 1) @test(err, at=0, code=incomplete, contains="undefined field: b", pos=[in.cue:19:10]) + Out3: list.FlattenN(Top, 1) & [...] @test(err, at=0, code=incomplete, contains="undefined field: b", pos=[in.cue:19:10]) + + // This evaluates to a list with an incomplete element. + Top: [ + [for _, F in _Sub {F}], + ] @test(err, at=0, code=incomplete, contains="undefined field: b", pos=[in.cue:19:10]) + + _Sub: a.b @test(err, code=incomplete, contains="undefined field: b", pos=[in.cue:19:10]) + a: {} // b does not +} + +list2: { + Out1: list.FlattenN(_Top, 1) @test(err, code=incomplete, contains="undefined field: b", pos=[9:10]) + Out2: [...] & list.FlattenN(_Top, 1) @test(err, code=incomplete, contains="undefined field: b", pos=[8:10]) + Out3: list.FlattenN(_Top, 1) & [...] @test(err, code=incomplete, contains="undefined field: b", pos=[7:10]) + + // This evaluates to a list with an incomplete element. + _Top: [ + for _, F in #Sub {F}, + ] @test(err, code=incomplete, contains="undefined field: b", pos=[4:10]) + + #Sub: a.b @test(err, code=incomplete, contains="undefined field: b", pos=[0:10]) + + a: {} // b does not +} + +value1: { + a: len('sf' | 'dd') @test(err, code=incomplete|eval, + hint="this can never be resolve so could be a permanent error" + contains="unresolved disjunction", pos=[0:5]) @test(err:todo, code=eval) +} + +value2: { + len('sf' | 'dd') + + @test(err, code=incomplete|eval, + hint="this can never be resolve so could be a permanent error" + contains="unresolved disjunction") + @test(err:todo, code=eval) +} + +incompleteArgDecimalList: { + a: #a & {param: 123} @test(eq, {param: 123, transformed: 123, max: 123}) + #a: { + param: int + transformed: +param @test(err, code=incomplete, contains="operand param of '+' not concrete", pos=[0:17]) + max: list.Max([transformed]) @test(err, code=incomplete, contains="operand param of '+' not concrete", pos=[0:16, -1:17]) + } +} + +incompleteArgStringList: { + a: #a & {param: "123"} @test(eq, {param: "123", transformed: "123", joined: "123"}) + #a: { + param: string + transformed: param + "" @test(err, code=incomplete, contains="non-concrete value string in operand to +", pos=[0:16, -1:16]) + joined: strings.Join([transformed], "-") @test(err, code=incomplete, contains="non-concrete value string in operand to +", pos=[0:16, -2:16, -1:16]) + } +} + +incompleteList: { + x: _ + decimal: list.Max(x) @test(err, code=incomplete, contains="non-concrete list for argument 0", pos=[0:11]) + str: strings.Join(x, "") @test(err, code=incomplete, contains="non-concrete list for argument 0", pos=[0:11]) +} + +// TODO: add better error positions. +incompleteListError: { + x: y + [] @test(err, code=incomplete, contains="non-concrete value _ in operand to +", pos=[0:11, 1:11]) + y: _ + decimal: list.Max(x) @test(err, code=incomplete, contains="non-concrete value _ in operand to +", pos=[-2:11, -1:11]) + str: strings.Join(x, "") @test(err, code=incomplete, contains="non-concrete value _ in operand to +", pos=[-3:11, -2:11]) +} + +badListType: { + x: 2 + decimal: list.Max(x) @test(err, code=eval, contains="cannot use 2 (type int) as list", pos=[-1:11]) + str: strings.Join(x, "") @test(err, code=eval, contains="cannot use 2 (type int) as list", pos=[-2:11]) +} + +badListError: { + x: 2 + y @test(err, code=eval, contains="invalid operands 2 and \"foo\" to '+'", pos=[0:11, 1:11]) + y: "foo" + decimal: list.Max(x) @test(err, code=eval, contains="invalid operands 2 and \"foo\" to '+'", pos=[-2:11, -1:11]) + str: strings.Join(x, "") @test(err, code=eval, contains="invalid operands 2 and \"foo\" to '+'", pos=[-3:11, -2:11]) +} + +// Issue #1095 +// Preserve combined error severity for multiple errors. +multipleErrors: { + #T: { + params: { + x: string + y: string + } + out: template.Execute("{{.x}} {{.y}}", params) @test(err, code=incomplete, contains="cannot convert non-concrete value string", pos=[0:8, -3:4]) + } +} +-- out/compile -- +--- in.cue +{ + list1: { + Out1: 〈import;list〉.FlattenN(〈0;Top〉, 1) + Out2: ([ + ..., + ] & 〈import;list〉.FlattenN(〈0;Top〉, 1)) + Out3: (〈import;list〉.FlattenN(〈0;Top〉, 1) & [ + ..., + ]) + Top: [ + [ + for _, F in 〈2;_Sub〉 { + 〈1;F〉 + }, + ], + ] + _Sub: 〈0;a〉.b + a: {} + } + list2: { + Out1: 〈import;list〉.FlattenN(〈0;_Top〉, 1) + Out2: ([ + ..., + ] & 〈import;list〉.FlattenN(〈0;_Top〉, 1)) + Out3: (〈import;list〉.FlattenN(〈0;_Top〉, 1) & [ + ..., + ]) + _Top: [ + for _, F in 〈1;#Sub〉 { + 〈1;F〉 + }, + ] + #Sub: 〈0;a〉.b + a: {} + } + value1: { + a: len(('sf'|'dd')) + } + value2: { + len(('sf'|'dd')) + } + incompleteArgDecimalList: { + a: (〈0;#a〉 & { + param: 123 + }) + #a: { + param: int + transformed: +〈0;param〉 + max: 〈import;list〉.Max([ + 〈1;transformed〉, + ]) + } + } + incompleteArgStringList: { + a: (〈0;#a〉 & { + param: "123" + }) + #a: { + param: string + transformed: (〈0;param〉 + "") + joined: 〈import;strings〉.Join([ + 〈1;transformed〉, + ], "-") + } + } + incompleteList: { + x: _ + decimal: 〈import;list〉.Max(〈0;x〉) + str: 〈import;strings〉.Join(〈0;x〉, "") + } + incompleteListError: { + x: (〈0;y〉 + []) + y: _ + decimal: 〈import;list〉.Max(〈0;x〉) + str: 〈import;strings〉.Join(〈0;x〉, "") + } + badListType: { + x: 2 + decimal: 〈import;list〉.Max(〈0;x〉) + str: 〈import;strings〉.Join(〈0;x〉, "") + } + badListError: { + x: (2 + 〈0;y〉) + y: "foo" + decimal: 〈import;list〉.Max(〈0;x〉) + str: 〈import;strings〉.Join(〈0;x〉, "") + } + multipleErrors: { + #T: { + params: { + x: string + y: string + } + out: 〈import;"text/template"〉.Execute("{{.x}} {{.y}}", 〈0;params〉) + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/intdiv.txtar b/internal/core/compile/testdata/sync/builtins/intdiv.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/intdiv.txtar @@ -0,0 +1,72 @@ +-- in.cue -- +quo1: quo(5, 2) @test(eq, 2) +quo2: quo(5, -2) @test(eq, -2) +quo3: quo(-5, 2) @test(eq, -2) +quo4: quo(-5, -2) @test(eq, 2) + +quoDivByZero: quo(2, 0) @test(err, code=eval, contains="division by zero", pos=[0:15]) + +quoTypeError1: quo(2.0, 1) @test(err, code=eval, contains="cannot use 2.0 (type float) as int in argument 1 to quo", pos=[0:20]) +quoTypeError2: quo(2, 1.0) @test(err, code=eval, contains="cannot use 1.0 (type float) as int in argument 2 to quo", pos=[0:23]) + +rem1: rem(5, 2) @test(eq, 1) +rem2: rem(5, -2) @test(eq, 1) +rem3: rem(-5, 2) @test(eq, -1) +rem4: rem(-5, -2) @test(eq, -1) + +remDivByZero: rem(2, 0) @test(err, code=eval, contains="division by zero", pos=[0:15]) + +remTypeError1: rem(2.0, 1) @test(err, code=eval, contains="cannot use 2.0 (type float) as int in argument 1 to rem", pos=[0:20]) +remTypeError2: rem(2, 1.0) @test(err, code=eval, contains="cannot use 1.0 (type float) as int in argument 2 to rem", pos=[0:23]) + +div1: div(5, 2) @test(eq, 2) +div2: div(5, -2) @test(eq, -2) +div3: div(-5, 2) @test(eq, -3) +div4: div(-5, -2) @test(eq, 3) + +divDivByZero: div(2, 0) @test(err, code=eval, contains="division by zero", pos=[0:15]) + +divTypeError1: div(2.0, 1) @test(err, code=eval, contains="cannot use 2.0 (type float) as int in argument 1 to div", pos=[0:20]) +divTypeError2: div(2, 1.0) @test(err, code=eval, contains="cannot use 1.0 (type float) as int in argument 2 to div", pos=[0:23]) + +mod1: mod(5, 2) @test(eq, 1) +mod2: mod(5, -2) @test(eq, 1) +mod3: mod(-5, 2) @test(eq, 1) +mod4: mod(-5, -2) @test(eq, 1) + +modDivByZero: mod(2, 0) @test(err, code=eval, contains="division by zero", pos=[0:15]) + +modTypeError1: mod(2.0, 1) @test(err, code=eval, contains="cannot use 2.0 (type float) as int in argument 1 to mod", pos=[0:20]) +modTypeError2: mod(2, 1.0) @test(err, code=eval, contains="cannot use 1.0 (type float) as int in argument 2 to mod", pos=[0:23]) +-- out/compile -- +--- in.cue +{ + quo1: quo(5, 2) + quo2: quo(5, -2) + quo3: quo(-5, 2) + quo4: quo(-5, -2) + quoDivByZero: quo(2, 0) + quoTypeError1: quo(2.0, 1) + quoTypeError2: quo(2, 1.0) + rem1: rem(5, 2) + rem2: rem(5, -2) + rem3: rem(-5, 2) + rem4: rem(-5, -2) + remDivByZero: rem(2, 0) + remTypeError1: rem(2.0, 1) + remTypeError2: rem(2, 1.0) + div1: div(5, 2) + div2: div(5, -2) + div3: div(-5, 2) + div4: div(-5, -2) + divDivByZero: div(2, 0) + divTypeError1: div(2.0, 1) + divTypeError2: div(2, 1.0) + mod1: mod(5, 2) + mod2: mod(5, -2) + mod3: mod(-5, 2) + mod4: mod(-5, -2) + modDivByZero: mod(2, 0) + modTypeError1: mod(2.0, 1) + modTypeError2: mod(2, 1.0) +} diff --git a/internal/core/compile/testdata/sync/builtins/issue299.txtar b/internal/core/compile/testdata/sync/builtins/issue299.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/issue299.txtar @@ -0,0 +1,22 @@ +# Tests that list.UniqueItems correctly rejects lists with duplicate +# values, which were silently passed through instead of producing an error. +# https://cuelang.org/issue/299 +-- in.cue -- +import "list" + +x: list.UniqueItems +x: [string, ...string] +x: ["x", "x"] @test(err, code=eval, contains="does not satisfy list.UniqueItems", pos=[-2:4, -1:4, 0:4]) +-- out/compile -- +--- in.cue +{ + x: 〈import;list〉.UniqueItems + x: [ + string, + ...string, + ] + x: [ + "x", + "x", + ] +} diff --git a/internal/core/compile/testdata/sync/builtins/issue4208.txtar b/internal/core/compile/testdata/sync/builtins/issue4208.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/issue4208.txtar @@ -0,0 +1,53 @@ +# Test that error() in a disjunction used as a pattern constraint key +# surfaces the custom error message instead of the generic "field not allowed". +# +# Issue: https://cuelang.org/issue/4208 +-- in.cue -- +#Environment: "sbx" | "stg" | "pro" | error("Must specify a valid environment") +#Envs: [Env=#Environment]: {} + +// Valid key should work fine. +valid: #Envs @test(eq, {["sbx"|"stg"|"pro"]: {}, sbx: {}}, hint="user error should be preserved in pattern") +valid: sbx: {} + +// Invalid key should show the custom error message. +invalid: #Envs +invalid: foo: {} @test(err, code=eval, contains="field not allowed", incorrect) @test(err:todo, code=eval, contains="Must specify a valid environment") + + +@test(debug, """ + (_|_){ + // [eval] + #Environment: (string){ |((string){ "sbx" }, (string){ "stg" }, (string){ "pro" }) } + #Envs: (#struct){ + } + valid: (#struct){ + sbx: (#struct){ + } + } + invalid: (_|_){ + // [eval] + foo: (_|_){ + // [eval] invalid.foo: field not allowed: + // in.cue:10:10 + } + } + } + """) + +-- out/compile -- +--- in.cue +{ + #Environment: ("sbx"|"stg"|"pro"|error("Must specify a valid environment")) + #Envs: { + [〈1;#Environment〉]: {} + } + valid: 〈0;#Envs〉 + valid: { + sbx: {} + } + invalid: 〈0;#Envs〉 + invalid: { + foo: {} + } +} diff --git a/internal/core/compile/testdata/sync/builtins/issue490.txtar b/internal/core/compile/testdata/sync/builtins/issue490.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/issue490.txtar @@ -0,0 +1,42 @@ +# Tests that close() correctly rejects fields not present in the closed struct +# when the closed value is later unified with an open struct adding new fields. +# https://cuelang.org/issue/490 +-- test.cue -- +A: close({ + a: 1 + b: 2 +}) @test(eq, {a: 1, b: 2}) + +B: A & { + c: 3 +} @test(err, code=eval, at=c, contains="field not allowed", pos=[1:2]) + +@test(debugCheck, """ + (_|_){ + // [eval] + A: (#struct){ + a: (int){ 1 } + b: (int){ 2 } + } + B: (_|_){ + // [eval] + c: (_|_){ + // [eval] B.c: field not allowed: + // test.cue:7:2 + } + a: (int){ 1 } + b: (int){ 2 } + } + } + """) +-- out/compile -- +--- test.cue +{ + A: close({ + a: 1 + b: 2 + }) + B: (〈0;A〉 & { + c: 3 + }) +} diff --git a/internal/core/compile/testdata/sync/builtins/issue_3567.txtar b/internal/core/compile/testdata/sync/builtins/issue_3567.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/issue_3567.txtar @@ -0,0 +1,14 @@ +-- in.cue -- +import "strings" +a: strings.Join( [ strings.Join(["1"]), "2" ], "\n") @test(err, code=eval, contains="not enough arguments in call to strings.Join", pos=[0:4, 0:20]) + +-- out/compile -- +--- in.cue +{ + a: 〈import;strings〉.Join([ + 〈import;strings〉.Join([ + "1", + ]), + "2", + ], "\n") +} diff --git a/internal/core/compile/testdata/sync/builtins/matchif.txtar b/internal/core/compile/testdata/sync/builtins/matchif.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/matchif.txtar @@ -0,0 +1,60 @@ +-- in.cue -- +regularFields: { + [_]: matchIf({x!: >2}, {y!: 5}, {y!: 1}) + ok1: {x: 10, y: 5} @test(eq, {x: 10, y: 5}) + ok2: {x: 11, y: 5} @test(eq, {x: 11, y: 5}) + ok3: {x: 2, y: 1} @test(eq, {x: 2, y: 1}) + ok4: {x: 1, y: 1} @test(eq, {x: 1, y: 1}) + + // TODO: allow unwrapping errors so that we can test args in wrapped errors, + // without having to match the other arguments. + err1: {x: 10, y: 6} @test(err, code=eval, contains="conflicting values 5 and 6", pos=[in.cue:2:7, in.cue:2:30, 0:8, 0:19]) + err2: {x: 11, y: 6} @test(err, code=eval, contains="conflicting values 5 and 6", pos=[in.cue:2:7, in.cue:2:30, 0:8, 0:19]) + err3: {x: 2, y: 5} @test(err, code=eval, contains="conflicting values 1 and 5", pos=[in.cue:2:7, in.cue:2:39, 0:8, 0:18]) + err4: {x: 1, y: 2} @test(err, code=eval, contains="conflicting values 1 and 2", pos=[in.cue:2:7, in.cue:2:39, 0:8, 0:18]) +} +-- out/compile -- +--- in.cue +{ + regularFields: { + [_]: matchIf({ + x!: >2 + }, { + y!: 5 + }, { + y!: 1 + }) + ok1: { + x: 10 + y: 5 + } + ok2: { + x: 11 + y: 5 + } + ok3: { + x: 2 + y: 1 + } + ok4: { + x: 1 + y: 1 + } + err1: { + x: 10 + y: 6 + } + err2: { + x: 11 + y: 6 + } + err3: { + x: 2 + y: 5 + } + err4: { + x: 1 + y: 2 + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/matchn.txtar b/internal/core/compile/testdata/sync/builtins/matchn.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/matchn.txtar @@ -0,0 +1,1170 @@ +-- in.cue -- +import "math" + +#Foo: { + a: int +} + +match: { + [=~"^single"]: matchN(1, [#Foo]) + singleOK: {a: 2} @test(eq, {a: 2}) + singleErr: { + a: "foo" + @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:17, -2:24, 0:13]) + } + + [=~"^incomplete"]: matchN(1, [#Foo]) + incompleteOK: {a: int} @test(eq, {a: int}) + incompleteErr: { + a: string + @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:21, -2:28, 0:17]) + } + + #A: { + a: int + b: _ + ... + } + + defaults: { + // Because validators distribute over disjunctions, this validator may erase + // a default value. Nonethenless, it will be guaranteed that the value + // resulting from evaluation does not violate the validator. + // TODO(defaults): take this use case into consideration for the defaults + // rethink, as it seems less than ideal. Note that this typically not an + // issue if the schema matched against is not concrete. + [=~"^pickTop"]: matchN(1, [2]) + // TODO(inline): this matches the debug output, but it nonetheless doesn't pass. + pickTopOK1: *2 | int @test(eq:todo, *2 | matchN(1, [2]) & int) + pickTopOK2: int @test(eq, matchN(1, [2]) & int) + pickTopErr: *3 | int @test(eq:todo, + hint="or should this be an error? Depends on when value is finalized.", + matchN(1, [2]) & int) @test(debugCheck, """ + (int){ &(matchN(1, (#list){ + 0: (int){ 2 } + }), int) } + """) + + // Nested default values will be evaluated and may not be overridden by + // values in the validator. + [=~"^pickNested1"]: matchN(1, [{a: 2}]) + pickNested1OK1: {a: *2 | int} @test(eq, {a: *2 | int}) + pickNested1OK2: {a: int} @test(eq, {a: int}) + pickNested1Err: { + a: *3 | int + @test(err, code=eval, + hint="should this be an incomplete error, as a may still change and pass?", + contains="does not satisfy matchN", pos=[-3:23, -3:30, 0:19]) + } + + [=~"^pickNested2"]: matchN(1, [{a: <=2}]) + pickNested2OK1: {a: *2 | int} @test(eq, {a: *2 | int}) + pickNested2OK2: {a: int} @test(eq, {a: int}) + pickNested2Err: { + a: *3 | int + @test(err, code=eval, + hint="should this be an incomplete error, as a may still change and pass?", + contains="does not satisfy matchN", pos=[-3:23, -3:30, 0:19]) + } + } + + // Stress test potential exponential behavior. + nestedOK: { + matchN(4, [#A, #A, #A, #A]) + + a: 2 + b: { + matchN(4, [#A, #A, #A, #A]) + + a: 3 + b: matchN(4, [#A, #A, #A, #A]) + b: {a: 4} + c: matchN(4, [#A, #A, #A, #A]) + c: {a: 5} + + @test(eq, {a: 3, b: {a: 4}, c: {a: 5}}) + } + c: { + matchN(4, [#A, #A, #A, #A]) + + a: 3 + b: matchN(4, [#A, #A, #A, #A]) + b: {a: 4} + c: matchN(4, [#A, #A, #A, #A]) + c: {a: 5} + + @test(eq, {a: 3, b: {a: 4}, c: {a: 5}}) + } + } +} + +not: { + [=~"^single"]: matchN(0, [#Foo]) + singleOK: {a: "foo"} @test(eq, {a: "foo"}) + singleErr: { + a: 2 + @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:17, -2:24, 0:13]) + } + + [=~"^double"]: matchN(0, [matchN(0, [#Foo])]) + doubleOK: {a: 2} @test(eq, {a: 2}) + doubleErr: { + a: "foo" + @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:17, -2:24, 0:13]) + } +} + +oneOf: { + [=~"^multiple1"]: matchN(1, [math.MultipleOf(3), math.MultipleOf(5)]) + + multiple1Err1: 1 @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:20, -2:27, 0:17]) + + multiple1OK1: 3 @test(eq, 3) + multiple1OK2: 5 @test(eq, 5) + + multiple1Err2: 15 @test(err, code=eval, contains="does not satisfy matchN", pos=[-7:20, -7:27, 0:17]) +} + +anyOf: { + [=~"^multiple1"]: matchN(>0, [math.MultipleOf(3), math.MultipleOf(5)]) + + multiple1Err1: 1 @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:20, -2:27, 0:17]) + + multiple1OK1: 3 @test(eq, 3) + multiple1OK2: 5 @test(eq, 5) + multiple1OK3: 15 @test(eq, 15) +} + + +allOf: { + [=~"^multiple1"]: matchN(2, [math.MultipleOf(3), math.MultipleOf(5)]) + + multiple1Err1: 1 @test(err, code=eval, contains="does not satisfy matchN", pos=[-2:20, -2:27, 0:17]) + multiple1Err2: 3 @test(err, code=eval, contains="does not satisfy matchN", pos=[-3:20, -3:27, 0:17]) + multiple1Err3: 5 @test(err, code=eval, contains="does not satisfy matchN", pos=[-4:20, -4:27, 0:17]) + + multiple1OK1: 15 @test(eq, 15) +} + +bare: { + embed: t1: { + a: {matchN(1, [>10])} + b: {a} + + @test(eq, { + a: matchN(1, [>10]) + b: matchN(1, [>10]) + }) + } + embed: t2: { + b: {a} + a: {matchN(1, [>10])} + + @test(eq, { + b: matchN(1, [>10]) + a: matchN(1, [>10]) + }) + } + direct: t1: { + a: matchN(1, [>10]) + b: a + + @test(eq, { + a: matchN(1, [>10]) + b: matchN(1, [>10]) + }) + } + direct: t2: { + b: a + a: matchN(1, [>10]) + + @test(eq, { + b: matchN(1, [>10]) + a: matchN(1, [>10]) + }) + } +} + +required: { + ok1: { + x: matchN(0, [{foo!: string}]) + x: bar: 2 + @test(eq, {x: {bar: 2}}) + } + ok2: { + x: matchN(0, [{foo!: string}]) + @test(eq, {x: matchN(0, [{ foo!: string }])}) + } + // not matching for different reasons + ok3: { + x: matchN(0, [{bar!: string}]) + x: bar: 2 + @test(eq, {x: {bar: 2}}) + } +} + +// issue3575: Tests that matchN correctly validates structs with extra fields +// whether inside or outside a list argument. https://cuelang.org/issue/3575 +// A struct with extra fields should match whether or not inside a list. +// evalv2 would get this wrong but evalv3 got it right. +issue3575: { + test1: { + #x: matchN(1, [ + [{}], + ]) + x: #x + x: [{a: 1}] + @test(eq, {#x: matchN(1, [[{}]]), x: [{ a: 1 }]}) + } + test2: { + #x: matchN(1, [ + {}, + ]) + x: #x + x: {a: 1} + @test(eq, {#x: matchN(1, [{}]), x: {a: 1}}) + } +} + +-- incomplete.cue -- +import "math" + +// The errors in this section should be "incomplete" errors. +incomplete: { + // foo could still be provided later. + incomplete1: { + x: matchN(1, [{foo!: string}]) + x: bar: 2 + @test(err, code=incomplete, at=x, + suberr=(code=incomplete, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:18])) + } + // foo could still be provided later. + incomplete2: { + x: matchN(1, [{foo!: string}]) + @test(eq, {x: matchN(1, [{ + foo!: string + }])}) + } + // in case of doubt, we should mark an error as incomplete to be safe. + incomplete3: { + x: matchN(math.MultipleOf(2), [{bar!: int}, {foo!: int}]) + x: bar: 2 + @test(eq, {x: {bar: 2}}) + @test(err, code=incomplete, at=x, + suberr=(code=incomplete, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:48])) + } + incomplete4: { + x: matchN(math.MultipleOf(2), [{bar!: int}, {foo!: int}, {baz!: int}]) + x: bar: 2 + @test(eq, {x: {bar: 2}}) + @test(err, code=incomplete, at=x, + suberr=(code=incomplete, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:61]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:48])) + + } + incomplete5: { + x: matchN(>1 & <=3, [{bar!: int}, {foo!: int}, {baz!: int}]) + x: bar: 2 + @test(eq, {x: {bar: 2}}) + @test(err, code=incomplete, at=x, + suberr=(code=incomplete, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:38]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:51])) + } + incomplete6: { + x: matchN(2|3, [{bar!: int}, {foo!: int}, {baz!: int}]) + x: bar: 2 + @test(eq, {x: {bar: 2}}) + @test(err, code=incomplete, at=x, + suberr=(code=incomplete, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:33]), + suberr=(code=incomplete, contains="field is required but not present", pos=[1:6, 1:46])) + } + + // incorrect type cannot be corrected + err1: { + x: matchN(1, [{bar!: string}]) + x: bar: 2 + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]) + } + // additional incomplete matches should not be counted if they can otherwise + // not satisfy the constraint. + err2: { + x: matchN(0, [{bar!: int}, {foo!: int}]) + x: bar: 2 + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]) + } + // additional incomplete matches should not be counted if they can otherwise + // not satisfy the constraint. + err3: { + x: matchN(2, [{bar!: string}, {foo!: string}]) + x: bar: 2 + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]) + } + // one additional potential match cannot make up to satisfy the bound. + err4: { + x: matchN(>1, [{bar!: string}, {foo!: string}]) + x: bar: 2 + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]) + } + err5: { + x: matchN(<1, [{bar!: int}, {foo!: int}]) + x: bar: 2 + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[1:6, 1:13, 2:6]) + } +} +// issue3389: Tests that matchN only reports schema errors of lesser severity, +// not all constraint failures. https://cuelang.org/issue/3389 +issue3389: { + // only report schema errors that are of a lesser severity. + // TODO(inline): issue converting to tests. Documented later. + x: bar: 2 + x: matchN(1, [{bar: 3}, {bar: 2, foo!: int}]) + + @test(debug, """ + (struct){ + x: (_|_){ + // [incomplete] issue3389.x: invalid value {bar:2} (does not satisfy matchN): 0 matched, expected 1: + // incomplete.cue:96:5 + // incomplete.cue:95:5 + // incomplete.cue:96:12 + // issue3389.x.foo: field is required but not present: + // incomplete.cue:96:5 + // incomplete.cue:96:35 + bar: (int){ 2 } + } + } + """) +} +-- closedness.cue -- +ellipsis: ok: { + out: #Schema & { + field: shouldBeAllowed: 123 + } + #Schema: { + field?: #anything + #anything: matchN(1, [{ ... }]) + } + @test(eq, { + out: { + field: {shouldBeAllowed: 123} + #anything: matchN(1, [{ ... }]) + } + #Schema: { + field?: matchN(1, [{ ... }]) + #anything: matchN(1, [{ ... }]) + } + }) +} +// Arguments to function are not closed by enclosing definition. +openArguments: ok1: { + #Schema: {{ + a: matchN(1, ["all", {foo: "bar"}]) + }} + out: #Schema & { + a: baz: "allowed" + } + @test(eq, { + #Schema: {a: matchN(1, ["all", { + foo: "bar" + }])} + out: {a: {baz: "allowed"}} + }) +} +openArguments: err2: { + #Schema: {{ + a?: matchN(1, [ //fails + null, // fail + { [string]: string }, // pass + {b: {...}}, // pass + ]) + }} + out: #Schema & { + a: allowed: "once" + } + @test(err, code=eval, at=out.a, contains="does not satisfy matchN", pos=[2:13, 2:20, 9:6]) +} +explicitClose: err1: { + #Schema: {{ + a: matchN(1, ["all", close({foo: "bar"})]) + }} + out: #Schema & { + a: baz: "notAllowed" + } + @test(err, code=eval, at=out.a, contains="does not satisfy matchN", pos=[2:6, 2:13, 5:6]) +} +explicitClose: ok2: { + #Schema: {{ + a?: matchN(1, [ + null, // fail + close({ [string]: string }), // pass + close({b: {...}}), // fail + ]) + }} + out: #Schema & { + a: allowed: "once" + } @test(eq, {a: {allowed: "once"}}) +} +mixed: ok3: { + #Schema: { + exports?: matchN(1, [ + close({ never?: _ }), // fail + #exportsObject, // pass + ]) + + #exports: matchN(1, [string, #exportsObject]) + #exportsObject: exp1?: #exports + } + + out: #Schema & { + exports: exp1: "./main-module.js" + } + // TODO(inline): the errors here are legal structural cycles. We need to + // be able to print those. + @test(eq, { + #Schema: { + exports?: matchN(1, [close({ + never?: _ + }), _|_]) + #exports: matchN(1, [string, _|_]) + #exportsObject: { + exp1?: matchN(1, [string, _|_]) + } + } + out: { + exports: {exp1: "./main-module.js"} + #exports: matchN(1, [string, _|_]) + #exportsObject: { + exp1?: matchN(1, [string, _|_]) + } + } + }) +} + +closedByDefinition: ok4: { + #Schema: { + exports?: matchN(1, [string, #exportsObject]) + #exports: matchN(1, [string, #exportsObject]) + #exportsObject: exp1?: #exports + } + + out: #Schema & { + exports: exp1: "./main-module.js" + } + // TODO(inline): the errors here are legal structural cycles. We need to + // be able to print those. + @test(eq, { + #Schema: { + exports?: matchN(1, [string, _|_]) + #exports: matchN(1, [string, _|_]) + #exportsObject: { + exp1?: matchN(1, [string, _|_]) + } + } + out: { + exports: {exp1: "./main-module.js"} + #exports: matchN(1, [string, _|_]) + #exportsObject: { + exp1?: matchN(1, [string, _|_]) + } + } + }) +} +closedByDefinition: err5: { + #Schema: { + exports?: matchN(1, [null, #exportsObject]) + #exports: matchN(1, [null, #exportsObject]) + #exportsObject: exp1?: #exports + } + + out: #Schema & { + exports: exp1: "./main-module.js" + } + @test(err, code=eval, at=out.exports, contains="does not satisfy matchN", pos=[2:13, 2:20, 8:12]) +} + +-- issue3694.cue -- +// issue3694: Tests that matchN combined with close() correctly validates schemas +// requiring one of several required fields. https://cuelang.org/issue/3694 +issue3694: full: { + #step: matchN(1, [{ + uses!: _ + ... + }, { + run!: _ + ... + }]) + #step: close({ + uses?: string + run?: string + }) + + s: #step & { + run: "echo hello world" + } + @test(eq, { + #step: {uses?: string, run?: string} + s: {run: "echo hello world", uses?: string} + }) +} +issue3694: simple: { + #step: matchN(1, [{ + uses!: _ + }]) + #step: close({ + uses?: string + }) + @test(eq, {#step: {uses?: string}}) +} +@test(err, code=incomplete, at=issue3694.full.#step, contains="does not satisfy matchN", pos=[-29:9, -29:16, -22:9]) +@test(err, code=incomplete, at=issue3694.simple.#step, contains="does not satisfy matchN", pos=[-9:9, -9:16, -6:9]) +-- out/compile -- +--- closedness.cue +{ + ellipsis: { + ok: { + out: (〈0;#Schema〉 & { + field: { + shouldBeAllowed: 123 + } + }) + #Schema: { + field?: 〈0;#anything〉 + #anything: matchN(1, [ + { + ... + }, + ]) + } + } + } + openArguments: { + ok1: { + #Schema: { + { + a: matchN(1, [ + "all", + { + foo: "bar" + }, + ]) + } + } + out: (〈0;#Schema〉 & { + a: { + baz: "allowed" + } + }) + } + } + openArguments: { + err2: { + #Schema: { + { + a?: matchN(1, [ + null, + { + [string]: string + }, + { + b: { + ... + } + }, + ]) + } + } + out: (〈0;#Schema〉 & { + a: { + allowed: "once" + } + }) + } + } + explicitClose: { + err1: { + #Schema: { + { + a: matchN(1, [ + "all", + close({ + foo: "bar" + }), + ]) + } + } + out: (〈0;#Schema〉 & { + a: { + baz: "notAllowed" + } + }) + } + } + explicitClose: { + ok2: { + #Schema: { + { + a?: matchN(1, [ + null, + close({ + [string]: string + }), + close({ + b: { + ... + } + }), + ]) + } + } + out: (〈0;#Schema〉 & { + a: { + allowed: "once" + } + }) + } + } + mixed: { + ok3: { + #Schema: { + exports?: matchN(1, [ + close({ + never?: _ + }), + 〈1;#exportsObject〉, + ]) + #exports: matchN(1, [ + string, + 〈1;#exportsObject〉, + ]) + #exportsObject: { + exp1?: 〈1;#exports〉 + } + } + out: (〈0;#Schema〉 & { + exports: { + exp1: "./main-module.js" + } + }) + } + } + closedByDefinition: { + ok4: { + #Schema: { + exports?: matchN(1, [ + string, + 〈1;#exportsObject〉, + ]) + #exports: matchN(1, [ + string, + 〈1;#exportsObject〉, + ]) + #exportsObject: { + exp1?: 〈1;#exports〉 + } + } + out: (〈0;#Schema〉 & { + exports: { + exp1: "./main-module.js" + } + }) + } + } + closedByDefinition: { + err5: { + #Schema: { + exports?: matchN(1, [ + null, + 〈1;#exportsObject〉, + ]) + #exports: matchN(1, [ + null, + 〈1;#exportsObject〉, + ]) + #exportsObject: { + exp1?: 〈1;#exports〉 + } + } + out: (〈0;#Schema〉 & { + exports: { + exp1: "./main-module.js" + } + }) + } + } +} +--- in.cue +{ + #Foo: { + a: int + } + match: { + [=~"^single"]: matchN(1, [ + 〈2;#Foo〉, + ]) + singleOK: { + a: 2 + } + singleErr: { + a: "foo" + } + [=~"^incomplete"]: matchN(1, [ + 〈2;#Foo〉, + ]) + incompleteOK: { + a: int + } + incompleteErr: { + a: string + } + #A: { + a: int + b: _ + ... + } + defaults: { + [=~"^pickTop"]: matchN(1, [ + 2, + ]) + pickTopOK1: (*2|int) + pickTopOK2: int + pickTopErr: (*3|int) + [=~"^pickNested1"]: matchN(1, [ + { + a: 2 + }, + ]) + pickNested1OK1: { + a: (*2|int) + } + pickNested1OK2: { + a: int + } + pickNested1Err: { + a: (*3|int) + } + [=~"^pickNested2"]: matchN(1, [ + { + a: <=2 + }, + ]) + pickNested2OK1: { + a: (*2|int) + } + pickNested2OK2: { + a: int + } + pickNested2Err: { + a: (*3|int) + } + } + nestedOK: { + matchN(4, [ + 〈2;#A〉, + 〈2;#A〉, + 〈2;#A〉, + 〈2;#A〉, + ]) + a: 2 + b: { + matchN(4, [ + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + ]) + a: 3 + b: matchN(4, [ + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + ]) + b: { + a: 4 + } + c: matchN(4, [ + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + ]) + c: { + a: 5 + } + } + c: { + matchN(4, [ + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + ]) + a: 3 + b: matchN(4, [ + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + ]) + b: { + a: 4 + } + c: matchN(4, [ + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + 〈3;#A〉, + ]) + c: { + a: 5 + } + } + } + } + not: { + [=~"^single"]: matchN(0, [ + 〈2;#Foo〉, + ]) + singleOK: { + a: "foo" + } + singleErr: { + a: 2 + } + [=~"^double"]: matchN(0, [ + matchN(0, [ + 〈3;#Foo〉, + ]), + ]) + doubleOK: { + a: 2 + } + doubleErr: { + a: "foo" + } + } + oneOf: { + [=~"^multiple1"]: matchN(1, [ + 〈import;math〉.MultipleOf(3), + 〈import;math〉.MultipleOf(5), + ]) + multiple1Err1: 1 + multiple1OK1: 3 + multiple1OK2: 5 + multiple1Err2: 15 + } + anyOf: { + [=~"^multiple1"]: matchN(>0, [ + 〈import;math〉.MultipleOf(3), + 〈import;math〉.MultipleOf(5), + ]) + multiple1Err1: 1 + multiple1OK1: 3 + multiple1OK2: 5 + multiple1OK3: 15 + } + allOf: { + [=~"^multiple1"]: matchN(2, [ + 〈import;math〉.MultipleOf(3), + 〈import;math〉.MultipleOf(5), + ]) + multiple1Err1: 1 + multiple1Err2: 3 + multiple1Err3: 5 + multiple1OK1: 15 + } + bare: { + embed: { + t1: { + a: { + matchN(1, [ + >10, + ]) + } + b: { + 〈1;a〉 + } + } + } + embed: { + t2: { + b: { + 〈1;a〉 + } + a: { + matchN(1, [ + >10, + ]) + } + } + } + direct: { + t1: { + a: matchN(1, [ + >10, + ]) + b: 〈0;a〉 + } + } + direct: { + t2: { + b: 〈0;a〉 + a: matchN(1, [ + >10, + ]) + } + } + } + required: { + ok1: { + x: matchN(0, [ + { + foo!: string + }, + ]) + x: { + bar: 2 + } + } + ok2: { + x: matchN(0, [ + { + foo!: string + }, + ]) + } + ok3: { + x: matchN(0, [ + { + bar!: string + }, + ]) + x: { + bar: 2 + } + } + } + issue3575: { + test1: { + #x: matchN(1, [ + [ + {}, + ], + ]) + x: 〈0;#x〉 + x: [ + { + a: 1 + }, + ] + } + test2: { + #x: matchN(1, [ + {}, + ]) + x: 〈0;#x〉 + x: { + a: 1 + } + } + } +} +--- incomplete.cue +{ + incomplete: { + incomplete1: { + x: matchN(1, [ + { + foo!: string + }, + ]) + x: { + bar: 2 + } + } + incomplete2: { + x: matchN(1, [ + { + foo!: string + }, + ]) + } + incomplete3: { + x: matchN(〈import;math〉.MultipleOf(2), [ + { + bar!: int + }, + { + foo!: int + }, + ]) + x: { + bar: 2 + } + } + incomplete4: { + x: matchN(〈import;math〉.MultipleOf(2), [ + { + bar!: int + }, + { + foo!: int + }, + { + baz!: int + }, + ]) + x: { + bar: 2 + } + } + incomplete5: { + x: matchN((>1 & <=3), [ + { + bar!: int + }, + { + foo!: int + }, + { + baz!: int + }, + ]) + x: { + bar: 2 + } + } + incomplete6: { + x: matchN((2|3), [ + { + bar!: int + }, + { + foo!: int + }, + { + baz!: int + }, + ]) + x: { + bar: 2 + } + } + err1: { + x: matchN(1, [ + { + bar!: string + }, + ]) + x: { + bar: 2 + } + } + err2: { + x: matchN(0, [ + { + bar!: int + }, + { + foo!: int + }, + ]) + x: { + bar: 2 + } + } + err3: { + x: matchN(2, [ + { + bar!: string + }, + { + foo!: string + }, + ]) + x: { + bar: 2 + } + } + err4: { + x: matchN(>1, [ + { + bar!: string + }, + { + foo!: string + }, + ]) + x: { + bar: 2 + } + } + err5: { + x: matchN(<1, [ + { + bar!: int + }, + { + foo!: int + }, + ]) + x: { + bar: 2 + } + } + } + issue3389: { + x: { + bar: 2 + } + x: matchN(1, [ + { + bar: 3 + }, + { + bar: 2 + foo!: int + }, + ]) + } +} +--- issue3694.cue +{ + issue3694: { + full: { + #step: matchN(1, [ + { + uses!: _ + ... + }, + { + run!: _ + ... + }, + ]) + #step: close({ + uses?: string + run?: string + }) + s: (〈0;#step〉 & { + run: "echo hello world" + }) + } + } + issue3694: { + simple: { + #step: matchN(1, [ + { + uses!: _ + }, + ]) + #step: close({ + uses?: string + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/or.txtar b/internal/core/compile/testdata/sync/builtins/or.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/or.txtar @@ -0,0 +1,47 @@ +-- in.cue -- +// unwrap into single value +unwrap: or([1, 1, 1]) @test(eq, 1) + +// unique duplicate values +unique1: or([2, 1, 1, 2]) @test(eq, 2 | 1) + +unique2: or([{a: 1}, {a: 1}, {a: 2}]) @test(eq, {a: 1} | {a: 2}) + +// do not unique embedded scalars with differing values for child definitions. +embed1: or([{2, #x: 1}, {2, #x: 2}]) @test(eq, {2, #x: 1} | {2, #x: 2}) +-- out/compile -- +--- in.cue +{ + unwrap: or([ + 1, + 1, + 1, + ]) + unique1: or([ + 2, + 1, + 1, + 2, + ]) + unique2: or([ + { + a: 1 + }, + { + a: 1 + }, + { + a: 2 + }, + ]) + embed1: or([ + { + 2 + #x: 1 + }, + { + 2 + #x: 2 + }, + ]) +} diff --git a/internal/core/compile/testdata/sync/builtins/reclose.txtar b/internal/core/compile/testdata/sync/builtins/reclose.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/reclose.txtar @@ -0,0 +1,329 @@ +-- in.cue -- +@experiment(explicitopen) + +noClose: { + foo: a: int + a: __reclose({ + foo... + }) + + t1: ok: a & {b: 1} + @test(eq, { + foo: {a: int} + a: {a: int} + t1: {ok: {b: 1, a: int}} + }) +} + +recursive: { + #x: { foo: int} + // Basic usage of __reclose - makes structs recursively closed + a: __reclose({ + #x... + nested: field2: int + }) + + // Test that extra fields are not allowed (should error) + t1: err: a & {extra: "not allowed"} @test(err, code=eval, path=extra, contains="field not allowed", pos=[0:16]) + + t2: ok: a & {nested: field2: 5} @test(eq, {nested: {field2: 5}, foo: int}) + t3: ok: a & {foo: 5} @test(eq, {foo: 5, nested: {field2: int}}) + + + // Test that nested extra fields are not allowed (should error) + t4: err: a & { + nested: { + field2: 1 + extra: "not allowed" + } + } @test(err, code=eval, path=nested.extra, contains="field not allowed", pos=[3:4]) + + // Test with empty struct + // TODO(eval): is this correct? + e: __reclose({}) + t5: err: e & {extra: "not allowed"} @test(eq, {extra: "not allowed"}) +} + + +nonRecursive: { + x: __reclose({ + close({b: int})... + c: int + d: e: int + }) + y: err: x & {f: int} @test(err, code=eval, path=f, contains="field not allowed", pos=[0:15]) + z: ok: x & {d: f: int} @test(eq, {d: {f: int, e: int}, c: int, b: int}) +} + +// Test that __reclose detects and restores non-recursive closing from +// an embedded close()-d value that was opened with .... +nonRecursiveDetect: { + foo: close({b: {}}) + a: __reclose({ + foo... + }) + // Top-level field not allowed: non-recursive close restored by __reclose. + t1: err: a & {f: int} @test(err, code=eval, path=f, contains="field not allowed", pos=[0:16]) + // Nested field allowed: close was non-recursive, so b is still open. + t2: ok: a & {b: c: 1} @test(eq, {b: {c: 1}}) +} + +// Test that __reclose handles both recursive and non-recursive closing +// when both are present. +// +// NOTE: one would expect that with the old semantics, b.c is allowed in t2. +// But it is NOT. To mimic the old behavior, cue fix _could_ just use __closeAll +// in this case. Users can than chose to use __reclose instead to relax the +// condition. +mixedClose: { + #D: {x: y: int} + foo: close({b: {}}) + a: __reclose({ + #D... + foo... + }) + // Top-level extra field not allowed. + t1: err: a & {f: int} @test(err, code=eval, path=f, contains="field not allowed", pos=[0:16]) + // Allowed fields work. + t2: ok: a & {x: y: 5, b: c: 1} @test(eq, {x: {y: 5}, b: {c: 1}}) +} + +// Test that __reclose can wrap a close() call and conditionally add +// recursive closing on top. This is the pattern generated by cue fix +// when a close() at field-value level wraps a struct with embeddings. +recloseWrapsClose: { + #def: {a: b: int} + a: __reclose(close({ + #def... + })) + // Top-level extra field not allowed (close provides non-recursive). + t1: err: a & {f: int} @test(err, code=eval, path=f, contains="field not allowed", pos=[0:16]) + // Nested extra field not allowed (__reclose detects recursive from #def). + t2: err: a & {a: c: 1} @test(err, code=eval, path=a.c, contains="field not allowed", pos=[0:19]) + // Allowed nested field works. + t3: ok: a & {a: b: 5} @test(eq, {a: {b: 5}}) +} + +nonStructLiterals: { + // Test with non-struct should error + t1: err: __reclose("not a struct") @test(err, code=eval, contains="error in call to %s", args=[__reclose], pos=[0:11]) + + + #A: a: int + t4: err: __reclose(#A) @test(err, code=eval, contains="error in call to %s", args=[__reclose], pos=[0:11]) +} + +nonStructDefinitions: { + #Def: 1 + + a: __reclose({ + #Def... + }) + + t1: ok: a & 1 @test(eq, 1) + + // errors because of regular field + embedded scalar + t2: err: a & {b: 1} @test(err, code=eval, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[{b:1}, 1, struct, int], pos=[-9:8, 0:11, 0:15]) +} + +-- old.cue -- +retro: { + // May not be used if explicitopen is not set. + t1: err: __reclose({}) @test(err, code=eval, contains="error in call to %s", args=[__reclose], pos=[0:11]) +} + +-- out/compile -- +--- in.cue +{ + noClose: { + foo: { + a: int + } + a: __reclose({ + 〈1;foo〉... + }) + t1: { + ok: (〈1;a〉 & { + b: 1 + }) + } + } + recursive: { + #x: { + foo: int + } + a: __reclose({ + 〈1;#x〉... + nested: { + field2: int + } + }) + t1: { + err: (〈1;a〉 & { + extra: "not allowed" + }) + } + t2: { + ok: (〈1;a〉 & { + nested: { + field2: 5 + } + }) + } + t3: { + ok: (〈1;a〉 & { + foo: 5 + }) + } + t4: { + err: (〈1;a〉 & { + nested: { + field2: 1 + extra: "not allowed" + } + }) + } + e: __reclose({}) + t5: { + err: (〈1;e〉 & { + extra: "not allowed" + }) + } + } + nonRecursive: { + x: __reclose({ + close({ + b: int + })... + c: int + d: { + e: int + } + }) + y: { + err: (〈1;x〉 & { + f: int + }) + } + z: { + ok: (〈1;x〉 & { + d: { + f: int + } + }) + } + } + nonRecursiveDetect: { + foo: close({ + b: {} + }) + a: __reclose({ + 〈1;foo〉... + }) + t1: { + err: (〈1;a〉 & { + f: int + }) + } + t2: { + ok: (〈1;a〉 & { + b: { + c: 1 + } + }) + } + } + mixedClose: { + #D: { + x: { + y: int + } + } + foo: close({ + b: {} + }) + a: __reclose({ + 〈1;#D〉... + 〈1;foo〉... + }) + t1: { + err: (〈1;a〉 & { + f: int + }) + } + t2: { + ok: (〈1;a〉 & { + x: { + y: 5 + } + b: { + c: 1 + } + }) + } + } + recloseWrapsClose: { + #def: { + a: { + b: int + } + } + a: __reclose(close({ + 〈1;#def〉... + })) + t1: { + err: (〈1;a〉 & { + f: int + }) + } + t2: { + err: (〈1;a〉 & { + a: { + c: 1 + } + }) + } + t3: { + ok: (〈1;a〉 & { + a: { + b: 5 + } + }) + } + } + nonStructLiterals: { + t1: { + err: __reclose("not a struct") + } + #A: { + a: int + } + t4: { + err: __reclose(〈1;#A〉) + } + } + nonStructDefinitions: { + #Def: 1 + a: __reclose({ + 〈1;#Def〉... + }) + t1: { + ok: (〈1;a〉 & 1) + } + t2: { + err: (〈1;a〉 & { + b: 1 + }) + } + } +} +--- old.cue +{ + retro: { + t1: { + err: __reclose({}) + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/validators.txtar b/internal/core/compile/testdata/sync/builtins/validators.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/validators.txtar @@ -0,0 +1,600 @@ +-- in.cue -- +import ( + "encoding/json" + "list" + "struct" +) + +// non-monotonic builtins must fail with an "incomplete" error if there +// is a possibility the constraint can get resolved by becoming more specific. +incompleteError1: { + MyType: { + kv: struct.MinFields(1) + } + + foo: MyType & { + kv: joel: "testing" + } + @test(eq, { + MyType: {kv: struct.MinFields(1)} + foo: {kv: {joel: "testing"}} + }) +} + +incompleteError2: { + MyType: { + kv: [string]: string + kv: struct.MinFields(1) @test(err, code=incomplete, + contains="does not satisfy struct.MinFields(1)", pos=[0:7, -1:7, 0:24]) + } + + foo: MyType & { + kv: joel: "testing" + } @test(eq, { + kv: {joel: "testing"} + }) +} + +incompleteError3: { + t: string + t: json.Validate(string) + @test(eq, {t: string & json.Validate(string)}) +} + +uniqueConstrains1: { + t: string + t: json.Validate(string) + t: json.Validate(string) + @test(eq, {t: json.Validate(string) & string}) +} + +uniqueConstrains2: { + t: struct.MaxFields(1) + t: struct.MaxFields(1) + @test(eq, {t: struct.MaxFields(1)}) +} + +violation: { + #MyType: { + kv: [string]: string + kv: struct.MinFields(1) @test(err, code=incomplete, contains="does not satisfy struct.MinFields(1)", pos=[0:7, -1:7, 0:24]) + } + + foo: #MyType & { + kv: joel: "testing" + kv: tony: "testing" + } @test(eq, {kv: {joel: "testing", tony: "testing"}}) +} + +conjuncts: { + kv: struct.MinFields(1) + kv: struct.MaxFields(3) + @test(eq, {kv: struct.MinFields(1) & struct.MaxFields(3)}) +} + +// TODO: stripe off conflicting pairs +// conflicting: { +// kv: struct.MinFields(3) +// kv: struct.MaxFields(1) +// } + +// Builtins with bool return that can be used as validator. + +bareBuiltin: { + a: json.Valid + a: json.Valid + @test(eq, { a: json.Valid() }) +} + +bareBuiltinCheck: { + a: json.Valid + a: "3" + @test(eq, {a: "3"}) +} + +builtinValidator: { + a: json.Valid() + a: json.Valid() + @test(eq, {a: json.Valid()}) +} + +builtinValidatorCheck: { + a: json.Valid() + a: "3" + @test(eq, {a: "3"}) +} + +callOfCallToValidator: { + a: json.Valid + b: a() @test(eq, { json.Valid() }) + e: b() @test(err, code=eval, contains="cannot call previously called validator", pos=[0:5]) + e: "5" +} + +validatorAsFunction: { + a: json.Valid + b: a("3") + c: json.Valid("3") + @test(eq, {a: json.Valid(), b: true, c: true}) +} + +// issue2098: Tests that list.MinItems() does not panic when combined with list +// embedding and index access. https://cuelang.org/issue/2098 +issue2098: ok1: { + _a: [1, ...] + _a: list.MinItems(1) + _a[0] + @test(eq, {_a: [1], 1}) +} + +issue2098: incomplete1: { + _a: [...] + _a: list.MinItems(1) + _a[0] + @test(err, code=incomplete, contains="index out of range", pos=[3:5]) +} + +-- issue3418.cue -- +// issue3418: Tests that matchN correctly reports validation failures when +// combined with conflicting constraints, regardless of operand order. +// https://cuelang.org/issue/3418 +issue3418: t1: "foo" & matchN(1, [1&2]) & matchN(1, [_]) @test(err, code=eval, + contains="does not satisfy matchN", pos=[0:24, 0:16, 0:31, 0:35, 0:37]) + +issue3418: t2: "foo" & matchN(1, [_]) & matchN(1, [1&2]) @test(err, code=eval, + contains="does not satisfy matchN", pos=[0:41, 0:16, 0:48, 0:52, 0:54]) + +issue3418: t3: { + x: "foo" + x: matchN(1, [_]) + x: matchN(1, [1&2]) + + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[3:5, 1:5, 2:5, 3:12, 3:16, 3:18]) + +} +issue3418: t4: { + x: "foo" + x: matchN(1, [1&2]) + x: matchN(1, [_]) + + @test(err, code=eval, at=x, contains="does not satisfy matchN", pos=[2:5, 1:5, 2:12, 2:16, 2:18, 3:5]) +} + + +-- issue3474.cue -- +import "struct" + +// issue3474: Tests that struct.MinFields/MaxFields validators correctly handle +// fields added by conditional comprehensions. https://cuelang.org/issue/3474 +issue3474: structValidator: ok: { + // Passes only after the comprehension is evaluated. + A: struct.MinFields(1) + A: { + if true {B: true} + } + @test(eq, {A: {B: true}}) +} +issue3474: structValidator: failAfter: { + // Passes only before the comprehension is evaluated. + A: struct.MaxFields(1) + A: { + C: true + if true {B: true} + } @test(err, code=eval, contains="does not satisfy struct.MaxFields(1)", pos=[-1:5, -1:22, 0:5]) +} +issue3474: structValidator: incomplete: { + // Passes neither before nor after the comprehension is evaluated. + A: struct.MinFields(1) + A: { + if true {} + } @test(err, code=incomplete, contains="len(fields) < MinFields(1) (0 < 1)", pos=[-1:5, -1:22, 0:5]) +} +issue3474: structValidator: failClosed: { + // Passes neither before nor after the comprehension is evaluated. + #A: struct.MinFields(1) + #A: { + if true {} + } @test(err, code=eval, contains="does not satisfy struct.MinFields", pos=[-1:6, -1:23, 0:6]) +} + + +issue3474: topValidator: ok: { + A: matchN(1, [>10]) + A: { + if true {100} + } + @test(eq, {A: 100}) +} +issue3474: topValidator: fail: { + A: matchN(1, [>10]) + A: { + if true {1} + } @test(err, code=eval, contains="does not satisfy matchN", pos=[-1:5, -1:12, 0:5, 1:12]) + +} +issue3474: topValidator: incomplete: { + A: matchN(1, [>10]) + A: { + if true {int} + } + @test(eq, {A: matchN(1, [>10]) & int}) +} +issue3474: topValidator: failType: { + A: matchN(1, [>10]) + A: { + if true {C: 1} + } @test(err, code=eval, contains="does not satisfy matchN", pos=[-1:5, -1:12, 0:5]) +} + +-- validator_is_top.cue -- +// issue3639: Tests that embedding a matchN validator struct alongside direct +// application does not cause "field not allowed" errors. https://cuelang.org/issue/3639 +issue3639: { + a: {#X} & #X + a: b: 1 + #X: matchN(1, [{b: int}]) + @test(eq, { + a: {b: 1} + #X: matchN(1, [{ b: int }]) + }) +} +// issue3661: Tests that matchN with a required field validator works when +// applied via a pattern constraint. https://cuelang.org/issue/3661 +issue3661: { + #X: matchN(1, [{ b!: int }]) + a: b: 1 + a: #X + ["a"]: #X + @test(eq, { + #X: matchN(1, [{ b!: int }]) + a: {b: 1} + }) +} +// issue3678: Tests that matchN with multiple required-field alternatives does not +// produce spurious "field not allowed" errors. https://cuelang.org/issue/3678 +issue3678: { + #X: matchN(1, [{ + a!: string + }, { + c!: string + }]) + + x: c: "c" + + y: #X + y: x + x: #X + @test(eq, { + #X: matchN(1, [{ a!: string }, { c!: string }]) + x: {c: "c"} + y: {c: "c"} + }) +} +// issue3981: Tests that matchN combined with close() correctly handles open +// struct arguments without topological sort regressions. https://cuelang.org/issue/3981 +issue3981: matchWithClose: { + out: { + close({ + f1: matchN(1, [#openStruct]) + }) + #openStruct: {...} + } + out: f1: foo: ["bar"] + @test(eq, { + out: {#openStruct: {}, f1: {foo: ["bar"]}} + }) +} +-- out/compile -- +--- in.cue +{ + incompleteError1: { + MyType: { + kv: 〈import;struct〉.MinFields(1) + } + foo: (〈0;MyType〉 & { + kv: { + joel: "testing" + } + }) + } + incompleteError2: { + MyType: { + kv: { + [string]: string + } + kv: 〈import;struct〉.MinFields(1) + } + foo: (〈0;MyType〉 & { + kv: { + joel: "testing" + } + }) + } + incompleteError3: { + t: string + t: 〈import;"encoding/json"〉.Validate(string) + } + uniqueConstrains1: { + t: string + t: 〈import;"encoding/json"〉.Validate(string) + t: 〈import;"encoding/json"〉.Validate(string) + } + uniqueConstrains2: { + t: 〈import;struct〉.MaxFields(1) + t: 〈import;struct〉.MaxFields(1) + } + violation: { + #MyType: { + kv: { + [string]: string + } + kv: 〈import;struct〉.MinFields(1) + } + foo: (〈0;#MyType〉 & { + kv: { + joel: "testing" + } + kv: { + tony: "testing" + } + }) + } + conjuncts: { + kv: 〈import;struct〉.MinFields(1) + kv: 〈import;struct〉.MaxFields(3) + } + bareBuiltin: { + a: 〈import;"encoding/json"〉.Valid + a: 〈import;"encoding/json"〉.Valid + } + bareBuiltinCheck: { + a: 〈import;"encoding/json"〉.Valid + a: "3" + } + builtinValidator: { + a: 〈import;"encoding/json"〉.Valid() + a: 〈import;"encoding/json"〉.Valid() + } + builtinValidatorCheck: { + a: 〈import;"encoding/json"〉.Valid() + a: "3" + } + callOfCallToValidator: { + a: 〈import;"encoding/json"〉.Valid + b: 〈0;a〉() + e: 〈0;b〉() + e: "5" + } + validatorAsFunction: { + a: 〈import;"encoding/json"〉.Valid + b: 〈0;a〉("3") + c: 〈import;"encoding/json"〉.Valid("3") + } + issue2098: { + ok1: { + _a: [ + 1, + ..., + ] + _a: 〈import;list〉.MinItems(1) + 〈0;_a〉[0] + } + } + issue2098: { + incomplete1: { + _a: [ + ..., + ] + _a: 〈import;list〉.MinItems(1) + 〈0;_a〉[0] + } + } +} +--- issue3418.cue +{ + issue3418: { + t1: (("foo" & matchN(1, [ + (1 & 2), + ])) & matchN(1, [ + _, + ])) + } + issue3418: { + t2: (("foo" & matchN(1, [ + _, + ])) & matchN(1, [ + (1 & 2), + ])) + } + issue3418: { + t3: { + x: "foo" + x: matchN(1, [ + _, + ]) + x: matchN(1, [ + (1 & 2), + ]) + } + } + issue3418: { + t4: { + x: "foo" + x: matchN(1, [ + (1 & 2), + ]) + x: matchN(1, [ + _, + ]) + } + } +} +--- issue3474.cue +{ + issue3474: { + structValidator: { + ok: { + A: 〈import;struct〉.MinFields(1) + A: { + if true { + B: true + } + } + } + } + } + issue3474: { + structValidator: { + failAfter: { + A: 〈import;struct〉.MaxFields(1) + A: { + C: true + if true { + B: true + } + } + } + } + } + issue3474: { + structValidator: { + incomplete: { + A: 〈import;struct〉.MinFields(1) + A: { + if true {} + } + } + } + } + issue3474: { + structValidator: { + failClosed: { + #A: 〈import;struct〉.MinFields(1) + #A: { + if true {} + } + } + } + } + issue3474: { + topValidator: { + ok: { + A: matchN(1, [ + >10, + ]) + A: { + if true { + 100 + } + } + } + } + } + issue3474: { + topValidator: { + fail: { + A: matchN(1, [ + >10, + ]) + A: { + if true { + 1 + } + } + } + } + } + issue3474: { + topValidator: { + incomplete: { + A: matchN(1, [ + >10, + ]) + A: { + if true { + int + } + } + } + } + } + issue3474: { + topValidator: { + failType: { + A: matchN(1, [ + >10, + ]) + A: { + if true { + C: 1 + } + } + } + } + } +} +--- validator_is_top.cue +{ + issue3639: { + a: ({ + 〈1;#X〉 + } & 〈0;#X〉) + a: { + b: 1 + } + #X: matchN(1, [ + { + b: int + }, + ]) + } + issue3661: { + #X: matchN(1, [ + { + b!: int + }, + ]) + a: { + b: 1 + } + a: 〈0;#X〉 + ["a"]: 〈0;#X〉 + } + issue3678: { + #X: matchN(1, [ + { + a!: string + }, + { + c!: string + }, + ]) + x: { + c: "c" + } + y: 〈0;#X〉 + y: 〈0;x〉 + x: 〈0;#X〉 + } + issue3981: { + matchWithClose: { + out: { + close({ + f1: matchN(1, [ + 〈2;#openStruct〉, + ]) + }) + #openStruct: { + ... + } + } + out: { + f1: { + foo: [ + "bar", + ] + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/builtins/versionchk.txtar b/internal/core/compile/testdata/sync/builtins/versionchk.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/versionchk.txtar @@ -0,0 +1,15 @@ +#inlinetest:exclude the CUE source triggers a compile-time version error which +# prevents the inline runner from compiling the source. +-- cue.mod/module.cue -- +module: "cuelang.org/go/internal/core/adt/eval_test" +language: version: "v0.8.0" +-- in.cue -- +// error is not yet available in v0.8.0. +a: error("msg") +-- out/compile -- +a: builtin "error" is not available in version v0.8.0; it was added in version "v0.14.0": + ./in.cue:2:4 +--- in.cue +{ + a: _|_(builtin "error" is not available in version v0.8.0; it was added in version "v0.14.0")("msg") +} diff --git a/internal/core/compile/testdata/sync/choosedefault/000_pick_first.txtar b/internal/core/compile/testdata/sync/choosedefault/000_pick_first.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/choosedefault/000_pick_first.txtar @@ -0,0 +1,19 @@ +-- in.cue -- +a: *5 | "a" | true @test(eq, *5 | "a" | true) +b: c: *{ + a: 2 +} | { + a: 3 +} @test(eq, *{a: 2} | {a: 3}) +-- out/compile -- +--- in.cue +{ + a: (*5|"a"|true) + b: { + c: (*{ + a: 2 + }|{ + a: 3 + }) + } +} diff --git a/internal/core/compile/testdata/sync/choosedefault/001_simple_disambiguation_conflict.txtar b/internal/core/compile/testdata/sync/choosedefault/001_simple_disambiguation_conflict.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/choosedefault/001_simple_disambiguation_conflict.txtar @@ -0,0 +1,11 @@ +-- in.cue -- +a: *"a" | "b" @test(eq, *"a" | "b") +b: *"b" | "a" @test(eq, *"b" | "a") +c: a & b @test(eq, "a" | "b") +-- out/compile -- +--- in.cue +{ + a: (*"a"|"b") + b: (*"b"|"a") + c: (〈0;a〉 & 〈0;b〉) +} diff --git a/internal/core/compile/testdata/sync/choosedefault/002_associativity_of_defaults.txtar b/internal/core/compile/testdata/sync/choosedefault/002_associativity_of_defaults.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/choosedefault/002_associativity_of_defaults.txtar @@ -0,0 +1,143 @@ +#name: associativity of defaults +#evalFull +-- in.cue -- +a: *"a" | ("b" | "c") @test(eq, *"a" | "b" | "c") +b: (*"a" | "b") | "c" @test(eq, *"a" | "b" | "c") +c: *"a" | (*"b" | "c") @test(eq, *"a" | "b" | "c") +x: a & b @test(eq, *"a" | "b" | "c") +y: b & c @test(eq, *"a" | "b" | "c") + +s1: *1 | ((*2 | 3) & (2 | *3)) @test(eq, *1 | 2 | 3) +s2: *1 | ((*2 | 3) & (*2 | 3)) @test(eq, *1 | 2 | 3) +s3: *1 | ((*2 | 3) & 3) @test(eq, *1 | 3) +s4: *1 | ((*2 | 3) & 2) @test(eq, *1 | 2) +s5: *1 | *(*2 | 3) @test(eq, *1 | *2 | 3) + +e1: *(1&2) | (*"x" | string) @test(eq, "x" | string) +e2: (*"x" | string) | *(1&2) @test(eq, "x" | string) + +-- complex.cue -- +// add some test cases suggested by an automated prover based on this pattern: +// 1. ValK = (ValA & ValB_ND) & ValC_D \neq _|_ (the element we track must exist). +// 2. ValC_D & (ValA & ValB_D) = _|_ (for Path 1 Cond(ValC_D, Disj_AB) to be true). +// 3. ValC_D & ValB_D \neq _|_ (for Path 2 Cond(ValC_D, Disj_B) to be false). + +// Let's define these CUE values. The trick is that ValA must introduce a +// component that causes ValC_D to conflict with (ValA & ValB_D), +// but ValC_D must *not* conflict with ValB_D on its own. +t1: { + va: {a: 1, b: 2} + vb1: {c: 3} + vb2: {c: 4} + vc : {c: 4} + vd: string + + A: va | vd @test(eq, {a: 1, b: 2} | string) + B: *vb1 | vb2 | vd @test(eq, *{c: 3} | {c: 4} | string) + C: *vc | vd @test(eq, *{c: 4} | string) + + p1: (A & B) & C @test(eq, *{a: 1, b: 2, c: 4} | string) + p2: A & (B & C) @test(eq, *{a: 1, b: 2, c: 4} | string) +} +t2: { + va: 0 | 1 | 2 + vb1: 2 | 3 + vb2: 0 | 1 | 4 + vc: 0 | 3 | 4 + vd: string + + A: va | vd @test(eq, 0 | 1 | 2 | string) + B: *vb1 | vb2 | vd @test(eq, *2 | *3 |0 | 1 | 4 | string) + C: *vc | vd @test(eq, *0 | *3 | *4 | string) + + p1: (A & B) & C @test(eq, *0 | string) + p2: A & (B & C) @test(eq, *0 | string) +} +-- issue3908.cue -- +// issue3908: Tests that nested defaults (e.g. null default overridden by a +// string default) are handled correctly in evalv3. https://cuelang.org/issue/3908 +issue3908: reduced: { + @test(permute) + string | *null + string | *"str" + @test(eq, *"str" | string) +} +issue3908: full: { + out: #Schema & { field: string | *"dataDefault" } + #Schema: field: string | *null + @test(eq, { + out: field: *"dataDefault" | string + #Schema: field: *null | string + }) +} +-- out/compile -- +--- complex.cue +{ + t1: { + va: { + a: 1 + b: 2 + } + vb1: { + c: 3 + } + vb2: { + c: 4 + } + vc: { + c: 4 + } + vd: string + A: (〈0;va〉|〈0;vd〉) + B: (*〈0;vb1〉|〈0;vb2〉|〈0;vd〉) + C: (*〈0;vc〉|〈0;vd〉) + p1: ((〈0;A〉 & 〈0;B〉) & 〈0;C〉) + p2: (〈0;A〉 & (〈0;B〉 & 〈0;C〉)) + } + t2: { + va: (0|1|2) + vb1: (2|3) + vb2: (0|1|4) + vc: (0|3|4) + vd: string + A: (〈0;va〉|〈0;vd〉) + B: (*〈0;vb1〉|〈0;vb2〉|〈0;vd〉) + C: (*〈0;vc〉|〈0;vd〉) + p1: ((〈0;A〉 & 〈0;B〉) & 〈0;C〉) + p2: (〈0;A〉 & (〈0;B〉 & 〈0;C〉)) + } +} +--- in.cue +{ + a: (*"a"|("b"|"c")) + b: ((*"a"|"b")|"c") + c: (*"a"|(*"b"|"c")) + x: (〈0;a〉 & 〈0;b〉) + y: (〈0;b〉 & 〈0;c〉) + s1: (*1|((*2|3) & (2|*3))) + s2: (*1|((*2|3) & (*2|3))) + s3: (*1|((*2|3) & 3)) + s4: (*1|((*2|3) & 2)) + s5: (*1|*(*2|3)) + e1: (*(1 & 2)|(*"x"|string)) + e2: ((*"x"|string)|*(1 & 2)) +} +--- issue3908.cue +{ + issue3908: { + reduced: { + (string|*null) + (string|*"str") + } + } + issue3908: { + full: { + out: (〈0;#Schema〉 & { + field: (string|*"dataDefault") + }) + #Schema: { + field: (string|*null) + } + } + } +} diff --git a/internal/core/compile/testdata/sync/compile/alias.txtar b/internal/core/compile/testdata/sync/compile/alias.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/alias.txtar @@ -0,0 +1,18 @@ +-- in.cue -- +dynamic: { + @test(permute, count=6) + + X=(a): 1 + x: X + a: "name" + @test(eq, {x: 1, a: "name", name: 1}) +} +-- out/compile -- +--- in.cue +{ + dynamic: { + 〈0;a〉: 1 + x: 〈0;(〈0;a〉)〉 + a: "name" + } +} diff --git a/internal/core/compile/testdata/sync/compile/err_top.txtar b/internal/core/compile/testdata/sync/compile/err_top.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/err_top.txtar @@ -0,0 +1,69 @@ +#inlinetest:exclude skip — compile errors. +-- in.cue -- +disallowTopAsAlias: { + _=X: 1 +} + +disallowTopAsLet: { + let _ = 1 +} + +disallowTopAsLabel: { + _: 1 + a: _ // Should not compile to a reference. +} + +// TODO: disallow dollar as label? This is according to the spec, but it +// will be a breaking change and $ was reserved for referring to the root of +// a file, which we very likely will never implement. +// disallowDollarAsLabel: { +// $: 1 +// } + +// When printing errors with paths from the compiler or evaluator, +// ensure that odd string labels get quoted correctly. +nested: "_": _: 1 +nested: "_foo": _: 1 +nested: "#foo": _: 1 + +-- out/compile -- +disallowTopAsAlias: cannot use _ as alias or let clause: + ./in.cue:2:2 +disallowTopAsLet: cannot use _ as alias or let clause: + ./in.cue:6:6 +disallowTopAsLabel: cannot use _ as label: + ./in.cue:10:2 +nested."_": cannot use _ as label: + ./in.cue:23:14 +nested."_foo": cannot use _ as label: + ./in.cue:24:17 +nested."#foo": cannot use _ as label: + ./in.cue:25:17 +--- in.cue +{ + disallowTopAsAlias: { + X: 1 + } + disallowTopAsLet: { + let _ = 1 + } + disallowTopAsLabel: { + _|_(cannot use _ as label) + a: _ + } + nested: { + "_": { + _|_(cannot use _ as label) + } + } + nested: { + "_foo": { + _|_(cannot use _ as label) + } + } + nested: { + "#foo": { + _|_(cannot use _ as label) + } + } +} diff --git a/internal/core/compile/testdata/sync/compile/erralias.txtar b/internal/core/compile/testdata/sync/compile/erralias.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/erralias.txtar @@ -0,0 +1,30 @@ +// Caused a stack overflow on evalv2. +#inlinetest:exclude skip: compile errors. +-- in.cue -- + let X = {} + +[Y="foo"]: 3 +a: Y + +c: {} +for x in c {a: E} + +Z1=[Z2=string]: Z1 + Z2 +-- out/compile -- +unreferenced alias or let clause X: + ./in.cue:1:2 +a: reference "Y" not found: + ./in.cue:4:12 +for[].a: reference "E" not found: + ./in.cue:7:16 +--- in.cue +{ + let X#1 = {} + ["foo"]: 3 + a: _|_(reference "Y" not found) + c: {} + for _, x in 〈0;c〉 { + a: _|_(reference "E" not found) + } + [string]: (〈0;(〈0;-〉)〉 + 〈0;-〉) +} diff --git a/internal/core/compile/testdata/sync/compile/experiment.txtar b/internal/core/compile/testdata/sync/compile/experiment.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/experiment.txtar @@ -0,0 +1,20 @@ +-- cue.mod/module.cue -- +module: "x.test" +language: version: "v0.13.0" +-- off.cue -- +off: __test_experiment("off") @test(err, code=eval, contains="testing experiment disabled", pos=[0:6]) + +-- on.cue -- +@experiment(testing) + +on: __test_experiment("on") @test(eq, "on") + +-- out/compile -- +--- off.cue +{ + off: testExperiment("off") +} +--- on.cue +{ + on: testExperiment("on") +} diff --git a/internal/core/compile/testdata/sync/compile/fields.txtar b/internal/core/compile/testdata/sync/compile/fields.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/fields.txtar @@ -0,0 +1,13 @@ +-- in.cue -- +#dev: int @test(eq, int) +"#dev": int @test(eq, int) +_dev: int @test(eq, int) +_#dev: int @test(eq, int) +-- out/compile -- +--- in.cue +{ + #dev: int + "#dev": int + _dev: int + _#dev: int +} diff --git a/internal/core/compile/testdata/sync/compile/files.txtar b/internal/core/compile/testdata/sync/compile/files.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/files.txtar @@ -0,0 +1,30 @@ +# Issue #946: Tests that a for comprehension variable that shadows the source +# name (for a in a) compiles correctly and resolves scoping at the right depth. +# https://cuelang.org/issue/946 +-- in.cue -- +package repro + +a: [] @test(eq, []) +-- out.cue -- +package repro + +x: {for a in a {}} @test(eq, {}) +y: {{{for a in a {}}}} @test(eq, {}) +-- out/compile -- +--- in.cue +{ + a: [] +} +--- out.cue +{ + x: { + for _, a in 〈1;a〉 {} + } + y: { + { + { + for _, a in 〈3;a〉 {} + } + } + } +} diff --git a/internal/core/compile/testdata/sync/compile/json.txtar b/internal/core/compile/testdata/sync/compile/json.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/json.txtar @@ -0,0 +1,44 @@ +# Issue #721: Tests that front-style (leading) commas are allowed in CUE source. +# https://cuelang.org/issue/721 +#noformat +-- in.cue -- +// allow front-style commas +a +: { "key": "value" +, "key2" +: "value2" +} + +, b: [ + 0 +, 1 +, 2 + ,3, + 4 + + , 5 +] + +@test(eq, { + a: { + key: "value" + key2: "value2" + } + b: [0, 1, 2, 3, 4, 5] +}) +-- out/compile -- +--- in.cue +{ + a: { + key: "value" + key2: "value2" + } + b: [ + 0, + 1, + 2, + 3, + 4, + 5, + ] +} diff --git a/internal/core/compile/testdata/sync/compile/labels.txtar b/internal/core/compile/testdata/sync/compile/labels.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/labels.txtar @@ -0,0 +1,92 @@ +#inlinetest:exclude skip: compile errors. +-- in.cue -- +package compile + +import "list" + +dis1: "dev" | "prd" +dis2: *"dev" | "prd" + +con1: string +let con2 = string + +ok0: [string]: string +ok1: [name=string]: string +ok2: [con1]: string +ok3: [con2]: string +ok4: ["foo"]: string +ok5: [1]: string // disallowed in evaluator +ok6: [name=1]: string // disallowed in evaluator +ok7: [dis1]: string +ok8: [dis2]: string +ok9: [name=dis2]: string +ok10: [{foo: "bar"}]: string // disallowed in evaluator +ok11: [list.FlattenN([string], 1)]: string // disallowed in evaluator + +bad1: [for x in [1, 2, 3] {x}]: string + +saneReferencesInComprehensions: { + for _ in [1] { + a: _ // Should not compile to a reference. + } +} +-- out/compile -- +bad1: comprehension values not allowed in this position: + ./in.cue:24:8 +--- in.cue +{ + dis1: ("dev"|"prd") + dis2: (*"dev"|"prd") + con1: string + let con2#1 = string + ok0: { + [string]: string + } + ok1: { + [string]: string + } + ok2: { + [〈1;con1〉]: string + } + ok3: { + [〈1;let con2#1〉]: string + } + ok4: { + ["foo"]: string + } + ok5: { + [1]: string + } + ok6: { + [1]: string + } + ok7: { + [〈1;dis1〉]: string + } + ok8: { + [〈1;dis2〉]: string + } + ok9: { + [〈1;dis2〉]: string + } + ok10: { + [{ + foo: "bar" + }]: string + } + ok11: { + [〈import;list〉.FlattenN([ + string, + ], 1)]: string + } + bad1: { + [_|_(comprehension values not allowed in this position)]: string + } + saneReferencesInComprehensions: { + for _, _ in [ + 1, + ] { + a: _ + } + } +} diff --git a/internal/core/compile/testdata/sync/compile/let.txtar b/internal/core/compile/testdata/sync/compile/let.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/let.txtar @@ -0,0 +1,200 @@ +#expandLetExpr: true +#inlinetest:exclude skip: compile errors. +-- in.cue -- +a: { + let X = Y + let Y = c + + b: X + c: 5 +} + +b: { + let X = Y + let Y = X + + b: X + c: 5 +} + +fieldOffset: { + a: { + p1: { + let X = {value: Y} + let Y = 2 + x: X + } + p2: { + x: X + let Y = 2 + let X = {value: Y} + } + } + b: { + p1: { + let X = {x: y: Y} + let Y = 2 + x: X + } + p2: { + x: X + let Y = 2 + let X = {x: y: Y} + } + } +} + +issue767: { + #Foo: { + let _#bar = { + value: "" + } + let _#volmnts = { + x: _#baz.value + } + let _#baz = { + _#bar + } + out: _#volmnts + } +} +-- alignstack.cue -- +issue4051: full: { + #app: name: "foo" + + let N = #app.name + + out: (N): [{f1: f2: N}] +} +issue4051: reduced: { + (N): [{ f1: f2: N }] + let N = x + x: "s" +} +-- out/compile -- +b.let[]: cyclic references in let clause or alias: + ./in.cue:10:10 +--- alignstack.cue +{ + issue4051: { + full: { + #app: { + name: "foo" + } + let N#1 = 〈0;#app〉.name + out: { + 〈1;let N#1〉=>〈0;#app〉.name: [ + { + f1: { + f2: 〈4;let N#1〉=>〈0;#app〉.name + } + }, + ] + } + } + } + issue4051: { + reduced: { + 〈0;let N#2〉=>〈0;x〉: [ + { + f1: { + f2: 〈3;let N#2〉=>〈0;x〉 + } + }, + ] + let N#2 = 〈0;x〉 + x: "s" + } + } +} +--- in.cue +{ + a: { + let X#3 = 〈0;let Y#4〉=>〈0;c〉 + let Y#4 = 〈0;c〉 + b: 〈0;let X#3〉=>〈0;let Y#4〉=>〈0;c〉 + c: 5 + } + b: { + let X#5 = 〈0;let Y#6〉=>〈0;let X#5〉=>〈0;let Y#6〉=>_|_(cyclic references in let clause or alias) + let Y#6 = 〈0;let X#5〉=>〈0;let Y#6〉=>_|_(cyclic references in let clause or alias) + b: 〈0;let X#5〉=>〈0;let Y#6〉=>_|_(cyclic references in let clause or alias) + c: 5 + } + fieldOffset: { + a: { + p1: { + let X#7 = { + value: 〈1;let Y#8〉=>2 + } + let Y#8 = 2 + x: 〈0;let X#7〉=>{ + value: 〈1;let Y#8〉=>2 + } + } + p2: { + x: 〈0;let X#A〉=>{ + value: 〈1;let Y#9〉=>2 + } + let Y#9 = 2 + let X#A = { + value: 〈1;let Y#9〉=>2 + } + } + } + b: { + p1: { + let X#B = { + x: { + y: 〈2;let Y#C〉=>2 + } + } + let Y#C = 2 + x: 〈0;let X#B〉=>{ + x: { + y: 〈2;let Y#C〉=>2 + } + } + } + p2: { + x: 〈0;let X#E〉=>{ + x: { + y: 〈2;let Y#D〉=>2 + } + } + let Y#D = 2 + let X#E = { + x: { + y: 〈2;let Y#D〉=>2 + } + } + } + } + } + issue767: { + #Foo: { + let _#bar#F = { + value: "" + } + let _#volmnts#10 = { + x: 〈1;let _#baz#11〉=>{ + 〈1;let _#bar#F〉=>{ + value: "" + } + }.value + } + let _#baz#11 = { + 〈1;let _#bar#F〉=>{ + value: "" + } + } + out: 〈0;let _#volmnts#10〉=>{ + x: 〈1;let _#baz#11〉=>{ + 〈1;let _#bar#F〉=>{ + value: "" + } + }.value + } + } + } +} diff --git a/internal/core/compile/testdata/sync/compile/postfixexpr.txtar b/internal/core/compile/testdata/sync/compile/postfixexpr.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/postfixexpr.txtar @@ -0,0 +1,50 @@ +-- cue.mod/module.cue -- +module: "test.example" +language: version: "v0.15.0" + +-- with_experiment.cue -- +@experiment(explicitopen) + +#Base: { + x: int +} @test(shareID=Base) + +// Test postfix ... operator with struct +a: #Base... @test(shareID=Base) + +// Test with selector +b: foo.bar... @test(err, code=incomplete, contains="undefined field: bar", pos=[0:8]) + +// Test with parentheses +c: (x & y)... @test(eq, _) + +// Test with function call +d: fn()... @test(err, code=incomplete, contains="cannot call non-concrete value fn", pos=[0:4]) + +// As an expression +e: #Base... & {y: int} @test(eq, {y: int, x: int}) + +foo: {} @test(eq, {}) + +x: _ @test(eq, _) +y: _ @test(eq, _) +fn: _ @test(eq, _) + +-- out/compile -- +--- with_experiment.cue +{ + #Base: { + x: int + } + a: 〈0;#Base〉... + b: 〈0;foo〉.bar... + c: (〈0;x〉 & 〈0;y〉)... + d: 〈0;fn〉()... + e: (〈0;#Base〉... & { + y: int + }) + foo: {} + x: _ + y: _ + fn: _ +} diff --git a/internal/core/compile/testdata/sync/compile/scope.txtar b/internal/core/compile/testdata/sync/compile/scope.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/compile/scope.txtar @@ -0,0 +1,91 @@ +-- in.cue -- +a: { + {{ + b + c + d: b + e: c + }} + c: {} +} @test(eq, {d: {}, e: {}, c: {}}) +b: {} @test(eq, {}) +s: "foo" @test(eq, "foo") +c: s @test(eq, "foo") + +// s is technically in a new struct here so it will have a one higher count than +// the one before. +d: [s]: 3 @test(eq, {["foo"]: 3}) + +e: {} @test(eq, {}, hint="not the worst if this is not allowed") + +e & { + e: {} +} + +p: { + {X=["foo"]: b: X | null} + {[Y="bar"]: b: Y} + + @test(eq, { + ["foo"]: b: null @test(final) + ["bar"]: b: string + }, incorrect) + @test(eq:todo, { + ["foo"]: b: null @test(final) + ["bar"]: b: "bar" + }) +} + +let B = {open: int} +f: B @test(eq, {open: int}) + +schema: { + next: _schema_1 @test(err, code=structural_cycle) +} + +let _schema_1 = schema +-- out/compile -- +--- in.cue +{ + a: { + { + { + 〈3;b〉 + 〈2;c〉 + d: 〈3;b〉 + e: 〈2;c〉 + } + } + c: {} + } + b: {} + s: "foo" + c: 〈0;s〉 + d: { + [〈1;s〉]: 3 + } + e: {} + (〈0;e〉 & { + e: {} + }) + p: { + { + ["foo"]: { + b: (〈1;(〈0;-〉)〉|null) + } + } + { + ["bar"]: { + b: 〈1;-〉 + } + } + } + let B#1 = { + open: int + } + f: 〈0;let B#1〉 + schema: { + next: 〈1;let _schema_1#2〉 + } + let _schema_1#2 = 〈0;schema〉 +} diff --git a/internal/core/compile/testdata/sync/comprehensions/015_list_comprehension.txtar b/internal/core/compile/testdata/sync/comprehensions/015_list_comprehension.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/015_list_comprehension.txtar @@ -0,0 +1,41 @@ +-- in.cue -- +b: { + a: 1 + b: 2 + c: 3 + d: 4 +} + +a: [for k, v in b if k < "d" if v > b.a {k}] @test(eq, ["b", "c"]) +c: { + [for _, x in b for _, y in b if x < y {x}] + @test(eq, [1, 1, 1, 2, 2, 3]) +} +d: [for x, _ in a {x}] @test(eq, [0, 1]) +-- out/compile -- +--- in.cue +{ + b: { + a: 1 + b: 2 + c: 3 + d: 4 + } + a: [ + for k, v in 〈1;b〉 if (〈0;k〉 < "d") if (〈0;v〉 > 〈2;b〉.a) { + 〈1;k〉 + }, + ] + c: { + [ + for _, x in 〈2;b〉 for _, y in 〈3;b〉 if (〈1;x〉 < 〈0;y〉) { + 〈2;x〉 + }, + ] + } + d: [ + for x, _ in 〈1;a〉 { + 〈1;x〉 + }, + ] +} diff --git a/internal/core/compile/testdata/sync/comprehensions/045_comprehension_and_skipped_field.txtar b/internal/core/compile/testdata/sync/comprehensions/045_comprehension_and_skipped_field.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/045_comprehension_and_skipped_field.txtar @@ -0,0 +1,33 @@ +#name: comprehension and skipped field +#bug: true +#evalFull +# Tests that a comprehension iterating over a struct whose values contain +# a hidden field (_p) correctly skips that hidden field and still evaluates +# the visible result field using a disjunction with a comprehension body. +-- in.cue -- + +for key, value in {x: v: 1} { + "\(key)": { + v: *{for pod, _ in value.v {}} | {"\(value.v)": 2} + _p: 3 + } +} +@test(eq, {x: {v: {"1": 2}, _p: 3}}) +-- out/compile -- +--- in.cue +{ + for key, value in { + x: { + v: 1 + } + } { + "\(〈1;key〉)": { + v: (*{ + for pod, _ in 〈3;value〉.v {} + }|{ + "\(〈3;value〉.v)": 2 + }) + _p: 3 + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/checkdefined.txtar b/internal/core/compile/testdata/sync/comprehensions/checkdefined.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/checkdefined.txtar @@ -0,0 +1,316 @@ + +Issue #1969 +# Tests that undefined field comparisons with _|_ work correctly in +# comprehension conditions, including with close(), for loops, and let bindings. +# Issue #1969 and #2245. +-- in.cue -- +import "list" + +// All tests here should pass and the result of the okcN tests should be +// identical to those of the okoN tests. + +xc: close({field: {}}) +xo: field: {} + +okc0: { + if xc.undefined == _|_ {a: 1} + @test(eq, {a: 1}) +} +oko0: { + if xo.undefined == _|_ {a: 1} + @test(eq, {a: 1}) +} + +okc1: { + if xc.undefined != _|_ {a: 1} + @test(eq, {}) +} +oko1: { + if xo.undefined != _|_ {a: 1} + @test(eq, {}) +} + +okc2: { + if ({} & {s: [for y in xc.undefined {}]}) != _|_ {a: 1} + @test(eq, {}) +} + +oko2: { + if ({} & {s: [for y in xo.undefined {}]}) != _|_ {a: 1} + @test(eq, {a: 1}) +} + +okc3: { + if ({s: [for y in xc.undefined {}]}) != _|_ {a: 1} + @test(eq, {}) +} + +oko3: { + if ({s: [for y in xo.undefined {}]}) != _|_ {a: 1} + @test(eq, {a: 1}) +} + +// Should Field s exist in okc or not? Depends on whether comparison to bottom +// is recursive or not. It probably should not. +// TODO: fix for new evaluator. But possibly address this with new builtins. +// issue1969: Tests that comparing let-bound expressions involving undefined +// fields to _|_ works correctly with list comprehensions. +// https://cuelang.org/issue/1969 +issue1969: okc: { + let X = xc.undefined + let Y = {} & {s: [for y in list.Range(0, X, 1) {}]} + + if Y != _|_ {Y} + @test(eq, {}) +} + +issue1969: oko: { + let X = xo.undefined + let Y = {} & {s: [for y in list.Range(0, X, 1) {}]} + + if Y != _|_ {Y} + @test(eq, { + s: _|_ @test(err, code=incomplete, contains="issue1969.oko.X: undefined field: undefined", pos=[62:13]) + }) +} +-- issue2245.cue -- +// Evaluator regression where comparing an incomplete struct to bottom in a +// comprehension condition produced incorrect results. +// https://cuelang.org/issue/2245 +yo: { + f: int + g: f < 10 + @test(eq, { + f: int + g: _|_ @test(err, code=incomplete, contains="yo.g: non-concrete value int in operand to <", pos=[6:5, 5:5]) + }) +} +okyo: { + if yo != _|_ {a: 1} + @test(eq, {a: 1}) +} +okyog: { + if yo.g != _|_ {a: 1} + @test(eq, {}) +} + +-- incomplete.cue -- +// Comparing to string is not an error. But for legacy reasons we want to still +// support this. We intend to have more clean and precise behavior with the +// builtins isdefined, isvalid, and isconcrete. +checkIncomplete: t1: { + f: [string]: { + if a != _|_ { + b: "d\(a)" + } + a: string + } + f: blah: {} + @test(eq, {f: {blah: {a: string}}}) +} + +-- structs.cue -- +structs: { + bare: t1: ({y: 2} & {x: 3}) != _|_ @test(eq, true) + bare: f2: ({y: 2} & {x: 3}) == _|_ @test(eq, false) + bare: f3: ({x: 1, y: 2} & {x: 3}) != _|_ @test(eq, false) + bare: t4: ({x: 1, y: 2} & {x: 3}) == _|_ @test(eq, true) + + select: t1: ({y: 2} & {x: 3}).y != _|_ @test(eq, true) + select: f2: ({y: 2} & {x: 3}).y == _|_ @test(eq, false) + select: f3: ({x: 1, y: 2} & {x: 3}).y != _|_ @test(eq, false) + select: t4: ({x: 1, y: 2} & {x: 3}).y == _|_ @test(eq, true) +} + +-- out/compile -- +--- in.cue +{ + xc: close({ + field: {} + }) + xo: { + field: {} + } + okc0: { + if (〈1;xc〉.undefined == _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + oko0: { + if (〈1;xo〉.undefined == _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + okc1: { + if (〈1;xc〉.undefined != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + oko1: { + if (〈1;xo〉.undefined != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + okc2: { + if (({} & { + s: [ + for _, y in 〈3;xc〉.undefined {}, + ] + }) != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + oko2: { + if (({} & { + s: [ + for _, y in 〈3;xo〉.undefined {}, + ] + }) != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + okc3: { + if ({ + s: [ + for _, y in 〈3;xc〉.undefined {}, + ] + } != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + oko3: { + if ({ + s: [ + for _, y in 〈3;xo〉.undefined {}, + ] + } != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + issue1969: { + okc: { + let X#1 = 〈2;xc〉.undefined + let Y#2 = ({} & { + s: [ + for _, y in 〈import;list〉.Range(0, 〈2;let X#1〉, 1) {}, + ] + }) + if (〈0;let Y#2〉 != _|_(explicit error (_|_ literal) in source)) { + 〈1;let Y#2〉 + } + } + } + issue1969: { + oko: { + let X#3 = 〈2;xo〉.undefined + let Y#4 = ({} & { + s: [ + for _, y in 〈import;list〉.Range(0, 〈2;let X#3〉, 1) {}, + ] + }) + if (〈0;let Y#4〉 != _|_(explicit error (_|_ literal) in source)) { + 〈1;let Y#4〉 + } + } + } +} +--- incomplete.cue +{ + checkIncomplete: { + t1: { + f: { + [string]: { + if (〈0;a〉 != _|_(explicit error (_|_ literal) in source)) { + b: "d\(〈1;a〉)" + } + a: string + } + } + f: { + blah: {} + } + } + } +} +--- issue2245.cue +{ + yo: { + f: int + g: (〈0;f〉 < 10) + } + okyo: { + if (〈1;yo〉 != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } + okyog: { + if (〈1;yo〉.g != _|_(explicit error (_|_ literal) in source)) { + a: 1 + } + } +} +--- structs.cue +{ + structs: { + bare: { + t1: (({ + y: 2 + } & { + x: 3 + }) != _|_(explicit error (_|_ literal) in source)) + } + bare: { + f2: (({ + y: 2 + } & { + x: 3 + }) == _|_(explicit error (_|_ literal) in source)) + } + bare: { + f3: (({ + x: 1 + y: 2 + } & { + x: 3 + }) != _|_(explicit error (_|_ literal) in source)) + } + bare: { + t4: (({ + x: 1 + y: 2 + } & { + x: 3 + }) == _|_(explicit error (_|_ literal) in source)) + } + select: { + t1: (({ + y: 2 + } & { + x: 3 + }).y != _|_(explicit error (_|_ literal) in source)) + } + select: { + f2: (({ + y: 2 + } & { + x: 3 + }).y == _|_(explicit error (_|_ literal) in source)) + } + select: { + f3: (({ + x: 1 + y: 2 + } & { + x: 3 + }).y != _|_(explicit error (_|_ literal) in source)) + } + select: { + t4: (({ + x: 1 + y: 2 + } & { + x: 3 + }).y == _|_(explicit error (_|_ literal) in source)) + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/closed.txtar b/internal/core/compile/testdata/sync/comprehensions/closed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/closed.txtar @@ -0,0 +1,275 @@ +-- in.cue -- +dynamicTop: { + #D: { + for k, v in {foo: 123} {(k): v} + @test(eq, {foo: 123}) + } +} + +// Issue #1404 +dynamicDepth1: { + #D: { + a: foo: 123 + b: {for k, v in a {(k): v}} + @test(eq, {a: {foo: 123}, b: {foo: 123}}) + } +} + +allowed: { + #D: { + if true { + d: int + } + } + + vErr: #D & {d: 5} + @test(eq, {#D: {d: int}, vErr: {d: 5}}) +} + +disallowed: { + #D: { + if false { + d: int + } + } + + vErr: #D & {d: 5} + @test(err, code=eval, at=vErr.d, contains="field not allowed", pos=[7:14]) +} + +// Interpret comprehensions as embeddings. +// Issue #1956 +comprehensionIsEmbed: { + #A: size: int | *1 + #B: { + kind: string + + // Should be identical to just #A. That is, #A is treated as open. + if true { + #A + } + } + x: #B & { + kind: "A" + } + @test(eq, { + #A: {size: *1 | int} + #B: {kind: string, size: *1 | int} + x: {kind: "A", size: *1 | int} + }) +} + +// This comprehension is inside a definition and should still disallow b. +noEraseDefinition: { + #Foo: [if true {a: int}] + a: { #Foo & [{ b: 2 }] } // Error + @test(err, code=eval, at=a.0.b, contains="field not allowed", pos=[2:17]) +} + +// issue1956: Tests that conditional comprehensions correctly embed definitions +// inside a closed struct without spuriously rejecting fields. +// https://cuelang.org/issue/1956 +issue1956: { + #Details: { + size: int | *1 + } + + #Thing: { + kind: "KindA" | "KindB" + if kind == "KindA" { + #Details + } + } + + x: #Thing & { + kind: "KindA" + } + @test(eq, { + #Details: {size: *1 | int} + #Thing: {kind: "KindA" | "KindB"} + x: {kind: "KindA", size: *1 | int} + }) +} + +// This triggers adding the same "closedInfo" twice, potentially causing +// a cyclic linked list in the todo list. +dedupTodo: { + #sub: { + c: _ + if c.n == "c" { + X: test: c + } + } + + out: #sub // needs to be definition + out: { + c: n: "c" // Do not combine with &, as the original issue relies on this. + c: n: string + } + @test(eq, { + #sub: {c: _} + out: {c: {n: "c"}, X: {test: {n: "c"}}} + }) +} + +-- v3issues.cue -- +// issue3483: Tests that a falsy if comprehension inside a definition does not +// incorrectly produce "field not allowed" in evalv3. +// https://cuelang.org/issue/3483 +issue3483: { + #Schema: schemaField: int + out1: out2: #Schema & { + if false { + schemaField: 3 + } + } + @test(eq, { + #Schema: {schemaField: int} + out1: {out2: {schemaField: int}} + }) +} +// issue3486: Tests that embedding a definition inside an if comprehension does +// not produce spurious "field not allowed" errors. +// https://cuelang.org/issue/3486 +issue3486: { + #schema: {} + + if true { + out: { + #schema + // This field should be allowed as #schema is embedded. + extra: "foo" + } + } + @test(eq, {#schema: {}, out: {extra: "foo"}}) +} +-- out/compile -- +--- in.cue +{ + dynamicTop: { + #D: { + for k, v in { + foo: 123 + } { + 〈1;k〉: 〈1;v〉 + } + } + } + dynamicDepth1: { + #D: { + a: { + foo: 123 + } + b: { + for k, v in 〈1;a〉 { + 〈1;k〉: 〈1;v〉 + } + } + } + } + allowed: { + #D: { + if true { + d: int + } + } + vErr: (〈0;#D〉 & { + d: 5 + }) + } + disallowed: { + #D: { + if false { + d: int + } + } + vErr: (〈0;#D〉 & { + d: 5 + }) + } + comprehensionIsEmbed: { + #A: { + size: (int|*1) + } + #B: { + kind: string + if true { + 〈2;#A〉 + } + } + x: (〈0;#B〉 & { + kind: "A" + }) + } + noEraseDefinition: { + #Foo: [ + if true { + a: int + }, + ] + a: { + (〈1;#Foo〉 & [ + { + b: 2 + }, + ]) + } + } + issue1956: { + #Details: { + size: (int|*1) + } + #Thing: { + kind: ("KindA"|"KindB") + if (〈0;kind〉 == "KindA") { + 〈2;#Details〉 + } + } + x: (〈0;#Thing〉 & { + kind: "KindA" + }) + } + dedupTodo: { + #sub: { + c: _ + if (〈0;c〉.n == "c") { + X: { + test: 〈2;c〉 + } + } + } + out: 〈0;#sub〉 + out: { + c: { + n: "c" + } + c: { + n: string + } + } + } +} +--- v3issues.cue +{ + issue3483: { + #Schema: { + schemaField: int + } + out1: { + out2: (〈1;#Schema〉 & { + if false { + schemaField: 3 + } + }) + } + } + issue3486: { + #schema: {} + if true { + out: { + 〈2;#schema〉 + extra: "foo" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/deferfieldsetknown.txtar b/internal/core/compile/testdata/sync/comprehensions/deferfieldsetknown.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/deferfieldsetknown.txtar @@ -0,0 +1,43 @@ +-- in.cue -- +package x + +#PDB: {y: int} + +result: resources: { + if true { + x: #PDB & {y: 1} + } +} + +out: ({ + cfg: resources: _ + out: {for n, _ in cfg.resources {(n): "x"}} +} & {cfg: result}).out @test(eq, {x: "x"}) +-- out/compile -- +--- in.cue +{ + #PDB: { + y: int + } + result: { + resources: { + if true { + x: (〈3;#PDB〉 & { + y: 1 + }) + } + } + } + out: ({ + cfg: { + resources: _ + } + out: { + for n, _ in 〈1;cfg〉.resources { + 〈1;n〉: "x" + } + } + } & { + cfg: 〈1;result〉 + }).out +} diff --git a/internal/core/compile/testdata/sync/comprehensions/else.txtar b/internal/core/compile/testdata/sync/comprehensions/else.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/else.txtar @@ -0,0 +1,474 @@ +-- in.cue -- +@experiment(try) + +// if-else: condition true - no else +ifTrue: { + if true { a: 1 } else { b: 2 } + @test(eq, {a: 1}) +} + +// if-else: condition false - else yields +ifFalse: { + if false { a: 1 } else { b: 2 } + @test(eq, {b: 2}) +} + +// for-else: non-empty source - no else +forNonEmpty: { + for x in [1, 2] { "\(x)": x } fallback { empty: true } + @test(eq, {"1": 1, "2": 2}) +} + +// for-else: empty source - else yields +forEmpty: { + for x in [] { "\(x)": x } fallback { empty: true } + @test(eq, {empty: true}) +} + +// for-else with filter: filter removes all - else yields +forFilteredAll: { + for x in [1, 2, 3] if x > 10 { "\(x)": x } fallback { empty: true } + @test(eq, {empty: true}) +} + +// for-else with filter: filter keeps some - no else +forFilteredSome: { + for x in [1, 2, 3] if x > 1 { "\(x)": x } fallback { empty: true } + @test(eq, {"2": 2, "3": 3}) +} + +// if-for-fallback: if true, for empty - fallback yields +ifTrueForEmpty: { + if true for x in [] { "\(x)": x } fallback { empty: true } + @test(eq, {empty: true}) +} + +// if-for-fallback: if false, for non-empty - fallback yields (if blocks iteration) +ifFalseForNonEmpty: { + if false for x in [1, 2] { "\(x)": x } fallback { empty: true } + @test(eq, {empty: true}) +} + +// if-for-fallback: if true, for non-empty - no fallback +ifTrueForNonEmpty: { + if true for x in [1, 2] { "\(x)": x } fallback { empty: true } + @test(eq, {"1": 1, "2": 2}) +} + +// if-if-fallback: both true - no fallback +ifIfBothTrue: { + if true if true { a: 1 } fallback { b: 2 } + @test(eq, {a: 1}) +} + +// if-if-fallback: first false - fallback yields +ifIfFirstFalse: { + if false if true { a: 1 } fallback { b: 2 } + @test(eq, {b: 2}) +} + +// if-if-fallback: second false - fallback yields +ifIfSecondFalse: { + if true if false { a: 1 } fallback { b: 2 } + @test(eq, {b: 2}) +} + +// try-try-fallback: both succeed - no fallback +tryTryBothSucceed: { + a: 1 + b: 2 + try x = a? try y = b? { result: x + y } fallback { default: 0 } + @test(eq, {a: 1, b: 2, result: 3}) +} + +missing?: int + +// try-try-fallback: first fails - fallback yields +tryTryFirstFails: { + b: 2 + try x = missing? try y = b? { result: x + y } fallback { default: -1 } + @test(eq, {b: 2, default: -1}) +} + +// try-try-fallback: second fails - fallback yields +tryTrySecondFails: { + a: 1 + try x = a? try y = missing? { result: x + y } fallback { default: -2 } + @test(eq, {a: 1, default: -2}) +} + +// list if-else: true +listIfTrue: [ + if true { 1 } else { 2 } +] @test(eq, [1]) + +// list if-else: false +listIfFalse: [ + if false { 1 } else { 2 } +] @test(eq, [2]) + +// list for-else: empty +listForEmpty: [ + for x in [] { x } fallback { 0 } +] @test(eq, [0]) + +// list for-else: non-empty +listForNonEmpty: [ + for x in [1, 2] { x * 2 } fallback { 0 } +] @test(eq, [2, 4]) + +// else with multiple fields +elseMultipleFields: { + if false { a: 1 } else { b: 2, c: 3 } + @test(eq, {b: 2, c: 3}) +} + +// else embeds into existing struct +elseEmbeds: { + existing: 1 + if false { added: 2 } else { fallback: 3 } + @test(eq, {existing: 1, fallback: 3}) +} + +// fallback with outer scope access +outerScope: { + let threshold = 10 + for x in [] { x } fallback { fallbackField: threshold } + @test(eq, {fallbackField: 10}) +} + +// if-else: nested body fields - else yields once +ifNestedBody: { + if false { a: b: 1 } else { c: 2 } + @test(eq, {c: 2}) +} + +// if-else: nested else fields +ifNestedElse: { + if false { a: 1 } else { b: c: 2 } + @test(eq, {b: {c: 2}}) +} + +// if-else: nested fields in both +ifNestedBoth: { + if false { a: b: 1 } else { c: d: 2 } + @test(eq, {c: {d: 2}}) +} + +// if-else: deeply nested fields +ifDeeplyNested: { + if false { a: b: c: 1 } else { a: b: c: 2 } + @test(eq, {a: {b: {c: 2}}}) +} + +// for-fallback: nested body fields, empty source +forNestedEmpty: { + for x in [] { a: b: (x): x } fallback { a: b: none: true } + @test(eq, {a: {b: {none: true}}}) +} + +// for-fallback: nested body fields, non-empty source - no fallback +forNestedNonEmpty: { + for x in [1] { a: b: "\(x)": x } fallback { a: b: none: true } + @test(eq, {a: {b: {"1": 1}}}) +} + +// nested comprehensions - outer fallback triggers +nestedOuterFallback: { + for x in [] { for y in [1] { y } fallback { inner: true } } fallback { outer: true } + @test(eq, {outer: true}) +} + +// nested comprehensions - inner fallback triggers +nestedInnerFallback: { + for x in [1] { for y in [] { y } fallback { inner: true } } fallback { outer: true } + @test(eq, {inner: true}) +} +-- out/compile -- +--- in.cue +{ + ifTrue: { + if true { + a: 1 + } else { + b: 2 + } + } + ifFalse: { + if false { + a: 1 + } else { + b: 2 + } + } + forNonEmpty: { + for _, x in [ + 1, + 2, + ] { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + forEmpty: { + for _, x in [] { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + forFilteredAll: { + for _, x in [ + 1, + 2, + 3, + ] if (〈0;x〉 > 10) { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + forFilteredSome: { + for _, x in [ + 1, + 2, + 3, + ] if (〈0;x〉 > 1) { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + ifTrueForEmpty: { + if true for _, x in [] { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + ifFalseForNonEmpty: { + if false for _, x in [ + 1, + 2, + ] { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + ifTrueForNonEmpty: { + if true for _, x in [ + 1, + 2, + ] { + "\(〈1;x〉)": 〈1;x〉 + } else { + empty: true + } + } + ifIfBothTrue: { + if true if true { + a: 1 + } else { + b: 2 + } + } + ifIfFirstFalse: { + if false if true { + a: 1 + } else { + b: 2 + } + } + ifIfSecondFalse: { + if true if false { + a: 1 + } else { + b: 2 + } + } + tryTryBothSucceed: { + a: 1 + b: 2 + try x = 〈0;a〉? try y = 〈1;b〉? { + result: (〈2;x〉 + 〈1;y〉) + } else { + default: 0 + } + } + missing?: int + tryTryFirstFails: { + b: 2 + try x = 〈1;missing〉? try y = 〈1;b〉? { + result: (〈2;x〉 + 〈1;y〉) + } else { + default: -1 + } + } + tryTrySecondFails: { + a: 1 + try x = 〈0;a〉? try y = 〈2;missing〉? { + result: (〈2;x〉 + 〈1;y〉) + } else { + default: -2 + } + } + listIfTrue: [ + if true { + 1 + } else { + 2 + }, + ] + listIfFalse: [ + if false { + 1 + } else { + 2 + }, + ] + listForEmpty: [ + for _, x in [] { + 〈1;x〉 + } else { + 0 + }, + ] + listForNonEmpty: [ + for _, x in [ + 1, + 2, + ] { + (〈1;x〉 * 2) + } else { + 0 + }, + ] + elseMultipleFields: { + if false { + a: 1 + } else { + b: 2 + c: 3 + } + } + elseEmbeds: { + existing: 1 + if false { + added: 2 + } else { + fallback: 3 + } + } + outerScope: { + let threshold#1 = 10 + for _, x in [] { + 〈1;x〉 + } else { + fallbackField: 〈1;let threshold#1〉 + } + } + ifNestedBody: { + if false { + a: { + b: 1 + } + } else { + c: 2 + } + } + ifNestedElse: { + if false { + a: 1 + } else { + b: { + c: 2 + } + } + } + ifNestedBoth: { + if false { + a: { + b: 1 + } + } else { + c: { + d: 2 + } + } + } + ifDeeplyNested: { + if false { + a: { + b: { + c: 1 + } + } + } else { + a: { + b: { + c: 2 + } + } + } + } + forNestedEmpty: { + for _, x in [] { + a: { + b: { + 〈3;x〉: 〈3;x〉 + } + } + } else { + a: { + b: { + none: true + } + } + } + } + forNestedNonEmpty: { + for _, x in [ + 1, + ] { + a: { + b: { + "\(〈3;x〉)": 〈3;x〉 + } + } + } else { + a: { + b: { + none: true + } + } + } + } + nestedOuterFallback: { + for _, x in [] { + for _, y in [ + 1, + ] { + 〈1;y〉 + } else { + inner: true + } + } else { + outer: true + } + } + nestedInnerFallback: { + for _, x in [ + 1, + ] { + for _, y in [] { + 〈1;y〉 + } else { + inner: true + } + } else { + outer: true + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/else_compile_errors.txtar b/internal/core/compile/testdata/sync/comprehensions/else_compile_errors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/else_compile_errors.txtar @@ -0,0 +1,53 @@ +#inlinetest:exclude CUE source contains compile-time errors (out-of-scope references) +# which prevent the inline test runner from compiling the source. +-- in.cue -- +@experiment(try) + +// else cannot access for variable +forVarInElse: { + for i in [1,2,3] { "\(i)": i } fallback { bad: i } +} + +// else cannot access let variable from comprehension +letVarInElse: { + for x in [1,2,3] let y = x*2 { "\(x)": y } fallback { bad: y } +} + +// Note: Multiple clause cases with else are caught at parse time, not compile time: +// - if + let with else: if cond let x = val { ... } else { ... } +// - Two if clauses with else: if cond1 if cond2 { x } else { y } +// - Chained try with else: try x = a? try y = b? { ... } else { ... } +// - Mixed if/try with else: if cond try { x } else { y } +// - if + for with else: if cond for x in [] { x } else { y } +// These all produce parser error: "else clause only allowed with single 'if' or 'try' clause" +// or "use 'otherwise' with 'for' clauses" +-- out/compile -- +forVarInElse.bad: reference "i" not found: + ./in.cue:5:49 +letVarInElse.bad: reference "y" not found: + ./in.cue:10:61 +--- in.cue +{ + forVarInElse: { + for _, i in [ + 1, + 2, + 3, + ] { + "\(〈1;i〉)": 〈1;i〉 + } else { + bad: _|_(reference "i" not found) + } + } + letVarInElse: { + for _, x in [ + 1, + 2, + 3, + ] let y = (〈0;x〉 * 2) { + "\(〈2;x〉)": 〈1;y〉 + } else { + bad: _|_(reference "y" not found) + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/else_on_error.txtar b/internal/core/compile/testdata/sync/comprehensions/else_on_error.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/else_on_error.txtar @@ -0,0 +1,48 @@ +-- in.cue -- +@experiment(try) + +// When the source expression has an error, the error propagates +// rather than triggering the else clause. + +// Error in for source - else should NOT trigger +forSourceError: { + @test(err, code=eval, pos=[2:11], contains="cannot range") + for x in "not-a-list" { "\(x)": x } fallback { fallbackField: true } +} + +// Error in if condition - else should NOT trigger +ifConditionError: { + @test(err, code=eval, pos=[2:6, 2:14], contains="invalid operands") + if ("not" + 1) { a: 1 } else { b: 2 } +} + +// Bottom value in for source - else should NOT trigger +forSourceBottom: { + @test(err, code=user, pos=[2:11], contains="explicit error") + for x in _|_ { "\(x)": x } fallback { fallbackField: true } +} +-- out/compile -- +--- in.cue +{ + forSourceError: { + for _, x in "not-a-list" { + "\(〈1;x〉)": 〈1;x〉 + } else { + fallbackField: true + } + } + ifConditionError: { + if ("not" + 1) { + a: 1 + } else { + b: 2 + } + } + forSourceBottom: { + for _, x in _|_(explicit error (_|_ literal) in source) { + "\(〈1;x〉)": 〈1;x〉 + } else { + fallbackField: true + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/errors.txtar b/internal/core/compile/testdata/sync/comprehensions/errors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/errors.txtar @@ -0,0 +1,94 @@ +-- in.cue -- +circularIf: { + #list: { + tail: #list | *null + if tail != null { + } + @test(eq, {tail: null}) + } +} + +circularFor: { + #list: { + tail: #list | *null + for x in tail != null { + } + @test(err, code=eval, + contains="cannot range over %s (found %s, want list or struct)", + args=[tail != null, bool], pos=[2:12]) + } +} + +// Print a bit more sensible error message than "empty disjunction" here. +// Issue #465 +userError: { + a: string | *_|_ + if a != "" { + } + @test(err, code=incomplete, contains="non-concrete value string", pos=[2:5, 1:5]) +} + +intField: { + for i, _ in [1, 2] { + (i): { + } + } + @test(err, code=eval, contains="integer fields not supported", pos=[2:4]) +} + +// Issue #2403 +conflictRangingOverSelf: { + x: { + name: string + age: int + } + + x: { + for k, _ in x { + (k): k + } + } + @test(err, code=eval, at=x.age, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[int, "age", int, string], + pos=[3:9, 6:5, 7:3, 8:9]) +} +-- out/compile -- +--- in.cue +{ + circularIf: { + #list: { + tail: (〈1;#list〉|*null) + if (〈0;tail〉 != null) {} + } + } + circularFor: { + #list: { + tail: (〈1;#list〉|*null) + for _, x in (〈0;tail〉 != null) {} + } + } + userError: { + a: (string|*_|_(explicit error (_|_ literal) in source)) + if (〈0;a〉 != "") {} + } + intField: { + for i, _ in [ + 1, + 2, + ] { + 〈1;i〉: {} + } + } + conflictRangingOverSelf: { + x: { + name: string + age: int + } + x: { + for k, _ in 〈1;x〉 { + 〈1;k〉: 〈1;k〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/fields.txtar b/internal/core/compile/testdata/sync/comprehensions/fields.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/fields.txtar @@ -0,0 +1,137 @@ +Issue #560 +# Issue #560: Tests that for comprehensions correctly iterate over struct fields, +# skipping optionals, and that missing required fields produce errors. +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- in.cue -- +import "strings" + +dynamic: { + for _, s in ["foo"] { + (s): 1 + "\(s)bar": 2 + } + @test(eq, {foo: 1, foobar: 2}) +} + +ignoreOptional: { + #x: { + a?: string + b?: string + c: string + } + + y: { + for k,v in #x { + (k): "exists" + } + } + @test(eq, { + #x: {a?: string, b?: string, c: string} + y: {c: "exists"} + }) +} + +missingRequiredError: { + // Issue #2369 + #x: { + a!: string + b?: string + c: string + } + + y: { + for k,v in #x { + (k): "exists" + } + } + @test(err, code=incomplete, at=y, contains="missing required field", pos=[9:3, 3:3, 9:14]) +} + +// issue560: Tests that for comprehensions over definitions with interpolated +// field names correctly produce all expected output fields. +// https://cuelang.org/issue/560 +issue560: { + #User: { + tags_str: string + tags_map: { + for k, v in strings.Split(tags_str, " ") { + "\(v)": string + } + "{a}": string + } @test(err, code=incomplete, + contains="error in call to %s", args=[strings.Split], + pos=[1:16, -1:13]) + } + + user: { + #User + tags_str: "b {c}" + } + @test(eq, { + #User: { + tags_str: string + tags_map: {"{a}": string} + } + user: { + tags_str: "b {c}" + tags_map: { + "{a}": string + b: string + "{c}": string + } + } + }) +} +-- out/compile -- +--- in.cue +{ + dynamic: { + for _, s in [ + "foo", + ] { + 〈1;s〉: 1 + "\(〈1;s〉)bar": 2 + } + } + ignoreOptional: { + #x: { + a?: string + b?: string + c: string + } + y: { + for k, v in 〈1;#x〉 { + 〈1;k〉: "exists" + } + } + } + missingRequiredError: { + #x: { + a!: string + b?: string + c: string + } + y: { + for k, v in 〈1;#x〉 { + 〈1;k〉: "exists" + } + } + } + issue560: { + #User: { + tags_str: string + tags_map: { + for k, v in 〈import;strings〉.Split(〈1;tags_str〉, " ") { + "\(〈1;v〉)": string + } + "{a}": string + } + } + user: { + 〈1;#User〉 + tags_str: "b {c}" + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/for.txtar b/internal/core/compile/testdata/sync/comprehensions/for.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/for.txtar @@ -0,0 +1,56 @@ +-- in.cue -- +b: {for k, v in a {"\(k)": v + 1}} @test(eq, {b: 2, c: 3}) +a: {b: 1, c: 2} @test(eq, {b: 1, c: 2}) + +x: {for k, v in y {"\(k)": v}} @test(eq, {}) +y: {} // check that empty struct after reference works. + +k: {for v in e {v}} @test(err, code=eval, pos=[0:14], contains="cannot range") +e: int @test(eq, int) + +comprehensionBinds: { + @test(eq, {a: a: _, b: a: _}) + a: {for _ in [1] {a: _}} + b: {for _, _ in [1] {a: _}} +} +-- out/compile -- +--- in.cue +{ + b: { + for k, v in 〈1;a〉 { + "\(〈1;k〉)": (〈1;v〉 + 1) + } + } + a: { + b: 1 + c: 2 + } + x: { + for k, v in 〈1;y〉 { + "\(〈1;k〉)": 〈1;v〉 + } + } + y: {} + k: { + for _, v in 〈1;e〉 { + 〈1;v〉 + } + } + e: int + comprehensionBinds: { + a: { + for _, _ in [ + 1, + ] { + a: _ + } + } + b: { + for _, _ in [ + 1, + ] { + a: _ + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/iferror.txtar b/internal/core/compile/testdata/sync/comprehensions/iferror.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/iferror.txtar @@ -0,0 +1,217 @@ +-- in.cue -- +a: {b: 2, c: int} + +wrongConcreteType: { + if a.b { + 2 + } + @test(err, code=eval, contains="cannot use 2 (type int) as type bool", pos=[1:2, -2:8]) +} + +wrongType: { + if a.c { + 2 + } + @test(err, code=eval, contains="cannot use int (type int) as type bool", pos=[1:2, -9:14]) +} + +incomplete: err1: { + if a.d { + 2 + } + @test(err, code=incomplete, contains="undefined field: d", pos=[1:7]) +} +incomplete: err2: { + list: [1, 2, 3] + for x in list if a.d { + x + } + @test(err, code=incomplete, contains="undefined field: d", pos=[2:21]) +} + +// issue809: Tests that comprehension guards using `!= _|_` work correctly +// when the guarded field has a default value. In both cases below the field +// being tested is non-bottom (it carries a default), so the guard should +// pass and the comprehension should yield the entry. +// https://cuelang.org/issue/809 +useDefault: { + a: { + x: *"foo" | string + if x != _|_ { + y: x + } + } + + issue809: { + #A: { + a: string + b: *a | string + } + + s: [Name=string]: #A & {a: Name} + s: bar: _ + + foo: [ + for _, a in s if a.b != _|_ {a}, + ] + + @test(eq, { + #A: { + a: string + b: string + } + s: bar: { + a: "bar" + b: *"bar" | string + } + foo: [{ + a: "bar" + b: *"bar" | string + }] + }) + } +} + +// issue1972: Tests that mixing a list value with struct fields in a +// comprehension correctly produces a conflict error rather than a panic. +// https://cuelang.org/issue/1972 +issue1972: { + err1: { + #patchs: [] + #patchs + + #someCondition: _ + if #someCondition { + } + } + err1: { + someCondition: _ + patchs: [...{}] + patchs + if someCondition { + patchs: _ + } + } @test(err, code=eval, + contains="conflicting values %s and %s (mismatched types %s and %s)", + pos=[0:8, 2:11, 3:3] + ) + err2: { + #patchs: [] + #patchs + + #someCondition: _ + if #someCondition { + } + } @test(err, code=incomplete, contains="incomplete %s: %s", args=[bool, _], pos=[]) + err3: { + someCondition: _ + patchs: [...{}] + patchs + if someCondition { + patchs: _ + } + + // TODO(inline): support commas in arguments + @test(err, code=eval, contains="conflicting values %s and %s (mismatched types %s and %s)", + pos=[0:8, 2:11, 3:3] + ) + } +} +-- out/compile -- +--- in.cue +{ + a: { + b: 2 + c: int + } + wrongConcreteType: { + if 〈1;a〉.b { + 2 + } + } + wrongType: { + if 〈1;a〉.c { + 2 + } + } + incomplete: { + err1: { + if 〈2;a〉.d { + 2 + } + } + } + incomplete: { + err2: { + list: [ + 1, + 2, + 3, + ] + for _, x in 〈0;list〉 if 〈3;a〉.d { + 〈1;x〉 + } + } + } + useDefault: { + a: { + x: (*"foo"|string) + if (〈0;x〉 != _|_(explicit error (_|_ literal) in source)) { + y: 〈1;x〉 + } + } + issue809: { + #A: { + a: string + b: (*〈0;a〉|string) + } + s: { + [string]: (〈1;#A〉 & { + a: 〈1;-〉 + }) + } + s: { + bar: _ + } + foo: [ + for _, a in 〈1;s〉 if (〈0;a〉.b != _|_(explicit error (_|_ literal) in source)) { + 〈1;a〉 + }, + ] + } + } + issue1972: { + err1: { + #patchs: [] + 〈0;#patchs〉 + #someCondition: _ + if 〈0;#someCondition〉 {} + } + err1: { + someCondition: _ + patchs: [ + ...{}, + ] + 〈0;patchs〉 + if 〈0;someCondition〉 { + patchs: _ + } + } + err2: { + #patchs: [] + 〈0;#patchs〉 + #someCondition: _ + if 〈0;#someCondition〉 {} + } + err3: { + someCondition: _ + patchs: [ + ...{}, + ] + 〈0;patchs〉 + if 〈0;someCondition〉 { + patchs: _ + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/incomplete.txtar b/internal/core/compile/testdata/sync/comprehensions/incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/incomplete.txtar @@ -0,0 +1,23 @@ +-- in.cue -- +cond: bool +src: {} +top: _ +a: [ if cond {}] @test(err, code=incomplete, pos=[-3:7], contains="incomplete bool") +b: [for x in src.foo {}] @test(err, code=incomplete, pos=[0:18], contains="undefined field") +c: {for x in top {}} @test(err, code=incomplete, pos=[0:14], contains="cannot range") +-- out/compile -- +--- in.cue +{ + cond: bool + src: {} + top: _ + a: [ + if 〈1;cond〉 {}, + ] + b: [ + for _, x in 〈1;src〉.foo {}, + ] + c: { + for _, x in 〈1;top〉 {} + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue1732.txtar b/internal/core/compile/testdata/sync/comprehensions/issue1732.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue1732.txtar @@ -0,0 +1,351 @@ +# Tests comprehensions with definitions that use incomplete boolean conditions, +# including nested definition references and cross-struct comprehensions. +# Issue #1732: comprehension with abstract bool condition in definitions causes +# "incomplete bool" error propagation through nested structs. +-- in.cue -- +package config + +networkingv1: { + metav1: { + #LabelSelector: { + matchLabels: {[string]: string} + } + } + + #NetworkPolicy: { + spec: #NetworkPolicySpec + } + + #NetworkPolicySpec: { + ingress: [...#NetworkPolicyIngressRule] + egress: [...#NetworkPolicyEgressRule] + } + + #NetworkPolicyIngressRule: { + from: [...#NetworkPolicyPeer] + } + + #NetworkPolicyEgressRule: { + to: [...#NetworkPolicyPeer] + } + + #NetworkPolicyPeer: { + namespaceSelector: null | metav1.#LabelSelector + } +} + +global_config: { + #GlobalConfig: { + auth0: { + enabled: bool + } + } +} +common: { + #SomeConfig: { + enabled: bool + if enabled { + foo: string + } + @test(err, code=incomplete, contains="incomplete bool", pos=[1:12]) + } +} + +foo: { + #Values: { + global: global_config.#GlobalConfig + } +} + +#Config: R={ + tenant: id: string + + auth0: common.#SomeConfig & { + enabled: bool + if (enabled) { + foo: "\(tenant.id)-value" + } + } + + charts: { + "foo": foo.#Values & { + global: R.global + } + } + + global: global_config.#GlobalConfig & { + auth0: enabled: R.auth0.enabled + } +} + +#NetworkPolicy: networkingv1.#NetworkPolicy + +#Flux: R={ + #Config + + charts: _ + + formatOutput: {...} + + _outputs: {...} + + for _chartName, _chartValues in charts { + _outputs: "\(_chartName)": {} + } + + _outputs: { + for ns in ["ns"] { + "\(ns)/network": #NetworkPolicy & { + spec: { + ingress: [ + { + from: [{ + namespaceSelector: matchLabels: { + tenant: R.tenant.id + } + }] + }, + ] + egress: [ + { + to: [{ + namespaceSelector: matchLabels: { + tenant: R.tenant.id + } + }] + }, + ] + } + } + } + } + + for ns in ["ns"] { + for k, v in _outputs { + formatOutput: "\(k)": v + } + } +} +@test(eq, { + networkingv1: { + metav1: {#LabelSelector: {matchLabels: {}}} + #NetworkPolicy: {spec: {ingress: [], egress: []}} + #NetworkPolicySpec: {ingress: [], egress: []} + #NetworkPolicyIngressRule: {from: []} + #NetworkPolicyEgressRule: {to: []} + #NetworkPolicyPeer: { + namespaceSelector: null | {matchLabels: {}} + } + } + global_config: { + #GlobalConfig: {auth0: {enabled: bool}} + } + common: {#SomeConfig: {_|_, enabled: bool}} + foo: { + #Values: {global: {auth0: {enabled: bool}}} + } + #Config: { + tenant: {id: string} + auth0: {_|_, enabled: bool} + charts: { + foo: { + global: { + auth0: { + enabled: _|_ @test(err, code=incomplete, contains="#Config.auth0: incomplete bool: bool (and 1 more errors)", pos=[59:12]) + } + } + } + } + global: { + auth0: { + enabled: _|_ @test(err, code=incomplete, contains="#Config.auth0: incomplete bool: bool (and 1 more errors)", pos=[59:12]) + } + } + } + #NetworkPolicy: {spec: {ingress: [], egress: []}} + #Flux: { + charts: { + foo: {global: {auth0: {enabled: bool}}} + } + formatOutput: { + foo: {} + "ns/network": { + spec: { + ingress: [{ + from: [{ + namespaceSelector: {matchLabels: {tenant: string}} + }] + }] + egress: [{ + to: [{ + namespaceSelector: {matchLabels: {tenant: string}} + }] + }] + } + } + } + _outputs$config: { + foo: {} + "ns/network": { + spec: { + ingress: [{ + from: [{ + namespaceSelector: {matchLabels: {tenant: string}} + }] + }] + egress: [{ + to: [{ + namespaceSelector: {matchLabels: {tenant: string}} + }] + }] + } + } + } + tenant: {id: string} + auth0: {_|_, enabled: bool} + global: { + auth0: { + enabled: _|_ @test(err, code=incomplete, contains="#Flux.auth0: incomplete bool: bool (and 1 more errors)", pos=[59:12]) + } + } + } +}) +-- out/compile -- +--- in.cue +{ + networkingv1: { + metav1: { + #LabelSelector: { + matchLabels: { + [string]: string + } + } + } + #NetworkPolicy: { + spec: 〈1;#NetworkPolicySpec〉 + } + #NetworkPolicySpec: { + ingress: [ + ...〈2;#NetworkPolicyIngressRule〉, + ] + egress: [ + ...〈2;#NetworkPolicyEgressRule〉, + ] + } + #NetworkPolicyIngressRule: { + from: [ + ...〈2;#NetworkPolicyPeer〉, + ] + } + #NetworkPolicyEgressRule: { + to: [ + ...〈2;#NetworkPolicyPeer〉, + ] + } + #NetworkPolicyPeer: { + namespaceSelector: (null|〈1;metav1〉.#LabelSelector) + } + } + global_config: { + #GlobalConfig: { + auth0: { + enabled: bool + } + } + } + common: { + #SomeConfig: { + enabled: bool + if 〈0;enabled〉 { + foo: string + } + } + } + foo: { + #Values: { + global: 〈2;global_config〉.#GlobalConfig + } + } + #Config: { + tenant: { + id: string + } + auth0: (〈1;common〉.#SomeConfig & { + enabled: bool + if 〈0;enabled〉 { + foo: "\(〈2;tenant〉.id)-value" + } + }) + charts: { + foo: (〈2;foo〉.#Values & { + global: 〈3〉.global + }) + } + global: (〈1;global_config〉.#GlobalConfig & { + auth0: { + enabled: 〈3〉.auth0.enabled + } + }) + } + #NetworkPolicy: 〈0;networkingv1〉.#NetworkPolicy + #Flux: { + 〈1;#Config〉 + charts: _ + formatOutput: { + ... + } + _outputs(:config): { + ... + } + for _chartName, _chartValues in 〈0;charts〉 { + _outputs(:config): { + "\(〈2;_chartName(:config)〉)": {} + } + } + _outputs(:config): { + for _, ns in [ + "ns", + ] { + "\(〈1;ns〉)/network": (〈4;#NetworkPolicy〉 & { + spec: { + ingress: [ + { + from: [ + { + namespaceSelector: { + matchLabels: { + tenant: 〈12〉.tenant.id + } + } + }, + ] + }, + ] + egress: [ + { + to: [ + { + namespaceSelector: { + matchLabels: { + tenant: 〈12〉.tenant.id + } + } + }, + ] + }, + ] + } + }) + } + } + for _, ns in [ + "ns", + ] { + for k, v in 〈2;_outputs(:config)〉 { + formatOutput: { + "\(〈2;k〉)": 〈2;v〉 + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue2171.txtar b/internal/core/compile/testdata/sync/comprehensions/issue2171.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue2171.txtar @@ -0,0 +1,23 @@ +// Sometimes an arc should not "Finalize" itself. See Issue #2171 in eval.go. +-- in.cue -- +package x + +do: { + hello: { + } +} + +for k, v in do {do: (k): v} +@test(eq, {do: hello: {}}) +-- out/compile -- +--- in.cue +{ + do: { + hello: {} + } + for k, v in 〈0;do〉 { + do: { + 〈2;k〉: 〈2;v〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue2481.txtar b/internal/core/compile/testdata/sync/comprehensions/issue2481.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue2481.txtar @@ -0,0 +1,134 @@ +# Tests that mixing struct fields and embedded scalars in a comprehension body +# correctly reports an error. Issue #2481: nested for/if/let comprehensions +# triggered a spurious "circular dependency" error in the evaluator. +# https://cuelang.org/issue/2481 +// Mixing struct fields and embedded scalars should error. Using comprehensions +// this follows a different path which may miss the error. +// TODO: fix +-- in.cue -- +// Mixing struct fields and embedded scalars should error. Using comprehensions +// this follows a different path which may miss the error. +// TODO: fix +out: { + for k in keys { + if values[k] != _|_ { + val: k + if val != _|_ { + k + } + } + } + @test(err, code=eval, hint="string with struct") +} + +// multiple lets are mapped to the same location and will conflict. This is +// fine, though, as lets do not represent a single data field. This should +// therefore not error. +// TODO: fix +multiLets: { + for k in keys { + if values[k] != _|_ { + let val = k + if val != _|_ { + k + } + } + } + @test(eq, "b") +} + +keys: [ + // order matters + "a", + "b", +] @test(eq, ["a", "b"]) + +values: { + // order does not matter + "b": "member" + "c": "foo" + @test(eq, {b: "member", c: "foo"}) +} + +full: { + out: { + + // changing this to a list of the keys "fixes" things, i.e. this comprehension is required + for k, _ in #github_team_membership { + + // Remove this comprehension to trigger a different type of cycle error + if ( values[k] != _|_ ) { + + // This let is also required + let val = values[k] + + if val != null && ((val & string) != _|_) { + (k): val + } + } + } + } + + #github_team_membership: { + team_id: string + role: string + } + + values: { + "role": "member" + "username": "foo" + } + @test(eq, {out: {role: "member"}, #github_team_membership: {team_id: string, role: string}, values: {role: "member", username: "foo"}}) +} +-- out/compile -- +--- in.cue +{ + out: { + for _, k in 〈1;keys〉 { + if (〈3;values〉[〈1;k〉] != _|_(explicit error (_|_ literal) in source)) { + val: 〈2;k〉 + if (〈0;val〉 != _|_(explicit error (_|_ literal) in source)) { + 〈3;k〉 + } + } + } + } + multiLets: { + for _, k in 〈1;keys〉 { + if (〈3;values〉[〈1;k〉] != _|_(explicit error (_|_ literal) in source)) { + let val#1multi = 〈2;k〉 + if (〈0;let val#1〉 != _|_(explicit error (_|_ literal) in source)) { + 〈3;k〉 + } + } + } + } + keys: [ + "a", + "b", + ] + values: { + b: "member" + c: "foo" + } + full: { + out: { + for k, _ in 〈1;#github_team_membership〉 { + if (〈3;values〉[〈1;k〉] != _|_(explicit error (_|_ literal) in source)) { + let val#2multi = 〈4;values〉[〈2;k〉] + if ((〈0;let val#2〉 != null) && ((〈0;let val#2〉 & string) != _|_(explicit error (_|_ literal) in source))) { + 〈3;k〉: 〈1;let val#2〉 + } + } + } + } + #github_team_membership: { + team_id: string + role: string + } + values: { + role: "member" + username: "foo" + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue287.txtar b/internal/core/compile/testdata/sync/comprehensions/issue287.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue287.txtar @@ -0,0 +1,31 @@ +-- in.cue -- +if #E["x"] != _|_ { + #E: {y: true} +} +if #E["y"] != _|_ { + z: true +} +#E: [_]: bool +#E: x: true +#E: _ @test(eq, {y: true, x: true}) +z: _ @test(eq, true) +-- out/compile -- +--- in.cue +{ + if (〈0;#E〉["x"] != _|_(explicit error (_|_ literal) in source)) { + #E: { + y: true + } + } + if (〈0;#E〉["y"] != _|_(explicit error (_|_ literal) in source)) { + z: true + } + #E: { + [_]: bool + } + #E: { + x: true + } + #E: _ + z: _ +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue293.txtar b/internal/core/compile/testdata/sync/comprehensions/issue293.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue293.txtar @@ -0,0 +1,82 @@ +# Issue #1969: Tests that comparing fields to _|_ (checking if defined) works +# correctly for both closed and open structs, including edge cases with +# comprehensions and let clauses. +-- in.cue -- +#T: { + if true { + // We'd like to restrict the possible members of x in this case, + // but this doesn't work. + x: close({ + f1: int + }) + } + x: _ +// All tests here should pass and the result of the okcN tests should be +// identical to those of the okoN tests. +// Should Field s exist in okc or not? Depends on whether comparison to bottom +// is recursive or not. It probably should not. +// TODO: fix for new evaluator. But possibly address this with new builtins. +} +z: #T & { + x: { + f1: 99 + f2: "i want to disallow this" + } +} @test(err, code=eval, at=x.f2, contains="field not allowed", pos=[3:3]) + + +t: #C @test(eq, {p: "foo"}) +#C: { + if true { + p: _ +// Comparing to string is not an error. But for legacy reasons we want to still +// support this. We intend to have more clean and precise behavior with the +// builtins isdefined, isvalid, and isconcrete. + } +} +t: p: "foo" + +-- variant1.cue -- +#V1: { + x: close({ f1: int }) + x: f2: 2 @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} + +-- out/compile -- +--- in.cue +{ + #T: { + if true { + x: close({ + f1: int + }) + } + x: _ + } + z: (〈0;#T〉 & { + x: { + f1: 99 + f2: "i want to disallow this" + } + }) + t: 〈0;#C〉 + #C: { + if true { + p: _ + } + } + t: { + p: "foo" + } +} +--- variant1.cue +{ + #V1: { + x: close({ + f1: int + }) + x: { + f2: 2 + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue3762.txtar b/internal/core/compile/testdata/sync/comprehensions/issue3762.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue3762.txtar @@ -0,0 +1,238 @@ +# Tests that comprehensions over intersections of hidden fields work correctly. +# Issue #3762: for comprehensions over _a & _b where both have patterns. +-- in.cue -- +full: { + kube: node: n1: { + _CL: "l" + _cs: (_CL): _a[(_CL)] + _cs: (_CL): { + opts: {} + } + } + + _a: "l": { + _ba?: string + opts: { + if _ba != _|_ {b: (_ba)} + } + } + + for k, _ in _a & _b { + x: 5 + } + + _a: [ID=_]: vms: [{ name: "hello" }] + _b: [ID=_]: vms: [{ name: "again" }] + @test(eq, { + kube: node: n1: { + _CL: "l" + _cs: l: { + opts: {} + _ba?: string + vms: [{ + name: "hello" + }] + } + } + _a: l: { + _ba?: string + opts: {} + vms: [{ + name: "hello" + }] + } + x: 5 + _b: {} + }) +} +reduced: p1: { + _cs: _a.l & { + opts: {} + } + + _a: l: { + _ba?: string + opts: { + if _ba != _|_ { + b: _ba + } + } + vms: "hello" + } + + _b: l: vms: "again" + + for k, _ in _a & _b { + x: 5 + } + @test(eq, { + _cs: {opts: {}, _ba?: string, vms: "hello"} + _a: { + l: {_ba?: string, opts: {}, vms: "hello"} + } + _b: {l: {vms: "again"}} + x: 5 + }) +} +reduced: p2: { + for k, _ in _a & _b { + x: 5 + } + + _cs: _a.l & { + opts: {} + } + + _a: l: { + _ba?: string + opts: { + if _ba != _|_ { + b: _ba + } + } + vms: "hello" + } + + _b: l: vms: "again" + @test(eq, { + x: 5 + _cs: {opts: {}, _ba?: string, vms: "hello"} + _a: { + l: {_ba?: string, opts: {}, vms: "hello"} + } + _b: {l: {vms: "again"}} + }) +} +reference: { + _x: { + f: true + } + + _y: { + f: false + } + + for k, _ in _x & _y { + ok: true + } + @test(eq, { + _x: {f: true} + _y: {f: false} + ok: true + }) +} +-- out/compile -- +--- in.cue +{ + full: { + kube: { + node: { + n1: { + _CL: "l" + _cs: { + 〈1;_CL〉: 〈4;_a〉[〈1;_CL〉] + } + _cs: { + 〈1;_CL〉: { + opts: {} + } + } + } + } + } + _a: { + l: { + _ba?: string + opts: { + if (〈1;_ba〉 != _|_(explicit error (_|_ literal) in source)) { + b: 〈2;_ba〉 + } + } + } + } + for k, _ in (〈0;_a〉 & 〈0;_b〉) { + x: 5 + } + _a: { + [_]: { + vms: [ + { + name: "hello" + }, + ] + } + } + _b: { + [_]: { + vms: [ + { + name: "again" + }, + ] + } + } + } + reduced: { + p1: { + _cs: (〈0;_a〉.l & { + opts: {} + }) + _a: { + l: { + _ba?: string + opts: { + if (〈1;_ba〉 != _|_(explicit error (_|_ literal) in source)) { + b: 〈2;_ba〉 + } + } + vms: "hello" + } + } + _b: { + l: { + vms: "again" + } + } + for k, _ in (〈0;_a〉 & 〈0;_b〉) { + x: 5 + } + } + } + reduced: { + p2: { + for k, _ in (〈0;_a〉 & 〈0;_b〉) { + x: 5 + } + _cs: (〈0;_a〉.l & { + opts: {} + }) + _a: { + l: { + _ba?: string + opts: { + if (〈1;_ba〉 != _|_(explicit error (_|_ literal) in source)) { + b: 〈2;_ba〉 + } + } + vms: "hello" + } + } + _b: { + l: { + vms: "again" + } + } + } + } + reference: { + _x: { + f: true + } + _y: { + f: false + } + for k, _ in (〈0;_x〉 & 〈0;_y〉) { + ok: true + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue3763.txtar b/internal/core/compile/testdata/sync/comprehensions/issue3763.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue3763.txtar @@ -0,0 +1,189 @@ +# Tests that nested comprehensions with let bindings across multiple files work. +# Issue #3763: for comprehension with multi-level let bindings and pattern constraints. +-- reduced.cue -- +reduced: { + A: x1: y?: int // needs to be optional + A: x2: y?: int + A: x3: y?: int + + if true { + let Z = [for _, x in A {x}] + B: [for z in Z if z.y != _|_ { b: 1 }] + } + @test(eq, { + A: { + x1: {y?: int} + x2: {y?: int} + x3: {y?: int} + } + B: [] + }) +} +-- full.cue -- +full: { + _core_v1: { + #cp: { + hostPort?: int32 + cp: int32 + } + } + + @test(shareID=L, at=k.n.n1._cs.l) + k: n: n1: { + _CL: "l" + } + + let nc = { + _ports: [ID=_]: _core_v1.#cp + } + + _cl: [ID=_]: nc & { + _ports: { + "1": {} + "2": {} + "3": {} + } + } + + k: n: [ID=_]: { + _CL: string + _cs: (_CL): _cl[(_CL)] + } + + for _, n in k.n { + let cps = [for _, c in n._cs for _, cps in c._ports {cps}] + ports: [for cp in cps if cp.hostPort != _|_ { + port: "\(cp.hostPort)" + }] + } + + _cl: l: {} @test(shareID=L) + @test(eq, { + _core_v1: #cp: { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + k: n: n1: { + _CL: "l" + _cs: l: _ports: { + "1": { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + "2": { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + "3": { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + } + } + _cl: l: _ports: { + "1": { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + "2": { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + "3": { + hostPort?: >=-2147483648 & <=2147483647 & int + cp: >=-2147483648 & <=2147483647 & int + } + } + ports: [] + }) +} +-- out/compile -- +--- full.cue +{ + full: { + _core_v1: { + #cp: { + hostPort?: &(int, >=-2147483648, <=2147483647) + cp: &(int, >=-2147483648, <=2147483647) + } + } + k: { + n: { + n1: { + _CL: "l" + } + } + } + let nc#1 = { + _ports: { + [_]: 〈2;_core_v1〉.#cp + } + } + _cl: { + [_]: (〈1;let nc#1〉 & { + _ports: { + "1": {} + "2": {} + "3": {} + } + }) + } + k: { + n: { + [_]: { + _CL: string + _cs: { + 〈1;_CL〉: 〈4;_cl〉[〈1;_CL〉] + } + } + } + } + for _, n in 〈0;k〉.n { + let cps#2multi = [ + for _, c in 〈2;n〉._cs for _, cps in 〈0;c〉._ports { + 〈1;cps〉 + }, + ] + ports: [ + for _, cp in 〈1;let cps#2〉 if (〈0;cp〉.hostPort != _|_(explicit error (_|_ literal) in source)) { + port: "\(〈1;cp〉.hostPort)" + }, + ] + } + _cl: { + l: {} + } + } +} +--- reduced.cue +{ + reduced: { + A: { + x1: { + y?: int + } + } + A: { + x2: { + y?: int + } + } + A: { + x3: { + y?: int + } + } + if true { + let Z#3 = [ + for _, x in 〈2;A〉 { + 〈1;x〉 + }, + ] + B: [ + for _, z in 〈1;let Z#3〉 if (〈0;z〉.y != _|_(explicit error (_|_ literal) in source)) { + b: 1 + }, + ] + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue3929.txtar b/internal/core/compile/testdata/sync/comprehensions/issue3929.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue3929.txtar @@ -0,0 +1,299 @@ +# evalv3 regression: nested if-comprehensions inside a definition accessed via +# a for-comprehension over a pattern-constrained struct incorrectly produced an +# "incomplete value" error. The if-comprehensions (e.g. strings.HasSuffix +# guards) failed to evaluate when the definition was reached through multiple +# layers of embedding (_#cronjob → _#pod → _#container). evalv2 (v0.12.1) +# accepted the code correctly. +# https://cuelang.org/issue/3929 +-- in.cue -- +package main + +import "strings" + +reduced: { + #Input: { + @test(shareID=reducedInput) + name: string + age: "one" | "two" + if name != _|_ { + if true { + age: "one" + } + } + } + + #def1: { + IN=_in: _ + def1: #def2 & {_in: IN} + } + + #def2: { + IN=_in: _ + def2: #def3 & {_in: IN} + } + + #def3: { + _in: #Input @test(shareID=reducedInput) + def3: _in.age + } + + in: name: "foobar" + + out: (#def1 & {_in: in}).def1 + @test(eq, { + #Input: {name: string, age: "one" | "two"} + #def1: { + _in$main: _ + def1: { + _in$main: _ + def2: { + _in$main: {name: string, age: "one" | "two"} + def3: "one" | "two" + } + } + } + #def2: { + _in$main: _ + def2: { + _in$main: {name: string, age: "one" | "two"} + def3: "one" | "two" + } + } + #def3: { + _in$main: {name: string, age: "one" | "two"} + def3: "one" | "two" + } + in: {name: "foobar"} + out: { + _in$main: {name: "foobar"} + def2: { + _in$main: {name: "foobar", age: "one"} + def3: "one" + } + } + }) +} + +full: { + cronjob: [string]: #CronjobConfig + + #CronjobConfig: { + @test(shareID=cronjobConfig) + #PodConfig + } + + #PodConfig: { + @test(shareID=podConfig) + #ContainerConfig + } + + #ContainerConfig: { + @test(shareID=containerConfig) + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + if image != _|_ { + if strings.HasSuffix(image, ":latest") == true { + imagePullPolicy: "IfNotPresent" | *"Always" | "Never" + } + if strings.HasSuffix(image, ":latest") != true { + imagePullPolicy: *"IfNotPresent" | "Always" | "Never" + } + } + } + + _#cronjob: { + c=_config: #CronjobConfig @test(shareID=cronjobConfig) + + out: spec: jobTemplate: spec: template: _#pod & {_config: c} + } + + _#pod: { + c=_config: #PodConfig @test(shareID=podConfig) + + spec: containers: [{ + _#container & { + _config: c + } + }] + } + + _#container: { + c=_config: #ContainerConfig @test(shareID=containerConfig) + + imagePullPolicy: c.imagePullPolicy + } + + cronjob: "foobar": image: "foobar:latest" + + for k, v in cronjob { + objects: cronjob: "\(k)": (_#cronjob & {_config: v}).out + } + @test(eq, hint="update this once todo is fixed", { + cronjob: foobar: { + image: "foobar:latest" + imagePullPolicy: *"Always" | "IfNotPresent" | "Never" + } + #CronjobConfig: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + #PodConfig: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + #ContainerConfig: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + _#cronjob$main: { + _config$main: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + out: spec: jobTemplate: spec: template: { + _config$main: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + spec: containers: [{ + _config$main: _ @test(ignore) + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + }] + } + } + _#pod$main: { + _config$main: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + spec: containers: [{ + _config$main: _ @test(ignore) + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + }] + } + _#container$main: { + _config$main: { + image: string + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + imagePullPolicy: "IfNotPresent" | "Always" | "Never" + } + objects: cronjob: foobar: spec: jobTemplate: spec: template: { + _config$main: { + image: "foobar:latest" + imagePullPolicy: *"Always" | "IfNotPresent" | "Never" + } + spec: containers: [{ + _config$main: _ @test(ignore) + imagePullPolicy: *"Always" | "IfNotPresent" | "Never" + }] + } + }) + // TODO(inline) support at for closed. + // @test(closed, at=full.objects.cronjob.foobar) + +} +-- out/compile -- +--- in.cue +{ + reduced: { + #Input: { + name: string + age: ("one"|"two") + if (〈0;name〉 != _|_(explicit error (_|_ literal) in source)) { + if true { + age: "one" + } + } + } + #def1: { + _in(:main): _ + def1: (〈1;#def2〉 & { + _in(:main): 〈1;_in(:main)〉 + }) + } + #def2: { + _in(:main): _ + def2: (〈1;#def3〉 & { + _in(:main): 〈1;_in(:main)〉 + }) + } + #def3: { + _in(:main): 〈1;#Input〉 + def3: 〈0;_in(:main)〉.age + } + in: { + name: "foobar" + } + out: (〈0;#def1〉 & { + _in(:main): 〈1;in〉 + }).def1 + } + full: { + cronjob: { + [string]: 〈1;#CronjobConfig〉 + } + #CronjobConfig: { + 〈1;#PodConfig〉 + } + #PodConfig: { + 〈1;#ContainerConfig〉 + } + #ContainerConfig: { + image: string + imagePullPolicy: ("IfNotPresent"|"Always"|"Never") + if (〈0;image〉 != _|_(explicit error (_|_ literal) in source)) { + if (〈import;strings〉.HasSuffix(〈1;image〉, ":latest") == true) { + imagePullPolicy: ("IfNotPresent"|*"Always"|"Never") + } + if (〈import;strings〉.HasSuffix(〈1;image〉, ":latest") != true) { + imagePullPolicy: (*"IfNotPresent"|"Always"|"Never") + } + } + } + _#cronjob(:main): { + _config(:main): 〈1;#CronjobConfig〉 + out: { + spec: { + jobTemplate: { + spec: { + template: (〈5;_#pod(:main)〉 & { + _config(:main): 〈5;_config(:main)〉 + }) + } + } + } + } + } + _#pod(:main): { + _config(:main): 〈1;#PodConfig〉 + spec: { + containers: [ + { + (〈4;_#container(:main)〉 & { + _config(:main): 〈4;_config(:main)〉 + }) + }, + ] + } + } + _#container(:main): { + _config(:main): 〈1;#ContainerConfig〉 + imagePullPolicy: 〈0;_config(:main)〉.imagePullPolicy + } + cronjob: { + foobar: { + image: "foobar:latest" + } + } + for k, v in 〈0;cronjob〉 { + objects: { + cronjob: { + "\(〈3;k〉)": (〈4;_#cronjob(:main)〉 & { + _config(:main): 〈4;v〉 + }).out + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue436.txtar b/internal/core/compile/testdata/sync/comprehensions/issue436.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue436.txtar @@ -0,0 +1,47 @@ +# Tests that if-comprehensions inside a definition correctly match default +# values when the condition is satisfied. Issue #436: conditional in a definition +# unified with a concrete value was not evaluating the condition correctly. +# https://cuelang.org/issue/436 +-- in.cue -- +#a: { + val: string + result: string + @test(closed) +} + +a: #a & { + val: *"default" | string + result: *"not-matched" | string + if (val == "match") { + result: "matched" + } +} @test(eq, {val: *"default" | string, result: *"not-matched" | string}) @test(closed) + +match: a & { + val: "match" +} @test(eq, {val: "match", result: "matched"}) @test(closed) + +not: a & { + val: "other" +} @test(eq, {val: "other", result: *"not-matched" | string}) @test(closed) +-- out/compile -- +--- in.cue +{ + #a: { + val: string + result: string + } + a: (〈0;#a〉 & { + val: (*"default"|string) + result: (*"not-matched"|string) + if (〈0;val〉 == "match") { + result: "matched" + } + }) + match: (〈0;a〉 & { + val: "match" + }) + not: (〈0;a〉 & { + val: "other" + }) +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue507.txtar b/internal/core/compile/testdata/sync/comprehensions/issue507.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue507.txtar @@ -0,0 +1,59 @@ +# Tests that list comprehensions work correctly when iterating over lists with +# default values (disjunctions using *). Issue #507: comprehensions over +# [...T] | *[elem] lists failed with "invalid operand" errors. +# https://cuelang.org/issue/507 +-- in.cue -- +package x + +somelist: [...string] | *[] +// Works just fine +foo: [ + for e in somelist { + "hello foo: \(e)" + }, +] @test(eq, []) + +otherlist: ["something"] @test(eq, ["something"]) +// Works fine as well +z: [ + for e in otherlist { + "hello z: \(e)" + }, +] @test(eq, ["hello z: something"]) + +extlist: [...string] | *["something"] +bar: [ + for e in extlist { + "hello bar: \(e)" + }, +] @test(eq, ["hello bar: something"]) +-- out/compile -- +--- in.cue +{ + somelist: ([ + ...string, + ]|*[]) + foo: [ + for _, e in 〈1;somelist〉 { + "hello foo: \(〈1;e〉)" + }, + ] + otherlist: [ + "something", + ] + z: [ + for _, e in 〈1;otherlist〉 { + "hello z: \(〈1;e〉)" + }, + ] + extlist: ([ + ...string, + ]|*[ + "something", + ]) + bar: [ + for _, e in 〈1;extlist〉 { + "hello bar: \(〈1;e〉)" + }, + ] +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue837.txtar b/internal/core/compile/testdata/sync/comprehensions/issue837.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue837.txtar @@ -0,0 +1,157 @@ +# Tests that errors in definitions with complex reference chains are reported +# correctly, specifically undefined field errors via let bindings. Issue #837. +-- in.cue -- +#DeploymentManifest: #Manifest & {ref: kind: "deployment"} + +#Manifest: { + ref: #ManifestRef + description: #KumoriKinds[ref.kind] @test(err, code=incomplete, + contains="unresolved disjunction %v (type %s)", + args=["service" | "deployment", string], pos=[0:15]) +} + +#ManifestRef: kind: #KindsNames + +#KindsNames: "service" | "deployment" + +#KumoriKinds: deployment: #Deployment +#KumoriKinds: [string]: {...} + +#DoDeploy: { + _params: manifest: #DeploymentManifest + deployment: { + description: { + let dep = _params.manifest.description + service: (#Configure & { + _params: hsize: dep.hsize + }).service + @test(err, at=service.description.role, code=incomplete, + contains="undefined field: %s", args=[role], pos=[24:19]) + } + } +} + +#Configure: { + $p=_params: { + hsize: [string]: #RoleSize + } + service: { + description: { + let configed = (#RelabelService & { + _params: { + hsize: $p.hsize + } + role: "admin" + }).out + + role: configed.role @test(err, code=incomplete, + contains="undefined field: %s", args=[role], pos=[0:19]) + } + } +} + +#RelabelService: { + $p=_params: { + hsize: #RoleSize + } + + out: { + labstr: $p.label @test(err, code=eval, + contains="undefined field: %s", args=[label], pos=[0:14]) + + } +} @test(err, code=eval) + +#RoleSize: { + $_instances: >=0 | *1 +} + +#Deployment: { + service: #ServiceManifest + hsize: [service.description.#roles]: #RoleSize +} + +#ServiceManifest: #Manifest & {ref: kind: "service"} +@test(err, at=#ServiceManifest.description, code=incomplete, + contains="undefined field: %s", args=[service], pos=[-67:28]) + +-- out/compile -- +--- in.cue +{ + #DeploymentManifest: (〈0;#Manifest〉 & { + ref: { + kind: "deployment" + } + }) + #Manifest: { + ref: 〈1;#ManifestRef〉 + description: 〈1;#KumoriKinds〉[〈0;ref〉.kind] + } + #ManifestRef: { + kind: 〈1;#KindsNames〉 + } + #KindsNames: ("service"|"deployment") + #KumoriKinds: { + deployment: 〈1;#Deployment〉 + } + #KumoriKinds: { + [string]: { + ... + } + } + #DoDeploy: { + _params: { + manifest: 〈2;#DeploymentManifest〉 + } + deployment: { + description: { + let dep#1 = 〈2;_params〉.manifest.description + service: (〈3;#Configure〉 & { + _params: { + hsize: 〈2;let dep#1〉.hsize + } + }).service + } + } + } + #Configure: { + _params: { + hsize: { + [string]: 〈3;#RoleSize〉 + } + } + service: { + description: { + let configed#2 = (〈3;#RelabelService〉 & { + _params: { + hsize: 〈4;_params〉.hsize + } + role: "admin" + }).out + role: 〈0;let configed#2〉.role + } + } + } + #RelabelService: { + _params: { + hsize: 〈2;#RoleSize〉 + } + out: { + labstr: 〈1;_params〉.label + } + } + #RoleSize: { + $_instances: (>=0|*1) + } + #Deployment: { + service: 〈1;#ServiceManifest〉 + hsize: { + [〈1;service〉.description.#roles]: 〈2;#RoleSize〉 + } + } + #ServiceManifest: (〈0;#Manifest〉 & { + ref: { + kind: "service" + } + }) +} diff --git a/internal/core/compile/testdata/sync/comprehensions/issue843.txtar b/internal/core/compile/testdata/sync/comprehensions/issue843.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/issue843.txtar @@ -0,0 +1,121 @@ +# Tests that list comprehensions with definitions and nested constraints work. +# Issue #843: complex nested definition with list comprehensions and imports. +-- in.cue -- +package main + +import "list" + +#d1: { + as: [...string] + + #c: [ + #f1 & { + "as": list.Concat([["go"], as]) + }, + ] + @test(eq, { + as: [] + #c: [{ + do: "f1" + as: ["go"] + }] + }) +} + +#d2: { + p: *"." | string + + #c: [ + #f2 & { + from: #d1 & { + as: [p] + } + }, + ] + // TODO(inline): generatign this value is broken: hand-spun. + @test(eq, { + p: *"." | string + #c: [{ + do: "f2" + from: { + as: [*"."| string] + #c: [{ + do: "f1" + as: ["go", *"."| string] + }] + } + }] + }) +} + +#c1: { + #c: [...#o] + _ + ... + @test(eq, {_, #c: []}) +} + +#o: #f1 | #f2 + +#f1: { + do: "f1" + as: [...string] + @test(eq, {do: "f1", as: []}) +} + +@test(shareID=C1, at=#c1) +@test(shareID=C1, at=#f2.from) +#f2: { + do: "f2" + from: #c1 + @test(eq, {do: "f2", from: {_, #c: []}}) +} +-- out/compile -- +--- in.cue +{ + #d1: { + as: [ + ...string, + ] + #c: [ + (〈2;#f1〉 & { + as: 〈import;list〉.Concat([ + [ + "go", + ], + 〈3;as〉, + ]) + }), + ] + } + #d2: { + p: (*"."|string) + #c: [ + (〈2;#f2〉 & { + from: (〈3;#d1〉 & { + as: [ + 〈4;p〉, + ] + }) + }), + ] + } + #c1: { + #c: [ + ...〈2;#o〉, + ] + _ + ... + } + #o: (〈0;#f1〉|〈0;#f2〉) + #f1: { + do: "f1" + as: [ + ...string, + ] + } + #f2: { + do: "f2" + from: 〈1;#c1〉 + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/lists.txtar b/internal/core/compile/testdata/sync/comprehensions/lists.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/lists.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +a: [{a: 1}, {b: 2 & 3}] @test(err, code=eval, pos=[0:17, 0:21], contains="conflicting values") + +b: [for x in a {x}] @test(err, code=eval, pos=[-2:17, -2:21], contains="conflicting values") +-- out/compile -- +--- in.cue +{ + a: [ + { + a: 1 + }, + { + b: (2 & 3) + }, + ] + b: [ + for _, x in 〈1;a〉 { + 〈1;x〉 + }, + ] +} diff --git a/internal/core/compile/testdata/sync/comprehensions/multi.txtar b/internal/core/compile/testdata/sync/comprehensions/multi.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/multi.txtar @@ -0,0 +1,78 @@ +-- in.cue -- +list: [2, 3] @test(eq, [2, 3]) +a: [ 3, for x in list {x}, for x in list {x}] @test(eq, [3, 2, 3, 2, 3]) +b: [ 3, if true {3}, for x in list if x > 2 {x}] @test(eq, [3, 3, 3]) + +// issue574: Tests that if and for comprehensions inside list literals +// correctly include or exclude elements based on conditions. +// https://cuelang.org/issue/574 +issue574: { + greet: true + bye: true + + message1: [ + if greet {"hello"}, + "how are you doing?", + "bye", + ] + + message2: [ + if !greet {"hello"}, + "how are you doing?", + if bye { + "bye" + }, + ] + @test(eq, { + greet: true + bye: true + message1: ["hello", "how are you doing?", "bye"] + message2: ["how are you doing?", "bye"] + }) +} +-- out/compile -- +--- in.cue +{ + list: [ + 2, + 3, + ] + a: [ + 3, + for _, x in 〈1;list〉 { + 〈1;x〉 + }, + for _, x in 〈1;list〉 { + 〈1;x〉 + }, + ] + b: [ + 3, + if true { + 3 + }, + for _, x in 〈1;list〉 if (〈0;x〉 > 2) { + 〈1;x〉 + }, + ] + issue574: { + greet: true + bye: true + message1: [ + if 〈1;greet〉 { + "hello" + }, + "how are you doing?", + "bye", + ] + message2: [ + if !〈1;greet〉 { + "hello" + }, + "how are you doing?", + if 〈1;bye〉 { + "bye" + }, + ] + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/nested.txtar b/internal/core/compile/testdata/sync/comprehensions/nested.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/nested.txtar @@ -0,0 +1,208 @@ +# Tests that nested for comprehensions within field patterns work correctly. +# The test uses a kubernetes-like structure with services and deployments. +-- in.cue -- +package kube + +service: "node-exporter": { + spec: { + ports: [{ + name: "metrics" + port: 9100 + protocol: "TCP" + }] + } +} +deployment: "node-exporter": { + spec: template: { + spec: { + containers: [{ + ports: [{ + containerPort: 9100 + name: "scrape" + }] + }] + } + } + @test(eq, { + spec: template: spec: containers: [{ + ports: [{ + _export$kube: _ @test(ignore) + containerPort: 9100 + name: "scrape" + }] + name: string + }] + _name$kube: string + }) +} +service: [ID=string]: { + spec: { + ports: [...{ + port: int + protocol: *"TCP" | "UDP" + name: string | *"client" + }] + } +} +deployment: [ID=string]: {} +deployment: [ID=_]: _spec & {} +_spec: { + _name: string + spec: template: { + spec: containers: [{name: _name}] + } +} +_spec: spec: template: spec: containers: [...{ + ports: [...{ + _export: *true | false // include the port in the service + }] +}] +for k, v in deployment { + service: "\(k)": { + spec: selector: v.spec.template.metadata.labels + spec: ports: [ + for c in v.spec.template.spec.containers + for p in c.ports + if p._export { + let Port = p.containerPort // Port is an alias + port: *Port | int + targetPort: *Port | int + }, + ] + } +} +@test(eq, { + service: "node-exporter": spec: { + ports: [{ + name: "metrics" + port: 9100 + protocol: "TCP" + targetPort: *9100 | int + }] + selector: _|_ @test(err, code=incomplete, contains="service.\"node-exporter\".spec.selector: undefined field: metadata", pos=[59:35]) + } + deployment: "node-exporter": { + spec: template: spec: containers: [{ + ports: [{ + containerPort: 9100 + name: "scrape" + _export$kube: *true | false + }] + name: string + }] + _name$kube: string + } + _spec$kube: { + _name$kube: string + spec: template: spec: containers: [{ + name: string + ports: [] + }] + } +}) + +-- out/compile -- +--- in.cue +{ + service: { + "node-exporter": { + spec: { + ports: [ + { + name: "metrics" + port: 9100 + protocol: "TCP" + }, + ] + } + } + } + deployment: { + "node-exporter": { + spec: { + template: { + spec: { + containers: [ + { + ports: [ + { + containerPort: 9100 + name: "scrape" + }, + ] + }, + ] + } + } + } + } + } + service: { + [string]: { + spec: { + ports: [ + ...{ + port: int + protocol: (*"TCP"|"UDP") + name: (string|*"client") + }, + ] + } + } + } + deployment: { + [string]: {} + } + deployment: { + [_]: (〈1;_spec(:kube)〉 & {}) + } + _spec(:kube): { + _name(:kube): string + spec: { + template: { + spec: { + containers: [ + { + name: 〈5;_name(:kube)〉 + }, + ] + } + } + } + } + _spec(:kube): { + spec: { + template: { + spec: { + containers: [ + ...{ + ports: [ + ...{ + _export(:kube): (*true|false) + }, + ] + }, + ] + } + } + } + } + for k, v in 〈0;deployment〉 { + service: { + "\(〈2;k〉)": { + spec: { + selector: 〈4;v〉.spec.template.metadata.labels + } + spec: { + ports: [ + for _, c in 〈5;v〉.spec.template.spec.containers for _, p in 〈0;c〉.ports if 〈0;p〉._export(:kube) { + let Port#1 = 〈1;p〉.containerPort + port: (*〈0;let Port#1〉|int) + targetPort: (*〈0;let Port#1〉|int) + }, + ] + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/nested2.txtar b/internal/core/compile/testdata/sync/comprehensions/nested2.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/nested2.txtar @@ -0,0 +1,845 @@ +-- in.cue -- +given: { + INC: USD: 2.0 + USD: GBP: 3.0 + @test(eq, {INC: {USD: 2.0}, USD: {GBP: 3.0}}) +} +hydrated: { + for k, v in given { + for k1, r in v { + "\(k)": "\(k)": 1.0 + "\(k1)": "\(k1)": 1.0 + "\(k)": "\(k1)": r + "\(k1)": "\(k)": number + } + } + @test(eq, { + INC: {INC: 1.0, USD: 2.0} + USD: {USD: 1.0, INC: number, GBP: 3.0} + GBP: {GBP: 1.0, USD: number} + }) +} + +foo: { + a: 10 + if a < 20 { + if a < 50 { + b: 20 + } + } + @test(eq, {a: 10, b: 20}) +} + +indirectlyNested: { + a: true // must be declared outside of the nested comprehensions for test. + if true { + b: { + if a { + a + } + } + } + @test(eq, {a: true, b: true}) +} + +directlyNestedEmpty: { + a: true + if true { + if a { + } + } + @test(eq, {a: true}) +} + +directlyDoublyNestedEmpty: { + a: true + if true { + if a { + } + } + @test(eq, {a: true}) +} + +indirectlyDoublyNestedEmpty: { + a: true + b: { + if true { + if a { + if a { + a + } + } + if a { + a + } + } + } + @test(eq, {a: true, b: true}) +} + +indirectlyDoublyNested: { + a: true + if true { + if a { + if a { + b: 1 + } + } + if a { + c: 1 + } + } + @test(eq, {a: true, c: 1, b: 1}) +} + +// This case used to trigger an over-aggressive deduplication. +// issue1974: Tests that two-level nested for comprehensions do not lose keys +// due to over-aggressive deduplication. https://cuelang.org/issue/1974 +issue1974: { + X: { + foo: { + bar: "" + baz: "" + } + } + out: { + for k, v in X for vk, vv in v { + "\(k)": "\(vk)": vv + } + } + @test(eq, { + X: {foo: {bar: "", baz: ""}} + out: {foo: {bar: "", baz: ""}} + }) +} +-- pending.cue -- +// Trigger notification while an arc is still pending. +T: int @test(eq, 1) +for C in Y { + let X = C.M + T: X.V +} +Y: x: { + M: V: 1 + for _ in M { + if true { M: {} } + } + @test(eq, {M: {V: 1}}) +} +-- issue3940.cue -- +// issue3940: Tests that chained comprehension clauses do not trigger spurious +// structural cycle errors in evalv3. https://cuelang.org/issue/3940 +// Test chained comprehension clauses (without braces) +issue3940: reduced1: { + X + a: b: X + a: b: a: b: {y: X @test(shareID=reduced1X)} + + X: { + @test(shareID=reduced1X) + a: {} + + objects: { + for v in a + for _ in ({} & v).objects { + } + } + } + + // The eq:todo value is now the correct result: the pushdown fix + // properly handles chained comprehension clauses, unifying a.b + // into a single struct. + @test(eq, { + a: { + b: { + a: {b: {y: {a: {}, objects: {}}}} + objects: _|_ @test(err, code=incomplete, contains="issue3940.reduced1.a.b.objects: undefined field: objects", pos=[15:22]) + } + } + X: {a: {}, objects: {}} + objects: {} + }) + @test(eq:todo, { + a: b: { + a: {b: {y: {a: {}, objects: {}}}} + objects: {} + } + X: {a: {}, objects: {}} + objects: {} + }) +} + +// Test nested comprehensions (with braces) - should work as before +issue3940: reduced2: { + X + a: b: X + a: b: a: b: {y: X @test(shareID=reduced2X)} + + X: { + @test(shareID=reduced2X) + a: {} + + objects: { + for v in a + for _ in ({} & v).objects { + } + } + } + // The pushdown fix resolves the spurious "undefined field" error + // on objects: reduced2 is structurally identical to reduced1 and + // should produce the same result. + @test(eq, { + a: { + b: { + a: {b: {y: {a: {}, objects: {}}}} + objects: _|_ + } + } + X: {a: {}, objects: {}} + objects: {} + }) + @test(eq:todo, { + a: { + b: { + a: {b: {y: {a: {}, objects: {}}}} + objects: {} + } + } + X: {a: {}, objects: {}} + objects: {} + }) +} +issue3940: reduced3: { + a: E + a: i: x: E + a: i: x: i: x: E + E: { + i: {} + o: [for m in i for v in ({} & m).o {}] + } + @test(eq, { + a: { + i: {x: {i: {x: {i: {}, o: []}}, o: []}} + o: [] + } + E: {i: {}, o: []} + }) + +} +issue3940: reduced4: { + out: Exporter & { + _imports: [{ + objects: {...} + #export: Exporter & { + _imports: [{ #export: Exporter }] + } + }] + } + + Exporter: { + _imports: [...] + objects: [ + for v in _imports for obj in ({} & v.#export).objects { + obj + }, + ] + } + @test(eq, { + out: { + _imports: [{ + objects: {} + #export: { + _imports: [{ + #export: { + _imports: [] + objects: [] + } + }] + objects: [] + } + }] + objects: [] + } + Exporter: {_imports: [], objects: []} + }) +} +issue3940: let: { + X + a: b: X + a: b: a: b: {y: X @test(shareID=letX)} + + X: { + @test(shareID=letX) + a: {} + + objects: { + for v in a + let x = ({} & v) + for _ in x.objects { + } + } + } +} +issue3940: full: { + out: #Exporter & { + _imports: [_branch] + #conf: global: region: "Europe" + } + + _branch: { + objects: branch: { + #conf: {...} + region: #conf.global.region + } + imports: [_leaf] + #export: #Exporter & { + _objects: objects + _imports: imports + } + } + _leaf: { + objects: leaf: { + #conf: {...} + region: #conf.global.region + } + #export: #Exporter & { + _objects: objects + } + } + #Exporter: { + CONF=#conf: {...} + _objects: {...} + _imports: [...] + + objects: [ + // local objects + for name, obj in _objects & {[string]: #conf: CONF} { + (name): obj + }, + + // transitively imported objects + for import in _imports + for obj in ({#conf: CONF} & import.#export).objects { + obj + }, + ] + } + @test(eq, at=out, { + _imports: [{ + objects: branch: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + imports: [{ + objects: leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + #export: { + _objects: leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + #conf: _ @test(ignore) + _imports: [] + objects: [{ + leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + }] + } + }] + #export: { + _objects: branch: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + _imports: [{ + objects: leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + #export: { + _objects: leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + #conf: _ @test(ignore) + _imports: [] + objects: [{ + leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + }] + } + }] + #conf: _ @test(ignore) + objects: [{ + branch: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + }, { + leaf: { + #conf: _ @test(ignore) + region: _|_ @test(err, code=incomplete, contains="undefined field: global") + } + }] + } + }] + #conf: {global: {region: "Europe"}} + _objects: {} + objects: [{ + branch: { + #conf: {global: {region: "Europe"}} + region: "Europe" + } + }, { + leaf: { + #conf: {global: {region: "Europe"}} + region: "Europe" + } + }] + }) +} +-- issue3990.cue -- +// issue3990: Tests that nested comprehensions within struct definitions do not +// trigger "field set was already referenced" errors in evalv3. +// https://cuelang.org/issue/3990 +issue3990: { + _imports: [_noVolumes, _someVolumes] + _noVolumes: { + name: "noVolumes" + exportObjs: deployment: _Deployment & { + volumes: [] + } + } + _someVolumes: { + name: "someVolumes" + exportObjs: deployment: _Deployment & { + volumes: [{name: "data"}] + } + } + + for import in _imports + for _, obj in ({extra: "unused"} & import).exportObjs {(import.name): obj}, + + _Deployment: this={ + _names: { + for _, v in this.volumes { + (v.name): v.name + } + } + // skip volumeNames if empty + if len(_names) > 0 { + volumeNames: [for _, v in _names {v}] + } + } + @test(eq, { + _imports: [{ + name: "noVolumes" + exportObjs: deployment: {volumes: [], _names: {}} + }, { + name: "someVolumes" + exportObjs: deployment: { + _names: {data: "data"} + volumeNames: ["data"] + volumes: [{ + name: "data" + }] + } + }] + _noVolumes: { + name: "noVolumes" + exportObjs: {deployment: {volumes: [], _names: {}}} + } + _someVolumes: { + name: "someVolumes" + exportObjs: { + deployment: { + volumes: [{ name: "data" }] + _names: {data: "data"} + volumeNames: ["data"] + } + } + } + _Deployment: { + _names: _|_ @test(err, code=incomplete) + } + someVolumes: { + volumes: [{ name: "data" }] + _names: {data: "data"} + volumeNames: ["data"] + } + noVolumes: {volumes: [], _names: {}} + }) +} +-- out/compile -- +--- in.cue +{ + given: { + INC: { + USD: 2.0 + } + USD: { + GBP: 3.0 + } + } + hydrated: { + for k, v in 〈1;given〉 { + for k1, r in 〈1;v〉 { + "\(〈3;k〉)": { + "\(〈4;k〉)": 1.0 + } + "\(〈1;k1〉)": { + "\(〈2;k1〉)": 1.0 + } + "\(〈3;k〉)": { + "\(〈2;k1〉)": 〈2;r〉 + } + "\(〈1;k1〉)": { + "\(〈4;k〉)": number + } + } + } + } + foo: { + a: 10 + if (〈0;a〉 < 20) { + if (〈1;a〉 < 50) { + b: 20 + } + } + } + indirectlyNested: { + a: true + if true { + b: { + if 〈2;a〉 { + 〈3;a〉 + } + } + } + } + directlyNestedEmpty: { + a: true + if true { + if 〈1;a〉 {} + } + } + directlyDoublyNestedEmpty: { + a: true + if true { + if 〈1;a〉 {} + } + } + indirectlyDoublyNestedEmpty: { + a: true + b: { + if true { + if 〈2;a〉 { + if 〈3;a〉 { + 〈4;a〉 + } + } + if 〈2;a〉 { + 〈3;a〉 + } + } + } + } + indirectlyDoublyNested: { + a: true + if true { + if 〈1;a〉 { + if 〈2;a〉 { + b: 1 + } + } + if 〈1;a〉 { + c: 1 + } + } + } + issue1974: { + X: { + foo: { + bar: "" + baz: "" + } + } + out: { + for k, v in 〈1;X〉 for vk, vv in 〈0;v〉 { + "\(〈2;k〉)": { + "\(〈2;vk〉)": 〈2;vv〉 + } + } + } + } +} +--- issue3940.cue +{ + issue3940: { + reduced1: { + 〈0;X〉 + a: { + b: 〈1;X〉 + } + a: { + b: { + a: { + b: { + y: 〈4;X〉 + } + } + } + } + X: { + a: {} + objects: { + for _, v in 〈1;a〉 for _, _ in ({} & 〈0;v〉).objects {} + } + } + } + } + issue3940: { + reduced2: { + 〈0;X〉 + a: { + b: 〈1;X〉 + } + a: { + b: { + a: { + b: { + y: 〈4;X〉 + } + } + } + } + X: { + a: {} + objects: { + for _, v in 〈1;a〉 for _, _ in ({} & 〈0;v〉).objects {} + } + } + } + } + issue3940: { + reduced3: { + a: 〈0;E〉 + a: { + i: { + x: 〈2;E〉 + } + } + a: { + i: { + x: { + i: { + x: 〈4;E〉 + } + } + } + } + E: { + i: {} + o: [ + for _, m in 〈1;i〉 for _, v in ({} & 〈0;m〉).o {}, + ] + } + } + } + issue3940: { + reduced4: { + out: (〈0;Exporter〉 & { + _imports: [ + { + objects: { + ... + } + #export: (〈3;Exporter〉 & { + _imports: [ + { + #export: 〈6;Exporter〉 + }, + ] + }) + }, + ] + }) + Exporter: { + _imports: [ + ..., + ] + objects: [ + for _, v in 〈1;_imports〉 for _, obj in ({} & 〈0;v〉.#export).objects { + 〈1;obj〉 + }, + ] + } + } + } + issue3940: { + let: { + 〈0;X〉 + a: { + b: 〈1;X〉 + } + a: { + b: { + a: { + b: { + y: 〈4;X〉 + } + } + } + } + X: { + a: {} + objects: { + for _, v in 〈1;a〉 let x = ({} & 〈0;v〉) for _, _ in 〈0;x〉.objects {} + } + } + } + } + issue3940: { + full: { + out: (〈0;#Exporter〉 & { + _imports: [ + 〈2;_branch〉, + ] + #conf: { + global: { + region: "Europe" + } + } + }) + _branch: { + objects: { + branch: { + #conf: { + ... + } + region: 〈0;#conf〉.global.region + } + } + imports: [ + 〈2;_leaf〉, + ] + #export: (〈1;#Exporter〉 & { + _objects: 〈1;objects〉 + _imports: 〈1;imports〉 + }) + } + _leaf: { + objects: { + leaf: { + #conf: { + ... + } + region: 〈0;#conf〉.global.region + } + } + #export: (〈1;#Exporter〉 & { + _objects: 〈1;objects〉 + }) + } + #Exporter: { + #conf: { + ... + } + _objects: { + ... + } + _imports: [ + ..., + ] + objects: [ + for name, obj in (〈1;_objects〉 & { + [string]: { + #conf: 〈3;#conf〉 + } + }) { + 〈1;name〉: 〈1;obj〉 + }, + for _, import in 〈1;_imports〉 for _, obj in ({ + #conf: 〈3;#conf〉 + } & 〈0;import〉.#export).objects { + 〈1;obj〉 + }, + ] + } + } + } +} +--- issue3990.cue +{ + issue3990: { + _imports: [ + 〈1;_noVolumes〉, + 〈1;_someVolumes〉, + ] + _noVolumes: { + name: "noVolumes" + exportObjs: { + deployment: (〈2;_Deployment〉 & { + volumes: [] + }) + } + } + _someVolumes: { + name: "someVolumes" + exportObjs: { + deployment: (〈2;_Deployment〉 & { + volumes: [ + { + name: "data" + }, + ] + }) + } + } + for _, import in 〈0;_imports〉 for _, obj in ({ + extra: "unused" + } & 〈0;import〉).exportObjs { + 〈2;import〉.name: 〈1;obj〉 + } + _Deployment: { + _names: { + for _, v in 〈2〉.volumes { + 〈1;v〉.name: 〈1;v〉.name + } + } + if (len(〈0;_names〉) > 0) { + volumeNames: [ + for _, v in 〈2;_names〉 { + 〈1;v〉 + }, + ] + } + } + } +} +--- pending.cue +{ + T: int + for _, C in 〈0;Y〉 { + let X#1multi = 〈1;C〉.M + T: 〈0;let X#1〉.V + } + Y: { + x: { + M: { + V: 1 + } + for _, _ in 〈0;M〉 { + if true { + M: {} + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/nestembed.txtar b/internal/core/compile/testdata/sync/comprehensions/nestembed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/nestembed.txtar @@ -0,0 +1,51 @@ +Issue #556 +# Issue #556: Tests that nested comprehensions with list.Contains filtering +# correctly produces only the non-deleted entries. +-- in.cue -- +import "list" + +DeleteThis: ["this", "that"] @test(eq, ["this", "that"]) +useful_infra: { + gcp: cluters: 10 + aws: clusters: 20 + this: clusters: 1 + that: clusters: 2 + @test(eq, {gcp: {cluters: 10}, aws: {clusters: 20}, this: {clusters: 1}, that: {clusters: 2}}) +} +New_infra: { + for k, v in useful_infra { + if !list.Contains(DeleteThis, k) { + "\(k)": v + } + } + @test(eq, {gcp: {cluters: 10}, aws: {clusters: 20}}) +} +-- out/compile -- +--- in.cue +{ + DeleteThis: [ + "this", + "that", + ] + useful_infra: { + gcp: { + cluters: 10 + } + aws: { + clusters: 20 + } + this: { + clusters: 1 + } + that: { + clusters: 2 + } + } + New_infra: { + for k, v in 〈1;useful_infra〉 { + if !〈import;list〉.Contains(〈3;DeleteThis〉, 〈1;k〉) { + "\(〈2;k〉)": 〈2;v〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/open_iter_writeback.txtar b/internal/core/compile/testdata/sync/comprehensions/open_iter_writeback.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/open_iter_writeback.txtar @@ -0,0 +1,77 @@ +# Regression coverage for the original bug behind deferFieldSetKnown +# (commit f1f0c649f, "adt: fix premature fieldSetKnown freeze for open +# structs"). The motivating pattern: a comprehension iterates an open +# struct (HasEllipsis=true) and the comprehension body adds arcs back +# to that struct. +# +# Two cases: +# - openIter: a sibling comprehension iterates the same open struct +# that another for-clause is writing into. The for-loop must observe +# the source's full final field set, not a snapshot frozen mid- +# evaluation. +# - defOpen: an external conjunct (`inst: #T & { b: 2 }`) adds a field +# to an open definition whose own body conditionally adds another; +# a [for] over `inst` must see both arcs. +-- in.cue -- +openIter: { + src: { + a: 1 + b: 2 + ... + if true { c: 3 } + } + keys: [for k, _ in src { k }] + @test(eq, { + src: {a: 1, b: 2, c: 3, ...} + keys: ["a", "b", "c"] + }) +} + +defOpen: { + #T: { + [string]: int + if true { a: 1 } + } + inst: #T & { b: 2 } + keys: [for k, _ in inst { k }] + @test(eq, { + #T: {[string]: int, a: 1} + inst: {a: 1, b: 2} + keys: ["b", "a"] + }) +} +-- out/compile -- +--- in.cue +{ + openIter: { + src: { + a: 1 + b: 2 + ... + if true { + c: 3 + } + } + keys: [ + for k, _ in 〈1;src〉 { + 〈1;k〉 + }, + ] + } + defOpen: { + #T: { + [string]: int + if true { + a: 1 + } + } + inst: (〈0;#T〉 & { + b: 2 + }) + keys: [ + for k, _ in 〈1;inst〉 { + 〈1;k〉 + }, + ] + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/optional_ref_yield.txtar b/internal/core/compile/testdata/sync/comprehensions/optional_ref_yield.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/optional_ref_yield.txtar @@ -0,0 +1,91 @@ +# Tests that the yield-on-running heuristic in OpContext.evalState (expr.go) +# fires uniformly for any IncompleteError whose target node is currently +# being evaluated, regardless of whether the missing field is an +# ArcPending placeholder created by a pushed-down comprehension or an +# ArcOptional declaration that may yet be upgraded to a member. +# +# To exercise the yield, the reference must resolve while the target +# vertex itself is still mid-evaluation. The constructions below place +# the reference *inside* the target struct so its task fires before +# the sibling comprehension/declaration that produces the field. +-- cue.mod/module.cue -- +module: "mod.test" + +language: version: "v0.15.0" + +-- in.cue -- +// Test A: a self-reference picks up an optional field that gets upgraded to +// a member by a sibling comprehension. The reference (bar) fires before the +// comp body has run, so bar's lookup of x.foo initially returns ArcOptional +// (IncompleteError). The yield-on-running heuristic must fire so that bar +// re-resolves once foo is materialized as a member. +optionalUpgradesViaSiblingComp: { + x: { + bar: x.foo + foo?: int + if true { + foo: 5 + } + } + x: bar: int @test(eq, 5) +} + +// Test B: a self-reference to an optional field that stays optional +// permanently. The yield is harmless: after waiting for x's valueKnown the +// field is still optional and the result is the same incomplete error. +optionalStaysOptional: { + x: { + bar: x.foo + foo?: int + } + x: bar: _ @test(err, code=incomplete, contains="cannot reference optional field") +} + +// Test C: regression for the original ArcPending case — a self-reference +// to a member produced by a pushed-down comprehension. This is what the +// yield-on-running heuristic was originally introduced for. +pendingBecomesMember: { + x: { + bar: x.foo + if true { + foo: 5 + } + } + x: bar: int @test(eq, 5) +} +-- out/compile -- +--- in.cue +{ + optionalUpgradesViaSiblingComp: { + x: { + bar: 〈1;x〉.foo + foo?: int + if true { + foo: 5 + } + } + x: { + bar: int + } + } + optionalStaysOptional: { + x: { + bar: 〈1;x〉.foo + foo?: int + } + x: { + bar: _ + } + } + pendingBecomesMember: { + x: { + bar: 〈1;x〉.foo + if true { + foo: 5 + } + } + x: { + bar: int + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/pushdown.txtar b/internal/core/compile/testdata/sync/comprehensions/pushdown.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/pushdown.txtar @@ -0,0 +1,2868 @@ +# Working set of tests that unit test specifics of the aspect of the +# comprehension algorithm that pushes down evaluation to the arcs. +-- in.cue -- +linkChildren: { + w: 1 + v: { + x: 1 + if true { + y: 1 + if true { + z: 1 + + rw: w + rx: x + ry: y + rz: z + + n1a: na: [w, x, y, z] + n2a: n1a: na: [w, x, y, z] + n2z: n1z: nz: z + } + } + } + @test(eq, { + w: 1 + v: { + x: 1 + y: 1 + z: 1 + rw: 1 + rx: 1 + ry: 1 + rz: 1 + n1a: {na: [1, 1, 1, 1]} + n2a: {n1a: {na: [1, 1, 1, 1]}} + n2z: {n1z: {nz: 1}} + } + }) +} + +fail: { + a: { + // Condition of comprehensions must still hold after its evaluation. + // + // `b` is not defined, causing this if comprehension to evaluate to + // true. However, after inserting the corresponding result in curly + // braces, the condition would be true. This is not allowed. + if a.b == _|_ { + b: 1 + } + } @test(err, code=incomplete|cycle) +} + +embed: { + fail1: #C1 @test(err, code=eval, path=p, contains="field not allowed") + #C1: { + // TODO(errors): don't include all positions of p in the normal list of + // positions, or rather categorize the positions to show: + // 1) position of denied fields + // 2) position of structs that deny them + // 3) points at which those structs where mixed in (perhaps as tree) + // 4) conditionals that could enable allowing a field. + if false { + p: _ + } + } + fail1: p: "foo" // this should fail, as p is not present. + + + success2: #C2 @test(eq, {p: "foo"}) + #C2: { + if true { + p: _ + } + } + success2: p: "foo" // this succeeds as p is present. + + success3: #C3 @test(eq, {}) + #C3: {} + success3: { + if false { + // p does not exist in success3, but it is okay, as it is not added. + p: q: 1 + } + } + + success4: { + #X: y: string + x: y: string + x: { + for _ in ["iter-once"] { + #X + if false { + y: "foo" + } + } + } + } @test(eq, {#X: {y: string}, x: {y: string}}) + + fail4: #C4 + #C4: {} + fail4: { + if true { + // error as p is not allowed in fail4 + p: q: 1 + } + } @test(err, code=eval, path=p, contains="field not allowed", pos=[3:4]) + + incomplete5: { + a: bool + if a { + p: q: 1 + } + } @test(err, code=incomplete, contains="incomplete %s: %s", args=[bool, bool], pos=[1:6]) + + incomplete6: { + if false { + p: 1 + } + p: q + 1 + q: int + } @test(eq, { + p: _|_ @test(err, code=incomplete, contains="embed.incomplete6.p: non-concrete value int in operand to +", pos=[117:6, 118:6]) + q: int + }) + incomplete7: { + p: q + 1 + q: int + if false { + q: 1 // do not inadvertently pick up a void arc. + } + } @test(eq, { + p: _|_ @test(err, code=incomplete, contains="non-concrete value int") + // TODO(inline): do not fail on todo with position mismatch. @test(err:todo, pos=[124:6, 125:6, 126:3]) + q: int + }) +} + +// Mix of both dynamic and static fields. +mixedFieldsSuccess: { + a: { + for _, s in ["foo"] { + "\(s)": 1 + X: 1 + } + } + + b: #Def: { + for _, s in ["foo"] { + "\(s)": 1 + X: 1 + } + } + b: x: b.#Def + b: x: X: _ + b: x: foo: _ + + + c: #Def: { + X: int + foo: int + } + c: x: c.#Def + c: x: { + for _, s in ["foo"] { + "\(s)": 1 + X: 1 + } + } + @test(eq, { + a: {X: 1, foo: 1} + b: { + #Def: {X: 1, foo: 1} + x: {X: 1, foo: 1} + } + c: { + #Def: {X: int, foo: int} + x: {X: 1, foo: 1} + } + }) +} + +// fieldMismatch tests that an embedded scalar cannot be mixed with regular +// fields, even if they are added by a comprehension. +fieldMismatch: { + a: { + 2 + if true { + x: 3 + } + } + @test(err, code=eval, at=a, hint="int with struct") +} + +// b12aStructCycle presents a case that can easily lead to stack overflow in +// a naive implementation. It corresponds to test b12a in structural.txtar. +noStackOverflowStructCycle: { + #list: { + tail: #list + + if tail != null { + sum: tail.sum + } + } + + list: { + tail: list + + if tail != null { + sum: tail.sum + } + } + @test(err, code=structural_cycle, at="#list.tail", contains="structural cycle", pos=[]) +} + + +// #a is incomplete, but the missing values are provided by x. +provideIncompleteSuccess: { + t1: { + #a: { + if b { + c: 4 + } + b: bool + } + x: (#a & {b: true}) & {c: 4} + y: x + @test(eq, { + #a: {_|_, b: bool} + x: {b: true, c: 4} + y: {b: true, c: 4} + }) + } + + t2: { + // c should be allowed + #a: { + if b { + c: 4 + } + b: true + } @test(eq, {c: 4, b: true}) + + #c: {} + a: { + if b { + c: d: 4 + } + b: true + // d is disallowed, even though it is added by embedding. + // TODO: this seems right, but it may be good to clarify why. + c: #c @test(err, code=eval, at=d, contains="field not allowed", pos=[-5:8]) + } + } +} + +// voidArcs tests that fields are dropped and reference up counts are adjusted +// appropriately under various rewrite scenario. +voidArcs: { + scopes: { + x: 1 + a: { + y: 2 + if true { + b: x + c: d: x + e: y + f: g: y + } + } + } + + drop: { + x: 1 + a: { + y: 2 + if false { + b: x + c: d: x + e: y + f: g: y + } + } + } + @test(eq, { + scopes: { + x: 1 + a: {y: 2, b: 1, c: {d: 1}, e: 2, f: {g: 2}} + } + drop: {x: 1, a: {y: 2}} + }) +} + +cyclicError: { + a: { + // With pushdown, x and y remain bool (incomplete) rather than + // erroring: the if guards cannot resolve bool to a concrete + // value, so the comprehension bodies simply do not fire. + @test(err, code=incomplete) + x: bool + y: bool + if a.x { + y: true + } + if a.y { + x: true + } + b: {} + } + // With pushdown, evaluating a.b no longer forces a cycle error + // because the comprehension dependencies are pushed down to the + // individual fields rather than blocking the parent. + c: a.b @test(err, code=incomplete|cycle) + @test(eq, { + a: { + x: _|_ + y: _|_ + b: {} + } + c: _|_ + }) +} + +midwayReferences: { + a: { + for i, j in {a: 1, b: 2} { + x: y: z: (i): j + } + x: y: {} + } + b: a.x + c: a.x.y + d: a.x.y.z + @test(eq, { + a: {x: {y: {z: {a: 1, b: 2}}}} + b: {y: {z: {a: 1, b: 2}}} + c: {z: {a: 1, b: 2}} + d: {a: 1, b: 2} + }) +} + +// Ensure first closedness check is done after evaluation of +// comprehensions. +closedCheck: success1: { + a: b: [string]: #D + + #D: { + d: string + if d != "c" { + e: string + } + } + + a: b: c: { + d: "d" + e: "ok" + } + @test(eq, { + a: {b: {c: {d: "d", e: "ok"}}} + #D: {d: string} + }) +} + +closedCheck: success2: { + a: b: [string]: #D + + #D: { + d: string + if d != "c" { + ("foo"+"bar"): string + } + } + + a: b: c: { + d: "d" + foobar: "ok" + } + @test(eq, { + a: {b: {c: {d: "d", foobar: "ok"}}} + #D: {d: string} + }) +} + +closedCheck: success3: { + a: b: [string]: #D + + #D: { + d: string + e: { + if d != "c" { + string + } + @test(err, code=incomplete, contains="non-concrete value", pos=[1:7, -1:6]) + } + } + + a: b: c: { + d: "d" + e: "ok" + } + @test(eq, { + a: {b: {c: {d: "d", e: "ok"}}} + #D: { + d: string + e: _|_ + } + }) +} + +emptyComprehensionIncomplete: { + a: {} + b: { + // b should be an incomplete error + if a.b { + } + } @test(err, code=incomplete, contains="undefined field: %s", args=[b], pos=[2:8]) + @test(eq, { + a: {} + b: _|_ + }) +} + +// voidEliminationSuccess tests that "conditional" or "void" arcs are eliminated +// if their expression does not yield any result. +voidEliminationSuccess: t1: { + [string]: { + b: bool + if !b {} + } + if false { + a: b: true + } + @test(eq, {}) +} + +voidEliminationSuccess: t2: { + components: { + sinks: [string]: #C & { + kind: string + configuration: { + if kind != "source" { + inputs: { + required: true + } + } + } + } + + #C: { + kind: string + configuration: [string]: { + required: bool + if !required { + common: bool + } + } + } + } + + components: sinks: blah: { + kind: "source" + } + @test(eq, { + components: { + sinks: { + blah: {kind: "source", configuration: {}} + } + #C: {kind: string, configuration: {}} + } + }) +} + +voidEliminationSuccess: derefRef1: { + a: [string]: c: [string]: E + + a: b: c: { + if false { + d: e: true // resolves + } + } + + E: { + e: bool + f: !e @test(err, code=incomplete, contains="not concrete", pos=[0:7]) + } + @test(eq, { + a: {b: {c: {}}} + E: { + e: bool + f: _|_ + } + }) +} + +voidEliminationSuccess: derefRef2: { + a: [string]: c: [string]: E + + a: b: c: { + if false { + d: e: true // resolves + } + } + + E: #F + #F: { + e: bool + f: !e @test(err, code=incomplete, contains="not concrete", pos=[0:7]) + } + @test(eq, { + a: {b: {c: {}}} + E: { + e: bool + f: _|_ + } + #F: { + e: bool + f: _|_ @test(err, code=incomplete) + } + }) +} + +voidEliminationSuccess: derefDisj1: { + a: [string]: c: [string]: E + + a: b: c: { + if false { + d: e: true + } + } + + E: { + e: bool + f: !e + } | { + g: bool + h: !g + } + @test(eq, { + a: {b: {c: {}}} + E: _|_ @test(err, code=incomplete, contains="voidEliminationSuccess.derefDisj1.E: 2 errors in empty disjunction: (and 2 more errors)", pos=[]) + }) +} + +voidEliminationSuccess: derefDisj2: { + a: [string]: c: [string]: E & E + + a: b: c: { + if false { + d: e: true + } + } + + E: { + e: bool + f: !e + } | { + g: bool + h: !g + } + @test(eq, { + a: {b: {c: {}}} + E: _|_ @test(err, code=incomplete, contains="voidEliminationSuccess.derefDisj2.E: 2 errors in empty disjunction: (and 2 more errors)", pos=[]) + }) +} + +voidEliminationSuccess: bulk1: { + a: b: {} + a: [string]: { + c: { + e: string + if false { + e: "" + } + } + d: c.e + } + @test(eq, {a: {b: {c: {e: string}, d: string}}}) +} + +voidEliminationSuccess: opt1: { + a: b: {} + a: b?: { + c: { + e: string + if false { + e: "" + } + } + d: c.e + } + @test(eq, {a: {b: {c: {e: string}, d: string}}}) +} + +voidEliminationSuccess: noCycle1: { + _x: a.b + a: { + c: h: "stream" + b: { + if c.g != _|_ {} + } + c: { + if false {g: _} + } + } + @test(eq, {_x: {}, a: {c: {h: "stream"}, b: {}}}) +} + +voidEliminationSuccess: noCycle2: { + a: { + c: h: "stream" + b: { + if c.g != _|_ {} + } + c: { + if false {g: _} + } + } + _x: a.b + @test(eq, {a: {c: {h: "stream"}, b: {}}, _x: {}}) +} + +voidLookup: { + a: x: z: a.y.z.void + + a: y: { + c: _ + z: {} + } + + a: [string]: { + c: { + for k, v in z { + (k): null // don't add this arc anywhere + } + } + z: { + if false { + err: {} + } + } + } + @test(eq, { + a: { + x: { + z: _|_ + c: _|_ + } + y: {c: _, z: {}} + } + }) + @test(err, at=a.x.z, code=incomplete, + contains="undefined field: %s", args=[void], pos=[1:17]) + @test(err, at=a.x.c, code=incomplete, + path=voidLookup.a.x.z, contains="undefined field: %s", args=[void], pos=[1:17]) +} + + +// Eliminate the top value even if there is an error (especially incomplete +// errors). +topElimination: { + a: int + _ + if true { + x: a+1 + } + @test(eq, { + a: int + x: _|_ + }) + @test(err, at=x, code=incomplete, contains="non-concrete value %v in operand to %s", args=[int, +], pos=[4:6, 1:5]) +} + +voidEliminationSuccess: drop1: { + // Do not include x in s. + t: { + #ok: *true | bool + if #ok { + x: int + } + } + s: t & { + #ok: false + } + @test(eq, { + t: {#ok: *true | bool, x: int} + s: {#ok: false} + }) +} + +// should be error +// issue #465 +explicitDefaultError: { + a: string | *_|_ + + if a != "" { + } + @test(err, code=incomplete, contains="non-concrete value string", pos=[3:5, 1:5]) +} + +// Remove arcs for with no for comprehension results. +allArcsSuccess: p1: { + x: { + for k, _ in y { + (k): null + } + } + y: { + if false { + x: {} + } + } + @test(eq, {x: {}, y: {}}) +} + +allArcsSuccess: p2: { + y: { + if false { + x: {} + } + } + x: { + for k, _ in y { + (k): null + } + } + @test(eq, {y: {}, x: {}}) +} + +structShare: ok1: { + a: [string]: E + E: {} + + a: { + if true { + d: e: true // resolves + } + } + @test(eq, {a: {d: {e: true}}, E: {}}) +} + +structShare: err1: { + x: [string]: x.#E + x: #E: {} + if true { + x: d: e: true + } + @test(err, code=eval, at=x.d.e, contains="field not allowed", pos=[4:9]) +} + +-- issue2208.cue -- +// Regression where definitions that compiled correctly with 0.4.3 failed to +// compile with 0.5.0-beta.2 due to incorrect handling of void errors. +// https://cuelang.org/issue/2208 +voidErrorIncomplete: { + #Schema: [string]: { + required: bool + if !required { + } + } + + root: #Schema + root: { + if false { + child: required: false + } + } + @test(eq, {#Schema: {}, root: {}}) +} + +// TODO: should these always be errors, or only for cue vet? +// voidErrorFatal: pattern: { +// #Schema: [string]: { +// if "str" + 3 { +// } +// } +// +// root: #Schema +// root: { +// if false { +// child: required: false +// } +// } +// } +// +// voidErrorFatal: field: { +// root: { +// if false { +// child: 2 + "str" +// } +// } +// } + + +-- issue1759.cue -- +// Tests that len() and comprehensions correctly see the full struct/list value. +// https://cuelang.org/issue/1759 +// Tests derived from Unity. +unity: success1: { + #Config: { + name: string + type: string + } + + #AnyConfig: { + #Config + ... + } + + #Env: { + name: string + configurations: [string]: #AnyConfig + } + + envs: "e1": #Env & { + configurations: c1: #Config + } + + envs: [string]: configurations: [string]: { + type: "foo" + if type == "terraform" { + backend: { + type: "s3" + } + } + } + @test(eq, { + #Config: {name: string, type: string} + #AnyConfig: {name: string, type: string} + #Env: {name: string, configurations: {}} + envs: { + e1: { + configurations: {c1: {type: "foo", name: string}} + name: string + } + } + }) +} + +// issue1759: Tests that len() correctly sees the full struct value when +// used as a comprehension condition. https://cuelang.org/issue/1759 +issue1759: { + _ports_map: {} + if len(_ports_map) > 0 { + port: _ports_map.a.port + } + if true { + _ports_map: a: {port: "80"} + } + @test(eq, { + _ports_map: {a: {port: "80"}} + port: "80" + }) +} + +arcAlignment: t1: { + [string]: { + if true { } + } + if false { + c: _ + } + @test(eq, {}) +} + +-- issue2111.cue -- +// Evaluator regression where circular dependency in evaluation of conditionals +// caused incorrect results. All arc types, not just regular fields, should be pushed down. +// https://cuelang.org/issue/2111 +letPushdown: { + _c: y: 1 + + a: { + for k, v in _c { + let x = v + if x != _|_ { + } + } + } + @test(eq, {_c: {y: 1}, a: {}}) +} + +-- issue2113.cue -- +// Evaluator regression where a nested comprehension caused "was already used" +// errors when the enclosing value was not yet fully evaluated. +// https://cuelang.org/issue/2113 +// Ensure that an enclosing Value clause of a nested comprehension is evaluated +// before the nested comprehension itself is evaluated. +nestedWithEmbeddingOK: { + c: [1] + a: { + for k, v in c { + {x: 1} + if a.x != _|_ { + } + } + } + @test(eq, {c: [1], a: {x: 1}}) +} + +nestedWithDynamicFieldOK: { + _c: y: 1 + + a: { + for k, v in _c { + if x != _|_ { + } + x="\(k)": 1 + } + } + @test(eq, {_c: {y: 1}, a: {y: 1}}) +} + +// Errors in nested comprehensions should also be reported. +errorPropagation: { + deployment: _ + for k, v in deployment { + for k1, v2 in v.env2 { // Report this error. + deployment: (k): x1: 1 + } + } + for id in ["elem"] { deployment: (id): x2: 2 } + @test(err, code=incomplete, contains="undefined field: env2", pos=[3:19]) +} + +-- issue2131.cue -- +// issue2131: Tests that chained for comprehensions correctly produce output +// fields when iterating over nested structs. https://cuelang.org/issue/2131 +issue2131: tests: { + windows: { + eg1: in: #"c:\d"# + eg2: in: #"c:\test"# + eg3: in: #"c:\test\d"# + } + + for os, examples in tests for k, v in examples { + (os): (k): out: "test" + } + @test(eq, { + windows: { + eg1: {in: "c:\\d", out: "test"} + eg2: {in: "c:\\test", out: "test"} + eg3: {in: "c:\\test\\d", out: "test"} + } + }) +} +-- issue3533.cue -- +// issue3533: Tests that fields under two levels of comprehensions are not +// incorrectly rejected as "field not allowed" in evalv3. +// https://cuelang.org/issue/3533 +issue3533: { + #ObjectMeta: namespace?: string + out: { + for i, _ in ["iter-once"] { + metadata: #ObjectMeta + if false { + metadata: namespace: "foo" + } + } + } + out: metadata: namespace: *"default" | string + @test(eq, { + #ObjectMeta: {namespace?: string} + out: { + metadata: {namespace: *"default" | string} + } + }) +} +-- issue3535.cue -- +// issue3535: Tests that hidden fields inside if comprehensions do not +// trigger "field not allowed" errors in evalv3. +// https://cuelang.org/issue/3535 +issue3535: hidden: { + #X: { + kind: string + output: {} + } + foo: #X & { + kind: string + if kind == "foo" { + _hidden: {} + } + } + foo: kind: "foo" + @test(eq, { + #X: {kind: string, output: {}} + foo: {kind: "foo", _hidden: {}, output: {}} + }) +} +issue3535: regular: { + #X: { + kind: string + output: {} + } + foo: #X & { + kind: string + if kind == "foo" { + regular: {} + } + } + foo: kind: "foo" + @test(err, code=eval, at=foo.regular, contains="field not allowed", pos=[8:4]) +} +issue3535: def: { + #X: { + kind: string + output: {} + } + foo: #X & { + kind: string + if kind == "foo" { + #def: {} + } + } + foo: kind: "foo" + @test(eq, { + #X: {kind: string, output: {}} + foo: {kind: "foo", #def: {}, output: {}} + }) +} +-- reflect.cue -- +import "encoding/json" + + +unifyDynamicReflectSuccess: { + for _, s in ["foo"] { + X: {...} + "\(s)": { + X: {...} // cannot be _ + Y: json.Marshal(X) // cannot be yaml, X cannot be literal + } + } + + [string]: X: { + if true {// must be there + x: y: {} // at least 2 nestings needed to expose problem + } + } + @test(eq, { + X: {X: {x: {y: {}}}} + foo: { + X: {x: {y: {}}} + Y: "{\"x\":{\"y\":{}}}" + } + }) +} +-- issue3621.cue -- +// issue3621: evalv3 regression producing false "cyclic reference" errors for +// comprehensions with nested field definitions and references that evalv2 handles correctly. +// https://cuelang.org/issue/3621 +issue3621: reduced: t1: { + // This test ensures that when a reference is made within a comprehension, + // with vertices marked as "pending", that these are not completed the + // respective pushed-down comprehension is evaluated as well. + if true { + a: b1.b2.b3 + b1: b2: b3: "Foo" + } + @test(eq, {a: "Foo", b1: {b2: {b3: "Foo"}}}) +} +issue3621: reduced: t2: { + outer: {} + if true { + inner: inner2: name: "Foo" + outer: b: inner.inner2.name + } + @test(eq, { + outer: {b: "Foo"} + inner: {inner2: {name: "Foo"}} + }) +} +issue3621: full: { + hello: "world" + outer: [Name=string]: name: Name + if true { + inner: inner2: { + name: "Employees" + description: "All employees" + privacy: "secret" + create_default: false + } + outer: outer2: { + bar: (inner.inner2.name) + } + } + @test(eq, { + hello: "world" + outer: { + outer2: {bar: "Employees", name: "outer2"} + } + inner: { + inner2: { + name: "Employees" + description: "All employees" + privacy: "secret" + create_default: false + } + } + }) +} +-- issue3708.cue -- +// issue3708: evalv3 regression reporting a cyclic reference error when fields are +// accessed inside a comprehension using optional field patterns with if conditionals. +// https://cuelang.org/issue/3708 +issue3708: { + out: people.bob.kind + + // pattern constraint marks 'name' as member, which should not preclude name + // from being futher evaluated to determine whether 'people' is pending. + people: [string]: { + kind: "person" + name?: string + } + + if true { + people: bob: name: "Bob" + } + @test(eq, { + out: "person" + people: {bob: {name: "Bob", kind: "person"}} + }) +} +-- issue3729.cue -- +// issue3729: evalv3 incorrectly reports "incomplete value null" for fields typed +// as a disjunction containing null (e.g. null | #T) inside if comprehensions. +// https://cuelang.org/issue/3729 +issue3729: withDisjunction: { + #Root: sub1?: #sub2?: bool + root?: null | #Root + if true { + root: sub1?: #sub2: true + } + @test(eq, { + #Root: {sub1?: {#sub2?: bool}} + root: {sub1?: {#sub2: true}} + }) +} +issue3729: withoutDisjunction: { + root?: null + if true { + root: #sub1?: #sub2: true + } + @test(err, code=eval, contains="conflicting values null", pos=[0:32, 1:9, 2:2, 3:9]) +} +issue3729: withoutDisjunctionWithEmbed: { + root?: null + if true { + root: {_, #sub1?: #sub2: true} + } + @test(eq, {root: {null, #sub1?: {#sub2: true}}}) +} +issue3729: definitionsOnly: { + #Root: #sub1?: #sub2?: bool + root?: null | #Root + if true { + root: #sub1?: #sub2: true + } + @test(eq, { + #Root: {#sub1?: {#sub2?: bool}} + root: {#sub1?: {#sub2: true}} + }) +} +issue3729: withEmbed: incomplete: { + #Root: #sub1?: #sub2?: bool + root?: null | #Root + if true { + root: {_, #sub1?: #sub2: true} + } + @test(eq, { + #Root: {#sub1?: {#sub2?: bool}} + root: {null, #sub1?: {#sub2: true}} | {#sub1?: {#sub2: true}} + }) +} +issue3729: full: { + #Application: spec: #ApplicationSpec + #ApplicationSpec: syncPolicy?: null | #SyncPolicy + #SyncPolicy: automated?: null | #SyncPolicyAutomated + #SyncPolicyAutomated: { + prune?: bool + selfHeal?: bool + } + argoApp: #Application & { + spec: { + if true { + syncPolicy: automated: { + prune: true + selfHeal: true + } + } + } + } + argoApp: spec: _syncpolicy: "selfhealprune" + @test(eq, { + #Application: { + spec: { + syncPolicy?: null | {automated?: null | {prune?: bool, selfHeal?: bool}} + } + } + #ApplicationSpec: { + syncPolicy?: null | {automated?: null | {prune?: bool, selfHeal?: bool}} + } + #SyncPolicy: { + automated?: null | {prune?: bool, selfHeal?: bool} + } + #SyncPolicyAutomated: {prune?: bool, selfHeal?: bool} + argoApp: { + spec: { + syncPolicy: { + automated: {prune: true, selfHeal: true} + } + _syncpolicy: "selfhealprune" + } + } + }) +} +-- pending.cue -- +// resolving comprehensions arcs across disjunctions. +arcTypeAcrossTwo: { + a?: b?: { + c?: null | {} + } | null + if true { + a: b: c: d: true + } + @test(eq, {a: {b: {c: {d: true}}}}) +} +// issue3894: evalv3 regression where an if comprehension affecting an optional +// field with a disjunction returns an incorrect result instead of the properly +// constrained value. https://cuelang.org/issue/3894 +issue3894: reduced: p1: { + {a: string} | {b: value: string} + if true { b: value: "true" } + @test(eq, {b: {value: "true"}, a: string} | {b: {value: "true"}}) +} +issue3894: reduced: p2: { + {b: value: string} | {a: string} + if true { b: value: "true" } + @test(eq, {b: {value: "true"}} | {b: {value: "true"}, a: string}) +} +issue3894: full: { + #Output: {a?: string} | {b?: {value: string}} + out: #Output + out: { + if true == true { + b: {value: "true"} + } + } + @test(eq, { + #Output: {a?: string} | {b?: {value: string}} + out: {b: {value: "true"}} + }) +} +-- issue3935.cue -- +// issue3935: evalv3 incorrectly reports "field not allowed" when a schema defined +// with a disjunction is intersected with additional constraints. +// https://cuelang.org/issue/3935 +issue3935: reduced: { + out: #A | #B + out: #B & { + y: x: "bar" + } + #A: y: other: int + #B: { + if true { + x: y.x + } + y!: x!: _ + } + @test(eq, { + out: {y: {x: "bar"}, x: "bar"} + #A: {y: {other: int}} + #B: { + x: _|_ @test(err, code=incomplete, contains="issue3935.reduced.#B.x: required field missing: y", pos=[12:7]) + y!: {x!: _} + } + }) +} +issue3935: full: { + out: #SchemaOther | #SchemaSelected + out: #SchemaSelected & { + spec: { + name: "foo" + config: namespace: "bar" + } + } + #SchemaOther: { + spec: { + otherOptional?: int + otherRegular: int + otherRequired!: int + } + } + #SchemaSelected: { + spec!: { + name!: string + config!: _ + } + + if true { + namespace: _specConfig.namespace + } + + _specConfig: spec.config + } + @test(eq, { + out: { + spec: { + name: "foo" + config: {namespace: "bar"} + } + namespace: "bar" + _specConfig: {namespace: "bar"} + } + #SchemaOther: { + spec: { + otherOptional?: int + otherRegular: int + otherRequired!: int + } + } + #SchemaSelected: { + spec!: {name!: string, config!: _} + namespace: _|_ @test(err, code=incomplete, contains="issue3935.full.#SchemaSelected.namespace: undefined field: namespace", pos=[47:27]) + _specConfig: _|_ @test(err, code=incomplete, contains="issue3935.full.#SchemaSelected._specConfig: required field missing: spec", pos=[50:16]) + } + }) +} +-- rework.cue -- +regression1: { + #Primary: { + _Y: _ + let _X = _Y + if len(_X.spec.command) > 0 { + command: _X.spec.command + } + } + #Rollout: { + _X: _ + out: #Primary & {_Y: _X} & _X.patch + } + x: { + spec: command: ["a"] + patch: {} + } + out: #Rollout & {_X: x} @test(eq, at=out,{ + _Y: {spec: {command: ["a"]}, patch: {}} + command: ["a"] + }) +} +regression2: { + #Primary: { + _Y: _ + if len(_Y.spec.command) > 0 { + command: _Y.spec.command + } + } + #Rollout: { + _X: _ + out: #Primary & {_Y: _X} & _X.patch + } + x: { + spec: command: ["a"] + patch: {} + } + out: #Rollout & {_X: x} @test(eq, at=out,{ + _Y: {spec: {command: ["a"]}, patch: {}} + command: ["a"] + }) +} +letCycleSelf: { + #X: X={ + let this = X + hosts: [string]: _ + for h, _ in this.hosts {out: (h): 1} + for h, _ in this.hosts {out: (h): 2} + } + + x: [string]: #X + x: a: {} + + @test(eq, {#X: {hosts: {}}, x: {a: {hosts: {}}}}) +} +-- rework2.cue -- +@experiment(aliasv2) + +letCycleSelfKeyword: { + #E: { + let s = self + hosts: _ + for hv in s.hosts {out: (hv.x): "a"} + } + + env: #E & {hosts: h1: x: "k"} + + @test(eq, { + #E: _|_ @test(err, code=incomplete, path=letCycleSelf2.#E, + contains="cannot range over s.hosts (incomplete type _)", pos=[7:13]) + env: {hosts: {h1: {x: "k"}}, out: {k: "a"}} + }) +} +letCycleSelfKeyword2: { + #E: { + let s = self + ... + for hv in s.hosts { + let n = s.networks + a: n + } + } + + env: #E & { + hosts: h1: 1 + networks: n1: "x" + } + + @test(eq, { + #E: _|_ @test(err, code=incomplete, path=regression_let3.#E, + contains="cannot range over s.hosts (incomplete)", pos=[22:13]) + env: { + hosts: {h1: 1} + networks: {n1: "x"} + a: {n1: "x"} + } + }) +} +-- out/compile -- +--- in.cue +{ + linkChildren: { + w: 1 + v: { + x: 1 + if true { + y: 1 + if true { + z: 1 + rw: 〈3;w〉 + rx: 〈2;x〉 + ry: 〈1;y〉 + rz: 〈0;z〉 + n1a: { + na: [ + 〈5;w〉, + 〈4;x〉, + 〈3;y〉, + 〈2;z〉, + ] + } + n2a: { + n1a: { + na: [ + 〈6;w〉, + 〈5;x〉, + 〈4;y〉, + 〈3;z〉, + ] + } + } + n2z: { + n1z: { + nz: 〈2;z〉 + } + } + } + } + } + } + fail: { + a: { + if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { + b: 1 + } + } + } + embed: { + fail1: 〈0;#C1〉 + #C1: { + if false { + p: _ + } + } + fail1: { + p: "foo" + } + success2: 〈0;#C2〉 + #C2: { + if true { + p: _ + } + } + success2: { + p: "foo" + } + success3: 〈0;#C3〉 + #C3: {} + success3: { + if false { + p: { + q: 1 + } + } + } + success4: { + #X: { + y: string + } + x: { + y: string + } + x: { + for _, _ in [ + "iter-once", + ] { + 〈3;#X〉 + if false { + y: "foo" + } + } + } + } + fail4: 〈0;#C4〉 + #C4: {} + fail4: { + if true { + p: { + q: 1 + } + } + } + incomplete5: { + a: bool + if 〈0;a〉 { + p: { + q: 1 + } + } + } + incomplete6: { + if false { + p: 1 + } + p: (〈0;q〉 + 1) + q: int + } + incomplete7: { + p: (〈0;q〉 + 1) + q: int + if false { + q: 1 + } + } + } + mixedFieldsSuccess: { + a: { + for _, s in [ + "foo", + ] { + "\(〈1;s〉)": 1 + X: 1 + } + } + b: { + #Def: { + for _, s in [ + "foo", + ] { + "\(〈1;s〉)": 1 + X: 1 + } + } + } + b: { + x: 〈1;b〉.#Def + } + b: { + x: { + X: _ + } + } + b: { + x: { + foo: _ + } + } + c: { + #Def: { + X: int + foo: int + } + } + c: { + x: 〈1;c〉.#Def + } + c: { + x: { + for _, s in [ + "foo", + ] { + "\(〈1;s〉)": 1 + X: 1 + } + } + } + } + fieldMismatch: { + a: { + 2 + if true { + x: 3 + } + } + } + noStackOverflowStructCycle: { + #list: { + tail: 〈1;#list〉 + if (〈0;tail〉 != null) { + sum: 〈1;tail〉.sum + } + } + list: { + tail: 〈1;list〉 + if (〈0;tail〉 != null) { + sum: 〈1;tail〉.sum + } + } + } + provideIncompleteSuccess: { + t1: { + #a: { + if 〈0;b〉 { + c: 4 + } + b: bool + } + x: ((〈0;#a〉 & { + b: true + }) & { + c: 4 + }) + y: 〈0;x〉 + } + t2: { + #a: { + if 〈0;b〉 { + c: 4 + } + b: true + } + #c: {} + a: { + if 〈0;b〉 { + c: { + d: 4 + } + } + b: true + c: 〈1;#c〉 + } + } + } + voidArcs: { + scopes: { + x: 1 + a: { + y: 2 + if true { + b: 〈2;x〉 + c: { + d: 〈3;x〉 + } + e: 〈1;y〉 + f: { + g: 〈2;y〉 + } + } + } + } + drop: { + x: 1 + a: { + y: 2 + if false { + b: 〈2;x〉 + c: { + d: 〈3;x〉 + } + e: 〈1;y〉 + f: { + g: 〈2;y〉 + } + } + } + } + } + cyclicError: { + a: { + x: bool + y: bool + if 〈1;a〉.x { + y: true + } + if 〈1;a〉.y { + x: true + } + b: {} + } + c: 〈0;a〉.b + } + midwayReferences: { + a: { + for i, j in { + a: 1 + b: 2 + } { + x: { + y: { + z: { + 〈4;i〉: 〈4;j〉 + } + } + } + } + x: { + y: {} + } + } + b: 〈0;a〉.x + c: 〈0;a〉.x.y + d: 〈0;a〉.x.y.z + } + closedCheck: { + success1: { + a: { + b: { + [string]: 〈2;#D〉 + } + } + #D: { + d: string + if (〈0;d〉 != "c") { + e: string + } + } + a: { + b: { + c: { + d: "d" + e: "ok" + } + } + } + } + } + closedCheck: { + success2: { + a: { + b: { + [string]: 〈2;#D〉 + } + } + #D: { + d: string + if (〈0;d〉 != "c") { + ("foo" + "bar"): string + } + } + a: { + b: { + c: { + d: "d" + foobar: "ok" + } + } + } + } + } + closedCheck: { + success3: { + a: { + b: { + [string]: 〈2;#D〉 + } + } + #D: { + d: string + e: { + if (〈1;d〉 != "c") { + string + } + } + } + a: { + b: { + c: { + d: "d" + e: "ok" + } + } + } + } + } + emptyComprehensionIncomplete: { + a: {} + b: { + if 〈1;a〉.b {} + } + } + voidEliminationSuccess: { + t1: { + [string]: { + b: bool + if !〈0;b〉 {} + } + if false { + a: { + b: true + } + } + } + } + voidEliminationSuccess: { + t2: { + components: { + sinks: { + [string]: (〈1;#C〉 & { + kind: string + configuration: { + if (〈1;kind〉 != "source") { + inputs: { + required: true + } + } + } + }) + } + #C: { + kind: string + configuration: { + [string]: { + required: bool + if !〈0;required〉 { + common: bool + } + } + } + } + } + components: { + sinks: { + blah: { + kind: "source" + } + } + } + } + } + voidEliminationSuccess: { + derefRef1: { + a: { + [string]: { + c: { + [string]: 〈3;E〉 + } + } + } + a: { + b: { + c: { + if false { + d: { + e: true + } + } + } + } + } + E: { + e: bool + f: !〈0;e〉 + } + } + } + voidEliminationSuccess: { + derefRef2: { + a: { + [string]: { + c: { + [string]: 〈3;E〉 + } + } + } + a: { + b: { + c: { + if false { + d: { + e: true + } + } + } + } + } + E: 〈0;#F〉 + #F: { + e: bool + f: !〈0;e〉 + } + } + } + voidEliminationSuccess: { + derefDisj1: { + a: { + [string]: { + c: { + [string]: 〈3;E〉 + } + } + } + a: { + b: { + c: { + if false { + d: { + e: true + } + } + } + } + } + E: ({ + e: bool + f: !〈0;e〉 + }|{ + g: bool + h: !〈0;g〉 + }) + } + } + voidEliminationSuccess: { + derefDisj2: { + a: { + [string]: { + c: { + [string]: (〈3;E〉 & 〈3;E〉) + } + } + } + a: { + b: { + c: { + if false { + d: { + e: true + } + } + } + } + } + E: ({ + e: bool + f: !〈0;e〉 + }|{ + g: bool + h: !〈0;g〉 + }) + } + } + voidEliminationSuccess: { + bulk1: { + a: { + b: {} + } + a: { + [string]: { + c: { + e: string + if false { + e: "" + } + } + d: 〈0;c〉.e + } + } + } + } + voidEliminationSuccess: { + opt1: { + a: { + b: {} + } + a: { + b?: { + c: { + e: string + if false { + e: "" + } + } + d: 〈0;c〉.e + } + } + } + } + voidEliminationSuccess: { + noCycle1: { + _x: 〈0;a〉.b + a: { + c: { + h: "stream" + } + b: { + if (〈1;c〉.g != _|_(explicit error (_|_ literal) in source)) {} + } + c: { + if false { + g: _ + } + } + } + } + } + voidEliminationSuccess: { + noCycle2: { + a: { + c: { + h: "stream" + } + b: { + if (〈1;c〉.g != _|_(explicit error (_|_ literal) in source)) {} + } + c: { + if false { + g: _ + } + } + } + _x: 〈0;a〉.b + } + } + voidLookup: { + a: { + x: { + z: 〈2;a〉.y.z.void + } + } + a: { + y: { + c: _ + z: {} + } + } + a: { + [string]: { + c: { + for k, v in 〈1;z〉 { + 〈1;k〉: null + } + } + z: { + if false { + err: {} + } + } + } + } + } + topElimination: { + a: int + _ + if true { + x: (〈1;a〉 + 1) + } + } + voidEliminationSuccess: { + drop1: { + t: { + #ok: (*true|bool) + if 〈0;#ok〉 { + x: int + } + } + s: (〈0;t〉 & { + #ok: false + }) + } + } + explicitDefaultError: { + a: (string|*_|_(explicit error (_|_ literal) in source)) + if (〈0;a〉 != "") {} + } + allArcsSuccess: { + p1: { + x: { + for k, _ in 〈1;y〉 { + 〈1;k〉: null + } + } + y: { + if false { + x: {} + } + } + } + } + allArcsSuccess: { + p2: { + y: { + if false { + x: {} + } + } + x: { + for k, _ in 〈1;y〉 { + 〈1;k〉: null + } + } + } + } + structShare: { + ok1: { + a: { + [string]: 〈1;E〉 + } + E: {} + a: { + if true { + d: { + e: true + } + } + } + } + } + structShare: { + err1: { + x: { + [string]: 〈1;x〉.#E + } + x: { + #E: {} + } + if true { + x: { + d: { + e: true + } + } + } + } + } +} +--- issue1759.cue +{ + unity: { + success1: { + #Config: { + name: string + type: string + } + #AnyConfig: { + 〈1;#Config〉 + ... + } + #Env: { + name: string + configurations: { + [string]: 〈2;#AnyConfig〉 + } + } + envs: { + e1: (〈1;#Env〉 & { + configurations: { + c1: 〈3;#Config〉 + } + }) + } + envs: { + [string]: { + configurations: { + [string]: { + type: "foo" + if (〈0;type〉 == "terraform") { + backend: { + type: "s3" + } + } + } + } + } + } + } + } + issue1759: { + _ports_map: {} + if (len(〈0;_ports_map〉) > 0) { + port: 〈1;_ports_map〉.a.port + } + if true { + _ports_map: { + a: { + port: "80" + } + } + } + } + arcAlignment: { + t1: { + [string]: { + if true {} + } + if false { + c: _ + } + } + } +} +--- issue2111.cue +{ + letPushdown: { + _c: { + y: 1 + } + a: { + for k, v in 〈1;_c〉 { + let x#1multi = 〈1;v〉 + if (〈0;let x#1〉 != _|_(explicit error (_|_ literal) in source)) {} + } + } + } +} +--- issue2113.cue +{ + nestedWithEmbeddingOK: { + c: [ + 1, + ] + a: { + for k, v in 〈1;c〉 { + { + x: 1 + } + if (〈3;a〉.x != _|_(explicit error (_|_ literal) in source)) {} + } + } + } + nestedWithDynamicFieldOK: { + _c: { + y: 1 + } + a: { + for k, v in 〈1;_c〉 { + if (〈0;("\(〈1;k〉)")〉 != _|_(explicit error (_|_ literal) in source)) {} + "\(〈1;k〉)": 1 + } + } + } + errorPropagation: { + deployment: _ + for k, v in 〈0;deployment〉 { + for k1, v2 in 〈1;v〉.env2 { + deployment: { + 〈4;k〉: { + x1: 1 + } + } + } + } + for _, id in [ + "elem", + ] { + deployment: { + 〈2;id〉: { + x2: 2 + } + } + } + } +} +--- issue2131.cue +{ + issue2131: { + tests: { + windows: { + eg1: { + in: "c:\\d" + } + eg2: { + in: "c:\\test" + } + eg3: { + in: "c:\\test\\d" + } + } + for os, examples in 〈1;tests〉 for k, v in 〈0;examples〉 { + 〈2;os〉: { + 〈2;k〉: { + out: "test" + } + } + } + } + } +} +--- issue2208.cue +{ + voidErrorIncomplete: { + #Schema: { + [string]: { + required: bool + if !〈0;required〉 {} + } + } + root: 〈0;#Schema〉 + root: { + if false { + child: { + required: false + } + } + } + } +} +--- issue3533.cue +{ + issue3533: { + #ObjectMeta: { + namespace?: string + } + out: { + for i, _ in [ + "iter-once", + ] { + metadata: 〈3;#ObjectMeta〉 + if false { + metadata: { + namespace: "foo" + } + } + } + } + out: { + metadata: { + namespace: (*"default"|string) + } + } + } +} +--- issue3535.cue +{ + issue3535: { + hidden: { + #X: { + kind: string + output: {} + } + foo: (〈0;#X〉 & { + kind: string + if (〈0;kind〉 == "foo") { + _hidden: {} + } + }) + foo: { + kind: "foo" + } + } + } + issue3535: { + regular: { + #X: { + kind: string + output: {} + } + foo: (〈0;#X〉 & { + kind: string + if (〈0;kind〉 == "foo") { + regular: {} + } + }) + foo: { + kind: "foo" + } + } + } + issue3535: { + def: { + #X: { + kind: string + output: {} + } + foo: (〈0;#X〉 & { + kind: string + if (〈0;kind〉 == "foo") { + #def: {} + } + }) + foo: { + kind: "foo" + } + } + } +} +--- issue3621.cue +{ + issue3621: { + reduced: { + t1: { + if true { + a: 〈0;b1〉.b2.b3 + b1: { + b2: { + b3: "Foo" + } + } + } + } + } + } + issue3621: { + reduced: { + t2: { + outer: {} + if true { + inner: { + inner2: { + name: "Foo" + } + } + outer: { + b: 〈1;inner〉.inner2.name + } + } + } + } + } + issue3621: { + full: { + hello: "world" + outer: { + [string]: { + name: 〈1;-〉 + } + } + if true { + inner: { + inner2: { + name: "Employees" + description: "All employees" + privacy: "secret" + create_default: false + } + } + outer: { + outer2: { + bar: 〈2;inner〉.inner2.name + } + } + } + } + } +} +--- issue3708.cue +{ + issue3708: { + out: 〈0;people〉.bob.kind + people: { + [string]: { + kind: "person" + name?: string + } + } + if true { + people: { + bob: { + name: "Bob" + } + } + } + } +} +--- issue3729.cue +{ + issue3729: { + withDisjunction: { + #Root: { + sub1?: { + #sub2?: bool + } + } + root?: (null|〈0;#Root〉) + if true { + root: { + sub1?: { + #sub2: true + } + } + } + } + } + issue3729: { + withoutDisjunction: { + root?: null + if true { + root: { + #sub1?: { + #sub2: true + } + } + } + } + } + issue3729: { + withoutDisjunctionWithEmbed: { + root?: null + if true { + root: { + _ + #sub1?: { + #sub2: true + } + } + } + } + } + issue3729: { + definitionsOnly: { + #Root: { + #sub1?: { + #sub2?: bool + } + } + root?: (null|〈0;#Root〉) + if true { + root: { + #sub1?: { + #sub2: true + } + } + } + } + } + issue3729: { + withEmbed: { + incomplete: { + #Root: { + #sub1?: { + #sub2?: bool + } + } + root?: (null|〈0;#Root〉) + if true { + root: { + _ + #sub1?: { + #sub2: true + } + } + } + } + } + } + issue3729: { + full: { + #Application: { + spec: 〈1;#ApplicationSpec〉 + } + #ApplicationSpec: { + syncPolicy?: (null|〈1;#SyncPolicy〉) + } + #SyncPolicy: { + automated?: (null|〈1;#SyncPolicyAutomated〉) + } + #SyncPolicyAutomated: { + prune?: bool + selfHeal?: bool + } + argoApp: (〈0;#Application〉 & { + spec: { + if true { + syncPolicy: { + automated: { + prune: true + selfHeal: true + } + } + } + } + }) + argoApp: { + spec: { + _syncpolicy: "selfhealprune" + } + } + } + } +} +--- issue3935.cue +{ + issue3935: { + reduced: { + out: (〈0;#A〉|〈0;#B〉) + out: (〈0;#B〉 & { + y: { + x: "bar" + } + }) + #A: { + y: { + other: int + } + } + #B: { + if true { + x: 〈1;y〉.x + } + y!: { + x!: _ + } + } + } + } + issue3935: { + full: { + out: (〈0;#SchemaOther〉|〈0;#SchemaSelected〉) + out: (〈0;#SchemaSelected〉 & { + spec: { + name: "foo" + config: { + namespace: "bar" + } + } + }) + #SchemaOther: { + spec: { + otherOptional?: int + otherRegular: int + otherRequired!: int + } + } + #SchemaSelected: { + spec!: { + name!: string + config!: _ + } + if true { + namespace: 〈1;_specConfig〉.namespace + } + _specConfig: 〈0;spec〉.config + } + } + } +} +--- pending.cue +{ + arcTypeAcrossTwo: { + a?: { + b?: ({ + c?: (null|{}) + }|null) + } + if true { + a: { + b: { + c: { + d: true + } + } + } + } + } + issue3894: { + reduced: { + p1: { + ({ + a: string + }|{ + b: { + value: string + } + }) + if true { + b: { + value: "true" + } + } + } + } + } + issue3894: { + reduced: { + p2: { + ({ + b: { + value: string + } + }|{ + a: string + }) + if true { + b: { + value: "true" + } + } + } + } + } + issue3894: { + full: { + #Output: ({ + a?: string + }|{ + b?: { + value: string + } + }) + out: 〈0;#Output〉 + out: { + if (true == true) { + b: { + value: "true" + } + } + } + } + } +} +--- reflect.cue +{ + unifyDynamicReflectSuccess: { + for _, s in [ + "foo", + ] { + X: { + ... + } + "\(〈1;s〉)": { + X: { + ... + } + Y: 〈import;"encoding/json"〉.Marshal(〈0;X〉) + } + } + [string]: { + X: { + if true { + x: { + y: {} + } + } + } + } + } +} +--- rework.cue +{ + regression1: { + #Primary: { + _Y: _ + let _X#2 = 〈0;_Y〉 + if (len(〈0;let _X#2〉.spec.command) > 0) { + command: 〈1;let _X#2〉.spec.command + } + } + #Rollout: { + _X: _ + out: ((〈1;#Primary〉 & { + _Y: 〈1;_X〉 + }) & 〈0;_X〉.patch) + } + x: { + spec: { + command: [ + "a", + ] + } + patch: {} + } + out: (〈0;#Rollout〉 & { + _X: 〈1;x〉 + }) + } + regression2: { + #Primary: { + _Y: _ + if (len(〈0;_Y〉.spec.command) > 0) { + command: 〈1;_Y〉.spec.command + } + } + #Rollout: { + _X: _ + out: ((〈1;#Primary〉 & { + _Y: 〈1;_X〉 + }) & 〈0;_X〉.patch) + } + x: { + spec: { + command: [ + "a", + ] + } + patch: {} + } + out: (〈0;#Rollout〉 & { + _X: 〈1;x〉 + }) + } + letCycleSelf: { + #X: { + let this#3 = 〈1〉 + hosts: { + [string]: _ + } + for h, _ in 〈0;let this#3〉.hosts { + out: { + 〈2;h〉: 1 + } + } + for h, _ in 〈0;let this#3〉.hosts { + out: { + 〈2;h〉: 2 + } + } + } + x: { + [string]: 〈1;#X〉 + } + x: { + a: {} + } + } +} +--- rework2.cue +{ + letCycleSelfKeyword: { + #E: { + let s#4 = 〈1〉 + hosts: _ + for _, hv in 〈0;let s#4〉.hosts { + out: { + 〈2;hv〉.x: "a" + } + } + } + env: (〈0;#E〉 & { + hosts: { + h1: { + x: "k" + } + } + }) + } + letCycleSelfKeyword2: { + #E: { + let s#5 = 〈1〉 + ... + for _, hv in 〈0;let s#5〉.hosts { + let n#6 = 〈2;let s#5〉.networks + a: 〈0;let n#6〉 + } + } + env: (〈0;#E〉 & { + hosts: { + h1: 1 + } + networks: { + n1: "x" + } + }) + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/try.txtar b/internal/core/compile/testdata/sync/comprehensions/try.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/try.txtar @@ -0,0 +1,1099 @@ +-- in.cue -- +@experiment(try) + +// ============================================================================= +// Basic try with successful evaluation +// ============================================================================= + +a: 1 @test(eq, 1) +b: 2 @test(eq, 2) +c?: int // undefined optional field +incomplete: int + +// Try with successful optional references (both defined) +success: { + try { result: a? + b? } + @test(eq, {result: 3}) +} + +// Try with single optional reference +single: { + x: 5 + try { y: x? * 2 } + @test(eq, {x: 5, y: 10}) +} + +// ============================================================================= +// Try with else clause +// ============================================================================= + +// Else NOT triggered when try succeeds (value is defined) +fallbackDef: 42 +elseNotTriggered: { + try { v: fallbackDef? } else { fallback: 0 } + @test(eq, {v: 42}) +} + +// Else triggered when try fails (optional field undefined) +// Note: else uses different field name to avoid merge conflicts with trial evaluation +elseTriggered: { + try { v: c? } else { fallback: -1 } + @test(eq, {fallback: -1}) +} + +// Else with different field names (avoids conflict with trial evaluation) +elseMultiField: { + try { x: c?, y: c? } else { fallback: true } + @test(eq, {fallback: true}) +} + +// ============================================================================= +// Try with undefined optional references +// ============================================================================= + +// Try produces empty struct when optional fails (no else) +emptyOnFail: { + try { z: c? + 1 } + @test(eq, {}) +} + +// Try with mix of defined and undefined - all must succeed +mixedRefs: { + try { x: a?, y: c? } else { fallback: true } + @test(eq, {fallback: true}) +} + +incompleteOK: { + try { x: incomplete? } else { fallback: 23 } + @test(eq, {x: int}) +} + +// Nested struct in try body with incomplete value +incompleteNestedBody: { + try { x: y: incomplete? } else { fallback: 23 } + @test(eq, {x: {y: int}}) +} + +// ============================================================================= +// Required fields +// ============================================================================= + +// Unfilled required field triggers else +requiredUnfilled: { + a!: _ + try { x: a? } else { fallback: 23 } + @test(eq, { + a!: _ + x: _|_ @test(err, code=incomplete, contains="requiredUnfilled.x: required field missing: a", pos=[83:11]) + }) +} + +// Filled required field succeeds +requiredFilled: { + a!: _ + a: 5 + try { x: a? } else { fallback: 23 } + @test(eq, {a: 5, x: 5}) +} + +// Required field with type constraint triggers else +requiredWithType: { + a!: int + try { x: a? } else { fallback: 23 } + @test(eq, { + a!: int + x: _|_ @test(err, code=incomplete, contains="requiredWithType.x: required field missing: a", pos=[101:11]) + }) +} + +// ============================================================================= +// Try with for comprehension +// ============================================================================= + +// For with optional source that exists +forWithDefinedSource: { + try { for x in [b?] { val: x } } + @test(eq, {val: 2}) +} + +// For with optional source that's undefined +forWithUndefinedSource: { + try { for x in [c?] { val: x } } else { empty: true } + @test(eq, {empty: true}) +} + +// ============================================================================= +// Nested structures +// ============================================================================= + +nested: { + // Try inside struct + outer: { + try { inner: a? } + @test(eq, {inner: 1}) + } + + // Multiple try clauses in same struct + multi: { + try { first: a? } + try { second: b? } + @test(eq, {first: 1, second: 2}) + } + + // Try with nested struct in body + deepNested: { + try { + level1: { + level2: a? + } + } + @test(eq, {level1: {level2: 1}}) + } +} + +// ============================================================================= +// Complex expressions in try +// ============================================================================= + +complexExpr: { + // Binary operations + binOp: { + try { sum: a? + b?, prod: a? * b? } + @test(eq, {sum: 3, prod: 2}) + } + + // Conditional with optional + list: { + try { items: [a?, b?, a? + b?] } + @test(eq, {items: [1, 2, 3]}) + } +} + +// ============================================================================= +// Selector expressions with optional +// ============================================================================= + + selectorTests: { + data: { + nested: { + value: 100 + } + } + + // Selector on defined path + definedSelector: { + try { v: data.nested.value? } + } + + @test(eq, { + data: {nested: {value: 100}} + definedSelector: {v: 100} + }) + + // Note: selector on undefined path would be compile error +} + +// ============================================================================= +// Refer to closed structs +// ============================================================================= +closedness: { + #Def: {f: int} + + d: #Def + + exists: { + try { v: #Def.f? } + @test(eq, {v: int}) + } + notExistsDef: { + try { v: #Def.g? } + @test(err, code=eval, path=v, contains="undefined field: %s", args=[g], pos=[1:17]) + } + notExistsValue: { + try { v: d.g? } + @test(err, code=eval, path=v, contains="undefined field: %s", args=[g], pos=[1:14]) + } +} + + +// ============================================================================= +// Index expressions with optional +// ============================================================================= + +indexTests: { + closedList: [10, 20, 30] + openList: [10, 20, 30, ...] + + // Index on defined position (closed list) + definedIndex: { + try { v: closedList[0]? } + @test(eq, {v: 10}) + } + + // Index on defined position (middle) + middleIndex: { + try { v: closedList[1]? } + @test(eq, {v: 20}) + } + + // Index out of range on CLOSED list - should ERROR (can never be satisfied) + outOfRangeClosed: { + try { v: closedList[10]? } else { fallback: -1 } + @test(err, code=eval, path=v, contains="index out of range [%d] with length %d", args=[10, 3], pos=[1:23]) + } + + // Index out of range on CLOSED list without else - should ERROR + outOfRangeClosedNoElse: { + try { v: closedList[100]? } + @test(err, code=eval, path=v, contains="index out of range [%d] with length %d", args=[100, 3], pos=[1:23]) + } + + // Index out of range on OPEN list - should trigger else (list might grow) + outOfRangeOpen: { + try { v: openList[10]? } else { fallback: -1 } + @test(eq, {fallback: -1}) + } + + // Index out of range on OPEN list without else - empty struct + outOfRangeOpenNoElse: { + try { v: openList[100]? } + @test(eq, {}) + } + + // Multiple index accesses on closed list + multipleIndex: { + try { x: closedList[0]?, y: closedList[1]?, z: closedList[2]? } + @test(eq, {x: 10, y: 20, z: 30}) + } +} + +// ============================================================================= +// Edge cases +// ============================================================================= + +edgeCases: { + // Empty try body (should produce empty struct) + emptyBody: { + try { } + @test(eq, {}) + } + + // Try with only literal (no optional refs) - should always succeed + literalOnly: { + try { x: 42 } + @test(eq, {x: 42}) + } + + // Multiple optional refs, first fails + firstFails: { + try { x: c?, y: a? } else { skipped: true } + @test(eq, {skipped: true}) + } + + // Multiple optional refs, second fails + secondFails: { + try { x: a?, y: c? } else { skipped: true } + @test(eq, {skipped: true}) + } + + referenceError: { + a: 1 / 0 + a: _b: 2 + + direct: { + try { v: a? } else { skipped: true } + @test(err, code=eval, path=edgeCases.referenceError.a, contains="failed arithmetic: %v", args=[division by zero], pos=[-3:6]) + // v shares the error from a + } + dontSkipError1: { + try { a._b? } else { skipped: true } + @test(err, code=eval, path=edgeCases.referenceError.a, contains="failed arithmetic: %v", args=[division by zero], pos=[-8:6]) + } + dontSkipError2: { + try { a?._b? } else { skipped: true } + @test(err, code=eval, path=edgeCases.referenceError.a, contains="failed arithmetic: %v", args=[division by zero], pos=[-12:6]) + } + } +} + +// ============================================================================= +// Referencing into try results +// ============================================================================= + +// When referencing a field from a successful try, the field is guaranteed +// to exist and be concrete. No ? needed outside of try context. + +refIntoTry: { + // Try that succeeds - inner fields are accessible + source: { + try { val: a? } + @test(eq, {val: 1}) + } + // Reference into successful try result (no ? needed) + ref: source.val @test(eq, 1) // Should resolve to 1 + + // Nested try - outer succeeds, inner may or may not + nestedSource: { + try { + inner: { + try { deep: b? } + } + } + @test(eq, {inner: {deep: 2}}) + } + // Reference into nested try result (no ? needed) + nestedRef: nestedSource.inner.deep @test(eq, 2) // Should resolve to 2 + + // Try that fails - struct is empty, reference fails + nestedSkipped?: { try { c? } } @test(err, code=incomplete, path=refIntoTry, contains="field not found: %v", args=[nestedSkipped], pos=[]) + mixedSource: { + try { foo: nestedSkipped? } + bar?: 1 + baz: 1 + @test(eq, {bar?: 1, baz: 1}) + } + // Reference into failed try - use try to handle the missing field + skippedRef: { + try { v: mixedSource.foo? } else { missing: true } + @test(eq, {missing: true}) + } + failedRef1: { + try { v: mixedSource.foo } else { missing: true } + @test(eq, { + v: _|_ @test(err, code=incomplete, contains="refIntoTry.failedRef1.v: undefined field: foo", pos=[360:24]) + }) + } + failedRef2: { + try { v: mixedSource.foo } else { missing: true } + @test(eq, { + v: _|_ @test(err, code=incomplete, contains="refIntoTry.failedRef2.v: undefined field: foo", pos=[366:24]) + }) + } + successRef: { + try { v: mixedSource.baz? } else { missing: true } + @test(eq, {v: 1}) + } +} + +// ============================================================================= +// Error precedence: real errors should not be masked by OptionalUndefined +// ============================================================================= + +errorPrecedence: { + // Type error with optional that exists - should error + typeErrorDefined: { + try { v: a? + "string" } else { fallback: "ok" } + @test(err, code=eval, path=v, + contains="invalid operands %s and %s to '%s' (type %s and %s)", + args=[1, "string", +, int, string], pos=[1:12, -376:4, 1:17]) + } + + // Type error AND undefined optional - depends on evaluation order + // If c? is evaluated first and fails, the type error is never reached + typeErrorUndefined: { + try { v: c? + "string" } else { fallback: "ok" } + @test(eq, {fallback: "ok"}) + } + + // Division by zero with optional + divByZero: { + try { v: a? / 0 } else { fallback: "ok" } + @test(err, code=eval, path=v, contains="failed arithmetic: %v", + args=[division by zero], pos=[1:12]) + } + + // Error from conflicting values + conflictError: { + try { v: a? & "notanint" } else { fallback: "ok" } + @test(err, code=eval, path=v, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=["notanint", 1, string, int], + pos=[-398:4, 0:17, 1:3, 1:12, 1:17]) + } + + // Mixed case: OptionalUndefined in one field, real error in another + // The real error should still propagate + mixedError: { + try { + x: c? // undefined + y: 1 / 0 // real error (independent) + } else { fallback: "ok" } + @test(eq, {fallback: "ok"}) + } + + // Mixed case 2: multiple optionals, one undefined, one with error + mixedErrorMultiple: { + try { + x: a? // defined (1) + y: c? // undefined + z: a? / 0 // real error + } else { fallback: "ok" } + @test(eq, {fallback: "ok"}) + } +} + +// ============================================================================= +// Assignment form: try x = expr +// ============================================================================= + +assignmentForm: { + // Basic assignment with defined value + basicDefined: { + try x = a? { result: x } + @test(eq, {result: 1}) + } + + // Assignment with undefined optional - should trigger else + basicUndefined: { + try x = c? { result: x } else { fallback: 0 } + @test(eq, {fallback: 0}) + } + + // Assignment without else - should produce empty struct + noElseUndefined: { + try x = c? { result: x } + @test(eq, {}) + } + + // Assignment with expression + withExpression: { + try sum = a? + b? { result: sum } + @test(eq, {result: 3}) + } + + // Assignment with failing expression - triggers else + withFailingExpr: { + try sum = a? + c? { result: sum } else { fallback: -1 } + @test(eq, {fallback: -1}) + } + + // Chained assignments + chained: { + try x = a? try y = b? { result: x + y } + @test(eq, {result: 3}) + } + + // Assignment with selector + withSelector: { + data: { inner: 42 } + try v = data.inner? { result: v } + @test(eq, {data: {inner: 42}, result: 42}) + } + + // Assignment with index + withIndex: { + list: [10, 20, 30] + try v = list[1]? { result: v } + @test(eq, {list: [10, 20, 30], result: 20}) + } + + // Assignment with out-of-range index on closed list - should ERROR + withOutOfRangeIndex: { + list: [10, 20, 30] + try v = list[10]? { result: v } else { fallback: -1 } + @test(err, code=eval, path=result, + contains="index out of range [%d] with length %d", args=[10, 3], pos=[2:16]) + } + + // Assignment with out-of-range index on open list - should trigger else + withOutOfRangeIndexOpen: { + list: [10, 20, 30, ...] + try v = list[10]? { result: v } else { fallback: -1 } + @test(eq, {list: [10, 20, 30], fallback: -1}) + } + + // Assignment used in nested expression + nestedUse: { + try x = a? { inner: { value: x * 2 } } + @test(eq, {inner: {value: 2}}) + } + + // Multiple chained try assignments with one failing + chainedOneFails: { + try x = a? try y = c? { result: x + y } + @test(eq, {}) + } + + // Assignment with real error - should propagate + withRealError: { + try x = a? / 0 { result: x } else { fallback: "ok" } + @test(err, code=eval, path=result, + contains="failed arithmetic: %v", args=[division by zero], pos=[1:11]) + } + + // Assignment combined with for + withFor: { + try x = b? for i, v in [1, 2] { "\(i)": x + v } + @test(eq, {"0": 3, "1": 4}) + } + + // Assignment combined with if + withIf: { + try x = a? if x > 0 { positive: x } + @test(eq, {positive: 1}) + } + + // Assignment combined with let + withLet: { + try x = a? let y = x * 2 { doubled: y } + @test(eq, {doubled: 2}) + } +} + +// ============================================================================= +// Original recursive tests +// ============================================================================= + +recursive: t1: { try { for x in [b?] { x } } } @test(eq, 2) +recursive: t2: { try { {x: b?, y: c?} } } @test(eq, {}) +recursive: t3: { try { {x: b?, y: c?} } else { z: 23 }} @test(eq, {z: 23}) + +-- out/compile -- +--- in.cue +{ + a: 1 + b: 2 + c?: int + incomplete: int + success: { + try { + result: (〈2;a〉? + 〈2;b〉?) + } + } + single: { + x: 5 + try { + y: (〈1;x〉? * 2) + } + } + fallbackDef: 42 + elseNotTriggered: { + try { + v: 〈2;fallbackDef〉? + } else { + fallback: 0 + } + } + elseTriggered: { + try { + v: 〈2;c〉? + } else { + fallback: -1 + } + } + elseMultiField: { + try { + x: 〈2;c〉? + y: 〈2;c〉? + } else { + fallback: true + } + } + emptyOnFail: { + try { + z: (〈2;c〉? + 1) + } + } + mixedRefs: { + try { + x: 〈2;a〉? + y: 〈2;c〉? + } else { + fallback: true + } + } + incompleteOK: { + try { + x: 〈2;incomplete〉? + } else { + fallback: 23 + } + } + incompleteNestedBody: { + try { + x: { + y: 〈3;incomplete〉? + } + } else { + fallback: 23 + } + } + requiredUnfilled: { + a!: _ + try { + x: 〈1;a〉? + } else { + fallback: 23 + } + } + requiredFilled: { + a!: _ + a: 5 + try { + x: 〈1;a〉? + } else { + fallback: 23 + } + } + requiredWithType: { + a!: int + try { + x: 〈1;a〉? + } else { + fallback: 23 + } + } + forWithDefinedSource: { + try { + for _, x in [ + 〈3;b〉?, + ] { + val: 〈1;x〉 + } + } + } + forWithUndefinedSource: { + try { + for _, x in [ + 〈3;c〉?, + ] { + val: 〈1;x〉 + } + } else { + empty: true + } + } + nested: { + outer: { + try { + inner: 〈3;a〉? + } + } + multi: { + try { + first: 〈3;a〉? + } + try { + second: 〈3;b〉? + } + } + deepNested: { + try { + level1: { + level2: 〈4;a〉? + } + } + } + } + complexExpr: { + binOp: { + try { + sum: (〈3;a〉? + 〈3;b〉?) + prod: (〈3;a〉? * 〈3;b〉?) + } + } + list: { + try { + items: [ + 〈4;a〉?, + 〈4;b〉?, + (〈4;a〉? + 〈4;b〉?), + ] + } + } + } + selectorTests: { + data: { + nested: { + value: 100 + } + } + definedSelector: { + try { + v: 〈2;data〉.nested.value? + } + } + } + closedness: { + #Def: { + f: int + } + d: 〈0;#Def〉 + exists: { + try { + v: 〈2;#Def〉.f? + } + } + notExistsDef: { + try { + v: 〈2;#Def〉.g? + } + } + notExistsValue: { + try { + v: 〈2;d〉.g? + } + } + } + indexTests: { + closedList: [ + 10, + 20, + 30, + ] + openList: [ + 10, + 20, + 30, + ..., + ] + definedIndex: { + try { + v: 〈2;closedList〉[0]? + } + } + middleIndex: { + try { + v: 〈2;closedList〉[1]? + } + } + outOfRangeClosed: { + try { + v: 〈2;closedList〉[10]? + } else { + fallback: -1 + } + } + outOfRangeClosedNoElse: { + try { + v: 〈2;closedList〉[100]? + } + } + outOfRangeOpen: { + try { + v: 〈2;openList〉[10]? + } else { + fallback: -1 + } + } + outOfRangeOpenNoElse: { + try { + v: 〈2;openList〉[100]? + } + } + multipleIndex: { + try { + x: 〈2;closedList〉[0]? + y: 〈2;closedList〉[1]? + z: 〈2;closedList〉[2]? + } + } + } + edgeCases: { + emptyBody: { + try {} + } + literalOnly: { + try { + x: 42 + } + } + firstFails: { + try { + x: 〈3;c〉? + y: 〈3;a〉? + } else { + skipped: true + } + } + secondFails: { + try { + x: 〈3;a〉? + y: 〈3;c〉? + } else { + skipped: true + } + } + referenceError: { + a: (1 / 0) + a: { + _b: 2 + } + direct: { + try { + v: 〈2;a〉? + } else { + skipped: true + } + } + dontSkipError1: { + try { + 〈2;a〉._b? + } else { + skipped: true + } + } + dontSkipError2: { + try { + 〈2;a〉?._b? + } else { + skipped: true + } + } + } + } + refIntoTry: { + source: { + try { + val: 〈3;a〉? + } + } + ref: 〈0;source〉.val + nestedSource: { + try { + inner: { + try { + deep: 〈5;b〉? + } + } + } + } + nestedRef: 〈0;nestedSource〉.inner.deep + nestedSkipped?: { + try { + 〈3;c〉? + } + } + mixedSource: { + try { + foo: 〈2;nestedSkipped〉? + } + bar?: 1 + baz: 1 + } + skippedRef: { + try { + v: 〈2;mixedSource〉.foo? + } else { + missing: true + } + } + failedRef1: { + try { + v: 〈2;mixedSource〉.foo + } else { + missing: true + } + } + failedRef2: { + try { + v: 〈2;mixedSource〉.foo + } else { + missing: true + } + } + successRef: { + try { + v: 〈2;mixedSource〉.baz? + } else { + missing: true + } + } + } + errorPrecedence: { + typeErrorDefined: { + try { + v: (〈3;a〉? + "string") + } else { + fallback: "ok" + } + } + typeErrorUndefined: { + try { + v: (〈3;c〉? + "string") + } else { + fallback: "ok" + } + } + divByZero: { + try { + v: (〈3;a〉? / 0) + } else { + fallback: "ok" + } + } + conflictError: { + try { + v: (〈3;a〉? & "notanint") + } else { + fallback: "ok" + } + } + mixedError: { + try { + x: 〈3;c〉? + y: (1 / 0) + } else { + fallback: "ok" + } + } + mixedErrorMultiple: { + try { + x: 〈3;a〉? + y: 〈3;c〉? + z: (〈3;a〉? / 0) + } else { + fallback: "ok" + } + } + } + assignmentForm: { + basicDefined: { + try x = 〈2;a〉? { + result: 〈1;x〉 + } + } + basicUndefined: { + try x = 〈2;c〉? { + result: 〈1;x〉 + } else { + fallback: 0 + } + } + noElseUndefined: { + try x = 〈2;c〉? { + result: 〈1;x〉 + } + } + withExpression: { + try sum = (〈2;a〉? + 〈2;b〉?) { + result: 〈1;sum〉 + } + } + withFailingExpr: { + try sum = (〈2;a〉? + 〈2;c〉?) { + result: 〈1;sum〉 + } else { + fallback: -1 + } + } + chained: { + try x = 〈2;a〉? try y = 〈3;b〉? { + result: (〈2;x〉 + 〈1;y〉) + } + } + withSelector: { + data: { + inner: 42 + } + try v = 〈0;data〉.inner? { + result: 〈1;v〉 + } + } + withIndex: { + list: [ + 10, + 20, + 30, + ] + try v = 〈0;list〉[1]? { + result: 〈1;v〉 + } + } + withOutOfRangeIndex: { + list: [ + 10, + 20, + 30, + ] + try v = 〈0;list〉[10]? { + result: 〈1;v〉 + } else { + fallback: -1 + } + } + withOutOfRangeIndexOpen: { + list: [ + 10, + 20, + 30, + ..., + ] + try v = 〈0;list〉[10]? { + result: 〈1;v〉 + } else { + fallback: -1 + } + } + nestedUse: { + try x = 〈2;a〉? { + inner: { + value: (〈2;x〉 * 2) + } + } + } + chainedOneFails: { + try x = 〈2;a〉? try y = 〈3;c〉? { + result: (〈2;x〉 + 〈1;y〉) + } + } + withRealError: { + try x = (〈2;a〉? / 0) { + result: 〈1;x〉 + } else { + fallback: "ok" + } + } + withFor: { + try x = 〈2;b〉? for i, v in [ + 1, + 2, + ] { + "\(〈1;i〉)": (〈2;x〉 + 〈1;v〉) + } + } + withIf: { + try x = 〈2;a〉? if (〈0;x〉 > 0) { + positive: 〈1;x〉 + } + } + withLet: { + try x = 〈2;a〉? let y = (〈0;x〉 * 2) { + doubled: 〈1;y〉 + } + } + } + recursive: { + t1: { + try { + for _, x in [ + 〈4;b〉?, + ] { + 〈1;x〉 + } + } + } + } + recursive: { + t2: { + try { + { + x: 〈4;b〉? + y: 〈4;c〉? + } + } + } + } + recursive: { + t3: { + try { + { + x: 〈4;b〉? + y: 〈4;c〉? + } + } else { + z: 23 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/comprehensions/try_compile_errors.txtar b/internal/core/compile/testdata/sync/comprehensions/try_compile_errors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/comprehensions/try_compile_errors.txtar @@ -0,0 +1,79 @@ +#inlinetest:exclude CUE source contains compile-time errors (try-clause syntax, missing +# references) which prevent the inline runner from compiling the source. +-- in.cue -- +@experiment(try) + +// Struct-form try must be the last clause +structFormNotLast: { + try if true { x: 1 } +} + +// ? marker outside try context +optionalOutsideTry: { + a: 1 + b: a? +} + +// ? marker in for clause source (outside try) +optionalInForSource: { + a?: [1, 2, 3] + for x in a? { "\(x)": x } +} + +// ? marker in body of assignment-form try +optionalInAssignmentBody: { + a: 1 + b: 2 + try y = a? { x: b? } else { fallback: 23 } +} + +// Struct-form try must be the last clause +invalidUseOfOptional: { + try { x: c? } +} + +-- out/compile -- +structFormNotLast: struct-form try clause must be the last clause in a comprehension: + ./in.cue:5:5 +optionalOutsideTry.b: optional marker (?) is only valid within a try clause: + ./in.cue:11:8 +optionalInForSource: optional marker (?) is only valid within a try clause: + ./in.cue:17:14 +optionalInAssignmentBody.try[].x: optional marker (?) is only valid within a try clause: + ./in.cue:24:21 +invalidUseOfOptional.x: reference "c" not found: + ./in.cue:29:14 +--- in.cue +{ + structFormNotLast: { + _|_(struct-form try clause must be the last clause in a comprehension) + } + optionalOutsideTry: { + a: 1 + b: 〈0;a〉? + } + optionalInForSource: { + a?: [ + 1, + 2, + 3, + ] + for _, x in 〈0;a〉? { + "\(〈1;x〉)": 〈1;x〉 + } + } + optionalInAssignmentBody: { + a: 1 + b: 2 + try y = 〈0;a〉? { + x: 〈2;b〉? + } else { + fallback: 23 + } + } + invalidUseOfOptional: { + try { + x: _|_(reference "c" not found) + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/015_reference_across_tuples_and_back.txtar b/internal/core/compile/testdata/sync/cycle/015_reference_across_tuples_and_back.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/015_reference_across_tuples_and_back.txtar @@ -0,0 +1,23 @@ +-- in.cue -- +t1: { + a: {c: b.e, d: b.f} + b: {e: 3, f: a.c} + @test(eq, { + a: {c: 3, d: 3} + b: {e: 3, f: 3} + }) +} +-- out/compile -- +--- in.cue +{ + t1: { + a: { + c: 〈1;b〉.e + d: 〈1;b〉.f + } + b: { + e: 3 + f: 〈1;a〉.c + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/021_delayed_constraint_failure.txtar b/internal/core/compile/testdata/sync/cycle/021_delayed_constraint_failure.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/021_delayed_constraint_failure.txtar @@ -0,0 +1,20 @@ +#name: delayed constraint failure +#evalPartial +# Tests that cycles resolved by defaults produce correct values, while +# conflicting constraints on the same field produce errors. +-- in.cue -- +a: b - 100 @test(eq, 100) // Okay to have no error here, as long as there is an error with b. +b: a + 110 +b: 200 @test(err, code=eval, pos=[-1:4, 0:4]) + +x: 100 +x: x + 1 @test(err, code=eval, pos=[-1:4, 0:4]) +-- out/compile -- +--- in.cue +{ + a: (〈0;b〉 - 100) + b: (〈0;a〉 + 110) + b: 200 + x: 100 + x: (〈0;x〉 + 1) +} diff --git a/internal/core/compile/testdata/sync/cycle/023_reentrance.txtar b/internal/core/compile/testdata/sync/cycle/023_reentrance.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/023_reentrance.txtar @@ -0,0 +1,65 @@ +#name: reentrance +#evalFull +-- in.cue -- +// This indirection is needed to avoid binding references to fib +// within fib to the instantiated version. +fibRec: { + nn: int + out: (fib & {n: nn}).out + @test(err, code=incomplete, at=out) +} +fib: { + n: int + + if n >= 2 { + out: (fibRec & {nn: n - 2}).out + (fibRec & {nn: n - 1}).out + } + if n < 2 { + out: n + } + @test(err, code=incomplete) +} +fib1: (fib & {n: 1}).out @test(eq, 1) // MAY NOT be an error +fib2: (fib & {n: 2}).out @test(eq, 1) // MAY be an error +fib3: (fib & {n: 3}).out @test(err, code=structural_cycle) // SHOULD be an error +fib7: (fib & {n: 7}).out @test(err, code=structural_cycle) // Error +fib12: (fib & {n: 12}).out @test(err, code=structural_cycle) // Error + +-- out/compile -- +--- in.cue +{ + fibRec: { + nn: int + out: (〈1;fib〉 & { + n: 〈1;nn〉 + }).out + } + fib: { + n: int + if (〈0;n〉 >= 2) { + out: ((〈2;fibRec〉 & { + nn: (〈2;n〉 - 2) + }).out + (〈2;fibRec〉 & { + nn: (〈2;n〉 - 1) + }).out) + } + if (〈0;n〉 < 2) { + out: 〈1;n〉 + } + } + fib1: (〈0;fib〉 & { + n: 1 + }).out + fib2: (〈0;fib〉 & { + n: 2 + }).out + fib3: (〈0;fib〉 & { + n: 3 + }).out + fib7: (〈0;fib〉 & { + n: 7 + }).out + fib12: (〈0;fib〉 & { + n: 12 + }).out +} diff --git a/internal/core/compile/testdata/sync/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar b/internal/core/compile/testdata/sync/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/025_cannot_resolve_references_that_would_be_ambiguous.txtar @@ -0,0 +1,35 @@ +#name: cannot resolve references that would be ambiguous +#evalFull +-- in.cue -- +a1: *0 | 1 +a1: a3 - a2 @test(err, code=cycle, pos=[2:10]) +a2: *0 | 1 +a2: a3 - a1 @test(err, code=cycle, pos=[0:10]) +a3: 1 @test(eq, 1) + +b1: (*0 | 1) & b2 @test(eq, 0|1) +b2: (0 | *1) & b1 @test(eq, 0|1) + +c1: (*{a: 1} | {b: 1}) & c2 @test(eq, {a: 1, b: 2} | {b: 1, a: 2}) +c2: (*{a: 2} | {b: 2}) & c1 @test(eq, {a: 2, b: 1} | {b: 2, a: 1}) +-- out/compile -- +--- in.cue +{ + a1: (*0|1) + a1: (〈0;a3〉 - 〈0;a2〉) + a2: (*0|1) + a2: (〈0;a3〉 - 〈0;a1〉) + a3: 1 + b1: ((*0|1) & 〈0;b2〉) + b2: ((0|*1) & 〈0;b1〉) + c1: ((*{ + a: 1 + }|{ + b: 1 + }) & 〈0;c2〉) + c2: ((*{ + a: 2 + }|{ + b: 2 + }) & 〈0;c1〉) +} diff --git a/internal/core/compile/testdata/sync/cycle/049_self-reference_cycles_conflicts_with_strings.txtar b/internal/core/compile/testdata/sync/cycle/049_self-reference_cycles_conflicts_with_strings.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/049_self-reference_cycles_conflicts_with_strings.txtar @@ -0,0 +1,19 @@ +#name: self-reference cycles conflicts with strings +#evalPartial +-- in.cue -- +a: { + x: y + "?" + y: x + "!" @test(eq, "hey!") +} +a: x: "hey" @test(err, code=eval, contains="conflicting values", pos=[-3:5, 0:7]) +-- out/compile -- +--- in.cue +{ + a: { + x: (〈0;y〉 + "?") + y: (〈0;x〉 + "!") + } + a: { + x: "hey" + } +} diff --git a/internal/core/compile/testdata/sync/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar b/internal/core/compile/testdata/sync/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/050_resolved_self-reference_cycles_with_disjunctions.txtar @@ -0,0 +1,31 @@ +#name: resolved self-reference cycles with disjunctions +#evalPartial +-- in.cue -- +a: b & {x: 1} | {y: 1} // {x:1,y:3,z:2} | {y:1} +b: {x: 2} | c & {z: 2} // {x:2} | {x:1,y:3,z:2} +c: a & {y: 3} | {z: 3} // {x:1,y:3,z:2} | {z:3} + +@test(eq, { + a: {x: 1, z: 2, y: 3} | {y: 1} + b: {x: 2} | {z: 2, y: 3, x: 1} + c: {y: 3, x: 1, z: 2} | {z: 3} +}) +-- out/compile -- +--- in.cue +{ + a: ((〈0;b〉 & { + x: 1 + })|{ + y: 1 + }) + b: ({ + x: 2 + }|(〈0;c〉 & { + z: 2 + })) + c: ((〈0;a〉 & { + y: 3 + })|{ + z: 3 + }) +} diff --git a/internal/core/compile/testdata/sync/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar b/internal/core/compile/testdata/sync/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar @@ -0,0 +1,124 @@ +#name: resolved self-reference cycles with disjunction +#evalPartial + +// TODO(cycle) +// +// Some of these examples used to work, but the changes corresponding to this +// addition, it ceased to do so. Fixing these cycle issues seemed more +// important than keeping this esoteric case working, which was already broken +// in the last release anyway. +// +// Reproducer of underlying problem. Still works, but triggers unexpected +// condition. +// +// xb1: xb2 +// xb2: xb3 +// xb3: xb2 + 0 +-- in.cue -- +// The second disjunct in xa1 is not resolvable and can be +// eliminated: +// xa4 & 9 +// (xa2 + 2) & 9 +// ((xa3 + 2) + 2) & 9 +// (((6 & xa1-2) + 2) + 2) & 9 +// ((6 + 2) + 2) & 9 // 6 == xa1-2 +// 10 & 9 => _|_ +// The remaining values resolve. +xa1: (xa2 & 8) | (xa4 & 9) @test(eq, 8) +xa2: xa3 + 2 @test(eq, 8) +xa3: 6 & xa1-2 @test(eq, 6) +xa4: xa2 + 2 @test(eq, 10) + +// TODO(inline): make positions work here. +xb1: (xb2 & 8) | (xb4 & 9) @test(err, code=cycle, + suberr=(code=cycle, path=xb2, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, path=xb3, contains="%d errors in empty disjunction:", args=[3]), + suberr=(code=cycle, path=xb3, contains="unresolved disjunction: %v", args=[xb1]), + suberr=(code=cycle, path=xb3, contains="cycle with field: %v", args=[xb2])) +xb2: xb3 + 2 @test(err, code=cycle, + suberr=(code=cycle, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, path=xb3, contains="cycle with field: %v", args=[xb2])) +xb3: (6 & (xb1 - 2)) | (xb4 & 9) @test(err, code=cycle, + suberr=(code=cycle, path=xb2, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, contains="unresolved disjunction: %v", args=[xb1]), + suberr=(code=cycle, contains="cycle with field: %v", args=[xb2])) +xb4: xb2 + 2 @test(err, code=cycle, + suberr=(code=cycle, path=xb2, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, path=xb3, contains="cycle with field: %v", args=[xb2])) + +// Another variant with more disjunctions. xc1 remains with two +// possibilities. Technically, only the first value is valid. +// However, to fully determine that, all options of the remaining +// disjunction will have to be evaluated algebraically, which is +// not done. +xc1: xc2 & 8 | xc4 & 9 | xc5 & 9 @test(eq, 8|9) +xc2: xc3 + 2 @test(eq, 8) +xc3: 6 & xc1-2 @test(err, code=incomplete, + contains="unresolved disjunction %v (type %s)", args=[8 | 9, int], pos=[0:10]) +xc4: xc2 + 1 @test(eq, 9) +xc5: xc2 + 2 @test(eq, 10) + +// The below is resolved by setting xd1 explicitly. +xd1: xd2 & 8 | xd4 & 9 | xd5 & 9 // 8 see below +xd2: xd3 + 2 @test(eq, 8) +xd3: 6 & xd1-2 @test(eq, 6) +xd4: xd2 + 1 @test(eq, 9) +xd5: xd2 + 2 @test(eq, 10) +xd1: 8 @test(eq, 8) + +// The below is resolved by setting xd1 explicitly to the wrong +// value, resulting in an error. +xe1: xe2 & 8 | xe4 & 9 | xe5 & 9 +xe2: xe3 + 2 @test(eq, 8) +xe3: 6 & xe1-2 @test(err, code=eval, pos=[0:6, 0:10]) +xe4: xe2 + 1 @test(eq, 9) +xe5: xe2 + 2 @test(eq, 10) +xe1: 9 @test(eq, 9) + +xf1: xf2 & 8 | xf4 & 9 @test(err, code=cycle, pos=[]) +xf2: xf3 + 2 @test(err, code=cycle, pos=[0:6]) +xf3: 6 & xf1-2 | xf4 & 9 @test(err, code=cycle, pos=[-1:6]) +xf4: xf2 + 2 @test(err, code=cycle, pos=[-2:6]) + +z1: z2+1 | z3+5 @test(eq, 11|13) // +3 for fun +z2: z3 + 2 @test(eq, 10) +z3: z1 - 3 +z3: 8 @test(err, code=incomplete, + contains="unresolved disjunction %v (type %s)", args=[11 | 13, int], pos=[-1:5]) +-- out/compile -- +--- in.cue +{ + xa1: ((〈0;xa2〉 & 8)|(〈0;xa4〉 & 9)) + xa2: (〈0;xa3〉 + 2) + xa3: (6 & (〈0;xa1〉 - 2)) + xa4: (〈0;xa2〉 + 2) + xb1: ((〈0;xb2〉 & 8)|(〈0;xb4〉 & 9)) + xb2: (〈0;xb3〉 + 2) + xb3: ((6 & (〈0;xb1〉 - 2))|(〈0;xb4〉 & 9)) + xb4: (〈0;xb2〉 + 2) + xc1: ((〈0;xc2〉 & 8)|(〈0;xc4〉 & 9)|(〈0;xc5〉 & 9)) + xc2: (〈0;xc3〉 + 2) + xc3: (6 & (〈0;xc1〉 - 2)) + xc4: (〈0;xc2〉 + 1) + xc5: (〈0;xc2〉 + 2) + xd1: ((〈0;xd2〉 & 8)|(〈0;xd4〉 & 9)|(〈0;xd5〉 & 9)) + xd2: (〈0;xd3〉 + 2) + xd3: (6 & (〈0;xd1〉 - 2)) + xd4: (〈0;xd2〉 + 1) + xd5: (〈0;xd2〉 + 2) + xd1: 8 + xe1: ((〈0;xe2〉 & 8)|(〈0;xe4〉 & 9)|(〈0;xe5〉 & 9)) + xe2: (〈0;xe3〉 + 2) + xe3: (6 & (〈0;xe1〉 - 2)) + xe4: (〈0;xe2〉 + 1) + xe5: (〈0;xe2〉 + 2) + xe1: 9 + xf1: ((〈0;xf2〉 & 8)|(〈0;xf4〉 & 9)) + xf2: (〈0;xf3〉 + 2) + xf3: ((6 & (〈0;xf1〉 - 2))|(〈0;xf4〉 & 9)) + xf4: (〈0;xf2〉 + 2) + z1: ((〈0;z2〉 + 1)|(〈0;z3〉 + 5)) + z2: (〈0;z3〉 + 2) + z3: (〈0;z1〉 - 3) + z3: 8 +} diff --git a/internal/core/compile/testdata/sync/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar b/internal/core/compile/testdata/sync/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar @@ -0,0 +1,90 @@ +#name: resolved self-reference cycles with disjunction with defaults +#evalPartial +-- in.cue -- +// The disjunction in xa could be resolved, but as disjunctions +// are not resolved for expression, it remains unresolved. +xa1: (xa2 & 8) | *(xa4 & 9) @test(eq, 8) +xa2: xa3 + 2 @test(eq, 8) +xa3: 6 & xa1-2 @test(eq, 6) +xa4: xa2 + 2 @test(eq, 10) + +// TODO(inline): make positions work here. +xb1: *(xb2 & 8) | (xb4 & 9) @test(err, code=cycle, pos=[], + suberr=(code=cycle, path=xb2, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, path=xb3, contains="%d errors in empty disjunction:", args=[3]), + suberr=(code=cycle, path=xb3, contains="unresolved disjunction: %v", args=[xb1],), + suberr=(code=cycle, path=xb3, contains="cycle with field: %v", args=[xb2])) +xb2: xb3 + 2 @test(err, code=cycle, + suberr=(code=cycle, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, path=xb3, contains="cycle with field: %v", args=[xb2])) +xb3: *(6 & (xb1 - 2)) | (xb4 & 9) @test(err, code=cycle, + suberr=(code=cycle, path=xb2, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, contains="unresolved disjunction: %v", args=[xb1]), + suberr=(code=cycle, contains="cycle with field: %v", args=[xb2])) +xb4: xb2 + 2 @test(err, code=cycle, + suberr=(code=cycle, path=xb2, contains="unresolved disjunction: %v", args=[xb3]), + suberr=(code=cycle, path=xb3, contains="cycle with field: %v", args=[xb2])) + +// Another variant with more disjunctions. xc1 remains with two +// possibilities. Technically, only the first value is valid. +// However, to fully determine that, all options of the remaining +// disjunction will have to be evaluated algebraically, which is +// not done. +xc1: *(xc2 & 8) | (xc4 & 9) | (xc5 & 9) @test(eq, *8|9) +xc2: xc3 + 2 @test(eq, 8) +xc3: 6 & xc1-2 @test(eq, 6) +xc4: xc2 + 1 @test(eq, 9) +xc5: xc2 + 2 @test(eq, 10) + +// The above is resolved by setting xd1 explicitly. +xd1: *(xd2 & 8) | xd4 & 9 | xd5 & 9 @test(eq, *8|9) +xd2: xd3 + 2 @test(eq, 8) +xd3: 6 & xd1-2 @test(eq, 6) +xd4: xd2 + 1 @test(eq, 9) +xd5: xd2 + 2 @test(eq, 10) + +// The above is resolved by setting xd1 explicitly to the wrong +// value, resulting in an error. +xe1: *(xe2 & 8) | xe4 & 9 | xe5 & 9 +xe2: xe3 + 2 @test(eq, 8) +xe3: 6 & xe1-2 @test(err, code=eval, pos=[0:6, 0:10]) +xe4: xe2 + 1 @test(eq, 9) +xe5: xe2 + 2 @test(eq, 10) +xe1: 9 @test(eq, 9) + +z1: *(z2 + 1) | z3+5 @test(eq, *11|13) +z2: z3 + 2 @test(eq, 10) +z3: z1 - 3 +z3: 8 @test(eq, 8) +-- out/compile -- +--- in.cue +{ + xa1: ((〈0;xa2〉 & 8)|*(〈0;xa4〉 & 9)) + xa2: (〈0;xa3〉 + 2) + xa3: (6 & (〈0;xa1〉 - 2)) + xa4: (〈0;xa2〉 + 2) + xb1: (*(〈0;xb2〉 & 8)|(〈0;xb4〉 & 9)) + xb2: (〈0;xb3〉 + 2) + xb3: (*(6 & (〈0;xb1〉 - 2))|(〈0;xb4〉 & 9)) + xb4: (〈0;xb2〉 + 2) + xc1: (*(〈0;xc2〉 & 8)|(〈0;xc4〉 & 9)|(〈0;xc5〉 & 9)) + xc2: (〈0;xc3〉 + 2) + xc3: (6 & (〈0;xc1〉 - 2)) + xc4: (〈0;xc2〉 + 1) + xc5: (〈0;xc2〉 + 2) + xd1: (*(〈0;xd2〉 & 8)|(〈0;xd4〉 & 9)|(〈0;xd5〉 & 9)) + xd2: (〈0;xd3〉 + 2) + xd3: (6 & (〈0;xd1〉 - 2)) + xd4: (〈0;xd2〉 + 1) + xd5: (〈0;xd2〉 + 2) + xe1: (*(〈0;xe2〉 & 8)|(〈0;xe4〉 & 9)|(〈0;xe5〉 & 9)) + xe2: (〈0;xe3〉 + 2) + xe3: (6 & (〈0;xe1〉 - 2)) + xe4: (〈0;xe2〉 + 1) + xe5: (〈0;xe2〉 + 2) + xe1: 9 + z1: (*(〈0;z2〉 + 1)|(〈0;z3〉 + 5)) + z2: (〈0;z3〉 + 2) + z3: (〈0;z1〉 - 3) + z3: 8 +} diff --git a/internal/core/compile/testdata/sync/cycle/builtins.txtar b/internal/core/compile/testdata/sync/cycle/builtins.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/builtins.txtar @@ -0,0 +1,776 @@ +# Tests that evaluating a value through a builtin (regexp.FindNamedSubmatch) +# and then back into a value does not cause incorrect cycle detection. +-- in.cue -- +import "regexp" + +// Issue #655 +// When evaluating a value into a struct, and then back into a value, the +// evaluation mode flips from Partial to AllConjunctsDone to Back. This is +// typically not an issue, but if a referred field is within a struct generated +// by a builtin, effectively the entire struct needs to be evaluated and special +// care should be taking to not evaluate too early. +builtinCyclePerm: { + @test(permute, count=6) + X: "mod.test" + + Y: { + #components: regexp.FindNamedSubmatch(#"^(?P[[:alnum:].]+)$"#, X) + host: #components.host + } + + X: Y.host + + @test(eq, { + X: "mod.test" + Y: { + #components: {host: "mod.test"} + host: "mod.test" + } + }) +} +-- matchn.cue -- +// This should not be a structural cycle, as the list type is "optional". +issue3410: { + _s + _s: { + #x: matchN(1, [_s, [..._s]]) + } + // TODO(inline): inline test outputs references in calls. This was crafted + // by hand. + @test(eq, { + _s: {#x: matchN(1, [_|_, []])} + #x: matchN(1, [_|_, []]) + }) +} +issue3420: { + matches1: { + #S: matchN(1, [_, _|_]) + s: 2 + } + @test(eq, { + matches1: {#S: matchN(1, [_, _|_]), s: 2} + }) +} +issue3443: { + matchIf: { + #S: matchIf({x?: "b"}, {n?: #S & (int | {})}, _) + } + noCycle: { + // This is not a structural cycle, and should not hang, as n? is optional. + #S: matchN(1, [{n?: #S & (int | {})}]) + + noHang: { + s: #S + s: n: n: _ + } + } + + noCycle2: { + #S: matchN(1, [{n?: (int | #S)}]) + } + + cycle1: { + // This correct CUE, as matchN allows for schema to be errors. We should + // probably have a vet rule to catch this,though. + #S: matchN(1, [{n: #S}]) + + // This is not an error as the result is structure shared. Not sure if + // this should be accepted. + ok: { + s: #S + s: _ + } + + // This unifies deep enough to cause a structural cycle. It probably + // should not. + cycle: { + s: #S + s: n: n: _ + } + } + + cycle2: { + // TODO: this should probably fail, or at least be consistent with + // cycle1.cycle. + fail: #S: matchN(1, [{n: #S}]) & {n: n: n: _} + } + @test(err, pos=[2:7]) +} +issue3633: final: { + // With nested matchNs as below, the schema will become an incomplete error + // as a value of the root vertex. Make sure this edge case is properly + // handled. + data: {} & #s @test(err, code=incomplete, pos=[1:6, 0:8, 1:13]) + #s: matchN(1, [matchN(1, [{a!: _}])]) +} +issue3842: reduced: { + #recursive: [...matchIf({ + source?: "multi" + }, #recursive, _) & { + source?: string + }] + @test(eq, {#recursive: []}) +} +-- cycle.cue -- +import "strconv" + +noCycle: t1: { + _s + _s: { + #x: matchN(1, [_s]) + #x: {} // insert concrete value to trigger application of validator. + } + @test(err, pos=[3:7, 3:14, 4:13]) +} +issue3649: noCycle: t1: { + data: #c + data: a: b: "foo" + #c: { + // There should be no cycle because of these optional fields. + b?: string + a?: matchN(1, [#c]) + } + // Cannot use @test(eq) with self-referential #c in expected value. + @test(eq, "foo", at=data.a.b) + @test(debug, """ + (struct){ + data: (#struct){ + a: (#struct){ + b: (string){ "foo" } + } + b?: (string){ string } + } + #c: (#struct){ + b?: (string){ string } + a?: (_){ matchN(1, (#list){ + 0: (_|_){// 〈2;#c〉 + } + }) } + } + } + """) +} +// Same as above, but with longer paths. +issue3649: noCycle: t2: { + x: c + x: y: a: d: b: "foo" + c: { + b?: string + y: a?: matchN(1, [{d: c}]) + } + // Cannot use @test(eq) with self-referential c in expected value. + @test(eq, {a: {d: {b: "foo"}}}, at=x.y) + @test(debug, """ + (struct){ + x: (struct){ + y: (struct){ + a: (struct){ + d: (struct){ + b: (string){ "foo" } + } + } + } + b?: (string){ string } + } + c: (struct){ + b?: (string){ string } + y: (struct){ + a?: (_){ matchN(1, (#list){ + 0: (_|_){// { + // d: 〈4;c〉 + // } + } + }) } + } + } + } + """) +} +issue3649: cycle: t1: { + data: #c + data: a: b: "foo" + #c: { + b: string + a: matchN(1, [#c]) + } + @test(err, pos=[5:6, 2:11, 5:13]) +} + +// This used to cause a stack overflow. +issue4037: cycle: { + _intlike: x=matchN(1, [strconv.Atoi(x)]) + f: "1233" & _intlike + @test(err, pos=[1:14, 1:21, 2:5]) +} +-- yamlcycle.cue -- +import "encoding/yaml" + +yamlNoCycle: { + // the validator is invoked recursively and also unifies with a concrete + // value. This should nonetheless not result in a cycle error. + #c: { + b?: string + a?: yaml.Validate(#c) + } + data: #c + data: a: #"{a: "b: foo"}"# + @test(eq, { + #c: { + b?: string + a?: yaml.Validate({ + b?: string + a?: _ + }) + } + data: {a: "{a: \"b: foo\"}", b?: string} + }) +} +selfCycle: t1: { + c: matchN(1, [{d: c}]) + c: d: {} + @test(err, pos=[1:5, 1:12, 2:5]) +} +selfCycle: t2: { + // Even though only part of the path is unified with concrete data, this + // should still result in a cycle error. + c: matchN(1, [{d: c}]) + c: {} + @test(eq, {c: {}}) +} +selfCycle: yamlVal: t1: { + x: y: yaml.Validate(x) + x: y: "{}" + @test(err, pos=[1:8, 2:8]) +} +selfCycle: yamlVal: t2: { + // Duplicating validators can cause some tricky code paths, like finalizing + // a node while still in the middle of validation. + x: y: yaml.Validate(x) + x: y: "{}" + x: y: yaml.Validate(x) + x: y: "{}" + @test(err, pos=[3:8, 4:8, 5:8, 6:8]) +} +selfCycle: yamlFun: t1:{ + x: y?: yaml.Validate("{}", x) + @test(eq, {x: {y?: true}}) +} +selfCycle: yamlFun: t2: { + z: x & __no_sharing + z: y: "{}" + x: y: yaml.Validate("{}", x) + @test(err, pos=[3:8]) +} +selfCycle: yamlValidatePartial: { + x: y: yaml.ValidatePartial(x) + x: y: "{}" + @test(err, pos=[1:8, 2:8]) +} +-- jsoncycle.cue -- +import "encoding/json" + +jsonCycle: t1: { + x: y: json.Validate(x) + x: y: "{}" + @test(err, pos=[1:8, 2:8]) +} +-- listmatchncycle.cue -- +import "list" + +listMatchN: structCycle: { + x: y: list.MatchN(1, x) + x: y: [{}] + @test(err, pos=[1:8, 1:5, 1:20, 2:5, 2:8]) +} +listMatchN: ok: { + x: y?: list.MatchN(1, x) + z: x + z: y: [{}] + // x.y? is non-concrete (list.MatchN validator); only check z.y which is concrete. + @test(eq, [{}], at=z.y) + @test(debug, """ + (struct){ + x: (struct){ + y?: (list){ list.MatchN(1, listMatchN.ok.x) } + } + z: (struct){ + y: (#list){ + 0: (struct){ + } + } + } + } + """) +} +-- issue3634.cue -- +// evalv3 structural cycle regression: using `len(...)` with a `#Schema` +// embedding inside `list.Repeat` caused a spurious structural cycle error +// that did not occur in evalv2. +// https://cuelang.org/issue/3634 +import "list" + +issue3634: full: { + #Schema: { + required?: [...string] + properties?: [string]: null | #Schema + } + + out: len([...#Schema] & list.Repeat([{ + #Schema // removing this fixes the bug! + properties: foo: required: ["bar", "baz"] + }], 3)) + + @test(eq, { + #Schema: {required?: [], properties?: {}} + out: 3 + }) +} +issue3634: reduced: { + #D: { + b?: int + a?: #D + } + out: len(#D & list.Repeat([#D & { a: b: 1 }], 1)[0]) + + @test(eq, { + #D: { + b?: int + a?: _|_ @test(err, code=structural_cycle, contains="issue3634.reduced.#D.a: structural cycle", pos=[]) + } + out: 1 + }) +} +-- issue3743.cue -- +// Passing a cyclic value to `yaml.MarshalStream` caused a stack overflow +// instead of a clean structural cycle error. +// https://cuelang.org/issue/3743 +import "encoding/yaml" + +issue3743: { + #transform: { + in: _ + out: [ + if false {out}, // note that this is a cycle + in, + ] + } + + docs: [ (#transform & {in: "x"}).out ] + out: yaml.MarshalStream(docs) + + @test(eq, { + #transform: {in: _, out: [_]} + docs: [["x"]] + out: "- x\n" + }) +} +-- out/compile -- +--- cycle.cue +{ + noCycle: { + t1: { + 〈0;_s〉 + _s: { + #x: matchN(1, [ + 〈2;_s〉, + ]) + #x: {} + } + } + } + issue3649: { + noCycle: { + t1: { + data: 〈0;#c〉 + data: { + a: { + b: "foo" + } + } + #c: { + b?: string + a?: matchN(1, [ + 〈2;#c〉, + ]) + } + } + } + } + issue3649: { + noCycle: { + t2: { + x: 〈0;c〉 + x: { + y: { + a: { + d: { + b: "foo" + } + } + } + } + c: { + b?: string + y: { + a?: matchN(1, [ + { + d: 〈4;c〉 + }, + ]) + } + } + } + } + } + issue3649: { + cycle: { + t1: { + data: 〈0;#c〉 + data: { + a: { + b: "foo" + } + } + #c: { + b: string + a: matchN(1, [ + 〈2;#c〉, + ]) + } + } + } + } + issue4037: { + cycle: { + _intlike: matchN(1, [ + 〈import;strconv〉.Atoi(〈1〉), + ]) + f: ("1233" & 〈0;_intlike〉) + } + } +} +--- in.cue +{ + builtinCyclePerm: { + X: "mod.test" + Y: { + #components: 〈import;regexp〉.FindNamedSubmatch("^(?P[[:alnum:].]+)$", 〈1;X〉) + host: 〈0;#components〉.host + } + X: 〈0;Y〉.host + } +} +--- issue3634.cue +{ + issue3634: { + full: { + #Schema: { + required?: [ + ...string, + ] + properties?: { + [string]: (null|〈2;#Schema〉) + } + } + out: len(([ + ...〈1;#Schema〉, + ] & 〈import;list〉.Repeat([ + { + 〈2;#Schema〉 + properties: { + foo: { + required: [ + "bar", + "baz", + ] + } + } + }, + ], 3))) + } + } + issue3634: { + reduced: { + #D: { + b?: int + a?: 〈1;#D〉 + } + out: len((〈0;#D〉 & 〈import;list〉.Repeat([ + (〈1;#D〉 & { + a: { + b: 1 + } + }), + ], 1)[0])) + } + } +} +--- issue3743.cue +{ + issue3743: { + #transform: { + in: _ + out: [ + if false { + 〈2;out〉 + }, + 〈1;in〉, + ] + } + docs: [ + (〈1;#transform〉 & { + in: "x" + }).out, + ] + out: 〈import;"encoding/yaml"〉.MarshalStream(〈0;docs〉) + } +} +--- jsoncycle.cue +{ + jsonCycle: { + t1: { + x: { + y: 〈import;"encoding/json"〉.Validate(〈1;x〉) + } + x: { + y: "{}" + } + } + } +} +--- listmatchncycle.cue +{ + listMatchN: { + structCycle: { + x: { + y: 〈import;list〉.MatchN(1, 〈1;x〉) + } + x: { + y: [ + {}, + ] + } + } + } + listMatchN: { + ok: { + x: { + y?: 〈import;list〉.MatchN(1, 〈1;x〉) + } + z: 〈0;x〉 + z: { + y: [ + {}, + ] + } + } + } +} +--- matchn.cue +{ + issue3410: { + 〈0;_s〉 + _s: { + #x: matchN(1, [ + 〈2;_s〉, + [ + ...〈3;_s〉, + ], + ]) + } + } + issue3420: { + matches1: { + #S: matchN(1, [ + _, + _|_(explicit error (_|_ literal) in source), + ]) + s: 2 + } + } + issue3443: { + matchIf: { + #S: 〈1;matchIf〉({ + x?: "b" + }, { + n?: (〈1;#S〉 & (int|{})) + }, _) + } + noCycle: { + #S: matchN(1, [ + { + n?: (〈2;#S〉 & (int|{})) + }, + ]) + noHang: { + s: 〈1;#S〉 + s: { + n: { + n: _ + } + } + } + } + noCycle2: { + #S: matchN(1, [ + { + n?: (int|〈2;#S〉) + }, + ]) + } + cycle1: { + #S: matchN(1, [ + { + n: 〈2;#S〉 + }, + ]) + ok: { + s: 〈1;#S〉 + s: _ + } + cycle: { + s: 〈1;#S〉 + s: { + n: { + n: _ + } + } + } + } + cycle2: { + fail: { + #S: (matchN(1, [ + { + n: 〈2;#S〉 + }, + ]) & { + n: { + n: { + n: _ + } + } + }) + } + } + } + issue3633: { + final: { + data: ({} & 〈0;#s〉) + #s: matchN(1, [ + matchN(1, [ + { + a!: _ + }, + ]), + ]) + } + } + issue3842: { + reduced: { + #recursive: [ + ...(matchIf({ + source?: "multi" + }, 〈1;#recursive〉, _) & { + source?: string + }), + ] + } + } +} +--- yamlcycle.cue +{ + yamlNoCycle: { + #c: { + b?: string + a?: 〈import;"encoding/yaml"〉.Validate(〈1;#c〉) + } + data: 〈0;#c〉 + data: { + a: "{a: \"b: foo\"}" + } + } + selfCycle: { + t1: { + c: matchN(1, [ + { + d: 〈2;c〉 + }, + ]) + c: { + d: {} + } + } + } + selfCycle: { + t2: { + c: matchN(1, [ + { + d: 〈2;c〉 + }, + ]) + c: {} + } + } + selfCycle: { + yamlVal: { + t1: { + x: { + y: 〈import;"encoding/yaml"〉.Validate(〈1;x〉) + } + x: { + y: "{}" + } + } + } + } + selfCycle: { + yamlVal: { + t2: { + x: { + y: 〈import;"encoding/yaml"〉.Validate(〈1;x〉) + } + x: { + y: "{}" + } + x: { + y: 〈import;"encoding/yaml"〉.Validate(〈1;x〉) + } + x: { + y: "{}" + } + } + } + } + selfCycle: { + yamlFun: { + t1: { + x: { + y?: 〈import;"encoding/yaml"〉.Validate("{}", 〈1;x〉) + } + } + } + } + selfCycle: { + yamlFun: { + t2: { + z: (〈0;x〉 & _|_(no sharing)) + z: { + y: "{}" + } + x: { + y: 〈import;"encoding/yaml"〉.Validate("{}", 〈1;x〉) + } + } + } + } + selfCycle: { + yamlValidatePartial: { + x: { + y: 〈import;"encoding/yaml"〉.ValidatePartial(〈1;x〉) + } + x: { + y: "{}" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/chain.txtar b/internal/core/compile/testdata/sync/cycle/chain.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/chain.txtar @@ -0,0 +1,792 @@ +# Tests that chaining existing fields through comprehensions and builtins does +# not trigger spurious cycle detection errors. +-- in.cue -- +import "list" + +// The following just chains existing fields and should NOT trigger a cycle +// detection error. + + +chain: t1: { + #maxiter: 2 + + // Trigger lookup of a.x0 before the "regular" evaluation of a. + x: a.x0 + + a: { + for k, _ in [0, 1] { + "x\(k)": (#DepthF & {#in: a["x\(k+1)"]}).#out + } + } + + a: x2: null + + + #DepthF: { + #in: _ + #out: {} + } + @test(eq, { + #maxiter: 2 + x: {} + a: {x2: null, x0: {}, x1: {}} + #DepthF: {#in: _, #out: {}} + }) +} + +chain: t2: p1: { + X: 1 + + // Reference X through x.x0 before X is inserted. + for v in list.Concat([[0, X], []]) { + x: "x\(v)": {} + } + + x: _ + + x.x0 + @test(eq, {X: 1, x: {x0: {}, x1: {}}}) +} + +chain: t2: p2: { + // Reference X through x.x0 before X is inserted. + for v in list.Concat([[0, X], []]) { + x: "x\(v)": {} + } + + x: _ + + x.x0 + + X: 1 + @test(eq, {x: {x0: {}, x1: {}}, X: 1}) +} + +chain: t3: p1: { + X: 1 + + for v in list.Range(0, X, 1) { + x: "x\(v)": {} + } + + x: _ + + x.x0 +} + +chain: t3: p1: { + for v in list.Range(0, X, 1) { + x: "x\(v)": {} + } + + x: _ + + x.x0 + + X: 1 + @test(eq, {X: 1, x: {x0: {}}}) +} + +-- issue2052.cue -- +// Bounded recursion regression: a pattern that evaluated correctly in v0.4.3 +// began failing in v0.5.0-alpha.1 with spurious unbounded recursion errors. +// https://cuelang.org/issue/2052 +import ( + "list" + "math" +) +issue2052: reduced: t1: { + A: a: _ + Depth: { + #maxiter: 1 + if math.Abs(#maxiter) == 1 { + funcs: "\(0)": A + } + funcs: {} + funcs["0"] + } + @test(eq, { + A: {a: _} + Depth: { + #maxiter: 1 + funcs: {"0": {a: _}} + a: _ + } + }) +} +issue2052: reduced: t2: { + A: a: _ + Depth: { + maxiter: 1 + for k, v in list.Range(0, maxiter, 1) { + funcs: "\(0)": A + } + funcs: {} + funcs["0"] + } + @test(eq, { + A: {a: _} + Depth: {maxiter: 1, funcs: {"0": {a: _}}, a: _} + }) +} +issue2052: medium: t1: { + #Depth: { + #maxiter: 4 + + for k, v in list.Range(0, #maxiter, 1) { + #funcs: "\(k)": (#DepthF & {#next: #funcs["\(k+1)"]}).#func + } + + #funcs: "\(#maxiter)": null + + #funcs["0"] + } + + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: string | null + out: { + if (#in & #basic) != _|_ {1} + if (#in & #basic) == _|_ { + list.Max([for k, v in #in {(#next & {#in: v}).out}]) + 1 + } + } + } + } + + tree: "bar" + + d: #Depth & {#in: tree} + + @test(eq, { + #Depth: { + #maxiter: 4 + #funcs: { + "4": null + "0": {#in: _, #basic: string | null, out: 1} + "1": {#in: _, #basic: string | null, out: 1} + "2": {#in: _, #basic: string | null, out: 1} + "3": {#in: _, #basic: string | null, out: 1} + } + #in: _ + #basic: string | null + out: 1 + } + #DepthF: { + #next: _ + #func: {#in: _, #basic: string | null, out: 1} + } + tree: "bar" + d: { + #in: "bar" + #maxiter: 4 + #funcs: { + "4": null + "0": {#in: _, #basic: string | null, out: 1} + "1": {#in: _, #basic: string | null, out: 1} + "2": {#in: _, #basic: string | null, out: 1} + "3": {#in: _, #basic: string | null, out: 1} + } + #basic: string | null + out: 1 + } + }) +} + +issue2052: medium: t2: { + #Depth: { + #maxiter: 4 + + for k, v in list.Range(0, #maxiter, 1) { + #funcs: "\(k)": (#DepthF & {#next: #funcs["\(k+1)"]}).#func + } + + #funcs:{ + for k, v in list.Range(0, #maxiter, 1) { + "\(k)": (#DepthF & {#next: #funcs["\(k+1)"]}).#func + } + } + + #funcs: "\(#maxiter)": null + + #funcs["0"] + } + + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: string | null + out: { + if (#in & #basic) != _|_ {1} + if (#in & #basic) == _|_ { + list.Max([for k, v in #in {(#next & {#in: v}).out}]) + 1 + } + } + } + } + + tree: "bar" + + d: #Depth & {#in: tree} + @test(eq, { + #Depth: { + #maxiter: 4 + #funcs: { + "4": null + "0": {#in: _, #basic: string | null, out: 1} + "1": {#in: _, #basic: string | null, out: 1} + "2": {#in: _, #basic: string | null, out: 1} + "3": {#in: _, #basic: string | null, out: 1} + } + #in: _ + #basic: string | null + out: 1 + } + #DepthF: { + #next: _ + #func: {#in: _, #basic: string | null, out: 1} + } + tree: "bar" + d: { + #in: "bar" + #maxiter: 4 + #funcs: { + "4": null + "0": {#in: _, #basic: string | null, out: 1} + "1": {#in: _, #basic: string | null, out: 1} + "2": {#in: _, #basic: string | null, out: 1} + "3": {#in: _, #basic: string | null, out: 1} + } + #basic: string | null + out: 1 + } + }) +} + +issue2052: full: { + #RecurseN: { + // this is the bound on our recursion + #maxiter: uint | *4 + + // This is the function list element + // we generate this to simulate recursion + #funcFactory: { + #next: _ + #func: _ + } + + // this is our "recursion unrolling" + for k, v in list.Range(0, #maxiter, 1) { + // this is where we build up our indexed functions and the references between them + #funcs: "\(k)": (#funcFactory & {#next: #funcs["\(k+1)"]}).#func + } + + // our final value needs to be null + #funcs: "\(#maxiter)": null + + // we embed the head of the list so that the values + // we write this into can be used like other CUE "functions" + #funcs["0"] + } + + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: int | number | string | bytes | null + out: { + // if we have a basic type, we are at a leaf, depth is 1 + if (#in & #basic) != _|_ {1} + + // if we are not a basic type, then we are 1 + the max of children + if (#in & #basic) == _|_ { + // this is our "recursion" for each child + let depths = [for k, v in #in {(#next & {#in: v}).out}] + list.Max(depths) + 1 + } + } + } + } + + #Depth: #RecurseN & {#maxiter: 11, #funcFactory: #DepthF} + + tree: { + a: { + foo: "bar" + a: b: c: "d" + } + cow: "moo" + } + + d: #Depth & {#in: tree} + @test(eq, { + #RecurseN: { + #maxiter: *4 | >=0 & int + #funcFactory: {#next: _, #func: _} + #funcs: { + "4": null + "0": _ + "1": _ + "2": _ + "3": _ + } + } + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + } + #Depth: { + #maxiter: 11 + #funcFactory: { + #next: _ + #func: { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + } + #funcs: { + "11": null + "0": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "1": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "2": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "3": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "4": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "5": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "6": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "7": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "8": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "9": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "10": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + } + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + tree: { + a: {foo: "bar", a: {b: {c: "d"}}} + cow: "moo" + } + d: { + #in: { + a: {foo: "bar", a: {b: {c: "d"}}} + cow: "moo" + } + #maxiter: 11 + #funcFactory: { + #next: _ + #func: { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + } + #funcs: { + "11": null + "0": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "1": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "2": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "3": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "4": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "5": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "6": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "7": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "8": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "9": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + "10": { + #in: _ + #basic: int | number | string | bytes | null + out: {1} + } + } + #basic: int | number | string | bytes | null + out: {5} + } + }) +} +-- out/compile -- +--- in.cue +{ + chain: { + t1: { + #maxiter: 2 + x: 〈0;a〉.x0 + a: { + for k, _ in [ + 0, + 1, + ] { + "x\(〈1;k〉)": (〈3;#DepthF〉 & { + #in: 〈4;a〉["x\((〈2;k〉 + 1))"] + }).#out + } + } + a: { + x2: null + } + #DepthF: { + #in: _ + #out: {} + } + } + } + chain: { + t2: { + p1: { + X: 1 + for _, v in 〈import;list〉.Concat([ + [ + 0, + 〈2;X〉, + ], + [], + ]) { + x: { + "x\(〈2;v〉)": {} + } + } + x: _ + 〈0;x〉.x0 + } + } + } + chain: { + t2: { + p2: { + for _, v in 〈import;list〉.Concat([ + [ + 0, + 〈2;X〉, + ], + [], + ]) { + x: { + "x\(〈2;v〉)": {} + } + } + x: _ + 〈0;x〉.x0 + X: 1 + } + } + } + chain: { + t3: { + p1: { + X: 1 + for _, v in 〈import;list〉.Range(0, 〈0;X〉, 1) { + x: { + "x\(〈2;v〉)": {} + } + } + x: _ + 〈0;x〉.x0 + } + } + } + chain: { + t3: { + p1: { + for _, v in 〈import;list〉.Range(0, 〈0;X〉, 1) { + x: { + "x\(〈2;v〉)": {} + } + } + x: _ + 〈0;x〉.x0 + X: 1 + } + } + } +} +--- issue2052.cue +{ + issue2052: { + reduced: { + t1: { + A: { + a: _ + } + Depth: { + #maxiter: 1 + if (〈import;math〉.Abs(〈0;#maxiter〉) == 1) { + funcs: { + "\(0)": 〈3;A〉 + } + } + funcs: {} + 〈0;funcs〉["0"] + } + } + } + } + issue2052: { + reduced: { + t2: { + A: { + a: _ + } + Depth: { + maxiter: 1 + for k, v in 〈import;list〉.Range(0, 〈0;maxiter〉, 1) { + funcs: { + "\(0)": 〈4;A〉 + } + } + funcs: {} + 〈0;funcs〉["0"] + } + } + } + } + issue2052: { + medium: { + t1: { + #Depth: { + #maxiter: 4 + for k, v in 〈import;list〉.Range(0, 〈0;#maxiter〉, 1) { + #funcs: { + "\(〈2;k〉)": (〈4;#DepthF〉 & { + #next: 〈2;#funcs〉["\((〈3;k〉 + 1))"] + }).#func + } + } + #funcs: { + "\(〈1;#maxiter〉)": null + } + 〈0;#funcs〉["0"] + } + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: (string|null) + out: { + if ((〈1;#in〉 & 〈1;#basic〉) != _|_(explicit error (_|_ literal) in source)) { + 1 + } + if ((〈1;#in〉 & 〈1;#basic〉) == _|_(explicit error (_|_ literal) in source)) { + (〈import;list〉.Max([ + for k, v in 〈3;#in〉 { + (〈6;#next〉 & { + #in: 〈2;v〉 + }).out + }, + ]) + 1) + } + } + } + } + tree: "bar" + d: (〈0;#Depth〉 & { + #in: 〈1;tree〉 + }) + } + } + } + issue2052: { + medium: { + t2: { + #Depth: { + #maxiter: 4 + for k, v in 〈import;list〉.Range(0, 〈0;#maxiter〉, 1) { + #funcs: { + "\(〈2;k〉)": (〈4;#DepthF〉 & { + #next: 〈2;#funcs〉["\((〈3;k〉 + 1))"] + }).#func + } + } + #funcs: { + for k, v in 〈import;list〉.Range(0, 〈1;#maxiter〉, 1) { + "\(〈1;k〉)": (〈4;#DepthF〉 & { + #next: 〈4;#funcs〉["\((〈2;k〉 + 1))"] + }).#func + } + } + #funcs: { + "\(〈1;#maxiter〉)": null + } + 〈0;#funcs〉["0"] + } + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: (string|null) + out: { + if ((〈1;#in〉 & 〈1;#basic〉) != _|_(explicit error (_|_ literal) in source)) { + 1 + } + if ((〈1;#in〉 & 〈1;#basic〉) == _|_(explicit error (_|_ literal) in source)) { + (〈import;list〉.Max([ + for k, v in 〈3;#in〉 { + (〈6;#next〉 & { + #in: 〈2;v〉 + }).out + }, + ]) + 1) + } + } + } + } + tree: "bar" + d: (〈0;#Depth〉 & { + #in: 〈1;tree〉 + }) + } + } + } + issue2052: { + full: { + #RecurseN: { + #maxiter: (&(int, >=0)|*4) + #funcFactory: { + #next: _ + #func: _ + } + for k, v in 〈import;list〉.Range(0, 〈0;#maxiter〉, 1) { + #funcs: { + "\(〈2;k〉)": (〈3;#funcFactory〉 & { + #next: 〈2;#funcs〉["\((〈3;k〉 + 1))"] + }).#func + } + } + #funcs: { + "\(〈1;#maxiter〉)": null + } + 〈0;#funcs〉["0"] + } + #DepthF: { + #next: _ + #func: { + #in: _ + #basic: (int|number|string|bytes|null) + out: { + if ((〈1;#in〉 & 〈1;#basic〉) != _|_(explicit error (_|_ literal) in source)) { + 1 + } + if ((〈1;#in〉 & 〈1;#basic〉) == _|_(explicit error (_|_ literal) in source)) { + let depths#1 = [ + for k, v in 〈3;#in〉 { + (〈6;#next〉 & { + #in: 〈2;v〉 + }).out + }, + ] + (〈import;list〉.Max(〈0;let depths#1〉) + 1) + } + } + } + } + #Depth: (〈0;#RecurseN〉 & { + #maxiter: 11 + #funcFactory: 〈1;#DepthF〉 + }) + tree: { + a: { + foo: "bar" + a: { + b: { + c: "d" + } + } + } + cow: "moo" + } + d: (〈0;#Depth〉 & { + #in: 〈1;tree〉 + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/compbottom.txtar b/internal/core/compile/testdata/sync/cycle/compbottom.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/compbottom.txtar @@ -0,0 +1,148 @@ +// Issues: #667, #695, #622 + +// Comparing against bottom is not officially supported by the spec. +// In practice it is used for a variety of purposes. +// +// TODO: It should really be replaced with two builtins: +// +// - exists(reference): check if a certain field exists. +// - isvalid(value): check if a certain value is valid (recursively). +// +// For now it implements something in between these two: it fails if a value +// resolves to an error, but not necessarily if it does so recursively. +// Although adding a recursive check is easy, it will break existing +// configurations, as a recursive evaluation will trigger cycles where these +// are perhaps not expected. + +// To verify these tests, each result should have a field +// +// X: "user@example.com" +// +// for the large and medium examples and +// +// X: "message: hello" +// +// for the simple example. +-- in.cue -- +import "regexp" + +simple: { + #message: #"^(message: (?P.*))?$"# + + p1: { + @test(permute, count=24) + + X: "message: hello" + #aux: { + if Y.message == _|_ { + message: "" + } + if Y.message != _|_ { + message: "message: " + Y.message + } + } + + Y: regexp.FindNamedSubmatch(#message, X) + X: #aux.message + @test(eq, { + X: "message: hello" + #aux: {message: "message: hello"} + Y: {message: "hello"} + }) + } +} + +medium: { + #userHostPort: #"^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$"# + + p1: { + @test(permute, count=120) + + Y: { + userinfo: "user" + host: "mod.test" + } + + // X: "user@example.com" + X: #X.userinfo + #X.host + + #X: { + // userinfo: "user@" + // host: "mod.test" + + if Y.userinfo == _|_ { + userinfo: "" + } + if Y.userinfo != _|_ { + userinfo: Y.userinfo + "@" + } + + host: Y.host + } + + Y: { + // userinfo: "user" + // host: "mod.test" + + if #Y.userinfo != _|_ { + userinfo: #Y.userinfo + } + + host: #Y.host + } + + #Y: regexp.FindNamedSubmatch(#userHostPort, X) + @test(eq, { + Y: {userinfo: "user", host: "mod.test"} + X: "user@mod.test" + #X: {userinfo: "user@", host: "mod.test"} + #Y: {host: "mod.test", userinfo: "user"} + }) + } +} +-- out/compile -- +--- in.cue +{ + simple: { + #message: "^(message: (?P.*))?$" + p1: { + X: "message: hello" + #aux: { + if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { + message: "" + } + if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { + message: ("message: " + 〈2;Y〉.message) + } + } + Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) + X: 〈0;#aux〉.message + } + } + medium: { + #userHostPort: "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$" + p1: { + Y: { + userinfo: "user" + host: "mod.test" + } + X: (〈0;#X〉.userinfo + 〈0;#X〉.host) + #X: { + if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { + userinfo: "" + } + if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { + userinfo: (〈2;Y〉.userinfo + "@") + } + host: 〈1;Y〉.host + } + Y: { + if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { + userinfo: 〈2;#Y〉.userinfo + } + host: 〈1;#Y〉.host + } + #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/compbottom2.txtar b/internal/core/compile/testdata/sync/cycle/compbottom2.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/compbottom2.txtar @@ -0,0 +1,813 @@ +-- in.cue -- +self: { + // This is an incomplete error, as it may succeed when the user + // explicitly specifies a value for fail.a.b. + fail: { + a: { + if a.b == _|_ { + b: 1 + } + @test(err, code=incomplete|cycle) + } + } + + // This is an incomplete error, as it may succeed when the user + // explicitly specifies a value for a.b. + isConcreteFail: t1:{ + a: { + if a.b == _|_ { + b: 1 + } + b: int + @test(eq, {b: 1}) + } + } + + isConcreteFail: t2:{ + a: { + if a.b == _|_ { + b: 1 + } + b?: int + @test(err, code=cycle, + contains="circular dependency in evaluation of conditionals: %v changed after evaluation", args=[a.b], pos=[1:7]) + } + } + + // This is an incomplete error, as it may succeed when the user + // explicitly specifies a value for a.b. + // TODO: new builtin semantics. + // if isconcrete(a.b) -->> cyclic error evaluating isconcrete. + // if isdefined(a.b) -->> evaluate to true as a.b is int, result is 1 + // if !isdefined(a.b) -->> evaluate to false, a.b remains int + isNotConcrete: t1: { + a: { + if a.b != _|_ { + b: 1 + } + b: int + @test(eq, {b: int}) + } + } + isNotConcrete: t2: { + a: { + if a.b != _|_ { + b: 1 + } + b?: int + @test(eq, {b?: int}) + } + } + +} + +-- mutual.cue -- +mutual: { + noConflicts: { + a: {if b.foo == _|_ {new: ""}} + b: {if a.bar == _|_ {new: ""}} + @test(eq, {a: {new: ""}, b: {new: ""}}) + } + + mutualCycleFail: { + b: { + if a.bar == _|_ {foo: ""} + @test(err, code=incomplete|cycle) + } + a: { + if b.foo == _|_ {bar: ""} + @test(err, code=incomplete|cycle) + } + } + + brokenCycleSuccess: { + a: { if b.foo == _|_ { foo: "" } } + b: { if a.bar == _|_ { bar: "" } } + a: bar: "" + @test(eq, {a: {foo: "", bar: ""}, b: {}}) + } + + allowOneDirectionalDependency: { + p1: { + a: { if b.foo == _|_ { bar: "" } } // added + b: { if a.bar == _|_ { new: "" } } // not added + @test(eq, {a: {bar: ""}, b: {}}) + } + p2: { + a: { if b.foo == _|_ { new: "" } } + b: { if a.bar == _|_ { foo: "" } } + @test(eq, {a: {}, b: {foo: ""}}) + } + } + + oneDirectionalBrokenConflictSuccess: { + @test(permute, count=6) + b: foo: "" + a: { if b.foo == _|_ { bar: "" } } + b: { if a.bar == _|_ { new: "" } } + @test(eq, {b: {foo: "", new: ""}, a: {}}) + } +} + +-- mutualsamestruct.cue -- +sameStruct: { + chainSuccess: a: { + raises?: {} + if raises == _|_ { + ret: a: 1 + } + ret?: {} + if ret != _|_ { + foo: a: 1 + } + @test(eq, {raises?: {}, ret: {a: 1}, foo: {a: 1}}) + } + + chainSuccess: b: { + if ret != _|_ { + foo: a: 1 + } + raises?: {} + if raises == _|_ { + ret: a: 1 + } + ret?: {} + @test(eq, {foo: {a: 1}, raises?: {}, ret: {a: 1}}) + } + + cycleFail: t1: p1: { + raises?: {} + if raises == _|_ { + ret: a: 1 + } + ret?: {} + if ret != _|_ { + raises: a: 1 + } + @test(err, code=cycle|incomplete, any, contains="circular dependency in evaluation of conditionals: %v changed after evaluation", args=[raises]) + } + + cycleFail: t1: p2: { + ret?: {} + if ret != _|_ { + raises: a: 1 + } + raises?: {} + if raises == _|_ { + ret: a: 1 + } + @test(err, code=cycle, contains="circular dependency in evaluation of conditionals: %v changed after evaluation", args=[ret], pos=[2:6]) + } + + // This test should fail with a cycle error. Even though raises and ret are + // both known to be defined, comparison against bottom requires that the + // structs be recursively checked for errors. We disallow that here, because + // the structs mutually depend on each other. + // TODO: consider allowing a specific postCheck for determining if an arc + // is erroneous. + // Pushdown improvement: raises and ret are both defined as {} (not + // optional), so their bottom checks resolve eagerly without a cycle. + // raises == _|_ is false (raises is {}), so ret: a: 1 is NOT added. + // ret != _|_ is true (ret is {}), so raises: a: 1 IS added. + // ret still has a sub-field cyclic reference error. + cycleFail: t2: p1: { + raises: {} + if raises == _|_ { + ret: a: 1 + } + ret: {} + if ret != _|_ { + raises: a: 1 + } + @test(err, any, code=cycle|incomplete) + } + + // Pushdown improvement: with this ordering, ret != _|_ fires first + // (ret is {}), so raises: a: 1 is added. But raises has a sub-field + // cyclic reference error. Result is ordering-dependent (compare p1). + cycleFail: t2: p2: { + ret: {} + if ret != _|_ { + raises: a: 1 + } + raises: {} + if raises == _|_ { + ret: a: 1 + } + @test(err, any, code=cycle|incomplete) + } + + // Pushdown improvement: raises is _ (top), raises == _|_ is false, + // so ret: a: 1 is NOT added. ret is _ (top), ret != _|_ is true, + // so raises: a: 1 IS added. ret has a sub-field cyclic reference. + // Result is ordering-dependent (compare with p2 below). + cycleFail: t3: p1: { + raises: _ + if raises == _|_ { + ret: a: 1 + } + ret: _ + if ret != _|_ { + raises: a: 1 + } + @test(err, any, code=cycle|incomplete) + } + + // Pushdown improvement: different ordering gives different result. + // Only raises has a sub-field cyclic reference error. + cycleFail: t3: p2: { + ret: _ + if ret != _|_ { + raises: a: 1 + } + raises: _ + if raises == _|_ { + ret: a: 1 + } + @test(err, any, code=cycle|incomplete) + } + + defCloseSuccess: { + #Example: { + raises?: { + runtime?: string + } + + if raises == _|_ { + ret?: _ + } + } + + expr: #Example & { + ret: 2 + } + @test(eq, { + #Example: {raises?: {runtime?: string}, ret?: _} + expr: {ret: 2, raises?: {runtime?: string}} + }) + } +} + +-- nestedchain.cue -- +// Issue +nestedChain: { + cycleFail: { + if #E.x != _|_ { + #E: y: true + } + if #E.y == _|_ { + #E: x: true + } + @test(err, code=incomplete|cycle) + #E: [_]: bool + } + + brokenCycleSuccess: { + if #E.x != _|_ { + #E: y: true + } + if #E.y == _|_ { + #E: x: true + } + #E: [_]: bool + #E: x: true + @test(eq, {#E: {y: true, x: true}}) + } + + doubleAddfail: { + if #E.x == _|_ { + #E: y: true + } + if #E.y == _|_ { + #E: x: true + } + #E: [_]: bool + @test(err, code=incomplete|cycle) + } + + trippleSuccess: { + if #E.x != _|_ { + #E: y: true + } + if #E.y != _|_ { + z: true + } + #E: x: true + @test(eq, {#E: {y: true, x: true}, z: true}) + } +} +-- issue3836.cue -- +// evalv3 regression: a conditional checking `(foo | bar) == _|_` (comparison +// to bottom) stopped working; the branch that fires when no optional field is +// set no longer triggers correctly. +// https://cuelang.org/issue/3836 +issue3836: hidden: { + _Value: { + foo?: _ + bar?: _ + if (foo | bar) == _|_ { + bar: type: "bar" + } + out: [if bar != _|_ {"bar is set"}] + } + _Value.out + // Pushdown improvement: the comprehension guard (foo|bar) == _|_ now + // correctly fires and sets bar, where previously (without pushdown) the + // guard saw a spurious non-bottom value and did not fire. + @test(eq, { + _Value: {foo?: _, bar: type: "bar", out: ["bar is set"]} + ["bar is set"] + }) +} +issue3836: exposed: { + foo?: _ + bar?: _ + if (foo | bar) == _|_ { + bar: type: "bar" + } + out: [if bar != _|_ {"bar is set"}] + @test(err, code=cycle, contains="circular dependency in evaluation of conditionals: %v changed after evaluation", args=[(foo|bar)], pos=[3:6]) +} +-- issue3838.cue -- +// evalv3 regression: `if in.opt != _|_` inside a list expression stopped +// evaluating correctly; evalv2 exported cleanly but evalv3 produced wrong output. +// https://cuelang.org/issue/3838 +issue3838: { + #T: { + subject: { + in: opt?: foo: int + out: [ + if in.opt != _|_ {in.opt.foo}, + 0, + ][0] + } + _test: { + assert: { + pass: bool + } + assert: { + notOk: _ + pass: false + } | { + invoke: _ + res: subject.out + pass: true + } + } + results: _test.assert.pass + } + (#T & { + _test: assert: invoke: "foo" + }).results + @test(eq, { + true + #T: { + subject: {in: {opt?: {foo: int}}, out: 0} + _test: { + assert: {pass: false, notOk: _} | {pass: true, invoke: _, res: 0} + } + results: _|_ @test(err, code=incomplete, contains="issue3838.#T.results: unresolved disjunction {pass:false,notOk:_} | {pass:true,invoke:_,res:0} (type struct)", pos=[26:12]) + } + }) +} +-- out/compile -- +--- in.cue +{ + self: { + fail: { + a: { + if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { + b: 1 + } + } + } + isConcreteFail: { + t1: { + a: { + if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { + b: 1 + } + b: int + } + } + } + isConcreteFail: { + t2: { + a: { + if (〈1;a〉.b == _|_(explicit error (_|_ literal) in source)) { + b: 1 + } + b?: int + } + } + } + isNotConcrete: { + t1: { + a: { + if (〈1;a〉.b != _|_(explicit error (_|_ literal) in source)) { + b: 1 + } + b: int + } + } + } + isNotConcrete: { + t2: { + a: { + if (〈1;a〉.b != _|_(explicit error (_|_ literal) in source)) { + b: 1 + } + b?: int + } + } + } + } +} +--- issue3836.cue +{ + issue3836: { + hidden: { + _Value: { + foo?: _ + bar?: _ + if ((〈0;foo〉|〈0;bar〉) == _|_(explicit error (_|_ literal) in source)) { + bar: { + type: "bar" + } + } + out: [ + if (〈1;bar〉 != _|_(explicit error (_|_ literal) in source)) { + "bar is set" + }, + ] + } + 〈0;_Value〉.out + } + } + issue3836: { + exposed: { + foo?: _ + bar?: _ + if ((〈0;foo〉|〈0;bar〉) == _|_(explicit error (_|_ literal) in source)) { + bar: { + type: "bar" + } + } + out: [ + if (〈1;bar〉 != _|_(explicit error (_|_ literal) in source)) { + "bar is set" + }, + ] + } + } +} +--- issue3838.cue +{ + issue3838: { + #T: { + subject: { + in: { + opt?: { + foo: int + } + } + out: [ + if (〈1;in〉.opt != _|_(explicit error (_|_ literal) in source)) { + 〈2;in〉.opt.foo + }, + 0, + ][0] + } + _test: { + assert: { + pass: bool + } + assert: ({ + notOk: _ + pass: false + }|{ + invoke: _ + res: 〈2;subject〉.out + pass: true + }) + } + results: 〈0;_test〉.assert.pass + } + (〈0;#T〉 & { + _test: { + assert: { + invoke: "foo" + } + } + }).results + } +} +--- mutual.cue +{ + mutual: { + noConflicts: { + a: { + if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { + new: "" + } + } + b: { + if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { + new: "" + } + } + } + mutualCycleFail: { + b: { + if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { + foo: "" + } + } + a: { + if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { + bar: "" + } + } + } + brokenCycleSuccess: { + a: { + if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { + foo: "" + } + } + b: { + if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { + bar: "" + } + } + a: { + bar: "" + } + } + allowOneDirectionalDependency: { + p1: { + a: { + if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { + bar: "" + } + } + b: { + if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { + new: "" + } + } + } + p2: { + a: { + if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { + new: "" + } + } + b: { + if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { + foo: "" + } + } + } + } + oneDirectionalBrokenConflictSuccess: { + b: { + foo: "" + } + a: { + if (〈1;b〉.foo == _|_(explicit error (_|_ literal) in source)) { + bar: "" + } + } + b: { + if (〈1;a〉.bar == _|_(explicit error (_|_ literal) in source)) { + new: "" + } + } + } + } +} +--- mutualsamestruct.cue +{ + sameStruct: { + chainSuccess: { + a: { + raises?: {} + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + ret?: {} + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + foo: { + a: 1 + } + } + } + } + chainSuccess: { + b: { + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + foo: { + a: 1 + } + } + raises?: {} + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + ret?: {} + } + } + cycleFail: { + t1: { + p1: { + raises?: {} + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + ret?: {} + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + raises: { + a: 1 + } + } + } + } + } + cycleFail: { + t1: { + p2: { + ret?: {} + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + raises: { + a: 1 + } + } + raises?: {} + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + } + } + } + cycleFail: { + t2: { + p1: { + raises: {} + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + ret: {} + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + raises: { + a: 1 + } + } + } + } + } + cycleFail: { + t2: { + p2: { + ret: {} + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + raises: { + a: 1 + } + } + raises: {} + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + } + } + } + cycleFail: { + t3: { + p1: { + raises: _ + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + ret: _ + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + raises: { + a: 1 + } + } + } + } + } + cycleFail: { + t3: { + p2: { + ret: _ + if (〈0;ret〉 != _|_(explicit error (_|_ literal) in source)) { + raises: { + a: 1 + } + } + raises: _ + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret: { + a: 1 + } + } + } + } + } + defCloseSuccess: { + #Example: { + raises?: { + runtime?: string + } + if (〈0;raises〉 == _|_(explicit error (_|_ literal) in source)) { + ret?: _ + } + } + expr: (〈0;#Example〉 & { + ret: 2 + }) + } + } +} +--- nestedchain.cue +{ + nestedChain: { + cycleFail: { + if (〈0;#E〉.x != _|_(explicit error (_|_ literal) in source)) { + #E: { + y: true + } + } + if (〈0;#E〉.y == _|_(explicit error (_|_ literal) in source)) { + #E: { + x: true + } + } + #E: { + [_]: bool + } + } + brokenCycleSuccess: { + if (〈0;#E〉.x != _|_(explicit error (_|_ literal) in source)) { + #E: { + y: true + } + } + if (〈0;#E〉.y == _|_(explicit error (_|_ literal) in source)) { + #E: { + x: true + } + } + #E: { + [_]: bool + } + #E: { + x: true + } + } + doubleAddfail: { + if (〈0;#E〉.x == _|_(explicit error (_|_ literal) in source)) { + #E: { + y: true + } + } + if (〈0;#E〉.y == _|_(explicit error (_|_ literal) in source)) { + #E: { + x: true + } + } + #E: { + [_]: bool + } + } + trippleSuccess: { + if (〈0;#E〉.x != _|_(explicit error (_|_ literal) in source)) { + #E: { + y: true + } + } + if (〈0;#E〉.y != _|_(explicit error (_|_ literal) in source)) { + z: true + } + #E: { + x: true + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/compbottomnofinal.txtar b/internal/core/compile/testdata/sync/cycle/compbottomnofinal.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/compbottomnofinal.txtar @@ -0,0 +1,219 @@ +// Issues: #667, #695, #622 +-- in.cue -- +import ( + "strconv" + "regexp" +) + +// In these test, it is impossible to determine the existence of some arcs due +// to mutual dependence on becoming concrete. +// +// This tests shows the essences of when an existence check cannot be resolved. +minimal: { + a: { + if b.port == _|_ { + port: "" + } + // Pushdown produces cycle error instead of incomplete. + @test(err, code=cycle|incomplete) + } + + b: { + if a.port == _|_ { + port: "" + } + // Pushdown produces cycle error instead of incomplete. + @test(err, code=cycle|incomplete) + } +} + +small: { + #userHostPort: #"^(:(?P\d+))?$"# + + p1: { + @test(permute, count=2) + #Y: regexp.FindNamedSubmatch(#userHostPort, #X.port) + + #X: { + if #Y.port == _|_ { + port: "" + } + if #Y.port != _|_ { + port: ":" + strconv.FormatInt(#Y.port, 10) + } + } + // Yield-on-running heuristic: the comp's referenced node + // #Y is not currently being processed (only scheduled), so + // the comp does not yield and instead reports a cycle error. + @test(eq, { + #Y: _|_ @test(err, code=cycle|incomplete) + #X: _|_ @test(err, code=cycle|incomplete) + }) + } +} + +medium: { + #userHostPort: #"^(:(?P\d+))?$"# + + p1: { + @test(permute, count=6) + + #Y: regexp.FindNamedSubmatch(#userHostPort, #X.port) @test(err, code=incomplete|cycle) + + // Yield-on-running heuristic: the comp's referenced node Y + // is not currently being processed, so the comp does not + // yield and instead reports a cycle error. + + Y: { + if #Y.port != _|_ { + port: strconv.Atoi(#Y.port) + } + } @test(err, code=incomplete|cycle) + + #X: { + // Can never determine whether Y.port exists as its resolution + // depends on #Y becoming finalized, which, in turn, depends on #X + // becoming finalized. + if Y.port == _|_ { + port: "" + } + if Y.port != _|_ { + port: ":" + strconv.FormatInt(Y.port, 10) + } + } @test(err, code=incomplete|cycle) + } +} + +large: { + #userHostPort: #"^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)(:(?P\d+))?$"# + + p1: { + @test(permute, count=120) + // Pushdown improvement: #Y, #X, and X now resolve successfully. + // Y gets a cycle error because #Y.port changed after evaluation. + // Permute disabled: pushdown introduces ordering sensitivity. + + Y: { + userinfo: "user" + host: "mod.test" + } + + X: #X.userinfo + #X.host + #X.port @test(err, any, code=incomplete|cycle) + + #X: { + if Y.userinfo == _|_ { + userinfo: "" + } + if Y.userinfo != _|_ { + userinfo: Y.userinfo + "@" + } + + host: Y.host + + if Y.port == _|_ { + port: "" + } + if Y.port != _|_ { + port: ":" + strconv.FormatInt(Y.port, 10) + } + } @test(err, any, code=incomplete|cycle) + + Y: { + if #Y.userinfo != _|_ { + userinfo: #Y.userinfo + } + + host: #Y.host + + if #Y.port != _|_ { + port: strconv.Atoi(#Y.port) + } + } @test(err, any, code=incomplete|cycle) + + #Y: regexp.FindNamedSubmatch(#userHostPort, X) @test(err, any, code=incomplete|cycle) + } +} +-- out/compile -- +--- in.cue +{ + minimal: { + a: { + if (〈1;b〉.port == _|_(explicit error (_|_ literal) in source)) { + port: "" + } + } + b: { + if (〈1;a〉.port == _|_(explicit error (_|_ literal) in source)) { + port: "" + } + } + } + small: { + #userHostPort: "^(:(?P\\d+))?$" + p1: { + #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;#X〉.port) + #X: { + if (〈1;#Y〉.port == _|_(explicit error (_|_ literal) in source)) { + port: "" + } + if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) { + port: (":" + 〈import;strconv〉.FormatInt(〈2;#Y〉.port, 10)) + } + } + } + } + medium: { + #userHostPort: "^(:(?P\\d+))?$" + p1: { + #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;#X〉.port) + Y: { + if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) { + port: 〈import;strconv〉.Atoi(〈2;#Y〉.port) + } + } + #X: { + if (〈1;Y〉.port == _|_(explicit error (_|_ literal) in source)) { + port: "" + } + if (〈1;Y〉.port != _|_(explicit error (_|_ literal) in source)) { + port: (":" + 〈import;strconv〉.FormatInt(〈2;Y〉.port, 10)) + } + } + } + } + large: { + #userHostPort: "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)(:(?P\\d+))?$" + p1: { + Y: { + userinfo: "user" + host: "mod.test" + } + X: ((〈0;#X〉.userinfo + 〈0;#X〉.host) + 〈0;#X〉.port) + #X: { + if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { + userinfo: "" + } + if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { + userinfo: (〈2;Y〉.userinfo + "@") + } + host: 〈1;Y〉.host + if (〈1;Y〉.port == _|_(explicit error (_|_ literal) in source)) { + port: "" + } + if (〈1;Y〉.port != _|_(explicit error (_|_ literal) in source)) { + port: (":" + 〈import;strconv〉.FormatInt(〈2;Y〉.port, 10)) + } + } + Y: { + if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { + userinfo: 〈2;#Y〉.userinfo + } + host: 〈1;#Y〉.host + if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) { + port: 〈import;strconv〉.Atoi(〈2;#Y〉.port) + } + } + #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/comprehension.txtar b/internal/core/compile/testdata/sync/cycle/comprehension.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/comprehension.txtar @@ -0,0 +1,1511 @@ +-- in.cue -- +import ( + "list" + "strings" +) + +// Allow lookup in partially evaluated struct as long as the end result is +// concrete. +A: { + a: { + parent: "" + children: [for k, v in A if v.parent == k {k}] + } @test(eq, {parent: "", children: []}) + b: { + parent: "a" + children: [for k, v in A if v.parent == k {k}] + } @test(eq, {parent: "a", children: []}) +} + +// This should result in an incomplete error (a reference cycle error classifies +// as incomplete). +B: { + a: { + parent: "" + children: [for k, v in B for _, w in v.children {k}] + } @test(eq, { + parent: "" + children: _|_ @test(err, code=incomplete, contains="B.a.children: cannot range over v.children (incomplete type list)", pos=[24:40]) + }) +} + +// Issue #486: stack overflow in v0.3.0 when evaluating parametric fields with +// conditional comprehensions; the same code worked correctly in v0.2.0. +// https://cuelang.org/issue/486 +Issue486: { + A: { + a: { + parent: "" + children: [...string] + } + b: { + parent: "a" + children: [...string] + } + c: { + parent: "b" + children: [...string] + } + } + + A: [Name=string]: { + children: [ + for k, v in A + if v.parent == Name { + k + }, + ] + } + @test(eq, { + A: { + a: {parent: "", children: ["b"]} + b: {parent: "a", children: ["c"]} + c: {parent: "b", children: []} + } + }) +} + +// Issue #1666: evaluator hangs indefinitely when combining disjunctions with +// for comprehensions iterating over mapped fields. +// https://cuelang.org/issue/1666 +issue1666: { + #E: { + f1: [string]: #E | [...#E] + f2: [string]: t: #E + } + + _e: #E + _e: f2: a: _ + + e: _e & { + f1: { + for fk, s in _e.f2 { + (fk): s.t + } + } + } + @test(eq, { + #E: {f1: {}, f2: {}} + _e: {f2: {a: {t: {f1: {}, f2: {}}}}, f1: {}} + e: { + f1: {a: {f1: {}, f2: {}}} + f2: {a: {t: {f1: {}, f2: {}}}} + } + }) +} + +// Issue #779: for comprehension incorrectly rejected valid bidirectional +// projection patterns, reporting a cycle error even when no true cycle exists. +// Should be allowed as long as the set of fields is not modified as a result +// of a comprehension. +// https://cuelang.org/issue/779 +issue779: { + X: Y.message + STATE: { + for k, v in Y { + if k != "message" { + "\(k)": v + } + } + } + Y: STATE & { message: X } + X: "test" + STATE: { code: 101 } + @test(eq, { + X: "test" + STATE: {code: 101} + Y: {message: "test", code: 101} + }) +} + +// Issue #1934: regression in v0.4.1 where nested comprehensions referencing +// fields within the same struct were incorrectly reported as cycles. +// Comprehension ends up inserting in the same arcs over which it +// is iterating. This is fine as long as the set is not altered. +// https://cuelang.org/issue/1934 +selfReferential: T1: { + S: d: "bar" + + T: e: S: a: "foo" + + for s, v in S for t, _ in T { + T: (t): S: (s): v + } + @test(eq, { + S: {d: "bar"} + T: {e: {S: {a: "foo", d: "bar"}}} + }) +} + +// selfReferential comprehension for list. +// https://cuelang.org/issue/1934 +selfReferential: list: { + panels: [ + for i, _ in panels { + id: i + } + ] + panels: [{}, {}, {}] + @test(eq, {panels: [{id: 0}, {id: 1}, {id: 2}]}) +} + +selfReferential: insertionError: { + A: { + foo: 1 + for x in A { + // May not insert foo3. Use dynamic references to force the + // comprehension to be evaluated in the struct in which it is + // defined. + ("foo3"): 1 + } + @test(err, code=eval, contains="adding field foo3 not allowed as field set was already referenced", pos=[6:14]) + } +} + +// A comprehension should not recursively evaluated arcs, so that a +// structural cycle can be avoided when unnecessary. +selfReferential: acrossOr: t1: p1: { + o: #Output & { retry: reject: "ok" } + + #AllOutputs: { + reject: string + resource: string + retry: #Output + } + + #Output: or([for name, config in #AllOutputs { + (name): config + }]) + @test(eq, { + o: {retry: {reject: "ok"}} + #AllOutputs: { + reject: string + resource: string + retry: {reject: string} | {resource: string} + } + #Output: {reject: string} | {resource: string} + }) +} + +selfReferential: acrossOr: t1: p2: { + #Output: or([for name, config in #AllOutputs { + (name): config + }]) + + o: #Output & { retry: reject: "ok" } + + #AllOutputs: { + reject: string + resource: string + retry: #Output + } + @test(eq, { + #Output: {reject: string} | {resource: string} + o: {retry: {reject: "ok"}} + #AllOutputs: { + reject: string + resource: string + retry: {reject: string} | {resource: string} + } + }) +} + +selfReferential: acrossOr: t1: p3: { + #Output: or([for name, config in #AllOutputs { + (name): config + }]) + + #AllOutputs: { + reject: string + resource: string + retry: #Output + } + + o: #Output & { retry: reject: "ok" } + @test(eq, { + #Output: {reject: string} | {resource: string} + #AllOutputs: { + reject: string + resource: string + retry: {reject: string} | {resource: string} + } + o: {retry: {reject: "ok"}} + }) +} + +selfReferential: acrossOr: t2: p1: { + d: or([for x, y in #A { y }]) + o: d & { b: 2 } + #A: { + d1: int + d2: string + d3: b: d + } + @test(eq, { + d: int | string + o: {b: 2} + #A: { + d1: int + d2: string + d3: {b: int | string} + } + }) +} + +selfReferential: acrossOr: t2: p2: { + o: d & { b: 2 } + d: or([for x, y in #A { y }]) + #A: { + d1: int + d2: string + d3: b: d + } + @test(eq, { + o: {b: 2} + d: int | string + #A: { + d1: int + d2: string + d3: {b: int | string} + } + }) +} + +selfReferential: acrossOr: t2: p3: { + o: d & { b: 2 } + #A: { + d1: int + d2: string + d3: b: d + } + d: or([for x, y in #A { y }]) + @test(eq, { + o: {b: 2} + #A: { + d1: int + d2: string + d3: {b: int | string} + } + d: int | string + }) +} + +// Issue #1881: evaluator required the source of a for comprehension to be +// fully evaluated before iterating, causing false structural cycle errors. +// https://cuelang.org/issue/1881 +issue1881: p1: { + o: #Output & { retry: output: reject: "ok" } + + #AllOutputs: { + reject: string + resource: string + retry: output: #Output + } + + #Output: or([for name, config in #AllOutputs { + (name): config + }]) + @test(eq, { + o: {retry: {output: {reject: "ok"}}} + #AllOutputs: { + reject: string + resource: string + retry: { + output: {reject: string} | {resource: string} + } + } + #Output: {reject: string} | {resource: string} + }) +} + +issue1881: p2: { + #AllOutputs: { + reject: string + resource: string + retry: output: #Output + } + + o: #Output & { retry: output: reject: "ok" } + + #Output: or([for name, config in #AllOutputs { + (name): config + }]) + @test(eq, { + #AllOutputs: { + reject: string + resource: string + retry: { + output: {reject: string} | {resource: string} + } + } + o: {retry: {output: {reject: "ok"}}} + #Output: {reject: string} | {resource: string} + }) +} + +issue1881: p3: { + #AllOutputs: { + reject: string + resource: string + retry: output: #Output + } + + #Output: or([for name, config in #AllOutputs { + (name): config + }]) + + o: #Output & { retry: output: reject: "ok" } + @test(eq, { + #AllOutputs: { + reject: string + resource: string + retry: { + output: {reject: string} | {resource: string} + } + } + #Output: {reject: string} | {resource: string} + o: {retry: {output: {reject: "ok"}}} + }) +} + +siblingInsertion: t1: p1: { + D: "logging": _ + deployment: _ + + for k, v in deployment + for k1, v2 in v.env2 { + deployment: (k): env: (k1): v2 + } + + for id, v in D { + deployment: (id): env2: ENV: "True" + } + @test(eq, { + D: {logging: _} + deployment: { + logging: { + env2: {ENV: "True"} + env: {ENV: "True"} + } + } + }) +} + +siblingInsertion: t1: p2: { + D: "logging": _ + deployment: _ + + for id, v in D { + deployment: (id): env2: ENV: "True" + } + + for k, v in deployment + for k1, v2 in v.env2 { + deployment: (k): env: (k1): v2 + } + @test(eq, { + D: {logging: _} + deployment: { + logging: { + env2: {ENV: "True"} + env: {ENV: "True"} + } + } + }) +} + +siblingInsertion: t2: p1: { + D: "logging": _ + deployment: _ + + for k, v in deployment { + for k1, v2 in v.env2 { + deployment: (k): env: (k1): v2 + } + } + + for id, v in D { + deployment: (id): env2: ENV: "True" + } + @test(eq, { + D: {logging: _} + deployment: { + logging: { + env2: {ENV: "True"} + env: {ENV: "True"} + } + } + }) +} + +siblingInsertion: t2: p2: { + D: "logging": _ + deployment: _ + + for k, v in deployment { + for k1, v2 in v.env2 { + deployment: (k): env: (k1): v2 + } + } + + for id, v in D { + deployment: (id): env2: ENV: "True" + } + @test(eq, { + D: {logging: _} + deployment: { + logging: { + env2: {ENV: "True"} + env: {ENV: "True"} + } + } + }) +} + +// Issue #1407: cue export produced a misleading, location-free "cycle error" +// for incomplete values; the actual problem was an incomplete value, not a +// true cycle. Ensure there is a useful error message. +// https://cuelang.org/issue/1407 +selfReferential: fail: { + a: {} + b: a.x != "" + if b { + } + @test(err, code=incomplete, contains="undefined field: x", pos=[2:7]) +} + +// Issue #2367: stack overflow triggered by a comprehension that inserts into +// the same field it iterates over; the evaluator recurses infinitely instead +// of returning an error. +// https://cuelang.org/issue/2367 +issue2367: { + a: _ + for x in [a] {a: x} + @test(eq, {a: _}) +} + +// Issue #2310: evalv2 incorrectly reported a structural cycle when a +// comprehension contained three or more identical substitutions, despite the +// same pattern working with two substitutions. +// https://cuelang.org/issue/2310 +issue2310: original: { + #s: {#_1: string, #_2: string, #_3: string, strings.Replace(#_1, #_2, #_3, -1)} + + #sub: { + #a: string + + // We can't use X=[#a, ...] yet because that is still disallowed + _#X: [#a, for i in list.Range(0, len(#subs), 1) {#subs[i] & {#_1: _#X[i], _}}] + + // Embedding would not be necessary if the X=[] form was allowed + _#X[len(_#X)-1] + } + + res: #sub & {#a: "aaa", _} + + // subs is a series of string substitutions we want to apply + #subs: [ + #s & {#_2: "a", #_3: "b", _}, + #s & {#_2: "c", #_3: "d", _}, + #s & {#_2: "e", #_3: "f", _}, + ] + @test(eq, { + #s: { + _|_ + #_1: string + #_2: string + #_3: string + } + #sub: { + _|_ + #a: string + _#X: [string, + {_|_, #_1: string, #_2: "a", #_3: "b"}, + { + _|_ + #_1: {_|_, #_1: string, #_2: "a", #_3: "b"} + #_2: "c" + #_3: "d" + }, + { + _|_ + #_1: { + _|_ + #_1: {_|_, #_1: string, #_2: "a", #_3: "b"} + #_2: "c" + #_3: "d" + } + #_2: "e" + #_3: "f" + }] + #_1: { + _|_ + #_1: {_|_, #_1: string, #_2: "a", #_3: "b"} + #_2: "c" + #_3: "d" + } + #_2: "e" + #_3: "f" + } + res: { + "bbb" + #a: "aaa" + _#X: ["aaa", + {"bbb", #_1: "aaa", #_2: "a", #_3: "b"}, + { + "bbb" + #_1: {"bbb", #_1: "aaa", #_2: "a", #_3: "b"} + #_2: "c" + #_3: "d" + }, + { + "bbb" + #_1: { + "bbb" + #_1: {"bbb", #_1: "aaa", #_2: "a", #_3: "b"} + #_2: "c" + #_3: "d" + } + #_2: "e" + #_3: "f" + }] + #_1: { + "bbb" + #_1: {"bbb", #_1: "aaa", #_2: "a", #_3: "b"} + #_2: "c" + #_3: "d" + } + #_2: "e" + #_3: "f" + } + #subs: [{_|_, #_2: "a", #_3: "b", #_1: string}, + {_|_, #_2: "c", #_3: "d", #_1: string}, + {_|_, #_2: "e", #_3: "f", #_1: string}] + }) +} +issue2310: reduced: { + res: { + #X[3] // Must be at least 3 to cause structural cycle. + + // expanding comprehension eliminates cycle. + #X: ["X", for i, _ in #subs {#s, #str: #X[i]}] + } + + #s: {#str: string, #str + "a"} + #subs: [0, 1, 2] + @test(eq, { + res: { + "Xaaa" + #X: ["X", + {"Xa", #str: "X"}, + {"Xaa", #str: {"Xa", #str: "X"}}, + { + "Xaaa" + #str: {"Xaa", #str: {"Xa", #str: "X"}} + }] + #str: {"Xaa", #str: {"Xa", #str: "X"}} + } + #s: {_|_, #str: string} + #subs: [0, 1, 2] + }) +} + +-- issue3903.cue -- +// evalv3 structural cycle regression: a schema with `_deps` and comprehensions +// over those deps triggered a spurious structural cycle error that exported +// successfully under evalv2. +// https://cuelang.org/issue/3903 +issue3903: reduced: { + s1: #Schema + s1: _deps: [#Schema] + #Schema: { + _deps: [...] + + objs: [ + for dep in _deps + for obj in (dep & {}).objs { + obj + } + ] + } + @test(eq, { + s1: { + _deps: [{_deps: [], objs: []}] + objs: [] + } + #Schema: {_deps: [], objs: []} + }) +} +issue3903: full: { + s1: #Schema & { + _deps: [s2] + _local: ["s1 local"] + } + s2: #Schema & { + _local: ["s2 local"] + } + + #Schema: { + _local: [...string] + _deps: [...] + + objs: [ + for obj in _local { obj }, + + for dep in _deps + for obj in (dep & {}).objs { + obj + }, + ] + } + @test(eq, { + s1: { + _deps: [{ + _local: ["s2 local"] + _deps: [] + objs: ["s2 local"] + }] + _local: ["s1 local"] + objs: ["s1 local", "s2 local"] + } + s2: { + _local: ["s2 local"] + _deps: [] + objs: ["s2 local"] + } + #Schema: {_local: [], _deps: [], objs: []} + }) +} +-- issue2405.cue -- +// A recursive disjunction type (`#Copy` with struct/list/scalar alternatives) +// was rejected as a structural cycle even though the structure is bounded and +// should evaluate successfully. +// https://cuelang.org/issue/2405 +issue2405: { + #Copy: { + param: {...} + result: { + for k, v in param { + (k): (#Copy & {param: v}).result + } + } + } | { + param: [...] + result: [ + for v in param { + (#Copy & {param: v}).result + }, + ] + } | { + param: number + result: param + } + + foo: #Copy + foo: param: a: [{b: 134}] + @test(eq, { + #Copy: {param: {}, result: {}} | {param: [], result: []} | {param: number, result: number} + foo: { + param: {a: [{b: 134}]} + result: {a: [{b: 134}]} + } + }) +} +-- issue3941.cue -- +// evalv3 regression: a comprehension iterating over a pattern-constrained field +// (`resource: [string]: [string]: #Resource`) produced a spurious "field set was +// already referenced" error that evalv2 did not emit. +// https://cuelang.org/issue/3941 +issue3941: full: { + #Metadata: name: string + #Resource: metadata: #Metadata + + out: { + _metadata: name: "foo" + resource: [string]: [string]: #Resource + + _names: [_metadata.name] + + for name in _names { + resource: level1: (name): { + metadata: _metadata + } + } + } + @test(eq, { + #Metadata: {name: string} + #Resource: {metadata: {name: string}} + out: { + _metadata: {name: "foo"} + resource: { + level1: {foo: {metadata: {name: "foo"}}} + } + _names: ["foo"] + } + }) +} +-- issue2229.cue -- +// A list comprehension whose result was unified back into the same list caused +// an endless recursion and panic rather than being caught as a structural cycle. +// https://cuelang.org/issue/2229 +issue2229: full_ok: X={ + build: bool | *true + test: bool | *true + + make: [ for k, v in X if (v & true) != _|_ { k } ] +} @test(eq, { + build: *true | bool + test: *true | bool + make: ["build", "test"] +}) +issue2229: reduced_fail: X={ + x: true + y: [ for _, v in X if v & true { _ } ] +} @test(err, code=eval, + suberr=(code=eval, contains="conflicting values", pos=[2:5, 2:24, 2:28]), + suberr=(code=eval, contains="conflicting values", pos=[2:5, 2:24, 2:28]), + suberr=(code=eval, contains="structural cycle", pos=[2:24]), +) +-- issue4100.cue -- +// Segmentation fault in `adt.(*OpContext).freeNodeContext` in v0.14.1, +// triggered by a let binding inside a conditional that feeds into a for loop. +// https://cuelang.org/issue/4100 +issue4100: { + a: { + let l = [0] + if l != _|_ { + l[:] + } + } + for _ in a {} + @test(eq, {a: [0]}) +} +-- out/compile -- +--- in.cue +{ + A: { + a: { + parent: "" + children: [ + for k, v in 〈3;A〉 if (〈0;v〉.parent == 〈0;k〉) { + 〈1;k〉 + }, + ] + } + b: { + parent: "a" + children: [ + for k, v in 〈3;A〉 if (〈0;v〉.parent == 〈0;k〉) { + 〈1;k〉 + }, + ] + } + } + B: { + a: { + parent: "" + children: [ + for k, v in 〈3;B〉 for _, w in 〈0;v〉.children { + 〈2;k〉 + }, + ] + } + } + Issue486: { + A: { + a: { + parent: "" + children: [ + ...string, + ] + } + b: { + parent: "a" + children: [ + ...string, + ] + } + c: { + parent: "b" + children: [ + ...string, + ] + } + } + A: { + [string]: { + children: [ + for k, v in 〈3;A〉 if (〈0;v〉.parent == 〈3;-〉) { + 〈1;k〉 + }, + ] + } + } + } + issue1666: { + #E: { + f1: { + [string]: (〈2;#E〉|[ + ...〈3;#E〉, + ]) + } + f2: { + [string]: { + t: 〈3;#E〉 + } + } + } + _e: 〈0;#E〉 + _e: { + f2: { + a: _ + } + } + e: (〈0;_e〉 & { + f1: { + for fk, s in 〈2;_e〉.f2 { + 〈1;fk〉: 〈1;s〉.t + } + } + }) + } + issue779: { + X: 〈0;Y〉.message + STATE: { + for k, v in 〈1;Y〉 { + if (〈1;k〉 != "message") { + "\(〈2;k〉)": 〈2;v〉 + } + } + } + Y: (〈0;STATE〉 & { + message: 〈1;X〉 + }) + X: "test" + STATE: { + code: 101 + } + } + selfReferential: { + T1: { + S: { + d: "bar" + } + T: { + e: { + S: { + a: "foo" + } + } + } + for s, v in 〈0;S〉 for t, _ in 〈1;T〉 { + T: { + 〈2;t〉: { + S: { + 〈5;s〉: 〈5;v〉 + } + } + } + } + } + } + selfReferential: { + list: { + panels: [ + for i, _ in 〈1;panels〉 { + id: 〈1;i〉 + }, + ] + panels: [ + {}, + {}, + {}, + ] + } + } + selfReferential: { + insertionError: { + A: { + foo: 1 + for _, x in 〈1;A〉 { + "foo3": 1 + } + } + } + } + selfReferential: { + acrossOr: { + t1: { + p1: { + o: (〈0;#Output〉 & { + retry: { + reject: "ok" + } + }) + #AllOutputs: { + reject: string + resource: string + retry: 〈1;#Output〉 + } + #Output: or([ + for name, config in 〈1;#AllOutputs〉 { + 〈1;name〉: 〈1;config〉 + }, + ]) + } + } + } + } + selfReferential: { + acrossOr: { + t1: { + p2: { + #Output: or([ + for name, config in 〈1;#AllOutputs〉 { + 〈1;name〉: 〈1;config〉 + }, + ]) + o: (〈0;#Output〉 & { + retry: { + reject: "ok" + } + }) + #AllOutputs: { + reject: string + resource: string + retry: 〈1;#Output〉 + } + } + } + } + } + selfReferential: { + acrossOr: { + t1: { + p3: { + #Output: or([ + for name, config in 〈1;#AllOutputs〉 { + 〈1;name〉: 〈1;config〉 + }, + ]) + #AllOutputs: { + reject: string + resource: string + retry: 〈1;#Output〉 + } + o: (〈0;#Output〉 & { + retry: { + reject: "ok" + } + }) + } + } + } + } + selfReferential: { + acrossOr: { + t2: { + p1: { + d: or([ + for x, y in 〈1;#A〉 { + 〈1;y〉 + }, + ]) + o: (〈0;d〉 & { + b: 2 + }) + #A: { + d1: int + d2: string + d3: { + b: 〈2;d〉 + } + } + } + } + } + } + selfReferential: { + acrossOr: { + t2: { + p2: { + o: (〈0;d〉 & { + b: 2 + }) + d: or([ + for x, y in 〈1;#A〉 { + 〈1;y〉 + }, + ]) + #A: { + d1: int + d2: string + d3: { + b: 〈2;d〉 + } + } + } + } + } + } + selfReferential: { + acrossOr: { + t2: { + p3: { + o: (〈0;d〉 & { + b: 2 + }) + #A: { + d1: int + d2: string + d3: { + b: 〈2;d〉 + } + } + d: or([ + for x, y in 〈1;#A〉 { + 〈1;y〉 + }, + ]) + } + } + } + } + issue1881: { + p1: { + o: (〈0;#Output〉 & { + retry: { + output: { + reject: "ok" + } + } + }) + #AllOutputs: { + reject: string + resource: string + retry: { + output: 〈2;#Output〉 + } + } + #Output: or([ + for name, config in 〈1;#AllOutputs〉 { + 〈1;name〉: 〈1;config〉 + }, + ]) + } + } + issue1881: { + p2: { + #AllOutputs: { + reject: string + resource: string + retry: { + output: 〈2;#Output〉 + } + } + o: (〈0;#Output〉 & { + retry: { + output: { + reject: "ok" + } + } + }) + #Output: or([ + for name, config in 〈1;#AllOutputs〉 { + 〈1;name〉: 〈1;config〉 + }, + ]) + } + } + issue1881: { + p3: { + #AllOutputs: { + reject: string + resource: string + retry: { + output: 〈2;#Output〉 + } + } + #Output: or([ + for name, config in 〈1;#AllOutputs〉 { + 〈1;name〉: 〈1;config〉 + }, + ]) + o: (〈0;#Output〉 & { + retry: { + output: { + reject: "ok" + } + } + }) + } + } + siblingInsertion: { + t1: { + p1: { + D: { + logging: _ + } + deployment: _ + for k, v in 〈0;deployment〉 for k1, v2 in 〈0;v〉.env2 { + deployment: { + 〈3;k〉: { + env: { + 〈4;k1〉: 〈4;v2〉 + } + } + } + } + for id, v in 〈0;D〉 { + deployment: { + 〈2;id〉: { + env2: { + ENV: "True" + } + } + } + } + } + } + } + siblingInsertion: { + t1: { + p2: { + D: { + logging: _ + } + deployment: _ + for id, v in 〈0;D〉 { + deployment: { + 〈2;id〉: { + env2: { + ENV: "True" + } + } + } + } + for k, v in 〈0;deployment〉 for k1, v2 in 〈0;v〉.env2 { + deployment: { + 〈3;k〉: { + env: { + 〈4;k1〉: 〈4;v2〉 + } + } + } + } + } + } + } + siblingInsertion: { + t2: { + p1: { + D: { + logging: _ + } + deployment: _ + for k, v in 〈0;deployment〉 { + for k1, v2 in 〈1;v〉.env2 { + deployment: { + 〈4;k〉: { + env: { + 〈4;k1〉: 〈4;v2〉 + } + } + } + } + } + for id, v in 〈0;D〉 { + deployment: { + 〈2;id〉: { + env2: { + ENV: "True" + } + } + } + } + } + } + } + siblingInsertion: { + t2: { + p2: { + D: { + logging: _ + } + deployment: _ + for k, v in 〈0;deployment〉 { + for k1, v2 in 〈1;v〉.env2 { + deployment: { + 〈4;k〉: { + env: { + 〈4;k1〉: 〈4;v2〉 + } + } + } + } + } + for id, v in 〈0;D〉 { + deployment: { + 〈2;id〉: { + env2: { + ENV: "True" + } + } + } + } + } + } + } + selfReferential: { + fail: { + a: {} + b: (〈0;a〉.x != "") + if 〈0;b〉 {} + } + } + issue2367: { + a: _ + for _, x in [ + 〈1;a〉, + ] { + a: 〈1;x〉 + } + } + issue2310: { + original: { + #s: { + #_1: string + #_2: string + #_3: string + 〈import;strings〉.Replace(〈0;#_1〉, 〈0;#_2〉, 〈0;#_3〉, -1) + } + #sub: { + #a: string + _#X: [ + 〈1;#a〉, + for _, i in 〈import;list〉.Range(0, len(〈2;#subs〉), 1) { + (〈4;#subs〉[〈1;i〉] & { + #_1: 〈4;_#X〉[〈2;i〉] + _ + }) + }, + ] + 〈0;_#X〉[(len(〈0;_#X〉) - 1)] + } + res: (〈0;#sub〉 & { + #a: "aaa" + _ + }) + #subs: [ + (〈1;#s〉 & { + #_2: "a" + #_3: "b" + _ + }), + (〈1;#s〉 & { + #_2: "c" + #_3: "d" + _ + }), + (〈1;#s〉 & { + #_2: "e" + #_3: "f" + _ + }), + ] + } + } + issue2310: { + reduced: { + res: { + 〈0;#X〉[3] + #X: [ + "X", + for i, _ in 〈2;#subs〉 { + 〈4;#s〉 + #str: 〈3;#X〉[〈1;i〉] + }, + ] + } + #s: { + #str: string + (〈0;#str〉 + "a") + } + #subs: [ + 0, + 1, + 2, + ] + } + } +} +--- issue2229.cue +{ + issue2229: { + full_ok: { + build: (bool|*true) + test: (bool|*true) + make: [ + for k, v in 〈2〉 if ((〈0;v〉 & true) != _|_(explicit error (_|_ literal) in source)) { + 〈1;k〉 + }, + ] + } + } + issue2229: { + reduced_fail: { + x: true + y: [ + for _, v in 〈2〉 if (〈0;v〉 & true) { + _ + }, + ] + } + } +} +--- issue2405.cue +{ + issue2405: { + #Copy: ({ + param: { + ... + } + result: { + for k, v in 〈1;param〉 { + 〈1;k〉: (〈4;#Copy〉 & { + param: 〈2;v〉 + }).result + } + } + }|{ + param: [ + ..., + ] + result: [ + for _, v in 〈1;param〉 { + (〈4;#Copy〉 & { + param: 〈2;v〉 + }).result + }, + ] + }|{ + param: number + result: 〈0;param〉 + }) + foo: 〈0;#Copy〉 + foo: { + param: { + a: [ + { + b: 134 + }, + ] + } + } + } +} +--- issue3903.cue +{ + issue3903: { + reduced: { + s1: 〈0;#Schema〉 + s1: { + _deps: [ + 〈2;#Schema〉, + ] + } + #Schema: { + _deps: [ + ..., + ] + objs: [ + for _, dep in 〈1;_deps〉 for _, obj in (〈0;dep〉 & {}).objs { + 〈1;obj〉 + }, + ] + } + } + } + issue3903: { + full: { + s1: (〈0;#Schema〉 & { + _deps: [ + 〈2;s2〉, + ] + _local: [ + "s1 local", + ] + }) + s2: (〈0;#Schema〉 & { + _local: [ + "s2 local", + ] + }) + #Schema: { + _local: [ + ...string, + ] + _deps: [ + ..., + ] + objs: [ + for _, obj in 〈1;_local〉 { + 〈1;obj〉 + }, + for _, dep in 〈1;_deps〉 for _, obj in (〈0;dep〉 & {}).objs { + 〈1;obj〉 + }, + ] + } + } + } +} +--- issue3941.cue +{ + issue3941: { + full: { + #Metadata: { + name: string + } + #Resource: { + metadata: 〈1;#Metadata〉 + } + out: { + _metadata: { + name: "foo" + } + resource: { + [string]: { + [string]: 〈3;#Resource〉 + } + } + _names: [ + 〈1;_metadata〉.name, + ] + for _, name in 〈0;_names〉 { + resource: { + level1: { + 〈3;name〉: { + metadata: 〈5;_metadata〉 + } + } + } + } + } + } + } +} +--- issue4100.cue +{ + issue4100: { + a: { + let l#1 = [ + 0, + ] + if (〈0;let l#1〉 != _|_(explicit error (_|_ literal) in source)) { + 〈1;let l#1〉[:] + } + } + for _, _ in 〈0;a〉 {} + } +} diff --git a/internal/core/compile/testdata/sync/cycle/constraints.txtar b/internal/core/compile/testdata/sync/cycle/constraints.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/constraints.txtar @@ -0,0 +1,673 @@ +# Tests various cycle patterns involving constraint propagation through pattern +# constraints, self-triggering cycles, and mutually triggering cycles. +-- in.cue -- +// Not a cycle: the structure in x (c) only triggers one further +// instantiation of y, but not enough to trigger another round. +safeCycle: simple2: { + y: [string]: b: c: y + x: y + x: c: y + @test(eq, { + y: {} + x: {c: {b: {c: {}, b: {c: {}}}}} + }) +} + +// Not a cycle: the structure in x (c) only triggers one further +// instantiation of y, but not enough to trigger another round. +safeCycle: long1: { + y: [string]: b: y + x: y + x: c: b: e: b: c: _ + @test(eq, { + y: {} + x: {c: {b: {e: {b: {c: {b: {}}}}}}} + }) +} + +// Not a cycle: the structure in x (c) only triggers one further +// instantiation of y, but not enough to trigger another round. +safeCycle: long2: { + a: [string]: b: a + x: a + x: c: b: c: b: c: {} + @test(eq, { + a: {} + x: {c: {b: {c: {b: {c: {b: {}}}}}}} + }) +} + +// noCyclePattern is similar to the above cases, but involving more patterns +// and various lengths. +noCyclePattern: _ + +noCyclePattern: t1: { + #D: [string]: #D + a: {} + [string]: #D + [string]: b: c: {} + @test(eq, {#D: {}, a: {b: {c: {}}}}) +} + +noCyclePattern: t2: { + #D: [string]: x: #D + a: {} + [string]: #D + [string]: b: x: c: {} + @test(eq, {#D: {}, a: {b: {x: {c: {x: {}}}}}}) +} + +noCyclePattern: t3: { + _D: [string]: _T + _T: x: _D + [string]: _D + [string]: b: x: c: {} + a: {} + @test(eq, { + _D: {} + _T: {x: {}} + a: {b: {x: {c: {x: {}}}}} + }) +} + +noCyclePattern: t4: { + _D: [string]: x: _T + _T: y: _D + [string]: _D + [string]: b: x: {} + a: {} + @test(eq, { + _D: {} + _T: {y: {}} + a: {b: {x: {y: {}}}} + }) +} + +noCyclePattern: t5: { + _D: [string]: x: _T + _T: y: _D + [string]: _D + [string]: b: x: y: c: x: {} + a: {} + @test(eq, { + _D: {} + _T: {y: {}} + a: {b: {x: {y: {c: {x: {y: {}}}}}}} + }) +} + +// This example also has an embedding, in which case it should still behave +// the same. +noCyclePattern: t6: { + #D: [string]: #E + + #E: t: #T + + #T: { + { object: #S } + } + + #S: y: #D + [string]: x: #D + [string]: x: r: t: object: y: foo: t: object: { + } + bar: {} + @test(eq, { + #D: {} + #E: {t: {object: {y: {}}}} + #T: {object: {y: {}}} + #S: {y: {}} + bar: { + x: { + r: { + t: { + object: {y: {foo: {t: {object: {y: {}}}}}} + } + } + } + } + }) +} + +// Cycle: x cyclic. The pattern constraint should not be seen as +// "adding new structure", thereby permitting the cycle. +noCancelSelfInvoke: t1: { + y: [string]: b: y + x: y + x: c: x @test(err, at=b.b, code=structural_cycle) @test(err, at=c, code=structural_cycle) + @test(err, code=structural_cycle) +} + + +// Even though these cycles cross pattern boundaries, they are still structural +// cycles as the reference includes a field that triggers the pattern. +selfTriggerCycle: _ + +// TODO: This does not show an explicit cycle within `a`, only a "child" cycle. +// However, upon investigation this error is present in the tree. Either way, +// the error only needs to be reported once, so this is not a huge problem. +selfTriggerCycle: t1: { + a: #T @test(shareID=T) + #T: { + [string]: #T + b: {} @test(err, at=b, code=structural_cycle) + } @test(shareID=T) +} + +selfTriggerCycle: t2: { + #T: [string]: X={ + a: X + } + b: #T + b: c: {} @test(err, at=a, code=structural_cycle) +} + +selfTriggerCycle: long1: { + // The long string of nested fields will initially exempt the structural + // cycle, but they will eventually run out, causing the cycle to be + // triggered. + a: [string]: b: a // -> record conjunct from pattern per field. + a: c: b: c: b: c: {} // -> track if any of the fields is not a cycle. + @test(err, at=a.c.b.c.b.c.b, code=structural_cycle) +} + +// TODO: see comment at selfTriggerCycle.t1 +selfTriggerCycle: issue1503: { + a: #T & { + a: one: link: a: two: {} + } + #T: { + a: [string]: link: #T + a: b: {} + } + @test(err, at=#T.a.b.link, code=structural_cycle) + @test(err, at=a.a.b.link, code=structural_cycle) + @test(err, at=a.a.one.link.a.b.link, code=structural_cycle) + @test(err, at=a.a.one.link.a.two.link, code=structural_cycle) +} + +mutuallyTriggeringCycle: t1: { + // Even though y itself, as well as each of the x fields are not cyclic, + // the combination of the two x conjuncts are, as the b fields of y will + // trigger the pattern constraints in an interleaved fashion. + y: [string]: b: y + x: y + x: c: y + @test(err, at=x.c.b.b.b.b.b, code=structural_cycle) +} +-- ring.cue -- +brokenRing: t1: { + // NOTE that two permutations here have different results. That is less + // of an issue than it seems, as the structural cycle is hidden behind + // an optional path, which we generally allow. + // TODO: it would be nicer, though, if the representation were consistent. + p1: { + D: a?: T + T: b: D + @test(err, code=structural_cycle) + // @test(debug) + } + p2: { + // TODO(eval): fix permute or eval: error messages differ based on path in the two cases. + // @test(permute, count=2) + T: b: D + D: a?: T + @test(eq, { + T: { + b: { + a?: _|_ @test(err, code=structural_cycle, contains="structural cycle", pos=[]) + } + } + D: { + a?: _|_ @test(err, code=structural_cycle, contains="structural cycle", pos=[]) + } + }) + } +} + +brokenRing: t2: p1: { + D: [string]: T + T: b: D + @test(eq, {D: {}, T: {b: {}}}) +} + +brokenRing: t2: p2: { + T: b: D + D: [string]: T + @test(eq, {T: {b: {}}, D: {}}) +} + +cyclicRing: t1: { + D: a: T + T: b: D + @test(err, at=T.b, code=structural_cycle) + @test(err, at=D.a.b, code=structural_cycle) + // TODO(inline): fix shareID here. + // @test(shareID=T, at=D.a) + // @test(shareID=T, at=T) +} +-- issue3476.cue -- +// `cue def -e '#a'` causes a stack overflow. The definition #a selects a +// field from a conjunction `(#b & {x: _}).x` where #b contains a +// self-referential pattern `#c: [string]: #c`. This combination causes the +// exporter to recurse infinitely instead of detecting the cycle. +// https://cuelang.org/issue/3476 +issue3476: { + #a: (#b & {x: _}).x + #b: { + x?: #c + #c: [string]: #c + } + @test(eq, {#a: {}, #b: {x?: {}, #c: {}}}) +} +-- issue3509.cue -- +// evalv3 causes infinite work and OOM panic where evalv2 is fast. A +// self-referential list constraint `#matrixConfig: [...#matrixConfig] | string` +// combined with indirect field access `#job: (#Workflow & {job: _}).job` causes +// the new evaluator to loop indefinitely. +// https://cuelang.org/issue/3509 +issue3509: { + out: #job.step & "foo" + + #job: (#Workflow & {job: _}).job + + #Workflow: { + job: step: string + + #matrixConfig: [...#matrixConfig] | string + matrix?: [string]: [...#matrixConfig] + } + + @test(eq, { + out: "foo" + #job: {step: string} + #Workflow: { + job: {step: string} + #matrixConfig: [] | string + matrix?: {} + } + }) +} +-- out/compile -- +--- in.cue +{ + safeCycle: { + simple2: { + y: { + [string]: { + b: { + c: 〈3;y〉 + } + } + } + x: 〈0;y〉 + x: { + c: 〈1;y〉 + } + } + } + safeCycle: { + long1: { + y: { + [string]: { + b: 〈2;y〉 + } + } + x: 〈0;y〉 + x: { + c: { + b: { + e: { + b: { + c: _ + } + } + } + } + } + } + } + safeCycle: { + long2: { + a: { + [string]: { + b: 〈2;a〉 + } + } + x: 〈0;a〉 + x: { + c: { + b: { + c: { + b: { + c: {} + } + } + } + } + } + } + } + noCyclePattern: _ + noCyclePattern: { + t1: { + #D: { + [string]: 〈1;#D〉 + } + a: {} + [string]: 〈0;#D〉 + [string]: { + b: { + c: {} + } + } + } + } + noCyclePattern: { + t2: { + #D: { + [string]: { + x: 〈2;#D〉 + } + } + a: {} + [string]: 〈0;#D〉 + [string]: { + b: { + x: { + c: {} + } + } + } + } + } + noCyclePattern: { + t3: { + _D: { + [string]: 〈1;_T〉 + } + _T: { + x: 〈1;_D〉 + } + [string]: 〈0;_D〉 + [string]: { + b: { + x: { + c: {} + } + } + } + a: {} + } + } + noCyclePattern: { + t4: { + _D: { + [string]: { + x: 〈2;_T〉 + } + } + _T: { + y: 〈1;_D〉 + } + [string]: 〈0;_D〉 + [string]: { + b: { + x: {} + } + } + a: {} + } + } + noCyclePattern: { + t5: { + _D: { + [string]: { + x: 〈2;_T〉 + } + } + _T: { + y: 〈1;_D〉 + } + [string]: 〈0;_D〉 + [string]: { + b: { + x: { + y: { + c: { + x: {} + } + } + } + } + } + a: {} + } + } + noCyclePattern: { + t6: { + #D: { + [string]: 〈1;#E〉 + } + #E: { + t: 〈1;#T〉 + } + #T: { + { + object: 〈2;#S〉 + } + } + #S: { + y: 〈1;#D〉 + } + [string]: { + x: 〈1;#D〉 + } + [string]: { + x: { + r: { + t: { + object: { + y: { + foo: { + t: { + object: {} + } + } + } + } + } + } + } + } + bar: {} + } + } + noCancelSelfInvoke: { + t1: { + y: { + [string]: { + b: 〈2;y〉 + } + } + x: 〈0;y〉 + x: { + c: 〈1;x〉 + } + } + } + selfTriggerCycle: _ + selfTriggerCycle: { + t1: { + a: 〈0;#T〉 + #T: { + [string]: 〈1;#T〉 + b: {} + } + } + } + selfTriggerCycle: { + t2: { + #T: { + [string]: { + a: 〈1〉 + } + } + b: 〈0;#T〉 + b: { + c: {} + } + } + } + selfTriggerCycle: { + long1: { + a: { + [string]: { + b: 〈2;a〉 + } + } + a: { + c: { + b: { + c: { + b: { + c: {} + } + } + } + } + } + } + } + selfTriggerCycle: { + issue1503: { + a: (〈0;#T〉 & { + a: { + one: { + link: { + a: { + two: {} + } + } + } + } + }) + #T: { + a: { + [string]: { + link: 〈3;#T〉 + } + } + a: { + b: {} + } + } + } + } + mutuallyTriggeringCycle: { + t1: { + y: { + [string]: { + b: 〈2;y〉 + } + } + x: 〈0;y〉 + x: { + c: 〈1;y〉 + } + } + } +} +--- issue3476.cue +{ + issue3476: { + #a: (〈0;#b〉 & { + x: _ + }).x + #b: { + x?: 〈0;#c〉 + #c: { + [string]: 〈1;#c〉 + } + } + } +} +--- issue3509.cue +{ + issue3509: { + out: (〈0;#job〉.step & "foo") + #job: (〈0;#Workflow〉 & { + job: _ + }).job + #Workflow: { + job: { + step: string + } + #matrixConfig: ([ + ...〈1;#matrixConfig〉, + ]|string) + matrix?: { + [string]: [ + ...〈2;#matrixConfig〉, + ] + } + } + } +} +--- ring.cue +{ + brokenRing: { + t1: { + p1: { + D: { + a?: 〈1;T〉 + } + T: { + b: 〈1;D〉 + } + } + p2: { + T: { + b: 〈1;D〉 + } + D: { + a?: 〈1;T〉 + } + } + } + } + brokenRing: { + t2: { + p1: { + D: { + [string]: 〈1;T〉 + } + T: { + b: 〈1;D〉 + } + } + } + } + brokenRing: { + t2: { + p2: { + T: { + b: 〈1;D〉 + } + D: { + [string]: 〈1;T〉 + } + } + } + } + cyclicRing: { + t1: { + D: { + a: 〈1;T〉 + } + T: { + b: 〈1;D〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/cycle_with_bounds.txtar b/internal/core/compile/testdata/sync/cycle/cycle_with_bounds.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/cycle_with_bounds.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +#Value: int + +foo: #Value +foo: !=bar +bar: #Value +bar: !=foo + +bar: 0 @test(eq, 0) +foo: 1 @test(eq, 1) +-- out/compile -- +--- in.cue +{ + #Value: int + foo: 〈0;#Value〉 + foo: !=〈0;bar〉 + bar: 〈0;#Value〉 + bar: !=〈0;foo〉 + bar: 0 + foo: 1 +} diff --git a/internal/core/compile/testdata/sync/cycle/disjunction.txtar b/internal/core/compile/testdata/sync/cycle/disjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/disjunction.txtar @@ -0,0 +1,156 @@ +-- in.cue -- +// cycle is a structural cycle +cycle: a: cycle @test(err, code=structural_cycle, pos=[]) + +// reference to outside structural cycle +r1a: cycle | int @test(eq, int) +r1b: int | cycle @test(eq, int) + +r2a: cycle | 1 @test(eq, 1) +r2b: 1 | cycle @test(eq, 1) + +r3a: cycle | null @test(eq, null) +r3b: null | cycle @test(eq, null) + +r4a: cycle | {} @test(eq, {}) +r4b: {} | cycle @test(eq, {}) + +r5a: cycle | [] @test(eq, []) +r5b: [] | cycle @test(eq, []) + +// reference to ancestor node +s1a: { + x: s1a | int + @test(eq, {x: int}) +} +s1b: { + x: int | s1b + @test(eq, {x: int}) +} + +s2a: { + x: s2a | 1 + @test(eq, {x: 1}) +} +s2b: { + x: 1 | s2b + @test(eq, {x: 1}) +} + +s3a: { + x: s3a | null + @test(eq, {x: null}) +} +s3b: { + x: null | s3b + @test(eq, {x: null}) +} + +s4a: { + x: s4a | {} + @test(eq, {x: {}}) +} +s4b: { + x: {} | s4b + @test(eq, {x: {}}) +} + +s5a: { + x: s5a | [] + @test(eq, {x: []}) +} +s5b: { + x: [] | s5b + @test(eq, {x: []}) +} + +-- issue3042.cue -- +// Array element validation not being enforced for elements nested inside +// a struct: invalid values passed validation without error. +// https://cuelang.org/issue/3042 +issue3042: { + // Recursively, any field named "name" should begin with "foo". + // The data value below should then fail. + #foo: =~"^foo" + #nesting: string | {name?: #foo, [string]: #nesting} | [...#nesting] + + data: #nesting & { + secret: { + infra: [ + {name: "bar1"} + ] + } + } + @test(err, code=eval, + suberr=(code=eval, path=data, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[{secret:{infra:[{name:"bar1"}]}}, [...#nesting], struct, list], pos=[4:57, 6:8, 6:19]), + suberr=(code=eval, path=data, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[{secret:{infra:[{name:"bar1"}]}}, string, struct, string], pos=[4:12, 6:8, 6:19]), + ) +} +-- out/compile -- +--- in.cue +{ + cycle: { + a: 〈1;cycle〉 + } + r1a: (〈0;cycle〉|int) + r1b: (int|〈0;cycle〉) + r2a: (〈0;cycle〉|1) + r2b: (1|〈0;cycle〉) + r3a: (〈0;cycle〉|null) + r3b: (null|〈0;cycle〉) + r4a: (〈0;cycle〉|{}) + r4b: ({}|〈0;cycle〉) + r5a: (〈0;cycle〉|[]) + r5b: ([]|〈0;cycle〉) + s1a: { + x: (〈1;s1a〉|int) + } + s1b: { + x: (int|〈1;s1b〉) + } + s2a: { + x: (〈1;s2a〉|1) + } + s2b: { + x: (1|〈1;s2b〉) + } + s3a: { + x: (〈1;s3a〉|null) + } + s3b: { + x: (null|〈1;s3b〉) + } + s4a: { + x: (〈1;s4a〉|{}) + } + s4b: { + x: ({}|〈1;s4b〉) + } + s5a: { + x: (〈1;s5a〉|[]) + } + s5b: { + x: ([]|〈1;s5b〉) + } +} +--- issue3042.cue +{ + issue3042: { + #foo: =~"^foo" + #nesting: (string|{ + name?: 〈1;#foo〉 + [string]: 〈1;#nesting〉 + }|[ + ...〈1;#nesting〉, + ]) + data: (〈0;#nesting〉 & { + secret: { + infra: [ + { + name: "bar1" + }, + ] + } + }) + } +} diff --git a/internal/core/compile/testdata/sync/cycle/evaluate.txtar b/internal/core/compile/testdata/sync/cycle/evaluate.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/evaluate.txtar @@ -0,0 +1,301 @@ +-- in.cue -- +// All these cases whose name end with cycle should fail with a structural +// error. These are all uncommon code paths, triggered when container types +// are evalated within a nested expression such as as an argument to a +// function call. +// +// The builtins are typically used to trigger the uncommon path. The choice of +// builtin is irrelevant, as long as they don't finalize args before processing. + +import "list" + +// This is a resolvable reference cycle, were b is equated to c. +letCycleOK: t1: { + b: c + let X = b + c: X + @test(eq, {b: _, c: _}) +} + +// The let has structural cycle, but it is only used in a way that the +// structural cycle is avoided. +letCycleOK: t2: { + a: { + b: 1 + let X = a + c: X.b + } + @test(eq, {a: {b: 1, c: 1}}) +} + +// Ensure that the cycle exemption algorithm does not bypass actual structural +// cycles. +letCycleFail: t1: { + a: { + b: 1 + let X = a + c: X + } + @test(err, code=structural_cycle, path=a.c, contains="structural cycle", pos=[]) +} + +// Cycles should also be detected in evaluation paths that descend into +// recursion at non-field boundaries. +letCycleFail: t2: { + a: { + let X = a + if X == _|_ { } + x: y: "" + } + @test(eq, {a: {x: {y: ""}}}) + // TODO(eval): not sure if it really should fail here, so this may be okay. + @test(debug, """ + (struct){ + a: (struct){ + let X#4 = (_|_){ + // [structural_cycle] letCycleFail.t2.a.X: structural cycle + } + x: (struct){ + y: (string){ "" } + } + } + } + """) +} + +listCycleOK: { + a: b + b: and([c]) + c: a + @test(eq, {a: _, b: _, c: _}) +} + +disjunctionCycle: { + a: b + b: and(1 | c) + c: a + @test(err, code=eval, path=b, + hint="This probably should be a totally different error message.", + contains="cannot use %s (type %s) as %s in argument %d to %v", + args=[1, int, list, 1, and], pos=[2:9]) +} + +forCycle: { + #A: a: #B // TODO(errors): Correct error position, or at all. + #B: or([for x in #A { b: x }]) + @test(err, code=structural_cycle, path=#B.b, contains="structural cycle", pos=[]) +} + +letCycleWithAnd: { + a: d: b + b: and([for x in a let y = x { y }]) + c: a + @test(eq, {a: {d: {}}, b: {}, c: {d: {}}}) +} + +closeCycle: { + a: b + b: close({d: c}) + c: a + @test(err, code=structural_cycle, path=c, contains="structural cycle", pos=[]) +} + +structCycle: { + a: b + b: and([{d: c}]) + c: a + @test(err, code=structural_cycle, path=c, contains="structural cycle", pos=[]) +} + +embedCycle: { + a: b + b: close({c}) + c: a + @test(eq, {a: {}, b: {}, c: {}}) +} + +listAddCycle: { + a: b + b: list.Concat([[c], [c]]) + c: a + @test(err, code=structural_cycle, path=b, contains="error in call to %s", args=[list.Concat], pos=[2:5]) +} + +listMulCycle: { + a: b + b: list.Repeat([{a: b: c}], 3) + c: a + @test(err, code=structural_cycle, path=b, contains="error in call to %s", args=[list.Repeat], pos=[2:5]) +} + +// consult the correct closeness info in the face of it being passed down +// from parent. +closeFail: { + #T: [_]: _ + #T: close({"a": string}) + x: #T + x: b: "foo" + @test(err, code=eval, path=x.b, contains="field not allowed", pos=[1:6, 4:5]) +} + +printCycle: { + a: { + X: a + if X { + } + } + @test(err, code=structural_cycle, path=a.X, contains="structural cycle", pos=[]) +} +-- self.cue -- +issue3978: { + a: self={ + if self.missing != _|_ { + } + } + @test(eq, {a: {}}) +} +-- out/compile -- +--- in.cue +{ + letCycleOK: { + t1: { + b: 〈0;c〉 + let X#1 = 〈0;b〉 + c: 〈0;let X#1〉 + } + } + letCycleOK: { + t2: { + a: { + b: 1 + let X#2 = 〈1;a〉 + c: 〈0;let X#2〉.b + } + } + } + letCycleFail: { + t1: { + a: { + b: 1 + let X#3 = 〈1;a〉 + c: 〈0;let X#3〉 + } + } + } + letCycleFail: { + t2: { + a: { + let X#4 = 〈1;a〉 + if (〈0;let X#4〉 == _|_(explicit error (_|_ literal) in source)) {} + x: { + y: "" + } + } + } + } + listCycleOK: { + a: 〈0;b〉 + b: and([ + 〈1;c〉, + ]) + c: 〈0;a〉 + } + disjunctionCycle: { + a: 〈0;b〉 + b: and((1|〈0;c〉)) + c: 〈0;a〉 + } + forCycle: { + #A: { + a: 〈1;#B〉 + } + #B: or([ + for _, x in 〈1;#A〉 { + b: 〈1;x〉 + }, + ]) + } + letCycleWithAnd: { + a: { + d: 〈1;b〉 + } + b: and([ + for _, x in 〈1;a〉 let y = 〈0;x〉 { + 〈1;y〉 + }, + ]) + c: 〈0;a〉 + } + closeCycle: { + a: 〈0;b〉 + b: close({ + d: 〈1;c〉 + }) + c: 〈0;a〉 + } + structCycle: { + a: 〈0;b〉 + b: and([ + { + d: 〈2;c〉 + }, + ]) + c: 〈0;a〉 + } + embedCycle: { + a: 〈0;b〉 + b: close({ + 〈1;c〉 + }) + c: 〈0;a〉 + } + listAddCycle: { + a: 〈0;b〉 + b: 〈import;list〉.Concat([ + [ + 〈2;c〉, + ], + [ + 〈2;c〉, + ], + ]) + c: 〈0;a〉 + } + listMulCycle: { + a: 〈0;b〉 + b: 〈import;list〉.Repeat([ + { + a: { + b: 〈3;c〉 + } + }, + ], 3) + c: 〈0;a〉 + } + closeFail: { + #T: { + [_]: _ + } + #T: close({ + a: string + }) + x: 〈0;#T〉 + x: { + b: "foo" + } + } + printCycle: { + a: { + X: 〈1;a〉 + if 〈0;X〉 {} + } + } +} +--- self.cue +{ + issue3978: { + a: { + if (〈1〉.missing != _|_(explicit error (_|_ literal) in source)) {} + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/expression.txtar b/internal/core/compile/testdata/sync/cycle/expression.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/expression.txtar @@ -0,0 +1,214 @@ +-- in.cue -- +t1: a: { + a1: a0 + 2 @test(eq, 7.0) + b1: a1 - 2 @test(eq, 5.0) + a0: X @test(eq, 5.0) + X: b1 @test(eq, 5.0) + X: 5.0 +} + +t1: b: { + X: 5.0 @test(eq, 5.0) + a1: a0 + 2 @test(eq, 7.0) + b1: a1 - 2 @test(eq, 5.0) + a0: X @test(eq, 5.0) + X: b1 + @test(eq, {X: 5.0, a1: 7.0, b1: 5.0, a0: 5.0}) +} + +// TODO: did we really mean to have 3 times c? +t1: c: { + a1: a0 + 2 @test(eq, 7.0) + b1: a1 - 2 @test(eq, 5.0) + X: 5.0 @test(eq, 5.0) + a0: X @test(eq, 5.0) + X: b1 +} + +t1: c: { + b1: a1 - 2 + a1: a0 + 2 + X: 5.0 + a0: X + X: b1 +} + +t1: c: { + b1: a1 - 2 + X: 5.0 + a1: a0 + 2 + a0: X + X: b1 + @test(eq, {a1: 7.0, b1: 5.0, X: 5.0, a0: 5.0}) +} + +t1total: { + for _, v in t1 {v} + @test(eq, {a1: 7.0, b1: 5.0, a0: 5.0, X: 5.0}) +} + +// Issue #622 +// `cue export` errors on a solvable mutual cycle: `X = b1 = b0/2 = Y/2 = a1/2 = a0 = X` +// with a concrete value `X: 5.0` should resolve, but instead reports a cycle error. +// https://cuelang.org/issue/622 +// +// TODO: are these meant to be permutations? If so use @test(permute) +t2: a: { + a0: X @test(eq, 5.0) + a1: a0 * 2 @test(eq, 10.0) + Y: a1 @test(eq, 10.0) + + b0: Y @test(eq, 10.0) + b1: b0 / 2 @test(eq, 5.0) + X: b1 @test(eq, 5.0) + + X: 5.0 + @test(eq, {a0: 5.0, a1: 10.0, Y: 10.0, b0: 10.0, b1: 5.0, X: 5.0}) +} + +t2: b: { + b0: Y @test(eq, 10.0) + b1: b0 / 2 @test(eq, 5.0) + X: b1 @test(eq, 5.0) + + a0: X @test(eq, 5.0) + a1: a0 * 2 @test(eq, 10.0) + Y: a1 @test(eq, 10.0) + + X: 5.0 + @test(eq, {b0: 10.0, b1: 5.0, X: 5.0, a0: 5.0, a1: 10.0, Y: 10.0}) +} + +t2: c: { + b0: Y @test(eq, 10.0) + b1: b0 / 2 @test(eq, 5.0) + X: b1 @test(eq, 5.0) + + X: 5.0 @test(eq, 5.0) + + a0: X @test(eq, 5.0) + a1: a0 * 2 @test(eq, 10.0) + Y: a1 @test(eq, 10.0) + @test(eq, {b0: 10.0, b1: 5.0, X: 5.0, a0: 5.0, a1: 10.0, Y: 10.0}) +} + +t2: d: { + b0: Y @test(eq, 10.0) + b1: b0 / 2 @test(eq, 5.0) + X: b1 @test(eq, 5.0) + + a0: X @test(eq, 5.0) + a1: a0 * 2 @test(eq, 10.0) + Y: a1 @test(eq, 10.0) + + X: 5.0 + @test(eq, {b0: 10.0, b1: 5.0, X: 5.0, a0: 5.0, a1: 10.0, Y: 10.0}) +} + +t2total: { + for _, v in t2 {v} + @test(eq, {a0: 5.0, a1: 10.0, Y: 10.0, b0: 10.0, b1: 5.0, X: 5.0}) +} +-- out/compile -- +--- in.cue +{ + t1: { + a: { + a1: (〈0;a0〉 + 2) + b1: (〈0;a1〉 - 2) + a0: 〈0;X〉 + X: 〈0;b1〉 + X: 5.0 + } + } + t1: { + b: { + X: 5.0 + a1: (〈0;a0〉 + 2) + b1: (〈0;a1〉 - 2) + a0: 〈0;X〉 + X: 〈0;b1〉 + } + } + t1: { + c: { + a1: (〈0;a0〉 + 2) + b1: (〈0;a1〉 - 2) + X: 5.0 + a0: 〈0;X〉 + X: 〈0;b1〉 + } + } + t1: { + c: { + b1: (〈0;a1〉 - 2) + a1: (〈0;a0〉 + 2) + X: 5.0 + a0: 〈0;X〉 + X: 〈0;b1〉 + } + } + t1: { + c: { + b1: (〈0;a1〉 - 2) + X: 5.0 + a1: (〈0;a0〉 + 2) + a0: 〈0;X〉 + X: 〈0;b1〉 + } + } + t1total: { + for _, v in 〈1;t1〉 { + 〈1;v〉 + } + } + t2: { + a: { + a0: 〈0;X〉 + a1: (〈0;a0〉 * 2) + Y: 〈0;a1〉 + b0: 〈0;Y〉 + b1: (〈0;b0〉 / 2) + X: 〈0;b1〉 + X: 5.0 + } + } + t2: { + b: { + b0: 〈0;Y〉 + b1: (〈0;b0〉 / 2) + X: 〈0;b1〉 + a0: 〈0;X〉 + a1: (〈0;a0〉 * 2) + Y: 〈0;a1〉 + X: 5.0 + } + } + t2: { + c: { + b0: 〈0;Y〉 + b1: (〈0;b0〉 / 2) + X: 〈0;b1〉 + X: 5.0 + a0: 〈0;X〉 + a1: (〈0;a0〉 * 2) + Y: 〈0;a1〉 + } + } + t2: { + d: { + b0: 〈0;Y〉 + b1: (〈0;b0〉 / 2) + X: 〈0;b1〉 + a0: 〈0;X〉 + a1: (〈0;a0〉 * 2) + Y: 〈0;a1〉 + X: 5.0 + } + } + t2total: { + for _, v in 〈1;t2〉 { + 〈1;v〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/freeze.txtar b/internal/core/compile/testdata/sync/cycle/freeze.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/freeze.txtar @@ -0,0 +1,252 @@ +// This files tests that values are properly "frozen" in case of mutual +// references. Non-structural cyclic references are okay, as long a property +// that is dependended upon in the cycle is not changed after the fact, +// that is, a value may not become more specific after it is used. +-- in.cue -- +freezing: t1: ok: { + #a: x: "a" + len(#a) // 1 + @test(eq, {1, #a: {x: "a"}}) +} + +-- comprehension.cue -- +// This should be an incomplete error, as z is inserted in x, over which the +// comprehension loops. Adding a field z to x would fix this. +// This test would fail in the old evaluator, depending on ordering. +comprehension: t1: _ +comprehension: t1: ok:{ + @test(permute, count=) + + x: y: {} + // order of comprehensions matter in old evaluator. + for _ in x { + if true { x: z: a: {} } + } + if true { + if true { x: z: a: {} } + } + @test(eq, {x: {y: {}, z: {a: {}}}}) +} + +comprehension: t2: err: { + a: { + x: 1 + for k, v in a { + (k+"q"): v // This increases the set of fields in a. + } + @test(err, code=eval, contains="adding field %v not allowed as field set was already referenced", args=[xq], pos=[3:13]) + } +} + +comprehension: t3: err: { + // mutual dependencies not okay in this case, as the set of fields grows. + a: x: 1 + b: y: 1 + a: { + for k, v in b { + (k+"q"): v + } + @test(err, code=eval, + suberr=(code=eval, contains="adding field %v not allowed as field set was already referenced", args=[yq], pos=[2:13]), + suberr=(code=eval, contains="adding field %v not allowed as field set was already referenced", args=[xq], pos=[2:13])) + } + b: { + for k, v in a { + (k): v + } + @test(eq, {y: 1, x: 1}) + } +} + +comprehension: t4: ok: { + // It is okay to make x more specific as long as no fields are added. + x: y: {} + for _ in x { + if true { x: y: a: {} } + } + @test(eq, {x: {y: {a: {}}}}) +} + +comprehension: moreSpecific: ok: { + a: { + x: int + for k, v in a { + (k): 1 + } + @test(eq, {x: 1}) + } +} + +comprehension: moreSpecific: err: { + a: { + x: {y: 1} + // len(v) should free the size of x. + for k, v in a if len(v) > 0 { + (k): {z: 1} + } + @test(err, code=eval, path=x, + contains="adding field %v not allowed as field set was already referenced", args=[z], pos=[4:9]) + } +} +-- issue3178.cue -- +// evalv3 regression: exporting via the Go API produced an error that evalv2 +// did not, for a case involving chained comprehensions. +// https://cuelang.org/issue/3178 +issue3178: { + // This should pass. Reasoning: + // - second comprehension runs + // - in order to satisfy, first comprehension must run + // - first comprehension runs and completes + input: [ "Value" ] + output: {...} + for name in input { + output: "\(name)": true + } + for name, v in output { + } + @test(eq, {input: ["Value"], output: {Value: true}}) +} +-- out/compile -- +--- comprehension.cue +{ + comprehension: { + t1: _ + } + comprehension: { + t1: { + ok: { + x: { + y: {} + } + for _, _ in 〈0;x〉 { + if true { + x: { + z: { + a: {} + } + } + } + } + if true { + if true { + x: { + z: { + a: {} + } + } + } + } + } + } + } + comprehension: { + t2: { + err: { + a: { + x: 1 + for k, v in 〈1;a〉 { + (〈1;k〉 + "q"): 〈1;v〉 + } + } + } + } + } + comprehension: { + t3: { + err: { + a: { + x: 1 + } + b: { + y: 1 + } + a: { + for k, v in 〈1;b〉 { + (〈1;k〉 + "q"): 〈1;v〉 + } + } + b: { + for k, v in 〈1;a〉 { + 〈1;k〉: 〈1;v〉 + } + } + } + } + } + comprehension: { + t4: { + ok: { + x: { + y: {} + } + for _, _ in 〈0;x〉 { + if true { + x: { + y: { + a: {} + } + } + } + } + } + } + } + comprehension: { + moreSpecific: { + ok: { + a: { + x: int + for k, v in 〈1;a〉 { + 〈1;k〉: 1 + } + } + } + } + } + comprehension: { + moreSpecific: { + err: { + a: { + x: { + y: 1 + } + for k, v in 〈1;a〉 if (len(〈0;v〉) > 0) { + 〈1;k〉: { + z: 1 + } + } + } + } + } + } +} +--- in.cue +{ + freezing: { + t1: { + ok: { + #a: { + x: "a" + } + len(〈0;#a〉) + } + } + } +} +--- issue3178.cue +{ + issue3178: { + input: [ + "Value", + ] + output: { + ... + } + for _, name in 〈0;input〉 { + output: { + "\(〈2;name〉)": true + } + } + for name, v in 〈0;output〉 {} + } +} diff --git a/internal/core/compile/testdata/sync/cycle/inline.txtar b/internal/core/compile/testdata/sync/cycle/inline.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/inline.txtar @@ -0,0 +1,462 @@ +-- x.cue -- +// variants of fib + +inline: small: { + f: { + n: int + out: (f & {"n": n - 1}).out @test(err, code=structural_cycle, contains="structural cycle", pos=[0:9]) + } +} + +inline: medium: { + f2: (f & {n: 2}).out @test(err, code=structural_cycle, contains="structural cycle", pos=[1:24]) + fRec: {nn: int, out: (f & {n: nn}).out} + @test(err, at=fRec.out, code=structural_cycle, contains="structural cycle", pos=[6:9]) + f: { + n: int + out: (fRec & {nn: n - 1}).out @test(err, code=structural_cycle, contains="structural cycle", pos=[0:9]) + } +} + +inline: patterns: { + f: n: (f & {n: {}}).n + f: n: {} @test(err, code=structural_cycle, contains="structural cycle", pos=[-1:9]) + [string]: {n: {}} + f: [string]: {} + f: {} +} + +inline: acrossFields: fail1: { + f: { + in: number + out: in + 1 + } + k00: 0 + k10: (f & {in: k00}).out + k20: (f & {in: k10}).out + k30: (f & {in: k20}).out + + // invalid recursion is here. + k10: (f & {in: k30}).out + @test(eq, { + f: { + in: number + out: _|_ @test(err, code=incomplete, contains="inline.acrossFields.fail1.f.out: non-concrete value number in operand to +", pos=[31:8, 30:8]) + } + k00: 0 + k10: _|_ @test(err, code=incomplete, contains="in: non-concrete value number in operand to +", pos=[31:8, 30:8, 36:17]) + k20: _|_ @test(err, code=incomplete, contains="in: non-concrete value number in operand to +", pos=[31:8, 30:8, 39:17]) + k30: _|_ @test(err, code=incomplete, contains="in: non-concrete value number in operand to +", pos=[31:8, 30:8, 35:17]) + }) +} + +// Issue #2163 +inline: acrossFields: ok1: { + f: { + in: number + out: in + } + k00: 0 + k10: (f & {in: k00}).out + k20: (f & {in: k10}).out + k30: (f & {in: k20}).out + + // TODO: what is correct behavior here. + // This is borderline okay. + k10: (f & {in: k30}).out + @test(eq, { + f: {in: number, out: number} + k00: 0 + k10: 0 + k20: 0 + k30: 0 + }, hint="might be okay to fail") +} +-- inlineexpand.cue -- +inlined: { + X: { + input: a: _ + output: input.a + } + root: a: (X & {input: root}).output + @test(eq, { + X: {input: {a: _}, output: _} + root: {a: _} + }) +} +expanded1: hasCycle: { + X: { + input: a: _ + output: input.a + } + root: { + a: _a.output + _a: X & {input: root} + } + @test(err, code=structural_cycle, at=root._a.input._a.input, contains="structural cycle", pos=[]) +} +expanded2: noCycle: { + X: { + input: a: _ + output: input.a + } + root: a: _a.output + _a: X & {input: root} + @test(eq, { + X: {input: {a: _}, output: _} + root: {a: _} + _a: {input: {a: _}, output: _} + }) +} +issue3731: reduced: { + #lookup: { + input: {...} + output: [ + for _, v in input if v.show != _|_ { v }, + ] + } + + root: { + self: show: true + others: (#lookup & {input: root}).output + } + @test(eq, { + #lookup: {input: {}, output: []} + root: { + self: {show: true} + others: [{show: true}] + } + }) +} +issue3731: expanded: { + #lookup: { + input: {...} + output: [ + for _, v in input if v.show != _|_ { v }, + ] + } + + root: { + self: show: true + others: _others.output + _others: #lookup & {input: root} + } + @test(err, code=structural_cycle, at=root._others.input._others.input, contains="structural cycle", pos=[]) +} +issue3731: full: { + #Workspace: { + workspaceA?: {} + workspaceB?: {} + } + + #AccountConfig: { + workspaces: #Workspace + siblings?: [...string] + } + + #AccountConfigSub1: { + #AccountConfig + workspaces: "workspaceA": {} + } + + #AccountConfigSub2: { + #AccountConfig + workspaces: "workspaceB": {} + } + + tree: env1: { + "region1": { + "env1-r1-account-sub1": #AccountConfigSub1 + "env1-r1-account-sub2-1": #AccountConfigSub2 + } + } + + #lookupSiblings: { + envtree: {...} + out: [ + for region, v in envtree + for account, config in v + if config.workspaces."workspaceB" != _|_ { account }, + ] + } + + tree: ENVTREE=env1: [_]: [_]: #AccountConfig & { + siblings: (#lookupSiblings & {envtree: ENVTREE}).out + } + @test(eq, { + #Workspace: {workspaceA?: {}, workspaceB?: {}} + #AccountConfig: { + workspaces: {workspaceA?: {}, workspaceB?: {}} + siblings?: [] + } + #AccountConfigSub1: { + workspaces: {workspaceA: {}, workspaceB?: {}} + siblings?: [] + } + #AccountConfigSub2: { + workspaces: {workspaceB: {}, workspaceA?: {}} + siblings?: [] + } + tree: { + env1: { + region1: { + "env1-r1-account-sub1": { + siblings: ["env1-r1-account-sub2-1"] + workspaces: {workspaceA: {}, workspaceB?: {}} + } + "env1-r1-account-sub2-1": { + siblings: ["env1-r1-account-sub2-1"] + workspaces: {workspaceB: {}, workspaceA?: {}} + } + } + } + } + #lookupSiblings: {envtree: {}, out: []} + }) +} +-- out/compile -- +--- inlineexpand.cue +{ + inlined: { + X: { + input: { + a: _ + } + output: 〈0;input〉.a + } + root: { + a: (〈1;X〉 & { + input: 〈2;root〉 + }).output + } + } + expanded1: { + hasCycle: { + X: { + input: { + a: _ + } + output: 〈0;input〉.a + } + root: { + a: 〈0;_a〉.output + _a: (〈1;X〉 & { + input: 〈2;root〉 + }) + } + } + } + expanded2: { + noCycle: { + X: { + input: { + a: _ + } + output: 〈0;input〉.a + } + root: { + a: 〈1;_a〉.output + } + _a: (〈0;X〉 & { + input: 〈1;root〉 + }) + } + } + issue3731: { + reduced: { + #lookup: { + input: { + ... + } + output: [ + for _, v in 〈1;input〉 if (〈0;v〉.show != _|_(explicit error (_|_ literal) in source)) { + 〈1;v〉 + }, + ] + } + root: { + self: { + show: true + } + others: (〈1;#lookup〉 & { + input: 〈2;root〉 + }).output + } + } + } + issue3731: { + expanded: { + #lookup: { + input: { + ... + } + output: [ + for _, v in 〈1;input〉 if (〈0;v〉.show != _|_(explicit error (_|_ literal) in source)) { + 〈1;v〉 + }, + ] + } + root: { + self: { + show: true + } + others: 〈0;_others〉.output + _others: (〈1;#lookup〉 & { + input: 〈2;root〉 + }) + } + } + } + issue3731: { + full: { + #Workspace: { + workspaceA?: {} + workspaceB?: {} + } + #AccountConfig: { + workspaces: 〈1;#Workspace〉 + siblings?: [ + ...string, + ] + } + #AccountConfigSub1: { + 〈1;#AccountConfig〉 + workspaces: { + workspaceA: {} + } + } + #AccountConfigSub2: { + 〈1;#AccountConfig〉 + workspaces: { + workspaceB: {} + } + } + tree: { + env1: { + region1: { + "env1-r1-account-sub1": 〈3;#AccountConfigSub1〉 + "env1-r1-account-sub2-1": 〈3;#AccountConfigSub2〉 + } + } + } + #lookupSiblings: { + envtree: { + ... + } + out: [ + for region, v in 〈1;envtree〉 for account, config in 〈0;v〉 if (〈0;config〉.workspaces.workspaceB != _|_(explicit error (_|_ literal) in source)) { + 〈1;account〉 + }, + ] + } + tree: { + env1: { + [_]: { + [_]: (〈3;#AccountConfig〉 & { + siblings: (〈4;#lookupSiblings〉 & { + envtree: 〈4;env1〉 + }).out + }) + } + } + } + } + } +} +--- x.cue +{ + inline: { + small: { + f: { + n: int + out: (〈1;f〉 & { + n: (〈1;n〉 - 1) + }).out + } + } + } + inline: { + medium: { + f2: (〈0;f〉 & { + n: 2 + }).out + fRec: { + nn: int + out: (〈1;f〉 & { + n: 〈1;nn〉 + }).out + } + f: { + n: int + out: (〈1;fRec〉 & { + nn: (〈1;n〉 - 1) + }).out + } + } + } + inline: { + patterns: { + f: { + n: (〈1;f〉 & { + n: {} + }).n + } + f: { + n: {} + } + [string]: { + n: {} + } + f: { + [string]: {} + } + f: {} + } + } + inline: { + acrossFields: { + fail1: { + f: { + in: number + out: (〈0;in〉 + 1) + } + k00: 0 + k10: (〈0;f〉 & { + in: 〈1;k00〉 + }).out + k20: (〈0;f〉 & { + in: 〈1;k10〉 + }).out + k30: (〈0;f〉 & { + in: 〈1;k20〉 + }).out + k10: (〈0;f〉 & { + in: 〈1;k30〉 + }).out + } + } + } + inline: { + acrossFields: { + ok1: { + f: { + in: number + out: 〈0;in〉 + } + k00: 0 + k10: (〈0;f〉 & { + in: 〈1;k00〉 + }).out + k20: (〈0;f〉 & { + in: 〈1;k10〉 + }).out + k30: (〈0;f〉 & { + in: 〈1;k20〉 + }).out + k10: (〈0;f〉 & { + in: 〈1;k30〉 + }).out + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/inline_non_recursive.txtar b/internal/core/compile/testdata/sync/cycle/inline_non_recursive.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/inline_non_recursive.txtar @@ -0,0 +1,341 @@ +-- in.cue -- +// All these should pass. These look like recursive inlined calls, but they are +// not. + +ok1: { + f: { + in: number + out: in + } + k00: 0 + k10: (f & {in: k00}).out + k20: (f & {in: k10}).out + k30: (f & {in: k20}).out + @test(eq, { + f: {in: number, out: number} + k00: 0 + k10: 0 + k20: 0 + k30: 0 + }) +} + +ok2: { + f: { + in: number + out: in + } + k00: 0 + k10: {(f & {in: k00}).out} + k20: {(f & {in: k10}).out} + k30: {(f & {in: k20}).out} + @test(eq, { + f: {in: number, out: number} + k00: 0 + k10: 0 + k20: 0 + k30: 0 + }) +} + +ok3: { + f: { + in: number + out: in + } + k00: 0 + k10: {close((f & {in: k00})).out} + k20: {close((f & {in: k10})).out} + k30: {close((f & {in: k20})).out} + @test(eq, { + f: {in: number, out: number} + k00: 0 + k10: 0 + k20: 0 + k30: 0 + }) +} + +ok4: { + f: { + in: number + out: in + } + k00: 0 + k10: {out: {(f & {in: k00}).out}}.out + k20: {out: {(f & {in: k10}).out}}.out + k30: {out: {(f & {in: k20}).out}}.out + @test(eq, { + f: {in: number, out: number} + k00: 0 + k10: 0 + k20: 0 + k30: 0 + }) +} + +// Issue #1708: nested indirect selectors on a definition instantiated more than +// twice cause a false structural cycle. Concrete conjuncts like `{in: kN}` are +// not recognized as cycle-breakers, so successive `(#add10 & {in: k}).out` +// chains are incorrectly treated as self-recursive. +// https://cuelang.org/issue/1708 +issue1708: { + #add10: { + in: number + a10: { i: in, o: i + 10 } + out: a10.o + } + k00: 0 + k10: (#add10 & {in: k00}).out + k20: (#add10 & {in: k10}).out + k30: (#add10 & {in: k20}).out + + // TODO(inline): the generation of this value is broken, had to hand-adjust. + // TODO(inline): file positions are absolute instead of relative to the definition. + @test(eq, { + #add10: { + in: number + a10: { + i: number + o: _|_ @test(err, code=incomplete, contains="non-concrete value number in operand to +", pos=[84:20, 83:7]) + } + out: _|_ @test(err) + } + k00: 0 + k10: 10 + k20: 20 + k30: _|_ @test(err, code=incomplete, contains="undefined field: out", pos=[88:28]) + }) +} +-- issue3182.cue -- +// evalv3 regression: references under projections (e.g. `{ a: x }.a`) were +// not resolved correctly, producing errors or wrong output that evalv2 handled. +// https://cuelang.org/issue/3182 +issue3182: { + first: t1: { + x: { a: x }.a + @test(eq, {x: _}) + } + first: t2: { + x: { a: b: x }.a + @test(err, code=structural_cycle) + } + second: { + { t: x }.t.y + x: y: x: y: a: 1 + @test(eq, {x: {y: {x: {y: {a: 1}}, a: 1}}, a: 1}) + } + third: { + { + p: { + x: p + y: 1 + } + }.p.x.y + @test(eq, 1) + } +} +-- select.cue -- +// The value of #Step should be consistent between these test cases. +select: direct: { + #Step: (#Job & {opt: _}).opt + #Job: matchN(1, [#NormalJob]) + // TODO(inline): broken generation: retains reference. + @test(eq, { + #Step: _ + #Job: matchN(1, [{req!: int, opt?: {run?: string}}]) + }) +} +select: indirect: { + #Step: #Job.opt + #Job: matchN(1, [#NormalJob]) & {opt: _} + @test(eq, {#Step: _, #Job: {_|_, opt: _}}) +} +#NormalJob: { + req!: int + opt?: run?: string +} +-- out/compile -- +--- in.cue +{ + ok1: { + f: { + in: number + out: 〈0;in〉 + } + k00: 0 + k10: (〈0;f〉 & { + in: 〈1;k00〉 + }).out + k20: (〈0;f〉 & { + in: 〈1;k10〉 + }).out + k30: (〈0;f〉 & { + in: 〈1;k20〉 + }).out + } + ok2: { + f: { + in: number + out: 〈0;in〉 + } + k00: 0 + k10: { + (〈1;f〉 & { + in: 〈2;k00〉 + }).out + } + k20: { + (〈1;f〉 & { + in: 〈2;k10〉 + }).out + } + k30: { + (〈1;f〉 & { + in: 〈2;k20〉 + }).out + } + } + ok3: { + f: { + in: number + out: 〈0;in〉 + } + k00: 0 + k10: { + close((〈1;f〉 & { + in: 〈2;k00〉 + })).out + } + k20: { + close((〈1;f〉 & { + in: 〈2;k10〉 + })).out + } + k30: { + close((〈1;f〉 & { + in: 〈2;k20〉 + })).out + } + } + ok4: { + f: { + in: number + out: 〈0;in〉 + } + k00: 0 + k10: { + out: { + (〈2;f〉 & { + in: 〈3;k00〉 + }).out + } + }.out + k20: { + out: { + (〈2;f〉 & { + in: 〈3;k10〉 + }).out + } + }.out + k30: { + out: { + (〈2;f〉 & { + in: 〈3;k20〉 + }).out + } + }.out + } + issue1708: { + #add10: { + in: number + a10: { + i: 〈1;in〉 + o: (〈0;i〉 + 10) + } + out: 〈0;a10〉.o + } + k00: 0 + k10: (〈0;#add10〉 & { + in: 〈1;k00〉 + }).out + k20: (〈0;#add10〉 & { + in: 〈1;k10〉 + }).out + k30: (〈0;#add10〉 & { + in: 〈1;k20〉 + }).out + } +} +--- issue3182.cue +{ + issue3182: { + first: { + t1: { + x: { + a: 〈1;x〉 + }.a + } + } + first: { + t2: { + x: { + a: { + b: 〈2;x〉 + } + }.a + } + } + second: { + { + t: 〈1;x〉 + }.t.y + x: { + y: { + x: { + y: { + a: 1 + } + } + } + } + } + third: { + { + p: { + x: 〈1;p〉 + y: 1 + } + }.p.x.y + } + } +} +--- select.cue +{ + select: { + direct: { + #Step: (〈0;#Job〉 & { + opt: _ + }).opt + #Job: matchN(1, [ + 〈3;#NormalJob〉, + ]) + } + } + select: { + indirect: { + #Step: 〈0;#Job〉.opt + #Job: (matchN(1, [ + 〈3;#NormalJob〉, + ]) & { + opt: _ + }) + } + } + #NormalJob: { + req!: int + opt?: { + run?: string + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue1960.txtar b/internal/core/compile/testdata/sync/cycle/issue1960.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue1960.txtar @@ -0,0 +1,174 @@ +#inlinetest:exclude t2 contains an unreferenced-alias compile-time error, preventing +# full inline conversion. +# Tests let-alias cycles and comprehension cycles in deeply nested structs; t1 +# uses a let alias referencing an enclosing comprehension variable; t3 exercises +# recursive definitions with computed-field access through a let and comprehension. +-- issue1960.cue -- +// evalv3 regression: a spurious structural cycle error was reported for a +// pattern that had previously evaluated correctly, causing valid CUE to fail. +// https://cuelang.org/issue/1960 +t1: { + z: blah: s: [for z in z {}] + z: hello: { + for x in p {} + let q = z.blah + p: q.r // Incomplete error should not cause cycle. + p: t: 1 + } +} + +t2: { + z: blah: s: [for z in z {}] + z: hello: { + for x in p {} + let q = z.blah + p: t: 1 + } +} + +t3: { + #z: { + n: string + p: t: "e" + s: [...string] + _p: { + n: string + e: p: {} + } + r: (_p )[p.t] + for _, pl in r.p { + if pl.blah { + } + } + } + + #i: { + #z + t: "i" + r: e: {} + } + + #c: { + #z + t: "c" + n: string + } + + z: [N= =~"^b"]: #i & { + s: [ + for n, z in z + if z.t == "c" + if z.n == N {n}, + ] + } + + z: [N= =~"^h"]: #c & { + n: string + // Causes a structural cycle on its own, but not when referenced below. + let q = z[n] + p: q.r.e + } + + z: { + "blah": {} + "hello": n: "blah" + } +} +-- out/compile -- +t2.z.hello: unreferenced alias or let clause q: + ./issue1960.cue:18:3 +--- issue1960.cue +{ + t1: { + z: { + blah: { + s: [ + for _, z in 〈3;z〉 {}, + ] + } + } + z: { + hello: { + for _, x in 〈0;p〉 {} + let q#1 = 〈2;z〉.blah + p: 〈0;let q#1〉.r + p: { + t: 1 + } + } + } + } + t2: { + z: { + blah: { + s: [ + for _, z in 〈3;z〉 {}, + ] + } + } + z: { + hello: { + for _, x in 〈0;p〉 {} + let q#2 = 〈2;z〉.blah + p: { + t: 1 + } + } + } + } + t3: { + #z: { + n: string + p: { + t: "e" + } + s: [ + ...string, + ] + _p: { + n: string + e: { + p: {} + } + } + r: 〈0;_p〉[〈0;p〉.t] + for _, pl in 〈0;r〉.p { + if 〈1;pl〉.blah {} + } + } + #i: { + 〈1;#z〉 + t: "i" + r: { + e: {} + } + } + #c: { + 〈1;#z〉 + t: "c" + n: string + } + z: { + [=~"^b"]: (〈1;#i〉 & { + s: [ + for n, z in 〈3;z〉 if (〈0;z〉.t == "c") if (〈0;z〉.n == 〈3;-〉) { + 〈1;n〉 + }, + ] + }) + } + z: { + [=~"^h"]: (〈1;#c〉 & { + n: string + let q#3 = 〈2;z〉[〈0;n〉] + p: 〈0;let q#3〉.r.e + }) + } + z: { + blah: {} + hello: { + n: "blah" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue241.txtar b/internal/core/compile/testdata/sync/cycle/issue241.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue241.txtar @@ -0,0 +1,64 @@ +# `!=` applied to a disjunction before structural cycle is concrete: +# CUE incorrectly reports an empty disjunction error instead of handling +# the abstract `!=` constraint between fields sharing a disjunction type. +# https://cuelang.org/issue/241 +-- in.cue -- +#Value: 0 | 1 + +foo: #Value @test(err, code=cycle|incomplete, args=[bar], pos=[-2:13, 2:6, 3:6]) +foo: !=bar +bar: #Value @test(eq, 0 | 1) +bar: !=foo @test(err:todo, code=cycle|incomplete) + +#Value: 0 | 1 + +Foo: #Value @test(eq, 1) +Foo: !=Bar +Bar: #Value @test(eq, 0) +Bar: !=Foo +Bar: 0 + +cell: a: 0 | 1 +cell: a: !=cell.b +cell: b: 0 | 1 +cell: b: !=cell.a +cell: a: 0 @test(eq, 0) +cell: b: _ @test(eq, 1) + +a: cell.a @test(eq, 0) +b: cell.b @test(eq, 1) +-- out/compile -- +--- in.cue +{ + #Value: (0|1) + foo: 〈0;#Value〉 + foo: !=〈0;bar〉 + bar: 〈0;#Value〉 + bar: !=〈0;foo〉 + #Value: (0|1) + Foo: 〈0;#Value〉 + Foo: !=〈0;Bar〉 + Bar: 〈0;#Value〉 + Bar: !=〈0;Foo〉 + Bar: 0 + cell: { + a: (0|1) + } + cell: { + a: !=〈1;cell〉.b + } + cell: { + b: (0|1) + } + cell: { + b: !=〈1;cell〉.a + } + cell: { + a: 0 + } + cell: { + b: _ + } + a: 〈0;cell〉.a + b: 〈0;cell〉.b +} diff --git a/internal/core/compile/testdata/sync/cycle/issue242.txtar b/internal/core/compile/testdata/sync/cycle/issue242.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue242.txtar @@ -0,0 +1,296 @@ +# Stack overflow when multiple `!=` constraints are applied between fields +# in a structural cycle involving a disjunction (e.g. a grid where each cell +# must differ from its neighbors). +# https://cuelang.org/issue/242 +-- in.cue -- +#size: 2 +#CellValue: 0 | 1 | 2 | 3 +cell: "0": "0": #CellValue +cell: "0": "0": !=cell["0"]["1"] +cell: "0": "0": !=cell["1"]["0"] +cell: "0": "0": !=cell["1"]["1"] + +cell: "0": "1": #CellValue +cell: "0": "1": !=cell["0"]["0"] +cell: "0": "1": !=cell["1"]["0"] +cell: "0": "1": !=cell["1"]["1"] + +cell: "1": "0": #CellValue +cell: "1": "0": !=cell["0"]["0"] +cell: "1": "0": !=cell["0"]["1"] +cell: "1": "0": !=cell["1"]["1"] + +cell: "1": "1": #CellValue +cell: "1": "1": !=cell["0"]["0"] +cell: "1": "1": !=cell["0"]["1"] +cell: "1": "1": !=cell["1"]["0"] + +cell: "0": "0": 0 +cell: "0": "1": 1 +cell: "1": "0": 2 +cell: "1": "1": 3 +@test(eq, { + "0": {"0": 0, "1": 1} + "1": {"0": 2, "1": 3} +}, at=cell) + +cell2: a: 0 | 1 +cell2: a: !=cell2.b + +cell2: b: 0 | 1 +cell2: b: !=cell2.a + +cell2: a: _ +cell2: b: 1 +@test(eq, {a: 0, b: 1}, at=cell2) + +cell3: a: 0 | 1 +cell3: a: !=cell3.b + +cell3: b: 0 | 1 +cell3: b: !=cell3.a + +cell3: a: 0 +cell3: b: _ +@test(eq, {a: 0, b: 1}, at=cell3) + +cell4: a: 0 | 1 +cell4: a: !=cell4.b + +cell4: b: 0 | 1 +cell4: b: !=cell4.a + +cell4: b: _ +cell4: a: 0 + +cell5: b: 0 | 1 +cell5: b: !=cell5.a + +cell5: a: 0 | 1 +cell5: a: !=cell5.b + +cell5: b: _ +cell5: a: 0 + +a: #CellValue +a: !=b +a: !=c +a: !=d + +b: #CellValue +b: !=a +b: !=c +b: !=d + +c: #CellValue +c: !=a +c: !=b +c: !=d + +d: #CellValue +d: !=a +d: !=b +d: !=c + +a: 0 +b: 1 +c: 2 +d: 3 +-- out/compile -- +--- in.cue +{ + #size: 2 + #CellValue: (0|1|2|3) + cell: { + "0": { + "0": 〈2;#CellValue〉 + } + } + cell: { + "0": { + "0": !=〈2;cell〉["0"]["1"] + } + } + cell: { + "0": { + "0": !=〈2;cell〉["1"]["0"] + } + } + cell: { + "0": { + "0": !=〈2;cell〉["1"]["1"] + } + } + cell: { + "0": { + "1": 〈2;#CellValue〉 + } + } + cell: { + "0": { + "1": !=〈2;cell〉["0"]["0"] + } + } + cell: { + "0": { + "1": !=〈2;cell〉["1"]["0"] + } + } + cell: { + "0": { + "1": !=〈2;cell〉["1"]["1"] + } + } + cell: { + "1": { + "0": 〈2;#CellValue〉 + } + } + cell: { + "1": { + "0": !=〈2;cell〉["0"]["0"] + } + } + cell: { + "1": { + "0": !=〈2;cell〉["0"]["1"] + } + } + cell: { + "1": { + "0": !=〈2;cell〉["1"]["1"] + } + } + cell: { + "1": { + "1": 〈2;#CellValue〉 + } + } + cell: { + "1": { + "1": !=〈2;cell〉["0"]["0"] + } + } + cell: { + "1": { + "1": !=〈2;cell〉["0"]["1"] + } + } + cell: { + "1": { + "1": !=〈2;cell〉["1"]["0"] + } + } + cell: { + "0": { + "0": 0 + } + } + cell: { + "0": { + "1": 1 + } + } + cell: { + "1": { + "0": 2 + } + } + cell: { + "1": { + "1": 3 + } + } + cell2: { + a: (0|1) + } + cell2: { + a: !=〈1;cell2〉.b + } + cell2: { + b: (0|1) + } + cell2: { + b: !=〈1;cell2〉.a + } + cell2: { + a: _ + } + cell2: { + b: 1 + } + cell3: { + a: (0|1) + } + cell3: { + a: !=〈1;cell3〉.b + } + cell3: { + b: (0|1) + } + cell3: { + b: !=〈1;cell3〉.a + } + cell3: { + a: 0 + } + cell3: { + b: _ + } + cell4: { + a: (0|1) + } + cell4: { + a: !=〈1;cell4〉.b + } + cell4: { + b: (0|1) + } + cell4: { + b: !=〈1;cell4〉.a + } + cell4: { + b: _ + } + cell4: { + a: 0 + } + cell5: { + b: (0|1) + } + cell5: { + b: !=〈1;cell5〉.a + } + cell5: { + a: (0|1) + } + cell5: { + a: !=〈1;cell5〉.b + } + cell5: { + b: _ + } + cell5: { + a: 0 + } + a: 〈0;#CellValue〉 + a: !=〈0;b〉 + a: !=〈0;c〉 + a: !=〈0;d〉 + b: 〈0;#CellValue〉 + b: !=〈0;a〉 + b: !=〈0;c〉 + b: !=〈0;d〉 + c: 〈0;#CellValue〉 + c: !=〈0;a〉 + c: !=〈0;b〉 + c: !=〈0;d〉 + d: 〈0;#CellValue〉 + d: !=〈0;a〉 + d: !=〈0;b〉 + d: !=〈0;c〉 + a: 0 + b: 1 + c: 2 + d: 3 +} diff --git a/internal/core/compile/testdata/sync/cycle/issue2526.txtar b/internal/core/compile/testdata/sync/cycle/issue2526.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue2526.txtar @@ -0,0 +1,19 @@ +# The evaluator enters an infinite loop when processing a cycle involving +# struct embeddings, causing `cue eval` to hang indefinitely. +# https://cuelang.org/issue/2526 +-- in.cue -- +x +x: { + y + y: x +} +@test(err, code=structural_cycle, path=x.y, contains="structural cycle", pos=[]) +-- out/compile -- +--- in.cue +{ + 〈0;x〉 + x: { + 〈0;y〉 + y: 〈1;x〉 + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue306.txtar b/internal/core/compile/testdata/sync/cycle/issue306.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue306.txtar @@ -0,0 +1,18 @@ +# CUE panics/crashes instead of reporting a clean error when evaluating +# values with cyclic field dependencies. +# https://cuelang.org/issue/306 +-- in.cue -- +a: 12 @test(eq, 12) +#Controller: settings: { + controller: #Controller +} @test(err, code=structural_cycle, path=controller, contains="structural cycle", pos=[]) +-- out/compile -- +--- in.cue +{ + a: 12 + #Controller: { + settings: { + controller: 〈2;#Controller〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue3118.txtar b/internal/core/compile/testdata/sync/cycle/issue3118.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue3118.txtar @@ -0,0 +1,73 @@ +# Cycle errors report no source position information, making it impossible +# to locate the offending code. +# https://cuelang.org/issue/3118 +-- in.cue -- +#TimeSpan: { + start: float + duration: float + end: float + + start: end - duration + duration: end - start + end: start + duration + + start: <=end +} + +examples: [string]: #TimeSpan + +examples: eg1: { + start: 10.0 + duration: 2.1 + @test(eq, {start: 10.0, duration: 2.1, end: 12.1}) +} + +examples: eg2: { + start: 10.0 + @test(eq, { + start: _|_ @test(err, code=incomplete, pos=[6:12, 4:12, 8:12]) + duration: _|_ @test(err, code=incomplete, pos=[7:12, 4:12, 8:12]) + end: _|_ @test(err, code=incomplete, pos=[7:12, 4:12, 8:12]) +}) +} + +examples: eg3: { + end: 10.0 + @test(eq, { + end: _|_ @test(err, code=incomplete, pos=[8:12, 2:12, 6:12, 10:9]) + start: _|_ @test(err, code=incomplete, pos=[7:12, 2:12, 6:12, 10:9]) + duration: _|_ @test(err, code=incomplete, pos=[7:12, 2:12, 6:12, 10:9]) +}) +} +-- out/compile -- +--- in.cue +{ + #TimeSpan: { + start: float + duration: float + end: float + start: (〈0;end〉 - 〈0;duration〉) + duration: (〈0;end〉 - 〈0;start〉) + end: (〈0;start〉 + 〈0;duration〉) + start: <=〈0;end〉 + } + examples: { + [string]: 〈1;#TimeSpan〉 + } + examples: { + eg1: { + start: 10.0 + duration: 2.1 + } + } + examples: { + eg2: { + start: 10.0 + } + } + examples: { + eg3: { + end: 10.0 + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue3527.txtar b/internal/core/compile/testdata/sync/cycle/issue3527.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue3527.txtar @@ -0,0 +1,73 @@ +# evalv3 panics with nil pointer dereference on a reduced real-world CUE file +# involving `let` bindings and mutual references between definitions, whereas +# evalv2 handles it correctly. +# https://cuelang.org/issue/3527 +-- in.cue -- +package p + +_taxPayer: self: {} + +let sam = {taxPayer: _taxPayer} +assert: { + invoke: sam + invoke: _ + res: subject & {in: invoke} +} + +subject: { + in: #ReturnData + _computed: (#computeF1040 & {"in": in}) +} +#computeF1040: in: #ReturnData +#ReturnData: taxPayer?: #TaxPayer +#TaxPayer: self?: _ + +@test(eq, { + _taxPayer$p: {self: {}} + assert: { + invoke: {taxPayer: {self: {}}} + res: { + in: {taxPayer: {self: {}}} + _computed$p: {in: {taxPayer: {self: {}}}} + } + } + subject: { + in: {taxPayer?: {self?: _}} + _computed$p: {in: {taxPayer?: {self?: _}}} + } + #computeF1040: {in: {taxPayer?: {self?: _}}} + #ReturnData: {taxPayer?: {self?: _}} + #TaxPayer: {self?: _} +}) +-- out/compile -- +--- in.cue +{ + _taxPayer(:p): { + self: {} + } + let sam#1 = { + taxPayer: 〈1;_taxPayer(:p)〉 + } + assert: { + invoke: 〈1;let sam#1〉 + invoke: _ + res: (〈1;subject〉 & { + in: 〈1;invoke〉 + }) + } + subject: { + in: 〈1;#ReturnData〉 + _computed(:p): (〈1;#computeF1040〉 & { + in: 〈1;in〉 + }) + } + #computeF1040: { + in: 〈1;#ReturnData〉 + } + #ReturnData: { + taxPayer?: 〈1;#TaxPayer〉 + } + #TaxPayer: { + self?: _ + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue3570.txtar b/internal/core/compile/testdata/sync/cycle/issue3570.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue3570.txtar @@ -0,0 +1,16 @@ +# evalv2 panics in `DerefValue` when processing a specific CUE input +# discovered via oss-fuzz, reproducing on both v0.9.2 and v0.10.1. +# https://cuelang.org/issue/3570 +-- in.cue -- +foo: foo: 25 | 44 +foo +foo: foo @test(eq, {foo: _}) +-- out/compile -- +--- in.cue +{ + foo: { + foo: (25|44) + } + 〈0;foo〉 + foo: 〈0;foo〉 +} diff --git a/internal/core/compile/testdata/sync/cycle/issue3571.txtar b/internal/core/compile/testdata/sync/cycle/issue3571.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue3571.txtar @@ -0,0 +1,106 @@ +# evalv3 incorrectly reports a structural cycle error for a CUE definition that +# validates correctly under evalv2, representing a regression in cycle detection. +# https://cuelang.org/issue/3571 +-- in.cue -- +// These tests should NOT have structural cycles. +simplified: { + #T + in: _ + x: #T + x: x: #T + + #T: { + in: x + x: _ + } + + @test(eq, { + in: {x: {in: _, x: _}, in: {in: _, x: _}} + x: {x: {in: _, x: _}, in: {in: _, x: _}} + #T: {in: _, x: _} + }) +} + +issue3571: { + a: #T + a: in: f: true + a: #in: { + g: #T + g: #in: f: #T + g: #in: f: #in: x: true + f?: _ + } + + #T: { + in: #in + #in: _ + } + + @test(eq, { + a: { + in: { + f: true + g: { + #in: {f: {#in: {x: true}, in: {x: true}}} + in: {f: {#in: {x: true}, in: {x: true}}} + } + } + #in: { + g: { + #in: {f: {#in: {x: true}, in: {x: true}}} + in: {f: {#in: {x: true}, in: {x: true}}} + } + f?: _ + } + } + #T: {in: _, #in: _} + }) +} +-- out/compile -- +--- in.cue +{ + simplified: { + 〈0;#T〉 + in: _ + x: 〈0;#T〉 + x: { + x: 〈1;#T〉 + } + #T: { + in: 〈0;x〉 + x: _ + } + } + issue3571: { + a: 〈0;#T〉 + a: { + in: { + f: true + } + } + a: { + #in: { + g: 〈2;#T〉 + g: { + #in: { + f: 〈4;#T〉 + } + } + g: { + #in: { + f: { + #in: { + x: true + } + } + } + } + f?: _ + } + } + #T: { + in: 〈0;#in〉 + #in: _ + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue3827.txtar b/internal/core/compile/testdata/sync/cycle/issue3827.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue3827.txtar @@ -0,0 +1,77 @@ +# evalv3 incorrectly produces a "field not allowed" error when unifying against +# a definition that succeeds without error under evalv2, regressing on a +# real-world GitHub Actions schema. +# https://cuelang.org/issue/3827 +-- in.cue -- +reduced: { + A: b: (A.c & {}).x + A: null | { c: x: 1 } + @test(eq, {A: {b: 1, c: {x: 1}}}) +} + +full: { + out: #Workflow.#Step & { + uses: "actions/upload-artifact@v3" + with: { + name: "foo" + path: "bar" + } + } + + Y=#Workflow: #Step: (Y.steps & {x: {}}).x + + #Workflow: null | { + steps: [string]: { + uses?: string + with?: [string]: string + } + } + @test(eq, { + out: { + uses: "actions/upload-artifact@v3" + with: {name: "foo", path: "bar"} + } + #Workflow: { + #Step: {uses?: string, with?: {}} + steps: {} + } + }) +} +-- out/compile -- +--- in.cue +{ + reduced: { + A: { + b: (〈1;A〉.c & {}).x + } + A: (null|{ + c: { + x: 1 + } + }) + } + full: { + out: (〈0;#Workflow〉.#Step & { + uses: "actions/upload-artifact@v3" + with: { + name: "foo" + path: "bar" + } + }) + #Workflow: { + #Step: (〈1;#Workflow〉.steps & { + x: {} + }).x + } + #Workflow: (null|{ + steps: { + [string]: { + uses?: string + with?: { + [string]: string + } + } + } + }) + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue4203.txtar b/internal/core/compile/testdata/sync/cycle/issue4203.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue4203.txtar @@ -0,0 +1,91 @@ +# A CUE file using comprehensions and struct embeddings that exports +# successfully in v0.13.2 fails with "undefined field" in later versions. +# https://cuelang.org/issue/4203 +-- in.cue -- +import "strings" + +// Marking comprehension fields as optional for cycle detection +// should not prevent fixed fields from being resolved. +_listBuilder: { + kind: "kind1" + _deps: [...] + _kindJoin: { + _objs: [...] + _out: strings.Join([for d in _objs {d.kind}], ",") + } + _depKinds: {_kindJoin & {_objs: _deps}}._out + variable: "{" + _depKinds + "}" +} + +output: _ +if true { + _input: [{ + _listBuilder + _deps: [{_listBuilder}] + }] + + output: _input[0].variable +} +@test(eq, { + _listBuilder: { + kind: "kind1" + _deps: [] + _kindJoin: {_objs: [], _out: ""} + _depKinds: "" + variable: "{}" + } + output: "{kind1}" + _input: [{ + _deps: [{ + kind: "kind1" + _deps: [] + _kindJoin: {_objs: [], _out: ""} + _depKinds: "" + variable: "{}" + }] + kind: "kind1" + _kindJoin: {_objs: [], _out: ""} + _depKinds: "kind1" + variable: "{kind1}" + }] +}) +-- out/compile -- +--- in.cue +{ + _listBuilder: { + kind: "kind1" + _deps: [ + ..., + ] + _kindJoin: { + _objs: [ + ..., + ] + _out: 〈import;strings〉.Join([ + for _, d in 〈1;_objs〉 { + 〈1;d〉.kind + }, + ], ",") + } + _depKinds: { + (〈1;_kindJoin〉 & { + _objs: 〈2;_deps〉 + }) + }._out + variable: (("{" + 〈0;_depKinds〉) + "}") + } + output: _ + if true { + _input: [ + { + 〈3;_listBuilder〉 + _deps: [ + { + 〈5;_listBuilder〉 + }, + ] + }, + ] + output: 〈0;_input〉[0].variable + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue4210.txtar b/internal/core/compile/testdata/sync/cycle/issue4210.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue4210.txtar @@ -0,0 +1,67 @@ +# CUE hangs indefinitely when a structural cycle reference is wrapped in braces +# before a field selector, e.g. `a: b: c: {a}.b`. Without braces (`a: b: c: +# a.b`) the cycle is correctly detected and reported as an error. The braces +# prevent cycle detection, causing CUE to loop forever instead of reporting an +# error. Affects all variants: `{a & _}.b`, `{a.b}.c`, nested structs, etc. +# https://cuelang.org/issue/4210 +-- in.cue -- +t1: { + a: b: c: {a}.b + @test(err, code=structural_cycle, contains="structural cycle", pos=[]) +} +t2: { + a: b: c: {a & _}.b + @test(err, code=structural_cycle, contains="structural cycle", pos=[]) +} +t3: { + a: b: c: d: {a.b}.c + @test(err, code=structural_cycle, contains="structural cycle", pos=[]) +} +t4: { + x: y: z: {a}.y + a: x + @test(err, code=structural_cycle, contains="structural cycle", pos=[]) +} +-- out/compile -- +--- in.cue +{ + t1: { + a: { + b: { + c: { + 〈3;a〉 + }.b + } + } + } + t2: { + a: { + b: { + c: { + (〈3;a〉 & _) + }.b + } + } + } + t3: { + a: { + b: { + c: { + d: { + 〈4;a〉.b + }.c + } + } + } + } + t4: { + x: { + y: { + z: { + 〈3;a〉 + }.y + } + } + a: 〈0;x〉 + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue4228.txtar b/internal/core/compile/testdata/sync/cycle/issue4228.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue4228.txtar @@ -0,0 +1,197 @@ +# Test that cyclic error formatting doesn't cause stack overflow. +# The combination of error() with self interpolation and complex nested +# struct patterns can cause infinite recursion when formatting error messages. +# https://cuelang.org/issue/4228 +-- in.cue -- +package main + +_objectBase: self={ + name: string + k8s: metadata: name: self.name +} + +_namespacedResource: self={ + _objectBase + namespace: string + k8s: metadata: namespace: self.namespace +} + +// Key validation pattern with error() and self +_allValuesAreValidStructs: [_]: self={ + *{} | error("<- invalid \(self)") +} + +_setTypeMeta: self={ + #apiVersion!: string + #kind!: string + #template: k8s: { + apiVersion: self.#apiVersion + kind: self.#kind + } +} + +// Resource kinds pattern +_resourceKindsBase: { + _base!: _ + + [string]: { + _allValuesAreValidStructs + _setTypeMeta + #resourceSchema: _ + #template: { + _base + k8s: #resourceSchema + } + [_]: #template + } +} + +_namespacedResourceKinds: { + _resourceKindsBase + _base: _namespacedResource + [string]: [string]: namespace: string + + app: { + #apiVersion: "argoproj.io/v1alpha1" + #kind: "Application" + #resourceSchema: { + spec?: revisionHistoryLimit?: int + } + + #template: self={ + revisionHistoryLimit: *3 | int + k8s: spec: revisionHistoryLimit: self.revisionHistoryLimit + } + } +} + +// Usage +argocd: _namespacedResourceKinds & { + app: apps: {} +} @test(err, code=eval) + +-- export.cue -- +@experiment(aliasv2) + +package main + +import "encoding/yaml" + +let _globalScope = self + +#export: { + #entries: [...] + manifests: [ + for _entry in #entries + for _ns in _entry + for _kind, _objs in _ns + for _name, _obj in _objs { + _obj.k8s + }] + yamlStream: yaml.MarshalStream(manifests) +} + +#manifests: {#export, #entries: [_globalScope]}.yamlStream + +@test(err, code=eval) +-- out/compile -- +--- export.cue +{ + let _globalScope#1 = 〈1〉 + #export: { + #entries: [ + ..., + ] + manifests: [ + for _, _entry in 〈1;#entries〉 for _, _ns in 〈0;_entry(:main)〉 for _kind, _objs in 〈0;_ns(:main)〉 for _name, _obj in 〈0;_objs(:main)〉 { + 〈1;_obj(:main)〉.k8s + }, + ] + yamlStream: 〈import;"encoding/yaml"〉.MarshalStream(〈0;manifests〉) + } + #manifests: { + 〈1;#export〉 + #entries: [ + 〈2;let _globalScope#1〉, + ] + }.yamlStream +} +--- in.cue +{ + _objectBase(:main): { + name: string + k8s: { + metadata: { + name: 〈3〉.name + } + } + } + _namespacedResource(:main): { + 〈1;_objectBase(:main)〉 + namespace: string + k8s: { + metadata: { + namespace: 〈3〉.namespace + } + } + } + _allValuesAreValidStructs(:main): { + [_]: { + (*{}|error("<- invalid \(〈1〉)")) + } + } + _setTypeMeta(:main): { + #apiVersion!: string + #kind!: string + #template: { + k8s: { + apiVersion: 〈3〉.#apiVersion + kind: 〈3〉.#kind + } + } + } + _resourceKindsBase(:main): { + _base(:main)!: _ + [string]: { + 〈2;_allValuesAreValidStructs(:main)〉 + 〈2;_setTypeMeta(:main)〉 + #resourceSchema: _ + #template: { + 〈2;_base(:main)〉 + k8s: 〈1;#resourceSchema〉 + } + [_]: 〈0;#template〉 + } + } + _namespacedResourceKinds(:main): { + 〈1;_resourceKindsBase(:main)〉 + _base(:main): 〈1;_namespacedResource(:main)〉 + [string]: { + [string]: { + namespace: string + } + } + app: { + #apiVersion: "argoproj.io/v1alpha1" + #kind: "Application" + #resourceSchema: { + spec?: { + revisionHistoryLimit?: int + } + } + #template: { + revisionHistoryLimit: (*3|int) + k8s: { + spec: { + revisionHistoryLimit: 〈3〉.revisionHistoryLimit + } + } + } + } + } + argocd: (〈0;_namespacedResourceKinds(:main)〉 & { + app: { + apps: {} + } + }) +} diff --git a/internal/core/compile/testdata/sync/cycle/issue4230.txtar b/internal/core/compile/testdata/sync/cycle/issue4230.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue4230.txtar @@ -0,0 +1,48 @@ +# The new evaluator (v3) produces empty output for `or(["eu-west-1", "us-east-1"])` +# when used inside a self-referential struct, while the old evaluator produces the +# correct result. Replacing `or([...])` with a plain disjunction `"a" | "b"` works +# correctly. The root cause: calls with only literal arguments were incorrectly +# deferred when evaluated from within a cyclic context, resulting in empty output. +# https://cuelang.org/issue/4230 +-- in.cue -- +#transform: { + _input: {...} + _output: [ + if _input.app != _|_ { + _input.app.region + }, + ] +} + +x: X={ + regions: (#transform & {_input: X})._output + app: region: or(["west", "east"]) & "west" +} @test(eq, { + regions: ["west"] + app: {region: "west"} +}) +-- out/compile -- +--- in.cue +{ + #transform: { + _input: { + ... + } + _output: [ + if (〈1;_input〉.app != _|_(explicit error (_|_ literal) in source)) { + 〈2;_input〉.app.region + }, + ] + } + x: { + regions: (〈1;#transform〉 & { + _input: 〈2〉 + })._output + app: { + region: (or([ + "west", + "east", + ]) & "west") + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue4244.txtar b/internal/core/compile/testdata/sync/cycle/issue4244.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue4244.txtar @@ -0,0 +1,57 @@ +# A `let` binding that factors out a repeated expression changes the evaluation +# result unexpectedly compared to the inline form, indicating a bug in how +# `let`-bound values are resolved relative to their enclosing scope. +# https://cuelang.org/issue/4244 +-- in.cue -- +import "strings" + +#schema: { + let splits = strings.Split(id, "_never_") + let prefix = splits[0] + + #ID: =~"^\(prefix)$" @test(err, code=incomplete, contains="invalid interpolation", pos=[0:12, -2:22]) + #SubID: =~"^\(prefix):sub$" @test(err, code=incomplete, contains="invalid interpolation", pos=[0:12, -3:22]) + + id: #ID @test(err, code=incomplete, contains="invalid interpolation", pos=[-3:12, -5:22]) + subid: #SubID @test(err, code=incomplete, contains="invalid interpolation", pos=[-3:12, -6:22]) +} + +case1: #schema & { + id: "foo" + subid: "foo:sub" +} @test(eq, { + id: "foo" + subid: "foo:sub" + #ID: =~"^foo$" + #SubID: =~"^foo:sub$" +}) + +case2: #schema & { + subid: "foo:sub" + id: "foo" +} @test(eq, { + subid: "foo:sub" + id: "foo" + #ID: =~"^foo$" + #SubID: =~"^foo:sub$" +}) +-- out/compile -- +--- in.cue +{ + #schema: { + let splits#1 = 〈import;strings〉.Split(〈0;id〉, "_never_") + let prefix#2 = 〈0;let splits#1〉[0] + #ID: =~"^\(〈0;let prefix#2〉)$" + #SubID: =~"^\(〈0;let prefix#2〉):sub$" + id: 〈0;#ID〉 + subid: 〈0;#SubID〉 + } + case1: (〈0;#schema〉 & { + id: "foo" + subid: "foo:sub" + }) + case2: (〈0;#schema〉 & { + subid: "foo:sub" + id: "foo" + }) +} diff --git a/internal/core/compile/testdata/sync/cycle/issue4253.txtar b/internal/core/compile/testdata/sync/cycle/issue4253.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue4253.txtar @@ -0,0 +1,51 @@ +# Non-CallExpr conjuncts (=~, == _|_, interpolation) must not be deferred +# under a cyclic context; companion to issue4230.txtar which covers CallExpr. +# https://cuelang.org/issue/4253 +-- in.cue -- +@experiment(aliasv2) + +x: { + #tmpl: { + let _self = self + foo: 1 + k8s: foo: _self.foo + } + + #allowed: =~"^[a-z0-9]+$" + + [string]: { + [string]~(ID,_): { + #tmpl + if (#allowed & ID) == _|_ { + error("bad: \(ID)") + } + } + } + + gateway: whoami2: {} +} @test(eq, at=gateway.whoami2, {foo: 1, k8s: {foo: 1}}) +-- out/compile -- +--- in.cue +{ + x: { + #tmpl: { + let _self#1 = 〈1〉 + foo: 1 + k8s: { + foo: 〈1;let _self#1〉.foo + } + } + #allowed: =~"^[a-z0-9]+$" + [string]: { + [string]: { + 〈2;#tmpl〉 + if ((〈2;#allowed〉 & 〈1;-〉) == _|_(explicit error (_|_ literal) in source)) { + error("bad: \(〈2;-〉)") + } + } + } + gateway: { + whoami2: {} + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue429.txtar b/internal/core/compile/testdata/sync/cycle/issue429.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue429.txtar @@ -0,0 +1,123 @@ +# `cue export` incorrectly rejects a `#Size` definition with interdependent +# bound constraints (`num: >res | *(1+res)`, `max: >=num | *num`) when a +# concrete value is provided, e.g. `a: #Size & { num: 5 }`. Expected output +# would be `{ res: 0, num: 5, max: 5 }` but instead CUE reports empty +# disjunction errors for both `num` and `max`. Works correctly in v0.2.1. +# TODO: a bound value resolving to a disjunction should probably be an error. +# In this case #Size.amx should resolve. +# https://cuelang.org/issue/429 +-- in.cue -- +// Range disjunction without cycle (checks only one-way). +#Size: { + res: uint | *0 + min: >res | *(1 + res) + max: >min | *min +} + +s0: #Size & {res: 1} @test(eq, { + res: 1 + min: *2 | >1 + max: *2 | >1 | >2 +}) + +// This discards the default for max. This is correct, but unfortunate. +// TODO: is there a tweak to the default mechanism possible that would fix that? +// Tread very carefully, though! Perhaps we could have a builtin that +// discards any default, so that we can at least manually override this +// behavior. +s1: #Size & {min: 5} @test(eq, { + min: 5 + res: *0 | >=0 & int + max: *5 | >5 +}) +s2: #Size & {max: 5} @test(eq, { + max: 5 + res: *0 | >=0 & int + min: *1 | >0 +}) +s3: #Size & { + min: 5 + max: 10 +} @test(eq, {min: 5, max: 10, res: *0 | >=0 & int}) +es3: #Size & { + min: 10 + max: 5 +} @test(err, code=eval, + suberr=(code=eval, path=max, contains="%d errors in empty disjunction:", args=[2], pos=[]), + suberr=(code=eval, path=max, contains="conflicting values %s and %s", args=[1, 5], pos=[-29:16, -28:15, 0:6, 2:7]), + suberr=(code=eval, path=max, contains="conflicting values %s and %s", args=[10, 5], pos=[-28:15, 0:6, 1:7, 2:7]), + suberr=(code=eval, path=max, contains="invalid value %v (out of bound %s)", args=[5, >10], pos=[-28:7, 2:7])) + +// Disjunctions with cycles +// TODO: improve error message here. Logic is correct, though. +#nonEmptyRange: { + min: *1 | int + min: min +} +r1: #nonEmptyRange & { + min: 3 +} @test(eq, { + min: _|_ @test(err, code=incomplete, contains="r1.min: non-concrete value max for bound < (and 2 more errors)", pos=[46:8]) + max: >3 +}) +r2: #nonEmptyRange & { + max: 5 +} @test(eq, {max: 5, min: *1 | <5 & int}) +r3: #nonEmptyRange & { + min: 3 + max: 6 +} @test(eq, {min: 3, max: 6}) + +er3: #nonEmptyRange & { + min: 5 + max: 5 +} @test(err, code=eval, + suberr=(code=eval, path=min, contains="conflicting values %s and %s", args=[1, 5], pos=[-18:8, 0:6, 1:7]), + suberr=(code=eval, path=min, contains="invalid value %v (out of bound %s)", args=[5, <5], pos=[-17:7, 1:7]), + suberr=(code=eval, path=min, contains="invalid value %v (out of bound %s)", args=[5, <5], pos=[-17:7, 1:7])) +-- out/compile -- +--- in.cue +{ + #Size: { + res: (&(int, >=0)|*0) + min: (>〈0;res〉|*(1 + 〈0;res〉)) + max: (>〈0;min〉|*〈0;min〉) + } + s0: (〈0;#Size〉 & { + res: 1 + }) + s1: (〈0;#Size〉 & { + min: 5 + }) + s2: (〈0;#Size〉 & { + max: 5 + }) + s3: (〈0;#Size〉 & { + min: 5 + max: 10 + }) + es3: (〈0;#Size〉 & { + min: 10 + max: 5 + }) + #nonEmptyRange: { + min: (*1|int) + min: <〈0;max〉 + max: >〈0;min〉 + } + r1: (〈0;#nonEmptyRange〉 & { + min: 3 + }) + r2: (〈0;#nonEmptyRange〉 & { + max: 5 + }) + r3: (〈0;#nonEmptyRange〉 & { + min: 3 + max: 6 + }) + er3: (〈0;#nonEmptyRange〉 & { + min: 5 + max: 5 + }) +} diff --git a/internal/core/compile/testdata/sync/cycle/issue494.txtar b/internal/core/compile/testdata/sync/cycle/issue494.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue494.txtar @@ -0,0 +1,110 @@ +# `a: [rn=string]: _Q[0:len(a[rn])]` silently produces wrong output: `a.ben` +# should be `[{pos: 0}]` (a one-element slice matching the concrete entry's +# length) but instead produces `[{}]` with `pos` missing and no error reported. +# The equivalent closed-type pattern `#d: [rn=string]: [...] & _Q[0:len(#d[rn])]` +# works correctly. The self-referential slice constraint is not being unified. +# https://cuelang.org/issue/494 +-- in.cue -- +_Q: [{pos: 0}, {pos: 1}] + +a: [rn=string]: _Q[0:len(a[rn])] +a: ben: [{}] @test(eq, [{pos: 0}]) + +b: [rn=string]: _Q[0:1] +b: ben: [{}] @test(eq, [{pos: 0}]) + +c: [rn=string]: [...{l: len(a[rn])}] +c: ben: [{}] @test(eq, [{l: 1}]) + +#d: [rn=string]: [...{pos: uint}] & _Q[0:len(#d[rn])] +#d: ben: [{}] @test(eq, [{pos: 0}]) + +d: #d @test(eq, {ben: [{pos: 0}]}) + +e: [rn=string]: _Q[0 : len(a[rn])+1] +e: ben: [{}, ...] @test(eq, [{pos: 0}, {pos: 1}]) + +f: [rn=string]: _Q[0 : len(a[rn])+1] +f: ben: [{}] @test(err, code=eval, contains="incompatible list lengths", pos=[]) + +g: [rn=string]: _Q[0:len(a[rn])] +g: ben: [{}, {}] @test(err, code=eval, contains="incompatible list lengths", pos=[]) +-- out/compile -- +--- in.cue +{ + _Q: [ + { + pos: 0 + }, + { + pos: 1 + }, + ] + a: { + [string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])] + } + a: { + ben: [ + {}, + ] + } + b: { + [string]: 〈1;_Q〉[0:1] + } + b: { + ben: [ + {}, + ] + } + c: { + [string]: [ + ...{ + l: len(〈3;a〉[〈2;-〉]) + }, + ] + } + c: { + ben: [ + {}, + ] + } + #d: { + [string]: ([ + ...{ + pos: &(int, >=0) + }, + ] & 〈1;_Q〉[0:len(〈1;#d〉[〈0;-〉])]) + } + #d: { + ben: [ + {}, + ] + } + d: 〈0;#d〉 + e: { + [string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)] + } + e: { + ben: [ + {}, + ..., + ] + } + f: { + [string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)] + } + f: { + ben: [ + {}, + ] + } + g: { + [string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])] + } + g: { + ben: [ + {}, + {}, + ] + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue502.txtar b/internal/core/compile/testdata/sync/cycle/issue502.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue502.txtar @@ -0,0 +1,175 @@ +# A recursive configuration using `_link: #T` in a map's entry struct is +# incorrectly rejected as a structural cycle in v0.3.0+, but worked in v0.2.2. +# The user expects config values to propagate through linked chains (e.g. nested +# `mas: one: { mas: two: { ... } }`) but gets "structural cycle" errors for +# `#a.mas.one._link.mas.two.link` etc. Shallow nesting (one level) works fine. +# https://cuelang.org/issue/502 +-- in.cue -- +#T: { + config: _ + body: _ + mas: [string]: { + cfg: _ + _link: #T + link: _link & {config: cfg} + } +} + +#a: #T & { + config: a: int + body: config.a + mas: one: { + cfg: b: config.a + _link: { + config: b: int + body: config.b + mas: two: { + cfg: c: config.b + _link: { + config: c: int + body: config.c + } + } + } + } +} + +a: #a & {config: a: 34} @test(eq, { + config: {a: 34} + body: 34 + mas: one: { + cfg: {b: 34} + _link: { + config: {b: int} + body: int + mas: two: { + cfg: {c: int} + _link: {config: {c: int}, body: int, mas: {}} + link: {config: {c: int}, body: int, mas: {}} + } + } + link: { + config: {b: 34} + body: 34 + mas: two: { + cfg: {c: 34} + _link: {config: {c: int}, body: int, mas: {}} + link: {config: {c: 34}, body: 34, mas: {}} + } + } + } +}) +-- reduced.cue -- +reduced: t1: { + #T: x: y?: { + V: _ + z: #T & V & {} + } + a: #T + a: x: y: V: x: y: V: {} + + @test(eq, { + #T: x: y?: { + V: _ + z: x: y?: { + _|_ + V: _ + z: _|_ @test(err, code=structural_cycle, contains="reduced.t1.#T.x.y.z.x.y.z: structural cycle", pos=[]) + } + } + a: x: y: { + V: x: y: V: {} + z: x: y: { + V: {} + z: x: y?: { + _|_ + V: _ + z: _|_ @test(err, code=structural_cycle, contains="reduced.t1.a.x.y.z.x.y.z.x.y.z: structural cycle", pos=[]) + } + } + } + }) +} +-- out/compile -- +--- in.cue +{ + #T: { + config: _ + body: _ + mas: { + [string]: { + cfg: _ + _link: 〈3;#T〉 + link: (〈0;_link〉 & { + config: 〈1;cfg〉 + }) + } + } + } + #a: (〈0;#T〉 & { + config: { + a: int + } + body: 〈0;config〉.a + mas: { + one: { + cfg: { + b: 〈3;config〉.a + } + _link: { + config: { + b: int + } + body: 〈0;config〉.b + mas: { + two: { + cfg: { + c: 〈3;config〉.b + } + _link: { + config: { + c: int + } + body: 〈0;config〉.c + } + } + } + } + } + } + }) + a: (〈0;#a〉 & { + config: { + a: 34 + } + }) +} +--- reduced.cue +{ + reduced: { + t1: { + #T: { + x: { + y?: { + V: _ + z: ((〈3;#T〉 & 〈0;V〉) & {}) + } + } + } + a: 〈0;#T〉 + a: { + x: { + y: { + V: { + x: { + y: { + V: {} + } + } + } + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/issue990.txtar b/internal/core/compile/testdata/sync/cycle/issue990.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/issue990.txtar @@ -0,0 +1,285 @@ +# CUE incorrectly reports a structural cycle error for a valid CUE expression +# that does not actually contain a cycle, producing a false positive. +# https://cuelang.org/issue/990 +-- in.cue -- +// A simple discriminated element +#AC: { + k: "simple" + d: #C +} + +// A recursive discriminated element +#AS: { + k: "complex" + d: #S +} + +#R: { + a: #AC | #AS +} + +// The structure of the recursive element +#S: { + n: string + r: [string]: #R +} + +// The structure of the simple element +#C: { + n: string +} + +#sub: { + $p=#p: #AS + dict: [string]: _ + + for rn, rd in $p.d.r if rd.a.k == "complex" { + let subs = #sub & {#p: rd.a} + for sn, sd in subs.dict { + dict: "\(rn)_\(sn)": sd + } + } + for rn, rd in $p.d.r if rd.a.k == "simple" { + dict: "\(rn)": rd + } +} + +// Data +_test: { + c1: #AC + c1: d: { + n: "c1" + } + + + s3: #AS + s3: d: { + n: "s3" + r: r1: a:c1 + } + + s2: #AS + s2: d: { + n: "s2" + r: { + r1: a: c1 + r2: a: s3 + } + } + + s1: #AS + s1: d: { + n: "s1" + r: { + r1: a: c1 + r2: a: s2 + } + } +} + +// Test + +out: #sub & {#p: _test.s1} + +// TODO(fmt): can we improve this? +@test(eq, { + #AC: {k: "simple", d: {n: string}} + #AS: {k: "complex", d: {n: string, r: {}}} + #R: { + a: {k: "simple", d: {n: string}} | {k: "complex", d: {n: string, r: {}}} + } + #S: {n: string, r: {}} + #C: {n: string} + #sub: { + #p: {k: "complex", d: {n: string, r: {}}} + dict: {} + } + _test: { + c1: {d: {n: "c1"}, k: "simple"} + s3: { + d: { + n: "s3" + r: {r1: {a: {d: {n: "c1"}, k: "simple"}}} + } + k: "complex" + } + s2: { + d: { + n: "s2" + r: { + r1: {a: {d: {n: "c1"}, k: "simple"}} + r2: { + a: { + d: { + n: "s3" + r: {r1: {a: {d: {n: "c1"}, k: "simple"}}} + } + k: "complex" + } + } + } + } + k: "complex" + } + s1: { + d: { + n: "s1" + r: { + r1: {a: {d: {n: "c1"}, k: "simple"}} + r2: { + a: { + d: { + n: "s2" + r: { + r1: {a: {d: {n: "c1"}, k: "simple"}} + r2: { + a: { + d: { + n: "s3" + r: {r1: {a: {d: {n: "c1"}, k: "simple"}}} + } + k: "complex" + } + } + } + } + k: "complex" + } + } + } + } + k: "complex" + } + } + out: { + #p: { + d: { + n: "s1" + r: { + r1: {a: {d: {n: "c1"}, k: "simple"}} + r2: { + a: { + d: { + n: "s2" + r: { + r1: {a: {d: {n: "c1"}, k: "simple"}} + r2: { + a: { + d: { + n: "s3" + r: {r1: {a: {d: {n: "c1"}, k: "simple"}}} + } + k: "complex" + } + } + } + } + k: "complex" + } + } + } + } + k: "complex" + } + dict: { + r1: {a: {d: {n: "c1"}, k: "simple"}} + r2_r1: {a: {d: {n: "c1"}, k: "simple"}} + r2_r2_r1: {a: {d: {n: "c1"}, k: "simple"}} + } + } +}) +-- out/compile -- +--- in.cue +{ + #AC: { + k: "simple" + d: 〈1;#C〉 + } + #AS: { + k: "complex" + d: 〈1;#S〉 + } + #R: { + a: (〈1;#AC〉|〈1;#AS〉) + } + #S: { + n: string + r: { + [string]: 〈2;#R〉 + } + } + #C: { + n: string + } + #sub: { + #p: 〈1;#AS〉 + dict: { + [string]: _ + } + for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "complex") { + let subs#1multi = (〈3;#sub〉 & { + #p: 〈2;rd〉.a + }) + for sn, sd in 〈0;let subs#1〉.dict { + dict: { + "\(〈4;rn〉)_\(〈2;sn〉)": 〈2;sd〉 + } + } + } + for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "simple") { + dict: { + "\(〈2;rn〉)": 〈2;rd〉 + } + } + } + _test: { + c1: 〈1;#AC〉 + c1: { + d: { + n: "c1" + } + } + s3: 〈1;#AS〉 + s3: { + d: { + n: "s3" + r: { + r1: { + a: 〈4;c1〉 + } + } + } + } + s2: 〈1;#AS〉 + s2: { + d: { + n: "s2" + r: { + r1: { + a: 〈4;c1〉 + } + r2: { + a: 〈4;s3〉 + } + } + } + } + s1: 〈1;#AS〉 + s1: { + d: { + n: "s1" + r: { + r1: { + a: 〈4;c1〉 + } + r2: { + a: 〈4;s2〉 + } + } + } + } + } + out: (〈0;#sub〉 & { + #p: 〈1;_test〉.s1 + }) +} diff --git a/internal/core/compile/testdata/sync/cycle/patterns.txtar b/internal/core/compile/testdata/sync/cycle/patterns.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/patterns.txtar @@ -0,0 +1,61 @@ +// Lots of cycle-reference goodness. +# Tests that pattern constraints on cyclically-referenced fields do not +# cause infinite evaluation. Also tests issue3326 (cyclic pattern constraints). +-- in.cue -- +[!~"^[.]"]: c +a: b +b: [string]: int +c: a: int +[string]: c +a: b @test(eq, {a: int}) +b: [string]: int +c: a: int @test(eq, int) + +-- issue3326.cue -- +// https://cuelang.org/issue/3326 +issue3326: { + // This issue triggered a cyclic evaluation in pattern constraints. + // + // It seems like there is still an issue as the evaluation of `x` in + // `and` may trigger a cyclic evaluation of `and`. However, `and` only + // does a shallow evaluation, and inserting `x`'s conjuncts into itself + // is identified as idempotent and thus further evaluation is skipped. + _self: x: [...and(x)] + _self + x: [1] + @test(eq, {_self: {x: []}, x: [1], a: int}) +} +-- out/compile -- +--- in.cue +{ + [!~"^[.]"]: 〈0;c〉 + a: 〈0;b〉 + b: { + [string]: int + } + c: { + a: int + } + [string]: 〈0;c〉 + a: 〈0;b〉 + b: { + [string]: int + } + c: { + a: int + } +} +--- issue3326.cue +{ + issue3326: { + _self: { + x: [ + ...and(〈1;x〉), + ] + } + 〈0;_self〉 + x: [ + 1, + ] + } +} diff --git a/internal/core/compile/testdata/sync/cycle/self.txtar b/internal/core/compile/testdata/sync/cycle/self.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/self.txtar @@ -0,0 +1,846 @@ +-- in.cue -- +@experiment(aliasv2) + +import "list" + +expr: error1: { + a: 3 + a: a + 1 + @test(err, code=eval, path=a, contains="conflicting values %s and %s", args=[4, 3], pos=[1:5, 2:5]) +} +expr: error2: { + a: a + 1 + a: 3 + @test(err, code=eval, path=a, contains="conflicting values %s and %s", args=[4, 3], pos=[1:5, 2:5]) +} +listConcat: error1: { + a: ["1", "2"] + a: list.Concat([a, ["3"]]) + @test(err, code=structural_cycle, path=a, contains="error in call to %s", args=[list.Concat], pos=[2:5]) +} + +listConcat: error2: { + a: list.Concat([["3"], a]) + a: ["1", "2"] + @test(err, code=structural_cycle, path=a, contains="error in call to %s", args=[list.Concat], pos=[1:5]) +} + +selfEmbed: ok1: { + a: x + Y: x + x: {Y} + @test(eq, {a: {}, Y: {}, x: {}}) +} + +selfEmbed: ok2: { + Y: x.b + a: x + x: b: {Y} + @test(eq, {Y: {}, a: {b: {}}, x: {b: {}}}) +} + +selfEmbed: ok3: { + Y: x + a: x + x: {Y} + @test(eq, {Y: {}, a: {}, x: {}}) +} + +selfEmbed: ok4: { + a: x + x: {Y} + Y: x + @test(eq, {a: {}, x: {}, Y: {}}) +} + +selfEmbed: ok5: { + x: {Y} + a: x + Y: x + @test(eq, {x: {}, a: {}, Y: {}}) +} + +selfEmbed: ok6: { + x: b: {Y} + Y: x.b + a: x + @test(eq, {x: {b: {}}, Y: {}, a: {b: {}}}) +} + + +disjSelf: ok1: { + #A: string | #A + x: #A + @test(eq, {#A: string | _, x: string | _}) +} + +disjSelf: ok2: { + x: #A + #A: string | #A + @test(eq, {x: string | _, #A: string | _}) +} + +disjSelf: ok3: { + #A: #A | string + x: #A + @test(eq, {#A: _ | string, x: _ | string}) +} + +disjSelf: ok4: { + x: #A + #A: #A | string + @test(eq, {x: _ | string, #A: _ | string}) +} + +disjEmbed: ok1: { + #A: string | {#A} + x: #A + @test(eq, {#A: string | {}, x: string | {}}) +} + +disjEmbed: ok2: { + x: #A + #A: string | {#A} + @test(eq, {x: string | {}, #A: string | {}}) +} + +disjEmbed: ok3: { + #A: {#A} | string + x: #A + @test(eq, {#A: {} | string, x: {} | string}) +} + +disjEmbed: ok4: { + x: #A + #A: {#A} | string + @test(eq, {x: {} | string, #A: {} | string}) +} + +// x and #A should yield the same result. +disjList: _ +disjList: ok1: { + #A: string | [#A] + x: #A + + y: x + y: [[[[string]]]] + @test(eq, { + #A: string + x: string + y: [[[[string]]]] + }) +} + +disjList: ok2: { + x: #A + #A: string | [#A] + @test(eq, {x: string, #A: string}) +} + +disjList: ok3: { + #A: [#A] | string + x: #A + @test(eq, {#A: string, x: string}) +} + +disjList: ok4: { + x: #A + #A: [#A] | string + @test(eq, {x: string, #A: string}) +} + +-- old.cue -- +name: "foo" +dynamicSelf: ok1: { + X=(name): string | X + x: X + @test(eq, {x: string | _, foo: string | _}) +} + +dynamicSelf: ok2: { + x: X + X=(name): string | X + @test(eq, {x: string | _, foo: string | _}) +} + +dynamicSelf: ok3: { + X=(name): X | string + x: X + @test(eq, {x: _ | string, foo: _ | string}) +} + +dynamicSelf: ok4: { + x: X + X=(name): X | string + @test(eq, {x: _ | string, foo: _ | string}) +} + +dynamicEmbed: ok1: { + X=(name): string | {X} + x: X + @test(eq, {x: string | {}, foo: string | {}}) +} + +dynamicEmbed: ok2: { + x: X + X=(name): string | {X} + @test(eq, {x: string | {}, foo: string | {}}) +} + +dynamicEmbed: ok3: { + X=(name): {X} | string + x: X + @test(eq, {x: {} | string, foo: {} | string}) +} + +dynamicEmbed: ok4: { + x: X + X=(name): {X} | string + @test(eq, {x: {} | string, foo: {} | string}) +} + +dynamicList: _ +dynamicList: ok1: { + X=(name): string | [X] + x: X + + y: x + y: [[[[string]]]] + @test(eq, { + x: string + y: [[[[string]]]] + foo: string + }) +} + +dynamicList: ok2: { + x: X + X=(name): string | [X] + @test(eq, {x: string, foo: string}) +} + +dynamicList: ok3: { + X=(name): [X] | string + x: X + @test(eq, {x: string, foo: string}) +} + +dynamicList: ok4: { + x: X + X=(name): [X] | string + @test(eq, {x: string, foo: string}) +} + +dynamicPatternSelf: ok1: { + X=[string]: string | X + @test(eq, {}) +} +dynamicPatternSelf: ok2: { + X=[string]: X | string + @test(eq, {}) +} +dynamicPatternEmbed: ok1: { + X=[string]: string | {X} + @test(eq, {}) +} +dynamicPatternEmbed: ok2: { + X=[string]: {X} | string + @test(eq, {}) +} +dynamicPatternList: ok1: { + X=[string]: string | [X] + @test(eq, {}) +} +dynamicPatternList: ok2: { + X=[string]: [X] | string + @test(eq, {}) +} + +valueSelf: ok1: { + y: X={string | X} + x: y + @test(eq, {y: string | {}, x: string | {}}) +} + +valueSelf: ok2: { + x: y + y: X={string | X} + @test(eq, {x: string | {}, y: string | {}}) +} + +valueSelf: ok3: { + y: X={X | string} + x: y + @test(eq, {y: {} | string, x: {} | string}) +} + +valueSelf: ok4: { + x: y + y: X={X | string} + @test(eq, {x: {} | string, y: {} | string}) +} + +valueEmbed: ok1: { + y: X={string | {X}} + x: y + @test(eq, {y: string | {}, x: string | {}}) +} + +valueEmbed: ok2: { + x: y + y: X={string | {X}} + @test(eq, {x: string | {}, y: string | {}}) +} + +valueEmbed: ok3: { + y: X={{X} | string} + x: y + @test(eq, {y: {} | string, x: {} | string}) +} + +valueEmbed: ok4: { + x: y + y: X={{X} | string} + @test(eq, {x: {} | string, y: {} | string}) +} + +valueList: ok1: { + y: X={string | [X]} + x: y + @test(eq, {y: string, x: string}) +} + +valueList: ok2: { + x: y + y: X={string | [X]} + @test(eq, {x: string, y: string}) +} + +valueList: ok3: { + y: X={[X] | string} + x: y + @test(eq, {y: string, x: string}) +} + +valueList: ok4: { + x: y + y: X={[X] | string} + @test(eq, {x: string, y: string}) +} + +// Issue #1729 +issue1729: t1: { + #x: { #x | {} } + x: #x & {} + @test(eq, {#x: {}, x: {}}) +} + +issue1729: t2: { + x: #x & {} + #x: { #x | {} } + @test(eq, {x: {}, #x: {}}) +} + +-- selfnew.cue -- +@experiment(aliasv2) + +issue4125: t1_self: { + let Root = self + a: Root.a + @test(eq, {a: _}) +} +-- selfold.cue -- +issue4125: t2_alias: X={ + let Y = X + b: Y.b + @test(eq, {b: _}) +} + +-- out/compile -- +--- in.cue +{ + expr: { + error1: { + a: 3 + a: (〈0;a〉 + 1) + } + } + expr: { + error2: { + a: (〈0;a〉 + 1) + a: 3 + } + } + listConcat: { + error1: { + a: [ + "1", + "2", + ] + a: 〈import;list〉.Concat([ + 〈1;a〉, + [ + "3", + ], + ]) + } + } + listConcat: { + error2: { + a: 〈import;list〉.Concat([ + [ + "3", + ], + 〈1;a〉, + ]) + a: [ + "1", + "2", + ] + } + } + selfEmbed: { + ok1: { + a: 〈0;x〉 + Y: 〈0;x〉 + x: { + 〈1;Y〉 + } + } + } + selfEmbed: { + ok2: { + Y: 〈0;x〉.b + a: 〈0;x〉 + x: { + b: { + 〈2;Y〉 + } + } + } + } + selfEmbed: { + ok3: { + Y: 〈0;x〉 + a: 〈0;x〉 + x: { + 〈1;Y〉 + } + } + } + selfEmbed: { + ok4: { + a: 〈0;x〉 + x: { + 〈1;Y〉 + } + Y: 〈0;x〉 + } + } + selfEmbed: { + ok5: { + x: { + 〈1;Y〉 + } + a: 〈0;x〉 + Y: 〈0;x〉 + } + } + selfEmbed: { + ok6: { + x: { + b: { + 〈2;Y〉 + } + } + Y: 〈0;x〉.b + a: 〈0;x〉 + } + } + disjSelf: { + ok1: { + #A: (string|〈0;#A〉) + x: 〈0;#A〉 + } + } + disjSelf: { + ok2: { + x: 〈0;#A〉 + #A: (string|〈0;#A〉) + } + } + disjSelf: { + ok3: { + #A: (〈0;#A〉|string) + x: 〈0;#A〉 + } + } + disjSelf: { + ok4: { + x: 〈0;#A〉 + #A: (〈0;#A〉|string) + } + } + disjEmbed: { + ok1: { + #A: (string|{ + 〈1;#A〉 + }) + x: 〈0;#A〉 + } + } + disjEmbed: { + ok2: { + x: 〈0;#A〉 + #A: (string|{ + 〈1;#A〉 + }) + } + } + disjEmbed: { + ok3: { + #A: ({ + 〈1;#A〉 + }|string) + x: 〈0;#A〉 + } + } + disjEmbed: { + ok4: { + x: 〈0;#A〉 + #A: ({ + 〈1;#A〉 + }|string) + } + } + disjList: _ + disjList: { + ok1: { + #A: (string|[ + 〈1;#A〉, + ]) + x: 〈0;#A〉 + y: 〈0;x〉 + y: [ + [ + [ + [ + string, + ], + ], + ], + ] + } + } + disjList: { + ok2: { + x: 〈0;#A〉 + #A: (string|[ + 〈1;#A〉, + ]) + } + } + disjList: { + ok3: { + #A: ([ + 〈1;#A〉, + ]|string) + x: 〈0;#A〉 + } + } + disjList: { + ok4: { + x: 〈0;#A〉 + #A: ([ + 〈1;#A〉, + ]|string) + } + } +} +--- old.cue +{ + name: "foo" + dynamicSelf: { + ok1: { + 〈2;name〉: (string|〈0;(〈2;name〉)〉) + x: 〈0;(〈2;name〉)〉 + } + } + dynamicSelf: { + ok2: { + x: 〈0;(〈2;name〉)〉 + 〈2;name〉: (string|〈0;(〈2;name〉)〉) + } + } + dynamicSelf: { + ok3: { + 〈2;name〉: (〈0;(〈2;name〉)〉|string) + x: 〈0;(〈2;name〉)〉 + } + } + dynamicSelf: { + ok4: { + x: 〈0;(〈2;name〉)〉 + 〈2;name〉: (〈0;(〈2;name〉)〉|string) + } + } + dynamicEmbed: { + ok1: { + 〈2;name〉: (string|{ + 〈1;(〈2;name〉)〉 + }) + x: 〈0;(〈2;name〉)〉 + } + } + dynamicEmbed: { + ok2: { + x: 〈0;(〈2;name〉)〉 + 〈2;name〉: (string|{ + 〈1;(〈2;name〉)〉 + }) + } + } + dynamicEmbed: { + ok3: { + 〈2;name〉: ({ + 〈1;(〈2;name〉)〉 + }|string) + x: 〈0;(〈2;name〉)〉 + } + } + dynamicEmbed: { + ok4: { + x: 〈0;(〈2;name〉)〉 + 〈2;name〉: ({ + 〈1;(〈2;name〉)〉 + }|string) + } + } + dynamicList: _ + dynamicList: { + ok1: { + 〈2;name〉: (string|[ + 〈1;(〈2;name〉)〉, + ]) + x: 〈0;(〈2;name〉)〉 + y: 〈0;x〉 + y: [ + [ + [ + [ + string, + ], + ], + ], + ] + } + } + dynamicList: { + ok2: { + x: 〈0;(〈2;name〉)〉 + 〈2;name〉: (string|[ + 〈1;(〈2;name〉)〉, + ]) + } + } + dynamicList: { + ok3: { + 〈2;name〉: ([ + 〈1;(〈2;name〉)〉, + ]|string) + x: 〈0;(〈2;name〉)〉 + } + } + dynamicList: { + ok4: { + x: 〈0;(〈2;name〉)〉 + 〈2;name〉: ([ + 〈1;(〈2;name〉)〉, + ]|string) + } + } + dynamicPatternSelf: { + ok1: { + [string]: (string|〈0;(〈0;-〉)〉) + } + } + dynamicPatternSelf: { + ok2: { + [string]: (〈0;(〈0;-〉)〉|string) + } + } + dynamicPatternEmbed: { + ok1: { + [string]: (string|{ + 〈1;(〈0;-〉)〉 + }) + } + } + dynamicPatternEmbed: { + ok2: { + [string]: ({ + 〈1;(〈0;-〉)〉 + }|string) + } + } + dynamicPatternList: { + ok1: { + [string]: (string|[ + 〈1;(〈0;-〉)〉, + ]) + } + } + dynamicPatternList: { + ok2: { + [string]: ([ + 〈1;(〈0;-〉)〉, + ]|string) + } + } + valueSelf: { + ok1: { + y: { + (string|〈1〉) + } + x: 〈0;y〉 + } + } + valueSelf: { + ok2: { + x: 〈0;y〉 + y: { + (string|〈1〉) + } + } + } + valueSelf: { + ok3: { + y: { + (〈1〉|string) + } + x: 〈0;y〉 + } + } + valueSelf: { + ok4: { + x: 〈0;y〉 + y: { + (〈1〉|string) + } + } + } + valueEmbed: { + ok1: { + y: { + (string|{ + 〈2〉 + }) + } + x: 〈0;y〉 + } + } + valueEmbed: { + ok2: { + x: 〈0;y〉 + y: { + (string|{ + 〈2〉 + }) + } + } + } + valueEmbed: { + ok3: { + y: { + ({ + 〈2〉 + }|string) + } + x: 〈0;y〉 + } + } + valueEmbed: { + ok4: { + x: 〈0;y〉 + y: { + ({ + 〈2〉 + }|string) + } + } + } + valueList: { + ok1: { + y: { + (string|[ + 〈2〉, + ]) + } + x: 〈0;y〉 + } + } + valueList: { + ok2: { + x: 〈0;y〉 + y: { + (string|[ + 〈2〉, + ]) + } + } + } + valueList: { + ok3: { + y: { + ([ + 〈2〉, + ]|string) + } + x: 〈0;y〉 + } + } + valueList: { + ok4: { + x: 〈0;y〉 + y: { + ([ + 〈2〉, + ]|string) + } + } + } + issue1729: { + t1: { + #x: { + (〈1;#x〉|{}) + } + x: (〈0;#x〉 & {}) + } + } + issue1729: { + t2: { + x: (〈0;#x〉 & {}) + #x: { + (〈1;#x〉|{}) + } + } + } +} +--- selfnew.cue +{ + issue4125: { + t1_self: { + let Root#1 = 〈1〉 + a: 〈0;let Root#1〉.a + } + } +} +--- selfold.cue +{ + issue4125: { + t2_alias: { + let Y#2 = 〈1〉 + b: 〈0;let Y#2〉.b + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/structural.txtar b/internal/core/compile/testdata/sync/cycle/structural.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/structural.txtar @@ -0,0 +1,1679 @@ +-- in.cue -- +import "list" + +a1: { + f: [f] + @test(err, code=structural_cycle, path=f.0, contains="structural cycle", pos=[]) +} + +a2: { + f: f + @test(eq, {f: _}) +} + +a3: { + f: {g: f} + @test(err, code=structural_cycle, path=f.g, contains="structural cycle", pos=[]) +} + +a4: { + a: [a | int] + @test(eq, {a: [int]}) +} + +a5: { + a: b: a | int + @test(eq, {a: {b: int}}) +} + +a6: { + a: a | int + @test(eq, {a: _ | int}) +} + +a7: { + a: c.x + b: { + x: c + y: "foo" + } + c: { + x: b.y + y: 3 + } + @test(eq, { + a: "foo" + b: {x: {x: "foo", y: 3}, y: "foo"} + c: {x: "foo", y: 3} + }) +} + +b1: { + b: a & [1] + a: [a | int] + @test(eq, {b: [1], a: [int]}) +} + +b2: { + a: [a | int] + b: a & [1] + @test(eq, {a: [int], b: [1]}) +} + +b3: { + x: a: [a | int] + b: x & {a: [1]} + @test(eq, {x: {a: [int]}, b: {a: [1]}}) +} + +b4: { + b: x.y & [1] + x: y: [y] + @test(err, code=eval, path=b.0, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[1, [y], int, list], pos=[1:5, 1:12, 2:8, 2:9]) +} + +// Ensure that the cycle error is not blindly copied to a referring field, +// as the cycle may not persist. +b4: cond1: { + b: x.y & { _z: false, [1] } + x: y: { + _z: *true | bool + if _z { + [y] + } + } + @test(err, code=structural_cycle, path=x.y.0, contains="structural cycle", pos=[]) +} + +// This reports a structural cycle at b4.cond2.b, because the value it refers +// has a structural cycle. Technically, this is incorrect, as the cycle +// really only occurs in b4.cond2.x.y. But since structural cycles are +// permanent, the entire configuration is invalidated, so the spurious +// additional cycle is merely cosmetic. By most logical standards, one can prove +// any fact from a contradiction. So assuming that, this is not incorrect. +// TODO: fix this cosmetic blemish. +b4: cond2: { + x: y: { + _z: *true | bool + if _z { + [y] + } + } + b: x.y & { _z: false, [1] } + @test(err, code=structural_cycle, path=x.y.0, contains="structural cycle", pos=[]) +} + +b5: { + b: x.y & {a: [1]} + x: y: a: [a | int] + @test(eq, {b: {a: [1]}, x: {y: {a: [int]}}}) +} + +b6: { + b: x & {a: [1]} + x: a: [a] + @test(err, code=eval, path=b.a.0, contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[1, [1], int, list], pos=[1:5, 1:13, 1:14, 2:9]) +} + +b7: { + b: a & [[1]] + a: [a] + @test(err, code=eval, path=b.0.0, contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[1, [a], int, list], pos=[1:5, 1:11, 2:5, 2:6]) +} + +// Issue #555 +b8: { + x: a + a: f: b + b: a | string + @test(eq, { + x: {f: string} + a: {f: string} + b: string + }) +} + +// Issue #555 +b9: { + #a: string | #b | #ref + #b: { + c: [#a, #a, #a] + } + #ref: ref: string + x: #b | #ref + @test(eq, { + #a: string | {ref: string} + #b: { + c: [string | {ref: string}, + string | {ref: string}, + string | {ref: string}] + } + #ref: {ref: string} + x: {c: [string | {ref: string}, + string | {ref: string}, + string | {ref: string}]} | {ref: string} + }) +} + +// Issue #534 +// TODO: the resolution here is arguably incorrect: c should be +// d: string | { b: string } +// However, this is not the end of the world, as the disjunction is preserved +// under the hood and still unifies with extended structure. +b10: { + a: close({ + b: string | a | c + }) + c: close({ + d: string | a + }) + + d: d: b: string + @test(eq, { + a: {b: string | {d: string}} + c: { + d: string | {b: string | {b: string | {b: string}}} + } + d: {d: {b: string}} + }) +} + +// Issue #509 -- with comprehension +b11: { + #list: { + tail: #list | *null + if tail != null { + } + } + @test(eq, {#list: {tail: null}}) +} + +// Issue #509 -- with comprehension +b12: { + #list: { + V=value: int + T=tail: #list | *null + if T != null { + sum: V + T.sum + } + if T == null { + sum: V + } + } + + list1: #list + list1: { + value: 1 + tail: { + value: 2 + tail: { + value: 3 + tail: { + value: 4 + } + } + } + } + @test(eq, { + #list: {value: int, tail: null, sum: int} + list1: { + value: 1 + tail: { + value: 2 + tail: { + value: 3 + tail: { + value: 4 + tail: *null | {value: int, tail: null, sum: int} + sum: 4 + } + sum: 7 + } + sum: 9 + } + sum: 10 + } + }) +} + +// More trigger happy on stack overflows. +b12b: { + #list: { + tail: #list + + if tail != null { + sum: tail.sum + } + } @test(err, code=structural_cycle, path=tail, contains="structural cycle", pos=[]) + + list1: #list @test(err, code=structural_cycle, path=b12b.#list.tail, contains="structural cycle", pos=[]) + list1: { + tail: { + tail: { + } + } + } +} + +// Issue #587 +b13: { + root: a: [for x in root {x}] + @test(err, code=structural_cycle, path=root.a.0.0, contains="structural cycle", pos=[]) +} + +// Issue #587 +// TODO: this should probably be okay if we allow shallow evaluation of +// comprehension sources. See #1881. +b14: { + root: { + a: [...int] + + for x in a { + "\(x)": {} + } + + b: [for x in root {x}] + } + @test(err, code=structural_cycle, path=root.b.1.1, contains="structural cycle", pos=[]) +} + +// This is okay +// Issue #587 +b15: { + root: a: {for x in root {x}} + @test(eq, {root: {a: {}}}) +} + +// Issue #502 -- unused bulk constraints are not cyclic +p1: { + #T: { + a: [string]: link: #T + } + + a: #T & { + a: one: link: a: two: {} + } + @test(eq, { + #T: {a: {}} + a: { + a: { + one: {link: {a: {two: {link: {a: {}}}}}} + } + } + }) +} + +// Issue #502 -- but they are if it is invoked within the struct. +p2: { + #T: { + a: [string]: link: #T + a: b: {} + } + + a: #T & { + a: one: link: a: two: {} + } + @test(eq, {one: {link: {a: {two: {}}}}}, at=a.a) + @test(err, code=structural_cycle, path=#T.a.b.link, contains="structural cycle", pos=[]) +} + +// Issue #502 -- or added later. +p3: { + #S: #T: { + a: [string]: link: #T + } + + #U: { + #S + #T: a: b: {} + } @test(err, code=structural_cycle, path=#T.a.b.link, contains="structural cycle", pos=[]) + + a: #U.#T & { + a: one: link: a: two: {} + } @test(err, code=structural_cycle, path=p3.#U.#T.a.b.link, contains="structural cycle", pos=[]) +} + +// Issue #502 -- unused bulk constraints are not cyclic +p4: { + #T: { + a: [...{link: #T}] + } + + a: #T & { + a: [{link: a: [{}]}] + } + @test(eq, { + #T: {a: []} + a: {a: [{link: {a: [{link: {a: []}}]}}]} + }) +} + +// Issue #502 -- but they are if it is invoked within the struct. +p5: { + #T: { + a: [...{link: #T}] + a: [{}] + } + + a: #T & { + a: [{link: a: [{}]}] + } + @test(err, code=structural_cycle, path=#T.a.0.link, contains="structural cycle", pos=[]) + @test(eq, [{link: {a: [{}]}}], at=a.a) +} + +// Issue #502 -- or added later. +p6: { + #S: #T: { + a: [...{link: #T}] + } + + #U: { + #S + #T: a: [{}] + } @test(err, code=structural_cycle, path=#T.a.0.link, contains="structural cycle", pos=[]) + + a: #U.#T & { + a: [{link: a: [{}]}] + } @test(err, code=structural_cycle, path=p6.#U.#T.a.0.link, contains="structural cycle", pos=[]) +} + +c1: { + a: { + b: {} + c: a & b + } + @test(err, code=structural_cycle, path=a.c.c, contains="structural cycle", pos=[]) +} + +// indirection +d1: { + a: b: c: d: {h: int, t: r} + @test(err, at=a.b.c.d.t, code=structural_cycle, path=d1.r, contains="structural cycle", pos=[]) + + r: a.b @test(err, code=structural_cycle, contains="structural cycle", pos=[]) + + x: a.b.c + +} + +d2: { + x: a.b.c @test(shareID=X) + @test(shareID=X, at=a.b.c) + + r: a.b @test(shareID=R) + @test(shareID=R, at=a.b) + + a: b: c: d: {h: int, t: r} +} + +d3: { + config: { + a: b: c: indirect + indirect: [a.b, null][i] + i: int | *1 + } + x: config & {i: 0} + @test(err, at=x.indirect, code=structural_cycle, contains="structural cycle", pos=[]) + @test(err, at=x.a.b.c, code=structural_cycle, contains="structural cycle", pos=[]) + @test(eq, at=config, { + a: {b: {c: null}} + indirect: null + i: *1 | int + }) +} + +// Ensure that the cycles here fail early. +// TODO: they can still be shorter. +shortPathFail: _ + +shortPathFail: doubleRef: { + // Avoid this: the first #List reference is different from the second, so + // the second #List reference counts as a first occurrence, causing the + // result to be longer than perhaps expected. + a: #List + #List: Next: #List | *null + @test(eq, {a: {Next: null}, #List: {Next: null}}) +} + +shortPathFail: elipsis: { + // Avoid this: the elipsis causes `_` to be mixed in with the #Foo + // reference, causing the first cycle to be discounted. + t1: { + #Foo: ref: null | #Foo + #Foo: { ... } + @test(eq, {#Foo: {ref: null}}) + } + t2: { + Foo: ref: Foo + Foo: {...} + @test(err, code=structural_cycle, at=Foo.ref, contains="structural cycle", pos=[]) + } +} + +// Issue #2374: a pattern constraint with an alias referring back to itself +// (e.g., `r=[string]: {b: r}`) should be detected as a structural cycle, +// but the evaluator instead emitted output with a renamed alias. +// https://cuelang.org/issue/2374 +patternFail: issue2374: { + r=[string]: {b: r} + a: {r: 0} + @test(err, code=structural_cycle, at=a.b, contains="structural cycle", pos=[]) +} + +shortPathFail: comprehension: { + #list: { + tail: #list | *null + if tail != null { + } + } + @test(eq, {#list: {tail: null}}) +} + +withLetFail: { + schema: next: _schema_1 + let _schema_1 = schema + @test(err, code=structural_cycle, at=schema.next, contains="structural cycle", pos=[]) +} + +// Issue #3310: `list.Sum` called with a comprehension iterating over the +// enclosing struct causes a structural cycle because `total` is included in +// its own computation. The cycle error is correct; evalv2 incorrectly produced +// a wrong numeric result instead of erroring. +// https://cuelang.org/issue/3310 +fieldsSumInfinite: issue3310: { + cheeseburger: 3.00 + fries: 2.00 + sprite: 1.00 + + total: list.Sum([for _, v in issue3310 {v}]) + @test(err, code=structural_cycle, at=total, contains="error in call to %s", args=[list.Sum], pos=[5:9]) +} + +listOptOK: { + list: { + head: int + tail?: list + } + a: list & {head: 3, tail: head: 2} + @test(eq, { + list: { + head: int + tail?: _|_ @test(err, code=structural_cycle, contains="list.tail: structural cycle", pos=[]) + } + a: { + head: 3 + tail: { + head: 2 + tail?: { + head: int + tail?: _|_ @test(err, code=structural_cycle, contains="list.tail: structural cycle", pos=[]) + } + } + } + }) +} + +// The cyclic definitions below used to work OK on old versions of evalv2, +// and broke around the release of CUE v0.6.0. evalv3 fixes this again. +// It should succeed, given that the optional field breaks the cycle. +issue2545: { + #A: { + B?: #B + } + #B: { + A: #A + } + @test(err, code=structural_cycle, + hint="the comment says this should succeed since the optional field breaks the cycle, but it still errors in both v2 and v3") + @test(eq:todo, { + #A: {B?: _ @test(ignore)} + #B: {A: {B?: _|_}} + }) +} + +// combining structural with reference cycles +e1: { + a: a + a: c: a + + b: c: b + b: b + @test(err, code=structural_cycle, at=a.c, contains="structural cycle", pos=[]) + @test(err, code=structural_cycle, at=b.c, contains="structural cycle", pos=[]) +} + +e2: { + a: {a} + a: c: a + + b: c: b + b: {b} + @test(err, code=structural_cycle, at=a.c, contains="structural cycle", pos=[]) + @test(err, code=structural_cycle, at=b.c, contains="structural cycle", pos=[]) +} + +e3: { + a: [a] @test(err, code=eval, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[[a], {c:a}, list, struct], pos=[0:5, 1:5]) + a: c: a @test(err, code=structural_cycle, contains="structural cycle", pos=[]) + + b: [b] @test(err, code=eval, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[[b], {c:b}, list, struct], pos=[0:5, 1:5]) + b: c: b +} + +e4: { + a: [a | {}] + a: [[{c: 1}]] + + b: [[{c: 1}]] + b: [b | {}] + @test(err, code=eval, + suberr=(code=eval, path=a.0, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[[{c:1}], {}, list, struct], pos=[1:10, 2:6]), + suberr=(code=eval, path=a.0.0, contains="conflicting values %s and %s (mismatched types %s and %s)", args=[{c:1}, [{c:1}], struct, list], pos=[1:6, 2:6, 2:7])) +} + +e5: { + a: c: a | int + a: a | int + + b: b | int + b: c: b | int + @test(eq, {a: {c: int}, b: {c: int}}) +} + +// validating values +nestedList: { + v1e: { + x: [x | int, 1] + y: x & [[[2], 1], 1] + @test(err, code=eval, + suberr=(code=eval, path=y.0, contains="conflicting values %s and %s (mismatched types %s and %s)", pos=[1:11, 2:6, 2:11]), + suberr=(code=eval, path=y.0.0, contains="%d errors in empty disjunction:", args=[2], pos=[]), + suberr=(code=eval, path=y.0.0, contains="conflicting values %s and %s (mismatched types %s and %s)", pos=[1:7, 1:11, 2:6, 2:12]), + suberr=(code=eval, path=y.0.0, contains="incompatible list lengths (%d and %d)", args=[1, 2], pos=[1:6])) + } + + v2e: { + y: x & [[[2], 1], 1] + x: [x | int, 1] + @test(err, code=eval, + suberr=(code=eval, path=y.0, contains="conflicting values %s and %s (mismatched types %s and %s)", pos=[1:6, 1:11, 2:11]), + suberr=(code=eval, path=y.0.0, contains="%d errors in empty disjunction:", args=[2], pos=[]), + suberr=(code=eval, path=y.0.0, contains="conflicting values %s and %s (mismatched types %s and %s)", pos=[1:6, 1:12, 2:7, 2:11]), + suberr=(code=eval, path=y.0.0, contains="incompatible list lengths (%d and %d)", args=[1, 2], pos=[2:6])) + } + + v1: { + x: [x | int, 1] + y: x & [[[2, 1], 1], 1] + @test(eq, {x: [int, 1], y: [[[2, 1], 1], 1]}) + } + + v2: { + y: x & [[[2, 1], 1], 1] + x: [x | int, 1] + @test(eq, {y: [[[2, 1], 1], 1], x: [int, 1]}) + } +} + +v3: { + list: { + head: int + tail: list | null + } + + myList: list + myList: { + head: 2 + tail: { + head: 3 + tail: { + head: 4 + } + } + } + @test(eq, { + list: {head: int, tail: null} + myList: { + head: 2 + tail: { + head: 3 + tail: { + head: 4 + tail: {head: int, tail: null} | null + } + } + } + }) +} + +v4: { + list: { + head: int + tail: list | 1 + } + + myList: list + myList: { + head: 2 + tail: head: 3 + } + @test(eq, { + list: {head: int, tail: 1} + myList: { + head: 2 + tail: { + head: 3 + tail: {head: int, tail: 1} | 1 + } + } + }) +} + +v5: { + list: { + head: int + tail: list | {} + } + + myList: list + myList: { + head: 2 + tail: head: 3 + } + @test(eq, { + list: {head: int, tail: {}} + myList: { + head: 2 + tail: {head: 3, tail: {head: int, tail: {}} | {}} | {head: 3} + } + }) +} + +// Example from "The Logic of Type Feature Structures" (Bob Carpenter)/ +z1: { + y: { + f: h: g + g: _ + } + x: { + f: _ + g: f + } + z: x & y + @test(err, code=structural_cycle, path=z.g, contains="structural cycle", pos=[]) +} + +// Cross references. Here there is no cycle, but the repeated instantiations +// of T will cause, in turn, cause repeated resolution of `x`. The algorithm +// should not identify these as cyclic references. Instead, it should be +// noted that the reference is each time referring to new content. +// Issue #754 +crossRefNoCycle: t1: { + T: { + x: _ + y: x + } + C: { x: T } & T + @test(eq, { + T: {x: _, y: _} + C: {x: {x: _, y: _}, y: {x: _, y: _}} + }) +} + +crossRefNoCycle: t2: { + T: { + x: _ + y: x + } + C: T & { x: T } + @test(eq, { + T: {x: _, y: _} + C: {x: {x: _, y: _}, y: {x: _, y: _}} + }) +} + +crossRefNoCycle: t3: { + T: { + x: _ + y: x + z: y + } + C: T & { x: T } + @test(eq, { + T: {x: _, y: _, z: _} + C: { + x: {x: _, y: _, z: _} + y: {x: _, y: _, z: _} + z: {x: _, y: _, z: _} + } + }) +} + +crossRefNoCycle: t4: { + T: { + x: _ + y: x + z: y + } + C: T & { x: T & { x: T } } + @test(eq, { + T: {x: _, y: _, z: _} + C: { + x: { + x: {x: _, y: _, z: _} + y: {x: _, y: _, z: _} + z: {x: _, y: _, z: _} + } + y: { + x: {x: _, y: _, z: _} + y: {x: _, y: _, z: _} + z: {x: _, y: _, z: _} + } + z: { + x: {x: _, y: _, z: _} + y: {x: _, y: _, z: _} + z: {x: _, y: _, z: _} + } + } + }) +} + +crossRefNoCycle: t5: { + T: X={ + y: X.x + } + C: T & { x: T } + @test(eq, { + T: { + y: _|_ @test(err, code=incomplete, contains="crossRefNoCycle.t5.T.y: undefined field: x", pos=[785:8]) + } + C: { + x: { + y: _|_ @test(err, code=incomplete, contains="crossRefNoCycle.t5.T.y: undefined field: x", pos=[785:8]) + } + y: { + y: _|_ @test(err, code=incomplete, contains="crossRefNoCycle.t5.T.y: undefined field: x", pos=[785:8]) + } + } + }) +} + +// Ensure these are NOT treated as structural errors. + +n1: { + a: b: int + @test(eq, {a: {b: int}}) +} +n2: { + n1 + a: n1 + @test(eq, {a: {b: int, a: {b: int}}}) +} +n3: { + n1 + @test(eq, {a: {b: int}}) +} +n4: { + n1 + x: { + n1 + y: { + n1 + z: int + } + } + @test(eq, { + x: {y: {z: int, a: {b: int}}, a: {b: int}} + a: {b: int} + }) +} +-- edge.cue -- +// TODO(eval): notice the difference, not a huge deal, but still. +resolveToAncestor: { + t1: X: { + a: b.a @test(eq, _) @test(err:todo, code=structural_cycle) + b: X @test(err, code=structural_cycle, contains="structural cycle", pos=[]) + } + t2: X: { + b: X @test(err, code=structural_cycle, contains="structural cycle", pos=[]) + a: b.a @test(err, code=structural_cycle, path=resolveToAncestor.t2.X.b, contains="structural cycle", pos=[]) + } +} +-- out/compile -- +--- edge.cue +{ + resolveToAncestor: { + t1: { + X: { + a: 〈0;b〉.a + b: 〈1;X〉 + } + } + t2: { + X: { + b: 〈1;X〉 + a: 〈0;b〉.a + } + } + } +} +--- in.cue +{ + a1: { + f: [ + 〈1;f〉, + ] + } + a2: { + f: 〈0;f〉 + } + a3: { + f: { + g: 〈1;f〉 + } + } + a4: { + a: [ + (〈1;a〉|int), + ] + } + a5: { + a: { + b: (〈1;a〉|int) + } + } + a6: { + a: (〈0;a〉|int) + } + a7: { + a: 〈0;c〉.x + b: { + x: 〈1;c〉 + y: "foo" + } + c: { + x: 〈1;b〉.y + y: 3 + } + } + b1: { + b: (〈0;a〉 & [ + 1, + ]) + a: [ + (〈1;a〉|int), + ] + } + b2: { + a: [ + (〈1;a〉|int), + ] + b: (〈0;a〉 & [ + 1, + ]) + } + b3: { + x: { + a: [ + (〈1;a〉|int), + ] + } + b: (〈0;x〉 & { + a: [ + 1, + ] + }) + } + b4: { + b: (〈0;x〉.y & [ + 1, + ]) + x: { + y: [ + 〈1;y〉, + ] + } + } + b4: { + cond1: { + b: (〈0;x〉.y & { + _z: false + [ + 1, + ] + }) + x: { + y: { + _z: (*true|bool) + if 〈0;_z〉 { + [ + 〈3;y〉, + ] + } + } + } + } + } + b4: { + cond2: { + x: { + y: { + _z: (*true|bool) + if 〈0;_z〉 { + [ + 〈3;y〉, + ] + } + } + } + b: (〈0;x〉.y & { + _z: false + [ + 1, + ] + }) + } + } + b5: { + b: (〈0;x〉.y & { + a: [ + 1, + ] + }) + x: { + y: { + a: [ + (〈1;a〉|int), + ] + } + } + } + b6: { + b: (〈0;x〉 & { + a: [ + 1, + ] + }) + x: { + a: [ + 〈1;a〉, + ] + } + } + b7: { + b: (〈0;a〉 & [ + [ + 1, + ], + ]) + a: [ + 〈1;a〉, + ] + } + b8: { + x: 〈0;a〉 + a: { + f: 〈1;b〉 + } + b: (〈0;a〉|string) + } + b9: { + #a: (string|〈0;#b〉|〈0;#ref〉) + #b: { + c: [ + 〈2;#a〉, + 〈2;#a〉, + 〈2;#a〉, + ] + } + #ref: { + ref: string + } + x: (〈0;#b〉|〈0;#ref〉) + } + b10: { + a: close({ + b: (string|〈1;a〉|〈1;c〉) + }) + c: close({ + d: (string|〈1;a〉) + }) + d: { + d: { + b: string + } + } + } + b11: { + #list: { + tail: (〈1;#list〉|*null) + if (〈0;tail〉 != null) {} + } + } + b12: { + #list: { + value: int + tail: (〈1;#list〉|*null) + if (〈0;tail〉 != null) { + sum: (〈1;value〉 + 〈1;tail〉.sum) + } + if (〈0;tail〉 == null) { + sum: 〈1;value〉 + } + } + list1: 〈0;#list〉 + list1: { + value: 1 + tail: { + value: 2 + tail: { + value: 3 + tail: { + value: 4 + } + } + } + } + } + b12b: { + #list: { + tail: 〈1;#list〉 + if (〈0;tail〉 != null) { + sum: 〈1;tail〉.sum + } + } + list1: 〈0;#list〉 + list1: { + tail: { + tail: {} + } + } + } + b13: { + root: { + a: [ + for _, x in 〈2;root〉 { + 〈1;x〉 + }, + ] + } + } + b14: { + root: { + a: [ + ...int, + ] + for _, x in 〈0;a〉 { + "\(〈1;x〉)": {} + } + b: [ + for _, x in 〈2;root〉 { + 〈1;x〉 + }, + ] + } + } + b15: { + root: { + a: { + for _, x in 〈2;root〉 { + 〈1;x〉 + } + } + } + } + p1: { + #T: { + a: { + [string]: { + link: 〈3;#T〉 + } + } + } + a: (〈0;#T〉 & { + a: { + one: { + link: { + a: { + two: {} + } + } + } + } + }) + } + p2: { + #T: { + a: { + [string]: { + link: 〈3;#T〉 + } + } + a: { + b: {} + } + } + a: (〈0;#T〉 & { + a: { + one: { + link: { + a: { + two: {} + } + } + } + } + }) + } + p3: { + #S: { + #T: { + a: { + [string]: { + link: 〈3;#T〉 + } + } + } + } + #U: { + 〈1;#S〉 + #T: { + a: { + b: {} + } + } + } + a: (〈0;#U〉.#T & { + a: { + one: { + link: { + a: { + two: {} + } + } + } + } + }) + } + p4: { + #T: { + a: [ + ...{ + link: 〈3;#T〉 + }, + ] + } + a: (〈0;#T〉 & { + a: [ + { + link: { + a: [ + {}, + ] + } + }, + ] + }) + } + p5: { + #T: { + a: [ + ...{ + link: 〈3;#T〉 + }, + ] + a: [ + {}, + ] + } + a: (〈0;#T〉 & { + a: [ + { + link: { + a: [ + {}, + ] + } + }, + ] + }) + } + p6: { + #S: { + #T: { + a: [ + ...{ + link: 〈3;#T〉 + }, + ] + } + } + #U: { + 〈1;#S〉 + #T: { + a: [ + {}, + ] + } + } + a: (〈0;#U〉.#T & { + a: [ + { + link: { + a: [ + {}, + ] + } + }, + ] + }) + } + c1: { + a: { + b: {} + c: (〈1;a〉 & 〈0;b〉) + } + } + d1: { + a: { + b: { + c: { + d: { + h: int + t: 〈4;r〉 + } + } + } + } + r: 〈0;a〉.b + x: 〈0;a〉.b.c + } + d2: { + x: 〈0;a〉.b.c + r: 〈0;a〉.b + a: { + b: { + c: { + d: { + h: int + t: 〈4;r〉 + } + } + } + } + } + d3: { + config: { + a: { + b: { + c: 〈2;indirect〉 + } + } + indirect: [ + 〈1;a〉.b, + null, + ][〈0;i〉] + i: (int|*1) + } + x: (〈0;config〉 & { + i: 0 + }) + } + shortPathFail: _ + shortPathFail: { + doubleRef: { + a: 〈0;#List〉 + #List: { + Next: (〈1;#List〉|*null) + } + } + } + shortPathFail: { + elipsis: { + t1: { + #Foo: { + ref: (null|〈1;#Foo〉) + } + #Foo: { + ... + } + } + t2: { + Foo: { + ref: 〈1;Foo〉 + } + Foo: { + ... + } + } + } + } + patternFail: { + issue2374: { + [string]: { + b: 〈1;(〈0;-〉)〉 + } + a: { + r: 0 + } + } + } + shortPathFail: { + comprehension: { + #list: { + tail: (〈1;#list〉|*null) + if (〈0;tail〉 != null) {} + } + } + } + withLetFail: { + schema: { + next: 〈1;let _schema_1#1〉 + } + let _schema_1#1 = 〈0;schema〉 + } + fieldsSumInfinite: { + issue3310: { + cheeseburger: 3.00 + fries: 2.00 + sprite: 1.00 + total: 〈import;list〉.Sum([ + for _, v in 〈2;issue3310〉 { + 〈1;v〉 + }, + ]) + } + } + listOptOK: { + list: { + head: int + tail?: 〈1;list〉 + } + a: (〈0;list〉 & { + head: 3 + tail: { + head: 2 + } + }) + } + issue2545: { + #A: { + B?: 〈1;#B〉 + } + #B: { + A: 〈1;#A〉 + } + } + e1: { + a: 〈0;a〉 + a: { + c: 〈1;a〉 + } + b: { + c: 〈1;b〉 + } + b: 〈0;b〉 + } + e2: { + a: { + 〈1;a〉 + } + a: { + c: 〈1;a〉 + } + b: { + c: 〈1;b〉 + } + b: { + 〈1;b〉 + } + } + e3: { + a: [ + 〈1;a〉, + ] + a: { + c: 〈1;a〉 + } + b: [ + 〈1;b〉, + ] + b: { + c: 〈1;b〉 + } + } + e4: { + a: [ + (〈1;a〉|{}), + ] + a: [ + [ + { + c: 1 + }, + ], + ] + b: [ + [ + { + c: 1 + }, + ], + ] + b: [ + (〈1;b〉|{}), + ] + } + e5: { + a: { + c: (〈1;a〉|int) + } + a: (〈0;a〉|int) + b: (〈0;b〉|int) + b: { + c: (〈1;b〉|int) + } + } + nestedList: { + v1e: { + x: [ + (〈1;x〉|int), + 1, + ] + y: (〈0;x〉 & [ + [ + [ + 2, + ], + 1, + ], + 1, + ]) + } + v2e: { + y: (〈0;x〉 & [ + [ + [ + 2, + ], + 1, + ], + 1, + ]) + x: [ + (〈1;x〉|int), + 1, + ] + } + v1: { + x: [ + (〈1;x〉|int), + 1, + ] + y: (〈0;x〉 & [ + [ + [ + 2, + 1, + ], + 1, + ], + 1, + ]) + } + v2: { + y: (〈0;x〉 & [ + [ + [ + 2, + 1, + ], + 1, + ], + 1, + ]) + x: [ + (〈1;x〉|int), + 1, + ] + } + } + v3: { + list: { + head: int + tail: (〈1;list〉|null) + } + myList: 〈0;list〉 + myList: { + head: 2 + tail: { + head: 3 + tail: { + head: 4 + } + } + } + } + v4: { + list: { + head: int + tail: (〈1;list〉|1) + } + myList: 〈0;list〉 + myList: { + head: 2 + tail: { + head: 3 + } + } + } + v5: { + list: { + head: int + tail: (〈1;list〉|{}) + } + myList: 〈0;list〉 + myList: { + head: 2 + tail: { + head: 3 + } + } + } + z1: { + y: { + f: { + h: 〈1;g〉 + } + g: _ + } + x: { + f: _ + g: 〈0;f〉 + } + z: (〈0;x〉 & 〈0;y〉) + } + crossRefNoCycle: { + t1: { + T: { + x: _ + y: 〈0;x〉 + } + C: ({ + x: 〈1;T〉 + } & 〈0;T〉) + } + } + crossRefNoCycle: { + t2: { + T: { + x: _ + y: 〈0;x〉 + } + C: (〈0;T〉 & { + x: 〈1;T〉 + }) + } + } + crossRefNoCycle: { + t3: { + T: { + x: _ + y: 〈0;x〉 + z: 〈0;y〉 + } + C: (〈0;T〉 & { + x: 〈1;T〉 + }) + } + } + crossRefNoCycle: { + t4: { + T: { + x: _ + y: 〈0;x〉 + z: 〈0;y〉 + } + C: (〈0;T〉 & { + x: (〈1;T〉 & { + x: 〈2;T〉 + }) + }) + } + } + crossRefNoCycle: { + t5: { + T: { + y: 〈1〉.x + } + C: (〈0;T〉 & { + x: 〈1;T〉 + }) + } + } + n1: { + a: { + b: int + } + } + n2: { + 〈1;n1〉 + a: 〈1;n1〉 + } + n3: { + 〈1;n1〉 + } + n4: { + 〈1;n1〉 + x: { + 〈2;n1〉 + y: { + 〈3;n1〉 + z: int + } + } + } +} diff --git a/internal/core/compile/testdata/sync/cycle/with_defaults.txtar b/internal/core/compile/testdata/sync/cycle/with_defaults.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/cycle/with_defaults.txtar @@ -0,0 +1,36 @@ +# Tests cycle patterns involving default values and range constraints. +-- in.cue -- +range1: { + min: *1 | int + range: >min + range: 8 + @test(eq, {min: *1 | int, range: 8}) +} +range2: { + min: *1 | int + max: int & >min + @test(eq, {min: *1 | int, max: >1 & int}) +} +rg: range2 +rg: { + // min: 1 + max: 8 + @test(eq, {max: 8, min: *1 | int}) +} +-- out/compile -- +--- in.cue +{ + range1: { + min: (*1|int) + range: >〈0;min〉 + range: 8 + } + range2: { + min: (*1|int) + max: (int & >〈0;min〉) + } + rg: 〈0;range2〉 + rg: { + max: 8 + } +} diff --git a/internal/core/compile/testdata/sync/definitions/026_combined_definitions.txtar b/internal/core/compile/testdata/sync/definitions/026_combined_definitions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/026_combined_definitions.txtar @@ -0,0 +1,76 @@ +#name: combined definitions +#evalPartial +-- in.cue -- +// Allow combining of structs within a definition +#D1: { + env: a: "A" + env: b: "B" + #def: {a: "A"} + #def: {b: "B"} +} +d1: #D1 & {env: c: "C" } @test(err, at=env.c, code=eval, contains="field not allowed", pos=[0:17]) +#D2: { + a: int +} +#D2: { + b: int +} @test(eq, {a: int, b: int}) +#D3: { + env: a: "A" +} +#D3: { + env: b: "B" +} @test(eq, { env: { a: "A", b: "B" } }) +#D4: { + env: #DC + env: b: int @test(err, code=eval, contains="field not allowed", pos=[0:7]) +} +#DC: {a: int} +-- out/compile -- +--- in.cue +{ + #D1: { + env: { + a: "A" + } + env: { + b: "B" + } + #def: { + a: "A" + } + #def: { + b: "B" + } + } + d1: (〈0;#D1〉 & { + env: { + c: "C" + } + }) + #D2: { + a: int + } + #D2: { + b: int + } + #D3: { + env: { + a: "A" + } + } + #D3: { + env: { + b: "B" + } + } + #D4: { + env: 〈1;#DC〉 + env: { + b: int + } + } + #DC: { + a: int + } +} diff --git a/internal/core/compile/testdata/sync/definitions/028_recursive_closing_starting_at_non-definition.txtar b/internal/core/compile/testdata/sync/definitions/028_recursive_closing_starting_at_non-definition.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/028_recursive_closing_starting_at_non-definition.txtar @@ -0,0 +1,36 @@ + +#name: recursive closing starting at non-definition +#evalPartial +-- in.cue -- +z: a: { + #B: { + c: d: 1 + c: f: 1 + } +} +A: z & {a: {#B: {c: e: 2}}} @test(eq, {a: #B: c: {e: 2, d: 1, f: 1}}) +-- out/compile -- +--- in.cue +{ + z: { + a: { + #B: { + c: { + d: 1 + } + c: { + f: 1 + } + } + } + } + A: (〈0;z〉 & { + a: { + #B: { + c: { + e: 2 + } + } + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/032_definitions_with_embedding.txtar b/internal/core/compile/testdata/sync/definitions/032_definitions_with_embedding.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/032_definitions_with_embedding.txtar @@ -0,0 +1,46 @@ +-- in.cue -- +#E: { + a: {b: int} +} + +#S: { + #E + a: {c: int} + b: 3 +} @test(eq, { + a: {b: int, c: int} + b: 3 +}) + +// adding a field to a nested struct that is closed. +#e1: #S & {a: d: 4} @test(err, at=a.d, code=eval, + contains="field not allowed", pos=[0:15]) + +// literal struct not closed until after unification. +#v1: #S & {a: c: 4} @test(eq, {a: {b: int, c: 4}, b: 3}) +-- out/compile -- +--- in.cue +{ + #E: { + a: { + b: int + } + } + #S: { + 〈1;#E〉 + a: { + c: int + } + b: 3 + } + #e1: (〈0;#S〉 & { + a: { + d: 4 + } + }) + #v1: (〈0;#S〉 & { + a: { + c: 4 + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/033_Issue_#153.txtar b/internal/core/compile/testdata/sync/definitions/033_Issue_#153.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/033_Issue_#153.txtar @@ -0,0 +1,57 @@ +# Tests that a comprehension-generated struct merged into a list element +# constrained by a closed definition correctly rejects fields not declared +# in the definition. Fields introduced via comprehension inside a list +# literal should still be subject to closedness checks. +# Issue: https://cuelang.org/issue/153 +-- in.cue -- +Foo: { + listOfCloseds: [...#Closed] +} + +#Closed: { + a: int | *0 +} + +Junk: { + b: 2 @test(eq, 2) +} + +Foo & { + listOfCloseds: [{ + for k, v in Junk { + "\(k)": v + } + }] +} +@test(eq, { + Foo: listOfCloseds: [] + #Closed: a: int | *0 + Junk: b: 2 + listOfCloseds: _|_ @test(err, at=0.b, code=eval, + hint="considerably more positions could be useful", + contains="field not allowed", pos=[16:4]) +}) +-- out/compile -- +--- in.cue +{ + Foo: { + listOfCloseds: [ + ...〈2;#Closed〉, + ] + } + #Closed: { + a: (int|*0) + } + Junk: { + b: 2 + } + (〈0;Foo〉 & { + listOfCloseds: [ + { + for k, v in 〈3;Junk〉 { + "\(〈1;k〉)": 〈1;v〉 + } + }, + ] + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/036_closing_with_failed_optional.txtar b/internal/core/compile/testdata/sync/definitions/036_closing_with_failed_optional.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/036_closing_with_failed_optional.txtar @@ -0,0 +1,68 @@ +-- in.cue -- +#k1: {a: int, b?: int} & #A @test(eq, {a: int}) @test(closed) + +#k2: #A & {a: int, b?: int} @test(eq, {a: int}) @test(closed) + +o1: {a?: 3} & {a?: 4} @test(eq, {a?: _|_}) @test(closed=false) + +// Optional fields with error values can be eliminated when closing +#o2: {a?: 3} & {a?: 4} @test(eq, {}) @test(closed) + +#d1: {a?: 2, b: 4} | {a?: 3, c: 5} @test(closed) @test(eq, { + a?: 2 + b: 4 + } | { + a?: 3 + c: 5 + }) + +// Note: a? can be discarded safely. +v1: #d1 & {a?: 3, b: 4} @test(closed) @test(eq, {b: 4}) @test(debug, """ + (#struct){ + a?: (_|_){ + // [eval] v1.a: conflicting values 2 and 3: + // in.cue:10:11 + // in.cue:19:5 + // in.cue:19:16 + } + b: (int){ 4 } + } + """) + +#A: {a: int} +-- out/compile -- +--- in.cue +{ + #k1: ({ + a: int + b?: int + } & 〈0;#A〉) + #k2: (〈0;#A〉 & { + a: int + b?: int + }) + o1: ({ + a?: 3 + } & { + a?: 4 + }) + #o2: ({ + a?: 3 + } & { + a?: 4 + }) + #d1: ({ + a?: 2 + b: 4 + }|{ + a?: 3 + c: 5 + }) + v1: (〈0;#d1〉 & { + a?: 3 + b: 4 + }) + #A: { + a: int + } +} diff --git a/internal/core/compile/testdata/sync/definitions/036_optionals_in_open_structs.txtar b/internal/core/compile/testdata/sync/definitions/036_optionals_in_open_structs.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/036_optionals_in_open_structs.txtar @@ -0,0 +1,29 @@ +-- in.cue -- +A: { + [=~"^[a-s]*$"]: int +} +B: { + [=~"^[m-z]*$"]: int +} +#C: {A & B} +c: #C & {aaa: 3} @test(eq, { + [=~"^[a-s]*$"]: int + [=~"^[m-z]*$"]: int + aaa: 3 +}) +-- out/compile -- +--- in.cue +{ + A: { + [=~"^[a-s]*$"]: int + } + B: { + [=~"^[m-z]*$"]: int + } + #C: { + (〈1;A〉 & 〈1;B〉) + } + c: (〈0;#C〉 & { + aaa: 3 + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/037_closing_with_comprehensions.txtar b/internal/core/compile/testdata/sync/definitions/037_closing_with_comprehensions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/037_closing_with_comprehensions.txtar @@ -0,0 +1,80 @@ +#name: closing with comprehensions +#evalPartial +-- in.cue -- +#A: {f1: int, f2: int} @test(eq, {f1: int, f2: int}) @test(closed) + +for k, v in {f3: int} { + a: #A & {"\(k)": v} +} +@test(err, at=a.f3, code=eval, contains="field not allowed", pos=[-2:11]) + +#B: { + for k, v in {f1: int} { + "\(k)": v + } +} @test(eq, { f1: int }) + +#C: { + f1: _ + for k, v in {f1: int} { + "\(k)": v + } +} @test(eq, { f1: int }) @test(closed) @test(allows=false, string) + +#D: { + for k, v in {f1: int} { + "\(k)": v + } + ... +} @test(eq, { f1: int }) @test(closed) @test(allows, string) + +#E: #A & { + for k, v in {f3: int} { + "\(k)": v + } +} @test(err, at=f3, code=eval, contains="field not allowed", pos=[2:3]) +-- out/compile -- +--- in.cue +{ + #A: { + f1: int + f2: int + } + for k, v in { + f3: int + } { + a: (〈2;#A〉 & { + "\(〈2;k〉)": 〈2;v〉 + }) + } + #B: { + for k, v in { + f1: int + } { + "\(〈1;k〉)": 〈1;v〉 + } + } + #C: { + f1: _ + for k, v in { + f1: int + } { + "\(〈1;k〉)": 〈1;v〉 + } + } + #D: { + for k, v in { + f1: int + } { + "\(〈1;k〉)": 〈1;v〉 + } + ... + } + #E: (〈0;#A〉 & { + for k, v in { + f3: int + } { + "\(〈1;k〉)": 〈1;v〉 + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/037_conjunction_of_optional_sets.txtar b/internal/core/compile/testdata/sync/definitions/037_conjunction_of_optional_sets.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/037_conjunction_of_optional_sets.txtar @@ -0,0 +1,44 @@ +-- in.cue -- +#A: { + [=~"^[a-s]*$"]: int +} +#B: { + [=~"^[m-z]*$"]: int +} + +#C: #A & #B @test(allows, moo) @test(allows=false, QQQ) @test(eq, { + [=~"^[a-s]*$"]: int + [=~"^[m-z]*$"]: int +}) +c: #C +c: {aaa: 3 } @test(err, code=eval, at=aaa, + hint="positions missing", + contains="field not allowed", pos=[in.cue:2:2, 0:5]) + +#D: {#A & #B} +d: #D +d: {aaa: 3 } @test(err, code=eval, at=aaa, + hint="positions missing", + contains="field not allowed", pos=[in.cue:2:2, 0:5]) +-- out/compile -- +--- in.cue +{ + #A: { + [=~"^[a-s]*$"]: int + } + #B: { + [=~"^[m-z]*$"]: int + } + #C: (〈0;#A〉 & 〈0;#B〉) + c: 〈0;#C〉 + c: { + aaa: 3 + } + #D: { + (〈1;#A〉 & 〈1;#B〉) + } + d: 〈0;#D〉 + d: { + aaa: 3 + } +} diff --git a/internal/core/compile/testdata/sync/definitions/038_continue_recursive_closing_for_optionals.txtar b/internal/core/compile/testdata/sync/definitions/038_continue_recursive_closing_for_optionals.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/038_continue_recursive_closing_for_optionals.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +#S: { + [string]: {a: int} +} +a: #S & { + v: {b: int} +} @test(err, at=v.b, code=eval, contains="field not allowed", pos=[1:6]) +-- out/compile -- +--- in.cue +{ + #S: { + [string]: { + a: int + } + } + a: (〈0;#S〉 & { + v: { + b: int + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/039_augment_closed_optionals.txtar b/internal/core/compile/testdata/sync/definitions/039_augment_closed_optionals.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/039_augment_closed_optionals.txtar @@ -0,0 +1,44 @@ +-- in.cue -- +#A: { + [=~"^[a-s]*$"]: int +} +#B: { + [=~"^[m-z]*?"]: int +} +#C: { + #A & #B + {[=~"^Q*$"]: int} +} @test(allows, moo) @test(allows, Qoo) @test(allows=false, string) +// TODO: What should this be? @test(allows=false, zoo) +c: #C & {QQ: 3} @test(eq, {QQ: 3}) +#D: { + #A + #B +} +d: #D & {aaa: 4} @test(eq, {aaa: 4}) +-- out/compile -- +--- in.cue +{ + #A: { + [=~"^[a-s]*$"]: int + } + #B: { + [=~"^[m-z]*?"]: int + } + #C: { + (〈1;#A〉 & 〈1;#B〉) + { + [=~"^Q*$"]: int + } + } + c: (〈0;#C〉 & { + QQ: 3 + }) + #D: { + 〈1;#A〉 + 〈1;#B〉 + } + d: (〈0;#D〉 & { + aaa: 4 + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/comprehensions.txtar b/internal/core/compile/testdata/sync/definitions/comprehensions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/comprehensions.txtar @@ -0,0 +1,31 @@ +-- in.cue -- +// Closedness should not be silently swallowed when propagated through +// comprehensions; fields added via comprehensions should still be checked. +// https://cuelang.org/issue/595 +issue595: { + // NOTE: this should eval with an EVAL error, not + // an incomplete error. See Issue #595. + #cfgs: [{ + name: "foo" + }] + _name: #cfgs[0].name + for cfg in #cfgs { + files: cfg.nam + } + @test(err, code=eval, at=files, contains="undefined field: nam", pos=[8:14]) +} +-- out/compile -- +--- in.cue +{ + issue595: { + #cfgs: [ + { + name: "foo" + }, + ] + _name: 〈0;#cfgs〉[0].name + for _, cfg in 〈0;#cfgs〉 { + files: 〈1;cfg〉.nam + } + } +} diff --git a/internal/core/compile/testdata/sync/definitions/defembed.txtar b/internal/core/compile/testdata/sync/definitions/defembed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/defembed.txtar @@ -0,0 +1,41 @@ +-- in.cue -- +a: { + #A +} + +a: c: 1 @test(err, code=eval, contains="field not allowed", pos=[0:4]) + +#A: b: 1 + +b: { + #A + leaf: "leaf value" + interpolation: "more \(leaf_ref)" + leaf_ref: leaf + + @test(eq, { + b: 1 + leaf: "leaf value" + interpolation: "more leaf value" + leaf_ref: "leaf value" + }) +} +-- out/compile -- +--- in.cue +{ + a: { + 〈1;#A〉 + } + a: { + c: 1 + } + #A: { + b: 1 + } + b: { + 〈1;#A〉 + leaf: "leaf value" + interpolation: "more \(〈0;leaf_ref〉)" + leaf_ref: 〈0;leaf〉 + } +} diff --git a/internal/core/compile/testdata/sync/definitions/dynamic.txtar b/internal/core/compile/testdata/sync/definitions/dynamic.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/dynamic.txtar @@ -0,0 +1,81 @@ +-- in.cue -- +#A: { + a: "foo" + "\(a)": 3 + + @test(eq, { + a: "foo" + foo: 3 + }) +} +#B: a: b: { + c: string + d: 2 +} @test(eq, { + c: string + d: 2 +}) + +#C: a: b: { + c: *"d" | string + (c): 2 +} @test(eq, { + c: *"d" | string + d: 2 +}) + +x: #B & #C @test(eq, { + a: b: { + c: *"d" | string + d: 2 + } +}) + +-- evalv3regress.cue -- +chained: x: { + // TODO: add this once the todo is fixed. + // @test(permute) + (a.b): "foo" + (x.hello): "true" + a: b: "hello" + + @test(eq, {a: b: "hello", hello: "foo"}, incorrect, hint="shouldn't foo be in here?") + @test(eq:todo, {a: b: "hello", hello: "foo", foo: "true"}) +} +-- out/compile -- +--- evalv3regress.cue +{ + chained: { + x: { + 〈0;a〉.b: "foo" + 〈1;x〉.hello: "true" + a: { + b: "hello" + } + } + } +} +--- in.cue +{ + #A: { + a: "foo" + "\(〈0;a〉)": 3 + } + #B: { + a: { + b: { + c: string + d: 2 + } + } + } + #C: { + a: { + b: { + c: (*"d"|string) + 〈0;c〉: 2 + } + } + } + x: (〈0;#B〉 & 〈0;#C〉) +} diff --git a/internal/core/compile/testdata/sync/definitions/embed.txtar b/internal/core/compile/testdata/sync/definitions/embed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/embed.txtar @@ -0,0 +1,164 @@ +-- in.cue -- +deployment: [string]: #Deployment + +deployment: foo: spec: replicas: 1 + +@test(eq, { + [string]: spec: replicas: int + foo: spec: replicas: 1 +}, at=deployment) + +#Deployment: { + #TypeMeta + + spec: #Spec +} + +#Spec: replicas: int + +#TypeMeta: {} + +recloseSimple: { + #foo: {} + a: {#foo} & {b: int} @test(err, at=b, code=eval, contains="field not allowed", pos=[0:15]) +} + +// Reclosing +reclose1: { + #D: { + x: int + y: int + } + #a: { + #D + b: { + c: int + } + } + + z: #a.b + z: d: 3 @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} + +reclose2: { + #D: { + x: int + y: int + } + a: { + #D + b: {// keep open + c: int + } + } + + z: a.b @test(eq, { c: int, d: 3 }) + z: d: 3 +} + +reclose3: { + #Step: { + (#A | #B) + #Common + } + #Common: { + Name: string + } + #A: { + #Common + Something: int + } + #B: { + #Common + Else: int + } + x: #Step + x: #A & { + Name: "a" + Something: 4 + } @test(eq, {Name: "a", Something: 4}) +} +-- out/compile -- +--- in.cue +{ + deployment: { + [string]: 〈1;#Deployment〉 + } + deployment: { + foo: { + spec: { + replicas: 1 + } + } + } + #Deployment: { + 〈1;#TypeMeta〉 + spec: 〈1;#Spec〉 + } + #Spec: { + replicas: int + } + #TypeMeta: {} + recloseSimple: { + #foo: {} + a: ({ + 〈1;#foo〉 + } & { + b: int + }) + } + reclose1: { + #D: { + x: int + y: int + } + #a: { + 〈1;#D〉 + b: { + c: int + } + } + z: 〈0;#a〉.b + z: { + d: 3 + } + } + reclose2: { + #D: { + x: int + y: int + } + a: { + 〈1;#D〉 + b: { + c: int + } + } + z: 〈0;a〉.b + z: { + d: 3 + } + } + reclose3: { + #Step: { + (〈1;#A〉|〈1;#B〉) + 〈1;#Common〉 + } + #Common: { + Name: string + } + #A: { + 〈1;#Common〉 + Something: int + } + #B: { + 〈1;#Common〉 + Else: int + } + x: 〈0;#Step〉 + x: (〈0;#A〉 & { + Name: "a" + Something: 4 + }) + } +} diff --git a/internal/core/compile/testdata/sync/definitions/exclude.txtar b/internal/core/compile/testdata/sync/definitions/exclude.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/exclude.txtar @@ -0,0 +1,197 @@ +-- in.cue -- +package p + +excludeLet: { + // Two lets with the same name should not unify and checked by definition. + #D: { let X = {}, #foo: X, f: _ } + a: #D + a: { let X = { a: 1 }, f: X } @test(debugCheck, """ + (#struct){ + let X#2 = (struct){ + a: (int){ 1 } + } + f: (#struct){ + a: (int){ 1 } + } + let X#1 = (#struct){ + } + #foo: (#struct){ + } + } + """) + + @test(eq, { + #D: { + #foo: {} + f: _ + } + a: { + #foo: {} + f: a: 1 + } + }) +} + +definition: { + // Check a definition only if it s contained withing a definition. + err1: { + #D: { #foo: a: int } + a: #D + a: { #foo: b: int @test(err, code=eval, contains="field not allowed", pos=[0:14]) } + } + ok1: { + #D: {} + a: #D + a: { #foo: b: int } + @test(eq, { + #D: {} + a: #foo: b: int + }) + } +} + +hidden: { + // Check a hidden field only if it s contained withing a definition. + err1: { + #D: { _foo: a: int } + a: #D + a: { _foo: b: int } @test(err, code=eval, at=_foo$p, contains="field not allowed", pos=[0:14]) + } + ok1: { + #D: {} + a: #D + a: { _foo: b: int } + } @test(eq, {#D: {}, a: {_foo$p: {b: int}}}) +} +-- regress.cue -- +package p + +import "encoding/json" + +definition: ok2: { + #Tree: { + #Leaf: leaf: string + #Branch: branch?: #Leaf + root: #Branch + } + out: json.Marshal(#Tree & {root: {}}) @test(eq, #"{"root":{}}"#) +} + +hidden: ok2: { + out: #Workflow & { + _hidden: #step & { + run: "foo bar" + } + } + #Workflow: { + } + #step: matchN(1, [{ + "run"!: _ + }]) + + @test(eq, { + out: _hidden$p: run: "foo bar" + #Workflow: {} + #step: matchN(1, [{ run!: _ }]) + }) +} +-- out/compile -- +--- in.cue +{ + excludeLet: { + #D: { + let X#1 = {} + #foo: 〈0;let X#1〉 + f: _ + } + a: 〈0;#D〉 + a: { + let X#2 = { + a: 1 + } + f: 〈0;let X#2〉 + } + } + definition: { + err1: { + #D: { + #foo: { + a: int + } + } + a: 〈0;#D〉 + a: { + #foo: { + b: int + } + } + } + ok1: { + #D: {} + a: 〈0;#D〉 + a: { + #foo: { + b: int + } + } + } + } + hidden: { + err1: { + #D: { + _foo(:p): { + a: int + } + } + a: 〈0;#D〉 + a: { + _foo(:p): { + b: int + } + } + } + ok1: { + #D: {} + a: 〈0;#D〉 + a: { + _foo(:p): { + b: int + } + } + } + } +} +--- regress.cue +{ + definition: { + ok2: { + #Tree: { + #Leaf: { + leaf: string + } + #Branch: { + branch?: 〈1;#Leaf〉 + } + root: 〈0;#Branch〉 + } + out: 〈import;"encoding/json"〉.Marshal((〈0;#Tree〉 & { + root: {} + })) + } + } + hidden: { + ok2: { + out: (〈0;#Workflow〉 & { + _hidden(:p): (〈1;#step〉 & { + run: "foo bar" + }) + }) + #Workflow: {} + #step: matchN(1, [ + { + run!: _ + }, + ]) + } + } +} diff --git a/internal/core/compile/testdata/sync/definitions/explicitopen.txtar b/internal/core/compile/testdata/sync/definitions/explicitopen.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/explicitopen.txtar @@ -0,0 +1,785 @@ +# Tests the explicitopen experiment: allows using the spread operator (...) to +# explicitly open closed structs. NewClosed1: {#A} is closed; NewOpen1: {#A...} +# is open. The test covers interactions between old and new style closedness. +-- cue.mod/module.cue -- +module: "mod.test" + +language: version: "v0.15.0" + +-- old.cue -- +package foo + +@test(shareID=AOpen2, at=#A) +#A: a: 1 +Old1: { + { + #A + b: 1 + } +} + +#Old2: { + { + #A + b: 1 + } +} + +useNewClosed1: { + t1: err: NewClosed1 & {c: 3} @test(err, code=eval, contains="field not allowed", pos=[0:25]) + t2: ok: {NewClosed1, c: 3} @test(eq, { a: 1, c: 3 }) +} + +useNewClosed2: { + t1: err: #NewClosed2 & {c: 3} @test(err, code=eval, contains="field not allowed", pos=[0:26]) + t2: ok: {#NewClosed2, c: 3} @test(eq, { a: 1, b: 1, c: 3 }) +} + +useNewOpen1: { + t1: ok: NewOpen1 & {c: 3} @test(eq, { a: 1, b: 1, c: 3 }) + t2: ok: {NewOpen1, c: 3} @test(eq, { a: 1, b: 1, c: 3 }) +} + +useNewOpen2: { + t1: ok: NewOpen2 & {c: 3} @test(eq, { a: 1, c: 3 }) + t2: ok: {NewOpen2, c: 3} @test(eq, { a: 1, c: 3 }) +} + +combineold: { + // all {a: 1} + a0: ok: #A & NewClosed1 @test(eq, { a: 1 }) + a1: ok: {#A, NewClosed1} @test(eq, { a: 1 }) + + a2: ok: NewClosed1 & NewOpen2 @test(eq, { a: 1 }) + a3: ok: {NewClosed1, NewOpen2} @test(eq, { a: 1 }) + + // all {a: 1, b: 2} + b0: ok: Old1 & #NewClosed2 @test(eq, { a: 1, b: 1 }) + b1: ok: #Old2 & #NewClosed2 @test(eq, { a: 1, b: 1 }) + + c1: ok: {#NewClosed2, Old1} @test(eq, { a: 1, b: 1 }) + c2: ok: {#NewClosed2, #Old2} @test(eq, { a: 1, b: 1 }) + + // {a: 1} and {a: 1, b: 2} + e0: err: #A & Old1 @test(err, code=eval, contains="field not allowed", pos=[-47:3]) + e1: err: #A & #Old2 @test(err, code=eval, contains="field not allowed", pos=[-41:3]) + e2: err: #A & #NewClosed2 @test(err, code=eval, contains="field not allowed", pos=[new.cue:12:2]) + e3: err: #A & NewOpen1 @test(err, code=eval, contains="field not allowed", pos=[new.cue:17:2]) + + e4: ok: {#A, Old1} @test(eq, { a: 1, b: 1 }) + e5: ok: {#A, #Old2} @test(eq, { a: 1, b: 1 }) + e6: ok: {#A, #NewClosed2} @test(eq, { a: 1, b: 1 }) + e7: ok: {#A, NewOpen1} @test(eq, { a: 1, b: 1 }) + + f0: err: NewClosed1 & Old1 @test(err, code=eval, contains="field not allowed", pos=[-57:3]) + f1: err: NewClosed1 & #Old2 @test(err, code=eval, contains="field not allowed", pos=[-51:3]) + f2: err: NewClosed1 & #NewClosed2 @test(err, code=eval, contains="field not allowed", pos=[new.cue:12:2]) + f3: err: NewClosed1 & NewOpen1 @test(err, code=eval, contains="field not allowed", pos=[new.cue:17:2]) + + f4: ok: {NewClosed1, Old1} @test(eq, { a: 1, b: 1 }) + f5: ok: {NewClosed1, #Old2} @test(eq, { a: 1, b: 1 }) + f6: ok: {NewClosed1, NewClosed1} @test(eq, { a: 1 }) + f7: ok: {NewClosed1, #NewClosed2} @test(eq, { a: 1, b: 1 }) + f8: ok: {NewClosed1, NewOpen1} @test(eq, { a: 1, b: 1 }) +} + +-- new.cue -- +@experiment(explicitopen) + +package foo + +NewClosed1: { + @test(shareID=NC1) + #A +} + +#NewClosed2: { + #A... + b: 1 +} + +NewOpen1: { + #A... + b: 1 +} + +NewOpen2: #A... @test(shareID=AOpen2) + +useOld1: { + t1: err: Old1 & {c: 3} @test(err, code=eval, contains="field not allowed", pos=[0:19]) + t2: err: {Old1, c: 3} @test(err, code=eval, contains="field not allowed", pos=[0:18]) // TODO + t3: ok: {Old1..., c: 3} @test(eq, {a: 1, b: 1, c: 3}) +} + +useOld2: { + t1: err: #Old2 & {c: 3} @test(err, code=eval, contains="field not allowed", pos=[0:20]) + t2: err: {#Old2, c: 3} @test(err, code=eval, contains="field not allowed", pos=[0:19]) + t3: ok: {#Old2..., c: 3} @test(eq, {a: 1, b: 1, c: 3}) +} + +combinenew: { + // all {a: 1} + a0: ok: #A & NewClosed1 @test(eq, {a: 1}) + a1: ok: {#A, NewClosed1} @test(eq, {a: 1}) + + a2: ok: NewClosed1 & NewOpen2 @test(eq, {a: 1}) + a3: ok: {NewClosed1, NewOpen2} @test(eq, {a: 1}) + a4: ok: {NewClosed1..., NewOpen2} @test(eq, {a: 1}) + + a5: ok: NewOpen2 & NewClosed1 @test(eq, {a: 1}) + a6: ok: {NewOpen2, NewClosed1} @test(eq, {a: 1}) + a7: ok: {NewOpen2..., NewClosed1} @test(eq, {a: 1}) + + // all {a: 1, b: 2} + b0: ok: Old1 & #NewClosed2 @test(eq, {a: 1, b: 1}) + b1: ok: #Old2 & #NewClosed2 @test(eq, {a: 1, b: 1}) + b2: ok: #NewClosed2 & Old1 @test(eq, {a: 1, b: 1}) + b3: ok: #NewClosed2 & #Old2 @test(eq, {a: 1, b: 1}) + + c1: ok: {#NewClosed2, Old1} @test(eq, {a: 1, b: 1}) + c2: ok: {#NewClosed2, #Old2} @test(eq, {a: 1, b: 1}) + c3: ok: {Old1, #NewClosed2} @test(eq, {a: 1, b: 1}) + c4: ok: {#Old2, #NewClosed2} @test(eq, {a: 1, b: 1}) + + d0: ok: {#NewClosed2, Old1...} @test(eq, {a: 1, b: 1}) + d1: ok: {#NewClosed2, #Old2...} @test(eq, {a: 1, b: 1}) + d2: ok: {#NewClosed2..., Old1} @test(eq, {a: 1, b: 1}) + d3: ok: {#NewClosed2..., #Old2} @test(eq, {a: 1, b: 1}) + d4: ok: {#NewClosed2..., Old1...} @test(eq, {a: 1, b: 1}) + d5: ok: {#NewClosed2..., #Old2...} @test(eq, {a: 1, b: 1}) + + d6: ok: {Old1..., #NewClosed2} @test(eq, {a: 1, b: 1}) + d7: ok: {#Old2..., #NewClosed2} @test(eq, {a: 1, b: 1}) + d8: ok: {Old1, #NewClosed2...,} @test(eq, {a: 1, b: 1}) + d9: ok: {#Old2, #NewClosed2...,} @test(eq, {a: 1, b: 1}) + d10: ok: {Old1..., #NewClosed2...,} @test(eq, {a: 1, b: 1}) + d11: ok: {#Old2..., #NewClosed2...,} @test(eq, {a: 1, b: 1}) + + // {a: 1} and {a: 1, b: 2} + e0: err: #A & Old1 @test(err, code=eval, contains="field not allowed", pos=[old.cue:8:3]) + e1: err: #A & #Old2 @test(err, code=eval, contains="field not allowed", pos=[old.cue:15:3]) + e2: err: #A & #NewClosed2 @test(err, code=eval, contains="field not allowed", pos=[-63:2]) + e3: err: #A & NewOpen1 @test(err, code=eval, contains="field not allowed", pos=[-59:2]) + + e4: err: {#A, Old1} @test(err, code=eval, contains="field not allowed", pos=[old.cue:8:3]) + e5: err: {#A, #Old2} @test(err, code=eval, contains="field not allowed", pos=[old.cue:15:3]) + e6: err: {#A, #NewClosed2} @test(err, code=eval, contains="field not allowed", pos=[-68:2]) + e7: err: {#A, NewOpen1} @test(err, code=eval, contains="field not allowed", pos=[-64:2]) + + e8: ok: {#A..., Old1} @test(eq, {a: 1, b: 1}) + e9: ok: {#A..., #Old2} @test(eq, {a: 1, b: 1}) + e10: ok: {#A..., #NewClosed2} @test(eq, {a: 1, b: 1}) + e11: ok: {#A..., NewOpen1} @test(eq, {a: 1, b: 1}) + + f0: err: NewClosed1 & Old1 @test(err, code=eval, contains="field not allowed", pos=[old.cue:8:3]) + f1: err: NewClosed1 & #Old2 @test(err, code=eval, contains="field not allowed", pos=[old.cue:15:3]) + f2: err: NewClosed1 & #NewClosed2 @test(err, code=eval, contains="field not allowed", pos=[-78:2]) + f3: err: NewClosed1 & NewOpen1 @test(err, code=eval, contains="field not allowed", pos=[-74:2]) + f4: ok: NewClosed1 & NewClosed1 @test(eq, {a: 1}) @test(shareID=NC1) + + f5: err: {NewClosed1, Old1} @test(err, code=eval, contains="field not allowed", pos=[old.cue:8:3]) + f6: err: {NewClosed1, #Old2} @test(err, code=eval, contains="field not allowed", pos=[old.cue:15:3]) + f7: err: {NewClosed1, #NewClosed2} @test(err, code=eval, contains="field not allowed", pos=[-84:2]) + f8: err: {NewClosed1, NewOpen1} @test(err, code=eval, contains="field not allowed", pos=[-80:2]) + f9: ok: {NewClosed1, NewClosed1} @test(err) + + f9: ok: {NewClosed1..., Old1} @test(err, code=eval, contains="field not allowed", pos=[old.cue:8:3], hint="see todo") + f10: ok: {NewClosed1..., #Old2} @test(eq, {a: 1, b: 1}) + f11: ok: {NewClosed1..., NewClosed1} @test(eq, {a: 1}) + f12: ok: {NewClosed1..., #NewClosed2} @test(eq, {a: 1, b: 1}) + f13: ok: {NewClosed1..., NewOpen1} @test(eq, {a: 1, b: 1}) + + f14: err: Old1 & NewClosed1 @test(eq, {a: 1, b: 1}, hint="see todo") + f15: err: #Old2 & NewClosed1 @test(eq, {a: 1, b: 1}, hint="see todo") + f16: err: #NewClosed2 & NewClosed1 @test(err, code=eval, contains="field not allowed", pos=[-96:2]) + f17: err: NewOpen1 & NewClosed1 @test(err, code=eval, contains="field not allowed", pos=[-92:2]) + f18: ok: NewClosed1 & NewClosed1 @test(eq, {a: 1}) @test(shareID=NC1) +} +-- issues.cue -- +@experiment(explicitopen) +// explicitopen experiment: postfix `...` spread cannot directly combine with +// `&`; tests open-struct spread behavior and non-struct operand tolerance. +// https://cuelang.org/issue/4150 +issue4150: { + #Def: a: int + + x: #Def... & { + a: 42 + b: 42 + } @test(eq, {a: 42, b: 42}) @test(closed) + + foo: {a: int} + bar: {b: int} + y: foo... & bar... @test(eq, {a: int, b: int}) + + // NOTE: we allow this, even though it doesn't mean anything. The benefit + // of this is that code doesn't become brittle using the spread operator + // for references. Consider this example: + // + // #Def: a: int + // foo: 1 | #Def + // bar: foo... + // + // Not allowing ... on any expression would mean #foo... may or may not be + // erroneous, depending on the value foo is set to. + z: 1... @test(eq, 1) +} +-- out/compile -- +--- issues.cue +{ + issue4150: { + #Def: { + a: int + } + x: (〈0;#Def〉... & { + a: 42 + b: 42 + }) + foo: { + a: int + } + bar: { + b: int + } + y: (〈0;foo〉... & 〈0;bar〉...) + z: 1... + } +} +--- new.cue +{ + NewClosed1: { + 〈1;#A〉 + } + #NewClosed2: { + 〈1;#A〉... + b: 1 + } + NewOpen1: { + 〈1;#A〉... + b: 1 + } + NewOpen2: 〈0;#A〉... + useOld1: { + t1: { + err: (〈2;Old1〉 & { + c: 3 + }) + } + t2: { + err: { + 〈3;Old1〉 + c: 3 + } + } + t3: { + ok: { + 〈3;Old1〉... + c: 3 + } + } + } + useOld2: { + t1: { + err: (〈2;#Old2〉 & { + c: 3 + }) + } + t2: { + err: { + 〈3;#Old2〉 + c: 3 + } + } + t3: { + ok: { + 〈3;#Old2〉... + c: 3 + } + } + } + combinenew: { + a0: { + ok: (〈2;#A〉 & 〈2;NewClosed1〉) + } + a1: { + ok: { + 〈3;#A〉 + 〈3;NewClosed1〉 + } + } + a2: { + ok: (〈2;NewClosed1〉 & 〈2;NewOpen2〉) + } + a3: { + ok: { + 〈3;NewClosed1〉 + 〈3;NewOpen2〉 + } + } + a4: { + ok: { + 〈3;NewClosed1〉... + 〈3;NewOpen2〉 + } + } + a5: { + ok: (〈2;NewOpen2〉 & 〈2;NewClosed1〉) + } + a6: { + ok: { + 〈3;NewOpen2〉 + 〈3;NewClosed1〉 + } + } + a7: { + ok: { + 〈3;NewOpen2〉... + 〈3;NewClosed1〉 + } + } + b0: { + ok: (〈2;Old1〉 & 〈2;#NewClosed2〉) + } + b1: { + ok: (〈2;#Old2〉 & 〈2;#NewClosed2〉) + } + b2: { + ok: (〈2;#NewClosed2〉 & 〈2;Old1〉) + } + b3: { + ok: (〈2;#NewClosed2〉 & 〈2;#Old2〉) + } + c1: { + ok: { + 〈3;#NewClosed2〉 + 〈3;Old1〉 + } + } + c2: { + ok: { + 〈3;#NewClosed2〉 + 〈3;#Old2〉 + } + } + c3: { + ok: { + 〈3;Old1〉 + 〈3;#NewClosed2〉 + } + } + c4: { + ok: { + 〈3;#Old2〉 + 〈3;#NewClosed2〉 + } + } + d0: { + ok: { + 〈3;#NewClosed2〉 + 〈3;Old1〉... + } + } + d1: { + ok: { + 〈3;#NewClosed2〉 + 〈3;#Old2〉... + } + } + d2: { + ok: { + 〈3;#NewClosed2〉... + 〈3;Old1〉 + } + } + d3: { + ok: { + 〈3;#NewClosed2〉... + 〈3;#Old2〉 + } + } + d4: { + ok: { + 〈3;#NewClosed2〉... + 〈3;Old1〉... + } + } + d5: { + ok: { + 〈3;#NewClosed2〉... + 〈3;#Old2〉... + } + } + d6: { + ok: { + 〈3;Old1〉... + 〈3;#NewClosed2〉 + } + } + d7: { + ok: { + 〈3;#Old2〉... + 〈3;#NewClosed2〉 + } + } + d8: { + ok: { + 〈3;Old1〉 + 〈3;#NewClosed2〉... + } + } + d9: { + ok: { + 〈3;#Old2〉 + 〈3;#NewClosed2〉... + } + } + d10: { + ok: { + 〈3;Old1〉... + 〈3;#NewClosed2〉... + } + } + d11: { + ok: { + 〈3;#Old2〉... + 〈3;#NewClosed2〉... + } + } + e0: { + err: (〈2;#A〉 & 〈2;Old1〉) + } + e1: { + err: (〈2;#A〉 & 〈2;#Old2〉) + } + e2: { + err: (〈2;#A〉 & 〈2;#NewClosed2〉) + } + e3: { + err: (〈2;#A〉 & 〈2;NewOpen1〉) + } + e4: { + err: { + 〈3;#A〉 + 〈3;Old1〉 + } + } + e5: { + err: { + 〈3;#A〉 + 〈3;#Old2〉 + } + } + e6: { + err: { + 〈3;#A〉 + 〈3;#NewClosed2〉 + } + } + e7: { + err: { + 〈3;#A〉 + 〈3;NewOpen1〉 + } + } + e8: { + ok: { + 〈3;#A〉... + 〈3;Old1〉 + } + } + e9: { + ok: { + 〈3;#A〉... + 〈3;#Old2〉 + } + } + e10: { + ok: { + 〈3;#A〉... + 〈3;#NewClosed2〉 + } + } + e11: { + ok: { + 〈3;#A〉... + 〈3;NewOpen1〉 + } + } + f0: { + err: (〈2;NewClosed1〉 & 〈2;Old1〉) + } + f1: { + err: (〈2;NewClosed1〉 & 〈2;#Old2〉) + } + f2: { + err: (〈2;NewClosed1〉 & 〈2;#NewClosed2〉) + } + f3: { + err: (〈2;NewClosed1〉 & 〈2;NewOpen1〉) + } + f4: { + ok: (〈2;NewClosed1〉 & 〈2;NewClosed1〉) + } + f5: { + err: { + 〈3;NewClosed1〉 + 〈3;Old1〉 + } + } + f6: { + err: { + 〈3;NewClosed1〉 + 〈3;#Old2〉 + } + } + f7: { + err: { + 〈3;NewClosed1〉 + 〈3;#NewClosed2〉 + } + } + f8: { + err: { + 〈3;NewClosed1〉 + 〈3;NewOpen1〉 + } + } + f9: { + ok: { + 〈3;NewClosed1〉 + 〈3;NewClosed1〉 + } + } + f9: { + ok: { + 〈3;NewClosed1〉... + 〈3;Old1〉 + } + } + f10: { + ok: { + 〈3;NewClosed1〉... + 〈3;#Old2〉 + } + } + f11: { + ok: { + 〈3;NewClosed1〉... + 〈3;NewClosed1〉 + } + } + f12: { + ok: { + 〈3;NewClosed1〉... + 〈3;#NewClosed2〉 + } + } + f13: { + ok: { + 〈3;NewClosed1〉... + 〈3;NewOpen1〉 + } + } + f14: { + err: (〈2;Old1〉 & 〈2;NewClosed1〉) + } + f15: { + err: (〈2;#Old2〉 & 〈2;NewClosed1〉) + } + f16: { + err: (〈2;#NewClosed2〉 & 〈2;NewClosed1〉) + } + f17: { + err: (〈2;NewOpen1〉 & 〈2;NewClosed1〉) + } + f18: { + ok: (〈2;NewClosed1〉 & 〈2;NewClosed1〉) + } + } +} +--- old.cue +{ + #A: { + a: 1 + } + Old1: { + { + 〈2;#A〉 + b: 1 + } + } + #Old2: { + { + 〈2;#A〉 + b: 1 + } + } + useNewClosed1: { + t1: { + err: (〈2;NewClosed1〉 & { + c: 3 + }) + } + t2: { + ok: { + 〈3;NewClosed1〉 + c: 3 + } + } + } + useNewClosed2: { + t1: { + err: (〈2;#NewClosed2〉 & { + c: 3 + }) + } + t2: { + ok: { + 〈3;#NewClosed2〉 + c: 3 + } + } + } + useNewOpen1: { + t1: { + ok: (〈2;NewOpen1〉 & { + c: 3 + }) + } + t2: { + ok: { + 〈3;NewOpen1〉 + c: 3 + } + } + } + useNewOpen2: { + t1: { + ok: (〈2;NewOpen2〉 & { + c: 3 + }) + } + t2: { + ok: { + 〈3;NewOpen2〉 + c: 3 + } + } + } + combineold: { + a0: { + ok: (〈2;#A〉 & 〈2;NewClosed1〉) + } + a1: { + ok: { + 〈3;#A〉 + 〈3;NewClosed1〉 + } + } + a2: { + ok: (〈2;NewClosed1〉 & 〈2;NewOpen2〉) + } + a3: { + ok: { + 〈3;NewClosed1〉 + 〈3;NewOpen2〉 + } + } + b0: { + ok: (〈2;Old1〉 & 〈2;#NewClosed2〉) + } + b1: { + ok: (〈2;#Old2〉 & 〈2;#NewClosed2〉) + } + c1: { + ok: { + 〈3;#NewClosed2〉 + 〈3;Old1〉 + } + } + c2: { + ok: { + 〈3;#NewClosed2〉 + 〈3;#Old2〉 + } + } + e0: { + err: (〈2;#A〉 & 〈2;Old1〉) + } + e1: { + err: (〈2;#A〉 & 〈2;#Old2〉) + } + e2: { + err: (〈2;#A〉 & 〈2;#NewClosed2〉) + } + e3: { + err: (〈2;#A〉 & 〈2;NewOpen1〉) + } + e4: { + ok: { + 〈3;#A〉 + 〈3;Old1〉 + } + } + e5: { + ok: { + 〈3;#A〉 + 〈3;#Old2〉 + } + } + e6: { + ok: { + 〈3;#A〉 + 〈3;#NewClosed2〉 + } + } + e7: { + ok: { + 〈3;#A〉 + 〈3;NewOpen1〉 + } + } + f0: { + err: (〈2;NewClosed1〉 & 〈2;Old1〉) + } + f1: { + err: (〈2;NewClosed1〉 & 〈2;#Old2〉) + } + f2: { + err: (〈2;NewClosed1〉 & 〈2;#NewClosed2〉) + } + f3: { + err: (〈2;NewClosed1〉 & 〈2;NewOpen1〉) + } + f4: { + ok: { + 〈3;NewClosed1〉 + 〈3;Old1〉 + } + } + f5: { + ok: { + 〈3;NewClosed1〉 + 〈3;#Old2〉 + } + } + f6: { + ok: { + 〈3;NewClosed1〉 + 〈3;NewClosed1〉 + } + } + f7: { + ok: { + 〈3;NewClosed1〉 + 〈3;#NewClosed2〉 + } + } + f8: { + ok: { + 〈3;NewClosed1〉 + 〈3;NewOpen1〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/definitions/fields.txtar b/internal/core/compile/testdata/sync/definitions/fields.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/fields.txtar @@ -0,0 +1,825 @@ +// Tests fields.go +-- in.cue -- +// TODO: reorganize ordered on what is tested by name. E.g. +// insertion: longPath: ok: p1: { +// a: .... @fail() +// } + +ok: t1: { + c: #R + c: [{b: int}] @test(allows=false, int) + #R: [...] @test(allows, int) + + @test(eq, { + c: [{b: int}] + #R: [] + }) +} + +ok: t2: { + #A: _ + l: #A + l: f: "hi" + + @test(eq, { + #A: _ + l: f: "hi" + }) +} + +ok: t3: { + #A: f: {...} + #A1: { #A } + s: [string]: #A1 + s: foo: f: d: foo: 1 + + @test(eq, { + #A: f: {} + #A1: f: {} + s: foo: f: d: foo: 1 + }) +} + +ok: t4: { + #T: { a: b: 1 } + W: { + {#T} + b: c: 2 + } + + @test(eq, { + #T: a: b: 1 + W: { + a: b: 1 + b: c: 2 + } + }) +} + +ok: t5: { + // TODO: move to err + #A: { + Common + _ + } + Common: { } + x: #A + x: c: int @test(err, code=eval, + hint="not sure if this is actually correct", + contains="field not allowed", pos=[0:5]) +} + +ok: t6: { + #A: { + Common + ... + } + Common: { } + x: #A @test(allows, string) + x: c: int + + @test(eq, { + #A: {} + Common: {} + x: c: int + }) +} + +ok: t7: { + a: {#A, #B} + #A: b: f: 1 + #B: b: g: 1 + + @test(eq, { + a: b: { + f: 1 + g: 1 + } + #A: b: f: 1 + #B: b: g: 1 + }) +} + +ok: t8: { + // TODO: this should pass + foo: #X @test(shareID=ok_t8_foox) + #X: { + @test(shareID=ok_t8_foox) + + a: b: c: C: 1 + for k, _ in a { + // dynamic field causes insertion one level higher. This causes + // b to be inserted in a, after it has been referenced. + a: (k): c: D: 2 + } + } + + @test(eq, { + foo: a: b: c: { + C: 1 + D: 2 + } + #X: a: b: c: { + C: 1 + D: 2 + } + }) +} + +ok: t9: { + c: #R + c: [{b: int}] + #R: [...] + + @test(eq, { + c: [{ + b: int + }] + #R: [] + }) +} + +ok: t10: { + #A: _ // top should allow everything + l: #A + l: f: "hi" + + @test(eq, { + #A: _ + l: f: "hi" + }) +} + +ok: t11: { + // indirections + #A: f: {...} + #A1: { #A } + s: [string]: #A1 + s: foo: f: d: foo: "bar" // should pass + + @test(eq, { + #A: f: {} + #A1: f: {} + s: foo: f: d: foo: "bar" + }) +} + +ok: t12: { + // nested embedding + #T: { a: b: 1 } + W: { + {#T} + b: c: 2 + } + + @test(eq, { + #T: { a: b: 1 } + W: { + a: b: 1 + b: c: 2 + } + }) +} + +ok: t13: { + // TODO: move to err + + // top DOES NOT open up + #A: { + Common + _ + } + Common: { } + x: #A + x: c: int @test(err, code=eval, contains="field not allowed", pos=[0:5]) + + @test(eq, { + #A: {} + Common: {} + x: c: _|_ + }) +} + +ok: t14: { + // ellipsis opens up + #A: { + Common + ... + } + Common: { } + x: #A + x: c: int + + @test(eq, { + #A: {} + Common: {} + x: c: int + }) +} + +// TODO: move this test to "ok": _ means any and implicitly defines all fields +// to be present as optional fields with _, recursively (as long as the type +// has not been picked to be non-struct). +// This was not observed in V2, but is now observed in V3. We should probably +// either allow for an error variant that only "allows" all fields but does not +// define them as optional top, or rethink the closedness model altogether. +err: t1: { + @test(permute, count=6) + #D: _ & {a: 2} + a: #D + a: disallowed: 1 @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} + +err: t2: { + @test(permute) + #S: { { c: d: 1 } } + V: #S + V: { c: e: 1 @test(err, code=eval, contains="field not allowed", pos=[0:10]) } +} + +err: t3: { + @test(permute) + #D: {} + a: #D + a: c: "C" @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} + +err: t4: { + @test(permute) + a: #A + #A: b: f: 1 + a: b: h: 1 @test(err, code=eval, contains="field not allowed", pos=[0:8]) +} + +err: t5: { + @test(permute) + // TODO: this should fail + a: {#A, #B} + #A: b: f: 1 + #B: b: g: 1 + b: a + b: b: h: 1 @test(err, code=eval, contains="field not allowed", pos=[0:8]) +} + +err: t6: { + @test(permute) + // TODO: this should fail + a: {#A, #B} + #A: b: c: d: e: f: 1 + #B: b: c: d: e: g: 1 + b: a + b: b: c: d: e: h: 1 @test(err, code=eval, contains="field not allowed", pos=[0:17]) +} + +// TODO: move this test to "ok": _ means any and implicitly defines all fields +// to be present as optional fields with _, recursively (as long as the type +// has not been picked to be non-struct). +// This was not observed in V2, but is now observed in V3. We should probably +// either allow for an error variant that only "allows" all fields but does not +// define them as optional top, or rethink the closedness model altogether. +err: t7: { + @test(permute) + #D: _ & {a: 2} + a: #D + a: b: 1 @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} + +err: t8: { + @test(permute) + // nested embedding + #S: { { c: d: 1 } } + V: #S + V: { c: e: 1 @test(err, code=eval, contains="field not allowed", pos=[0:10]) } +} +-- validators.cue -- +import "struct" + +// Validators represent top, but in the case of some validators, we should not +// allow a struct to "close" it. Basically, we any validator that takes a +// schema as argument (is marked as NonConcrete) will open up the struct. +// +// TODO: we should aim to eliminate this discrepancy in the closedness redesign. +validator: open: { + #Schema: { + matchN(1, [#x]) + #x: trailingComma?: "all" + } + data: trailingComma: "all" + data: #Schema + + @test(eq, { + #Schema: { + matchN(1, [{trailingComma: "all"}]) + #x: trailingComma?: "all" + } + data: { + // TODO: why is the matchN dropped here? + trailingComma: "all" + #x: trailingComma?: "all" + } + }) +} + +validator: keepClosed: { + #X: { + struct.MaxFields(1) + a?: int + b?: int + } + x: #X + x: c: 1 @test(err, code=eval, contains="field not allowed", pos=[-5:3, 0:5]) +} +-- issue1830.cue -- +// Closedness was not applied when accessing optional fields through a selector; +// extra fields should still be rejected by the definition. +// https://cuelang.org/issue/1830 +issue1830: { + #x: { + y: { + z?: { + name: string + } + } + } + + egs: { + x1: (#x & {y: z: _}).y.z & { + name: "blah" + age1: 5 + } @test(closed) @test(eq, { name: "blah", age1: 5 }, incorrect) + x2: (#x.y & {z: _}).z & { + name: "blah" + age2: 5 + } @test(closed) @test(eq, { name: "blah", age2: 5 }, incorrect) + + @test(err:todo, at=x1.age1, code=eval, contains="field not allowed") + @test(err:todo, at=x2.age2, code=eval, contains="field not allowed") + } +} +-- issue3491.cue -- +// evalv3 regression: "field not allowed" when unifying a definition with an +// optional field against a value that adds a regular field of the same name. +// https://cuelang.org/issue/3491 +issue3491: { + #Schema: field?: {} + + a: #Schema & { + field: {} + } + + a: b + b: #Extra: {} + + @test(eq, { + #Schema: field?: {} + a: { + field: {} + #Extra: {} + } + b: #Extra: {} + }) +} +-- out/compile -- +--- in.cue +{ + ok: { + t1: { + c: 〈0;#R〉 + c: [ + { + b: int + }, + ] + #R: [ + ..., + ] + } + } + ok: { + t2: { + #A: _ + l: 〈0;#A〉 + l: { + f: "hi" + } + } + } + ok: { + t3: { + #A: { + f: { + ... + } + } + #A1: { + 〈1;#A〉 + } + s: { + [string]: 〈1;#A1〉 + } + s: { + foo: { + f: { + d: { + foo: 1 + } + } + } + } + } + } + ok: { + t4: { + #T: { + a: { + b: 1 + } + } + W: { + { + 〈2;#T〉 + } + b: { + c: 2 + } + } + } + } + ok: { + t5: { + #A: { + 〈1;Common〉 + _ + } + Common: {} + x: 〈0;#A〉 + x: { + c: int + } + } + } + ok: { + t6: { + #A: { + 〈1;Common〉 + ... + } + Common: {} + x: 〈0;#A〉 + x: { + c: int + } + } + } + ok: { + t7: { + a: { + 〈1;#A〉 + 〈1;#B〉 + } + #A: { + b: { + f: 1 + } + } + #B: { + b: { + g: 1 + } + } + } + } + ok: { + t8: { + foo: 〈0;#X〉 + #X: { + a: { + b: { + c: { + C: 1 + } + } + } + for k, _ in 〈0;a〉 { + a: { + 〈2;k〉: { + c: { + D: 2 + } + } + } + } + } + } + } + ok: { + t9: { + c: 〈0;#R〉 + c: [ + { + b: int + }, + ] + #R: [ + ..., + ] + } + } + ok: { + t10: { + #A: _ + l: 〈0;#A〉 + l: { + f: "hi" + } + } + } + ok: { + t11: { + #A: { + f: { + ... + } + } + #A1: { + 〈1;#A〉 + } + s: { + [string]: 〈1;#A1〉 + } + s: { + foo: { + f: { + d: { + foo: "bar" + } + } + } + } + } + } + ok: { + t12: { + #T: { + a: { + b: 1 + } + } + W: { + { + 〈2;#T〉 + } + b: { + c: 2 + } + } + } + } + ok: { + t13: { + #A: { + 〈1;Common〉 + _ + } + Common: {} + x: 〈0;#A〉 + x: { + c: int + } + } + } + ok: { + t14: { + #A: { + 〈1;Common〉 + ... + } + Common: {} + x: 〈0;#A〉 + x: { + c: int + } + } + } + err: { + t1: { + #D: (_ & { + a: 2 + }) + a: 〈0;#D〉 + a: { + disallowed: 1 + } + } + } + err: { + t2: { + #S: { + { + c: { + d: 1 + } + } + } + V: 〈0;#S〉 + V: { + c: { + e: 1 + } + } + } + } + err: { + t3: { + #D: {} + a: 〈0;#D〉 + a: { + c: "C" + } + } + } + err: { + t4: { + a: 〈0;#A〉 + #A: { + b: { + f: 1 + } + } + a: { + b: { + h: 1 + } + } + } + } + err: { + t5: { + a: { + 〈1;#A〉 + 〈1;#B〉 + } + #A: { + b: { + f: 1 + } + } + #B: { + b: { + g: 1 + } + } + b: 〈0;a〉 + b: { + b: { + h: 1 + } + } + } + } + err: { + t6: { + a: { + 〈1;#A〉 + 〈1;#B〉 + } + #A: { + b: { + c: { + d: { + e: { + f: 1 + } + } + } + } + } + #B: { + b: { + c: { + d: { + e: { + g: 1 + } + } + } + } + } + b: 〈0;a〉 + b: { + b: { + c: { + d: { + e: { + h: 1 + } + } + } + } + } + } + } + err: { + t7: { + #D: (_ & { + a: 2 + }) + a: 〈0;#D〉 + a: { + b: 1 + } + } + } + err: { + t8: { + #S: { + { + c: { + d: 1 + } + } + } + V: 〈0;#S〉 + V: { + c: { + e: 1 + } + } + } + } +} +--- issue1830.cue +{ + issue1830: { + #x: { + y: { + z?: { + name: string + } + } + } + egs: { + x1: ((〈1;#x〉 & { + y: { + z: _ + } + }).y.z & { + name: "blah" + age1: 5 + }) + x2: ((〈1;#x〉.y & { + z: _ + }).z & { + name: "blah" + age2: 5 + }) + } + } +} +--- issue3491.cue +{ + issue3491: { + #Schema: { + field?: {} + } + a: (〈0;#Schema〉 & { + field: {} + }) + a: 〈0;b〉 + b: { + #Extra: {} + } + } +} +--- validators.cue +{ + validator: { + open: { + #Schema: { + matchN(1, [ + 〈1;#x〉, + ]) + #x: { + trailingComma?: "all" + } + } + data: { + trailingComma: "all" + } + data: 〈0;#Schema〉 + } + } + validator: { + keepClosed: { + #X: { + 〈import;struct〉.MaxFields(1) + a?: int + b?: int + } + x: 〈0;#X〉 + x: { + c: 1 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/definitions/files.txtar b/internal/core/compile/testdata/sync/definitions/files.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/files.txtar @@ -0,0 +1,59 @@ +// Treat fields of different files as belonging to the same struct. +// This means that a closed embedding in one file should not restrict the +// fields of another. +-- in.cue -- +package foo + +#theme: { + color: string + ctermbg: string +} +dark: #theme & { + color: "dark" + ctermbg: "239" +} @test(eq, {color: "dark", ctermbg: "239"}) + +light: #theme & { + color: "light" + ctermbg: "254" +} @test(eq, {color: "light", ctermbg: "254"}) + +#Config: { + console: dark | *light +} @test(eq, { + console: *{color: "light", ctermbg: "254"} | {color: "dark", ctermbg: "239"} +}) +-- box.cue -- +package foo + +#Config & { + console: dark +} + +@test(eq, {color: "dark", ctermbg: "239"}, at=console) + +-- out/compile -- +--- box.cue +{ + (〈0;#Config〉 & { + console: 〈1;dark〉 + }) +} +--- in.cue +{ + #theme: { + color: string + ctermbg: string + } + dark: (〈0;#theme〉 & { + color: "dark" + ctermbg: "239" + }) + light: (〈0;#theme〉 & { + color: "light" + ctermbg: "254" + }) + #Config: { + console: (〈1;dark〉|*〈1;light〉) + } +} diff --git a/internal/core/compile/testdata/sync/definitions/hidden.txtar b/internal/core/compile/testdata/sync/definitions/hidden.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/hidden.txtar @@ -0,0 +1,73 @@ +exec cue eval ./pkg:foo +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- in.cue -- +package foo + +import "mod.test/pkg" + +#def: { + _name: d: int +} + +d: pkg.#D & {_name: d: int, _val: f: 4} + +// TODO: this should fail, as the _name restricting it is in this +// package. +e: pkg.#D & #def & { + // This should fail as c is disallowed by the _name defined + // in this package + _name: c: int + + // This should not fail, as this is a different _val + _val: g: int +} @test(err, code=eval, at=_name$foo.c, contains="field not allowed", pos=[3:9]) + +f: pkg.#D & {_val: f: 4} @test(debugCheck, """ + (#struct){ + _val(:foo): (struct){ + f: (int){ 4 } + } + _val(mod.test/pkg): (#struct){ + f: (int){ 3 } + } + } + """) + +g: f._val @test(eq, {f: 4}) +-- pkg/bar.cue -- +package pkg + +#D: {_val: f: 3} +-- out/compile -- +--- in.cue +{ + #def: { + _name(:foo): { + d: int + } + } + d: (〈import;"mod.test/pkg"〉.#D & { + _name(:foo): { + d: int + } + _val(:foo): { + f: 4 + } + }) + e: ((〈import;"mod.test/pkg"〉.#D & 〈0;#def〉) & { + _name(:foo): { + c: int + } + _val(:foo): { + g: int + } + }) + f: (〈import;"mod.test/pkg"〉.#D & { + _val(:foo): { + f: 4 + } + }) + g: 〈0;f〉._val(:foo) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue271.txtar b/internal/core/compile/testdata/sync/definitions/issue271.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue271.txtar @@ -0,0 +1,27 @@ + +# Tests that a struct combining an open pattern constraint with close() correctly +# rejects fields not allowed by the close() constraint when unified with a value. +# https://cuelang.org/issue/271 +-- in.cue -- +#T: [_]: _ +#T: close({"a": string}) +x: #T +x: { + a: "hello" @test(eq, "hello") + b: "foo" @test(err, code=eval, contains="field not allowed", pos=[-5:5, 0:2]) +} +-- out/compile -- +--- in.cue +{ + #T: { + [_]: _ + } + #T: close({ + a: string + }) + x: 〈0;#T〉 + x: { + a: "hello" + b: "foo" + } +} diff --git a/internal/core/compile/testdata/sync/definitions/issue317.txtar b/internal/core/compile/testdata/sync/definitions/issue317.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue317.txtar @@ -0,0 +1,117 @@ + +# Allow otherField +# Tests that comprehension-based schemas and deployment configurations correctly +# allow fields defined through pattern constraints and let comprehensions. +# Issue: https://cuelang.org/issue/317 +-- in.cue -- +#T: { + #Schema: [_]: #D + concrete: #Schema +} +#D: { + fieldWithDefault: *0 | int + ... +} +s: #T & { + #Schema: { + foo: otherField: string + } + concrete: foo: otherField: "hello" +} @test(closed) @test(eq, { + #Schema: foo: { + fieldWithDefault: *0 | int + otherField: string + } + concrete: foo: { + fieldWithDefault: *0 | int + otherField: "hello" + } +}) +#Container: { + Env: [Name=string]: { + name: string + value: string + } +} +#Deployment: { + #Containers: [Name=string]: #Container + containers: [for c in #Containers {c}] // Problem is here. +} +Something: { + #Deployment + #Containers: { + // Does not allow entries other than value. Either add ... or embed + "a thing": Env: foobar: value: "foo" + } +} +x: Something & #Deployment @test(closed) @test(eq, { + #Containers: { + "a thing": Env: foobar: { + value: "foo" + name: string + } + } + containers: [{ + Env: foobar: { + name: string + value: "foo" + } + }] +}) +-- out/compile -- +--- in.cue +{ + #T: { + #Schema: { + [_]: 〈2;#D〉 + } + concrete: 〈0;#Schema〉 + } + #D: { + fieldWithDefault: (*0|int) + ... + } + s: (〈0;#T〉 & { + #Schema: { + foo: { + otherField: string + } + } + concrete: { + foo: { + otherField: "hello" + } + } + }) + #Container: { + Env: { + [string]: { + name: string + value: string + } + } + } + #Deployment: { + #Containers: { + [string]: 〈2;#Container〉 + } + containers: [ + for _, c in 〈1;#Containers〉 { + 〈1;c〉 + }, + ] + } + Something: { + 〈1;#Deployment〉 + #Containers: { + "a thing": { + Env: { + foobar: { + value: "foo" + } + } + } + } + } + x: (〈0;Something〉 & 〈0;#Deployment〉) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue320.txtar b/internal/core/compile/testdata/sync/definitions/issue320.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue320.txtar @@ -0,0 +1,34 @@ + +# Tests that "field not allowed" errors in closed structs include sufficient +# diagnostic information about the source of the restriction. +# https://cuelang.org/issue/320 +-- in.cue -- +#Foo: { + x: string + #More +} + +#More: [=~"^x-"]: _ + +foo: #Foo & { + x: "hello" + y: "goodbye" +} @test(err, at=y, code=eval, + hint="could use more positions, like in v2", + contains="field not allowed", + pos=[in.cue:10:2]) +-- out/compile -- +--- in.cue +{ + #Foo: { + x: string + 〈1;#More〉 + } + #More: { + [=~"^x-"]: _ + } + foo: (〈0;#Foo〉 & { + x: "hello" + y: "goodbye" + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue342.txtar b/internal/core/compile/testdata/sync/definitions/issue342.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue342.txtar @@ -0,0 +1,64 @@ +# Tests that Fill() followed by Validate(concrete) succeeds for complex disjunction +# definitions under dynamic (interpolated) keys, as it does for static keys. +# https://cuelang.org/issue/342 +-- in.cue -- +X: { + #Simple: { + ref: string + } @test(shareID=SIMPLE) + + #Complex: { + { + ref: string + } | { + local: string + } + } @test(eq, {ref: string} | {local: string}) @test(shareID=COMPLEX) + + + var: "bar" + + // Validate(concrete) after Fill() on Complex.ref from a "static" key will succeed + "test_1": #Complex @test(shareID=COMPLEX) @test(eq, { + ref: string + } | { + local: string + }) + + // Validate(concrete) after Fill() on "#Simple.ref" from a "dynamic" key will succeed + "test_2_\(var)": #Simple + @test(shareID=SIMPLE, at=test_2_bar) + @test(eq, at=test_2_bar, { ref: string }) + + // Validate(concrete) after Fill() on Complex.ref from a "dynamic" key will fail + "test_3_\(var)": #Complex + + test_3_bar: ref: "FOO" + @test(eq, at=test_3_bar, { ref: "FOO" }) +} + +Z: X.test_3_bar.ref @test(eq, "FOO") +-- out/compile -- +--- in.cue +{ + X: { + #Simple: { + ref: string + } + #Complex: { + ({ + ref: string + }|{ + local: string + }) + } + var: "bar" + test_1: 〈0;#Complex〉 + "test_2_\(〈0;var〉)": 〈0;#Simple〉 + "test_3_\(〈0;var〉)": 〈0;#Complex〉 + test_3_bar: { + ref: "FOO" + } + } + Z: 〈0;X〉.test_3_bar.ref +} diff --git a/internal/core/compile/testdata/sync/definitions/issue359.txtar b/internal/core/compile/testdata/sync/definitions/issue359.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue359.txtar @@ -0,0 +1,137 @@ +# Tests that inner structs within a definition template constraint are not +# incorrectly treated as closed when unified via a non-definition value. +# https://cuelang.org/issue/359 +-- in.cue -- +#simple: { + peso: *1 | int + edad: *2 | int +} + +// Second struct is not considered closed, as expected +good: #simple & { + peso: 4 +} @test(eq, {peso: 4, edad: *2 | int}) + +#complex: { + things: [string]: #simple +} + +// Still, no closedness issue in the second struct +#many: #complex & { + things: hola: peso: 2 + things: sol: peso: 3 +} @test(eq, { + things: { + hola: { + peso: 2 + edad: *2 | int + } + sol: { + peso: 3 + edad: *2 | int + } + } +}) + +// Inner struct in second struct IS considered closed: why? +bad: #many & { + things: hola: peso: 2 +} @test(eq, { + things: { + hola: { + peso: 2 + edad: *2 | int + } + sol: { + peso: 3 + edad: *2 | int + } + } +}) + +// non-definition equivalent +many: #complex & { + things: hola: peso: 2 + things: sol: peso: 3 +} @test(eq, { + things: { + hola: { + peso: 2 + edad: *2 | int + } + sol: { + peso: 3 + edad: *2 | int + } + } +}) + +// Now inner struct on second struct is NOT considered closed +notbad: many & { + things: hola: peso: 2 +} @test(eq, { + things: { + hola: { + peso: 2 + edad: *2 | int + } + sol: { + peso: 3 + edad: *2 | int + } + } +}) +-- out/compile -- +--- in.cue +{ + #simple: { + peso: (*1|int) + edad: (*2|int) + } + good: (〈0;#simple〉 & { + peso: 4 + }) + #complex: { + things: { + [string]: 〈2;#simple〉 + } + } + #many: (〈0;#complex〉 & { + things: { + hola: { + peso: 2 + } + } + things: { + sol: { + peso: 3 + } + } + }) + bad: (〈0;#many〉 & { + things: { + hola: { + peso: 2 + } + } + }) + many: (〈0;#complex〉 & { + things: { + hola: { + peso: 2 + } + } + things: { + sol: { + peso: 3 + } + } + }) + notbad: (〈0;many〉 & { + things: { + hola: { + peso: 2 + } + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue367.txtar b/internal/core/compile/testdata/sync/definitions/issue367.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue367.txtar @@ -0,0 +1,35 @@ +-- in.cue -- +#def1: l1: ["l2"]: {l3: int, l4: 26} +#special1: #def1 & {l1: l2: l3: <100} @test(eq, { + l1: l2: { + l3: int & <100 + l4: 26 + } +}) +instance: #special1 & {l1: l2: l3: 34} @test(eq, {l1: {l2: {l3: 34, l4: 26}}}) +-- out/compile -- +--- in.cue +{ + #def1: { + l1: { + ["l2"]: { + l3: int + l4: 26 + } + } + } + #special1: (〈0;#def1〉 & { + l1: { + l2: { + l3: <100 + } + } + }) + instance: (〈0;#special1〉 & { + l1: { + l2: { + l3: 34 + } + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue370.txtar b/internal/core/compile/testdata/sync/definitions/issue370.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue370.txtar @@ -0,0 +1,41 @@ +# Tests that embedding a definition (#C1) inside another definition (#C2) and +# then unifying with a concrete struct correctly validates all fields. +# https://cuelang.org/issue/370 +-- x.cue -- +package x + +#C1: { + name: string +} + +#C2: { + #C1 + age: int +} + +c1: #C1 & { + name: "cueckoo" +} @test(eq, {name: "cueckoo"}) + +c2: #C2 & { + c1 + age: 5 +} @test(eq, {age: 5, name: "cueckoo"}) +-- out/compile -- +--- x.cue +{ + #C1: { + name: string + } + #C2: { + 〈1;#C1〉 + age: int + } + c1: (〈0;#C1〉 & { + name: "cueckoo" + }) + c2: (〈0;#C2〉 & { + 〈1;c1〉 + age: 5 + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue3834.txtar b/internal/core/compile/testdata/sync/definitions/issue3834.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue3834.txtar @@ -0,0 +1,270 @@ +# Tests that hidden fields with disjunctions (close({y!: z?: _}) | _) work +# correctly when exposed through embedding. The key behavior is that _a unifies +# with close({y!: ...}) correctly even when exposed via {X} or X. +# Issue: https://cuelang.org/issue/3834 +-- in.cue -- +// expose at top level +X: { + _a: foo: true + _a: _ | close({y!: z?: _}) + _b: _a & {y: {}} + concrete: _b.y + isTrue: concrete != _|_ @test(eq, true) +} +{X} + +@test(eq, { + X: { + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + isTrue: true + } + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + isTrue: true + + sub: _ @test(ignore) + full: _ @test(ignore) +}) + +sub: t1: { + X: { + _a: foo: true + _a: _ | close({y!: z?: _}) + _b: _a & {y: {}} + concrete: _b.y + } + {X} + + @test(eq, { + X: { + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + } + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + }) +} +sub: t2: { + X: { + _a: foo: true + _a: _ | close({y!: z?: _}) + _b: _a & {y: {}} + concrete: _b.y @test(eq, {}) + } + X + + @test(eq, { + X: { + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + } + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + }) +} +sub: t3: { + #X: { + _a: foo: true + _a: _ | close({y!: z?: _}) + _b: _a & {y: {}} + concrete: _b.y @test(eq, {}) + } + {#X} + + @test(eq, { + #X: { + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + } + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + }) +} +sub: t4: { + #X: { + _a: foo: true + _a: _ | close({y!: z?: _}) + _b: _a & {y: {}} + concrete: _b.y @test(eq, {}) + @test(debug, """ + (#struct){ + _a: (#struct){ + foo: (bool){ true } + } + _b: (#struct){ + y: (#struct){ + } + foo: (bool){ true } + } + concrete: (#struct){ + } + } + """) + } + #X + + @test(eq, { + #X: { + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + } + _a: {foo: true} + _b: {y: {}, foo: true} + concrete: {} + }) +} + +full: { + #Foo: { + _data: Foo: true + _data: _ | close({Extra!: optional?: _}) + + _dataWithExtra: _data & {Extra: {}} + + out: _dataWithExtra.Extra != _|_ @test(eq, true) + } + + {#Foo} + + @test(eq, { + #Foo: { + _data: {Foo: true} + _dataWithExtra: {Extra: {}, Foo: true} + out: true + } + _data: {Foo: true} + _dataWithExtra: {Extra: {}, Foo: true} + out: true + }) +} +-- out/compile -- +--- in.cue +{ + X: { + _a: { + foo: true + } + _a: (_|close({ + y!: { + z?: _ + } + })) + _b: (〈0;_a〉 & { + y: {} + }) + concrete: 〈0;_b〉.y + isTrue: (〈0;concrete〉 != _|_(explicit error (_|_ literal) in source)) + } + { + 〈1;X〉 + } + sub: { + t1: { + X: { + _a: { + foo: true + } + _a: (_|close({ + y!: { + z?: _ + } + })) + _b: (〈0;_a〉 & { + y: {} + }) + concrete: 〈0;_b〉.y + } + { + 〈1;X〉 + } + } + } + sub: { + t2: { + X: { + _a: { + foo: true + } + _a: (_|close({ + y!: { + z?: _ + } + })) + _b: (〈0;_a〉 & { + y: {} + }) + concrete: 〈0;_b〉.y + } + 〈0;X〉 + } + } + sub: { + t3: { + #X: { + _a: { + foo: true + } + _a: (_|close({ + y!: { + z?: _ + } + })) + _b: (〈0;_a〉 & { + y: {} + }) + concrete: 〈0;_b〉.y + } + { + 〈1;#X〉 + } + } + } + sub: { + t4: { + #X: { + _a: { + foo: true + } + _a: (_|close({ + y!: { + z?: _ + } + })) + _b: (〈0;_a〉 & { + y: {} + }) + concrete: 〈0;_b〉.y + } + 〈0;#X〉 + } + } + full: { + #Foo: { + _data: { + Foo: true + } + _data: (_|close({ + Extra!: { + optional?: _ + } + })) + _dataWithExtra: (〈0;_data〉 & { + Extra: {} + }) + out: (〈0;_dataWithExtra〉.Extra != _|_(explicit error (_|_ literal) in source)) + } + { + 〈1;#Foo〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/definitions/issue3851.txtar b/internal/core/compile/testdata/sync/definitions/issue3851.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue3851.txtar @@ -0,0 +1,44 @@ +# Tests that a nested optional field structure combined with let bindings and +# disjunctions (#Output: null | #App) evaluates correctly without false errors. +# https://cuelang.org/issue/3851 +-- in.cue -- +#App: { + name?: string + sub1?: sub2?: null | _ +} +#Output: null | #App @test(eq, null | {name?: string, sub1?: {sub2?: null | _}}) +out: #Output & { + name: "foo" + sub1: sub2: {} | _ + sub1: sub2: { + sub3: { + let _let = "bar" + foo: _let + } + } +} @test(eq, {name: "foo", sub1: {sub2: {sub3: {foo: "bar"}}}}) +-- out/compile -- +--- in.cue +{ + #App: { + name?: string + sub1?: { + sub2?: (null|_) + } + } + #Output: (null|〈0;#App〉) + out: (〈0;#Output〉 & { + name: "foo" + sub1: { + sub2: ({}|_) + } + sub1: { + sub2: { + sub3: { + let _let#1 = "bar" + foo: 〈0;let _let#1〉 + } + } + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue4000.txtar b/internal/core/compile/testdata/sync/definitions/issue4000.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue4000.txtar @@ -0,0 +1,127 @@ +# Tests that list.Sort with complex type definitions involving defaults works. +# Issue: https://cuelang.org/issue/4000 +-- in.cue -- +import "list" + +items: list.Sort(#List.items, { + x: {} + y: {} + less: x.kind < y.kind +}) @test(eq, [{ + spec: [{rules: [{expr: "x"}]}] + kind: *"default" | string + + @test(shareID=L0) + },{ + spec: [{rules: [{expr: "y"}]}] + kind: *"default" | string + + @test(shareID=L1) + }] +) + +#List: items: list.Concat(_items) + +_items: [#VMRuleList] + +// This is an alternative way of writing sharing. +@test(shareID=L0, at=items.0) +@test(shareID=L1, at=items.1) +@test(shareID=L0, at=#VMRuleList.0) +@test(shareID=L1, at=#VMRuleList.1) + +#VMRuleList: [...null | #VMRule] & [{ + spec: [{ + rules: [{expr: "x"}] + }] +}, { + spec: [{ + rules: [{expr: "y"}] + }] +}] @test(eq, [{ + @test(shareID=L0) + + kind: *"default" | string + spec: [{ + rules: [{ + expr: "x" + }] + }] +}, { + @test(shareID=L1) + + kind: *"default" | string + spec: [{ + rules: [{ + expr: "y" + }] + }] +}]) + +#RuleGroup: rules: [...#Rule] + +#Rule: expr: string @test(eq, string) + +#VMRule: { + #TypeMeta + spec: [...#RuleGroup] +} +#TypeMeta: kind: string | *"default" +-- out/compile -- +--- in.cue +{ + items: 〈import;list〉.Sort(〈0;#List〉.items, { + x: {} + y: {} + less: (〈0;x〉.kind < 〈0;y〉.kind) + }) + #List: { + items: 〈import;list〉.Concat(〈1;_items〉) + } + _items: [ + 〈1;#VMRuleList〉, + ] + #VMRuleList: ([ + ...(null|〈1;#VMRule〉), + ] & [ + { + spec: [ + { + rules: [ + { + expr: "x" + }, + ] + }, + ] + }, + { + spec: [ + { + rules: [ + { + expr: "y" + }, + ] + }, + ] + }, + ]) + #RuleGroup: { + rules: [ + ...〈2;#Rule〉, + ] + } + #Rule: { + expr: string + } + #VMRule: { + 〈1;#TypeMeta〉 + spec: [ + ...〈2;#RuleGroup〉, + ] + } + #TypeMeta: { + kind: (string|*"default") + } +} diff --git a/internal/core/compile/testdata/sync/definitions/issue419.txtar b/internal/core/compile/testdata/sync/definitions/issue419.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue419.txtar @@ -0,0 +1,45 @@ +# Tests that a list constrained with [...#X] where #X is a disjunction of +# definitions correctly accepts values matching either branch of the disjunction. +# https://cuelang.org/issue/419 +-- in.cue -- +#A: { + a: string +} + +#B: { + b: string +} + +#X: #A | #B + +l: [...#X] + +l: [ + {b: "bar"}, +] + +@test(eq, { + #A: {a: string} + #B: {b: string} + #X: {a: string} | {b: string} + l: [{ b: "bar" }] +}) +-- out/compile -- +--- in.cue +{ + #A: { + a: string + } + #B: { + b: string + } + #X: (〈0;#A〉|〈0;#B〉) + l: [ + ...〈1;#X〉, + ] + l: [ + { + b: "bar" + }, + ] +} diff --git a/internal/core/compile/testdata/sync/definitions/issue471.txtar b/internal/core/compile/testdata/sync/definitions/issue471.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue471.txtar @@ -0,0 +1,56 @@ +# Tests that unifying a disjunction of definitions with an additional constraint +# (#a: (#c | #d) & {name: string}) does not incorrectly reject fields from either branch. +# https://cuelang.org/issue/471 +-- in.cue -- +package x + +#a: (#c | #d) & { + name: string +} + +#a1: #c & { + name: string +} + +#a2: #d & { + name: string +} + +#c: { + name: string + age: int +} + +#d: { + name: string + address: string +} + +@test(eq, { + #a: {name: string, age: int} | {name: string, address: string} + #a1: {name: string, age: int} + #a2: {name: string, address: string} + #c: {name: string, age: int} + #d: {name: string, address: string} +}) +-- out/compile -- +--- in.cue +{ + #a: ((〈0;#c〉|〈0;#d〉) & { + name: string + }) + #a1: (〈0;#c〉 & { + name: string + }) + #a2: (〈0;#d〉 & { + name: string + }) + #c: { + name: string + age: int + } + #d: { + name: string + address: string + } +} diff --git a/internal/core/compile/testdata/sync/definitions/issue483.txtar b/internal/core/compile/testdata/sync/definitions/issue483.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue483.txtar @@ -0,0 +1,40 @@ +# Tests that optional nested fields within a definition unified with an open struct +# (#Root: {...}) correctly accept concrete values without "field not allowed" errors. +# https://cuelang.org/issue/483 +-- in.cue -- +out: { + instance +} @test(eq, {alpha: bravo: charlie: true}) + +instance: #Type & { + alpha: bravo: charlie: true +} @test(eq, {alpha: bravo: charlie: true}) + +#Type: #Root & { + alpha?: bravo?: charlie?: bool +} +#Root: {...} +-- out/compile -- +--- in.cue +{ + out: { + 〈1;instance〉 + } + instance: (〈0;#Type〉 & { + alpha: { + bravo: { + charlie: true + } + } + }) + #Type: (〈0;#Root〉 & { + alpha?: { + bravo?: { + charlie?: bool + } + } + }) + #Root: { + ... + } +} diff --git a/internal/core/compile/testdata/sync/definitions/issue491.txtar b/internal/core/compile/testdata/sync/definitions/issue491.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue491.txtar @@ -0,0 +1,78 @@ +# Tests that a definition used as a list element type correctly propagates default +# values and does not incorrectly reject fields like Pattern when unified. +# https://cuelang.org/issue/491 +-- in.cue -- +package x + +#Prestep: { + Args: *null | _ +} + +#PrestepNewUser: #Prestep & { + Args: #NewUser +} + +#NewUser: { + Repos: [...#Repo] +} + +#Repo: { + Var: string + Pattern: *"*" | string +} + +x: [...#Repo] +x: [{ + Var: "REPO1" +}] @test(eq, [{Var: "REPO1", Pattern: *"*" | string}]) + +y: #Repo & { + Var: "REPO1" +} @test(eq, {Var: "REPO1", Pattern: *"*" | string}) + +z: #PrestepNewUser & { + Args: { + Repos: [{ + Var: "REPO1" + }] + } +} @test(eq, {Args: {Repos: [{Var: "REPO1", Pattern: *"*" | string}]}}) +-- out/compile -- +--- in.cue +{ + #Prestep: { + Args: (*null|_) + } + #PrestepNewUser: (〈0;#Prestep〉 & { + Args: 〈1;#NewUser〉 + }) + #NewUser: { + Repos: [ + ...〈2;#Repo〉, + ] + } + #Repo: { + Var: string + Pattern: (*"*"|string) + } + x: [ + ...〈1;#Repo〉, + ] + x: [ + { + Var: "REPO1" + }, + ] + y: (〈0;#Repo〉 & { + Var: "REPO1" + }) + z: (〈0;#PrestepNewUser〉 & { + Args: { + Repos: [ + { + Var: "REPO1" + }, + ] + } + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue493.txtar b/internal/core/compile/testdata/sync/definitions/issue493.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue493.txtar @@ -0,0 +1,31 @@ +# Tests that a disjunction of identical definitions (#Both: #App | #Atom where +# both alias the same type) correctly unifies with an additional constraint. +# https://cuelang.org/issue/493 +-- in.cue -- +#Artifact: { + body: _ + other: [string]: int +} @test(shareID=appAtom) + +#App: #Artifact @test(shareID=appAtom) +#Atom: #Artifact @test(shareID=appAtom) + +#Both: #App | #Atom + +t1: #Both & {body: 3} @test(eq, {body: 3, other: {}}) +-- out/compile -- +--- in.cue +{ + #Artifact: { + body: _ + other: { + [string]: int + } + } + #App: 〈0;#Artifact〉 + #Atom: 〈0;#Artifact〉 + #Both: (〈0;#App〉|〈0;#Atom〉) + t1: (〈0;#Both〉 & { + body: 3 + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue496.txtar b/internal/core/compile/testdata/sync/definitions/issue496.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue496.txtar @@ -0,0 +1,24 @@ +# Tests that hidden fields within a definition unified with #A: _ are correctly +# handled and do not cause spurious "field not allowed" errors. +# https://cuelang.org/issue/496 +-- in.cue -- +#A: _ + +#N: #A & { + _E: { + name: "hello" + } +} @test(shareID=lN) + +l: #N @test(shareID=lN) +-- out/compile -- +--- in.cue +{ + #A: _ + #N: (〈0;#A〉 & { + _E: { + name: "hello" + } + }) + l: 〈0;#N〉 +} diff --git a/internal/core/compile/testdata/sync/definitions/issue497.txtar b/internal/core/compile/testdata/sync/definitions/issue497.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue497.txtar @@ -0,0 +1,26 @@ +# Tests that nested fields within a definition unified with #A: _ are accepted +# and do not produce spurious "field not allowed" errors on the nested structure. +# https://cuelang.org/issue/497 +-- in.cue -- +#A: _ + +#N: #A & { + f: j: { + n: "hi" + } +} @test(shareID=lN) @test(eq, {f: {j: {n: "hi"}}}) + +l: #N @test(shareID=lN) +-- out/compile -- +--- in.cue +{ + #A: _ + #N: (〈0;#A〉 & { + f: { + j: { + n: "hi" + } + } + }) + l: 〈0;#N〉 +} diff --git a/internal/core/compile/testdata/sync/definitions/issue533.txtar b/internal/core/compile/testdata/sync/definitions/issue533.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue533.txtar @@ -0,0 +1,41 @@ +# Tests that hidden definitions (_#x) enforce closedness the same way regular +# definitions (#x) do, rejecting extra fields not declared in the definition. +# https://cuelang.org/issue/533 +-- in.cue -- +package x + +#x: { + Name: string +} + +_#x: { + Name: string +} + +x1: #x & { + Name: "hello" + Age: 50 +} @test(err, code=eval, at=Age, contains="field not allowed", pos=[2:2]) + +x2: _#x & { + Name: "hello" + Age: 50 +} @test(err, code=eval, at=Age, contains="field not allowed", pos=[2:2]) +-- out/compile -- +--- in.cue +{ + #x: { + Name: string + } + _#x(:x): { + Name: string + } + x1: (〈0;#x〉 & { + Name: "hello" + Age: 50 + }) + x2: (〈0;_#x(:x)〉 & { + Name: "hello" + Age: 50 + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/issue539.txtar b/internal/core/compile/testdata/sync/definitions/issue539.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/issue539.txtar @@ -0,0 +1,34 @@ +# Tests that combining a definition with open spread (`...`) and a non-definition +# struct preserves the expected fields including hidden definitions and defaults. +# Issue: https://cuelang.org/issue/539 +-- in.cue -- +#Schema: { + ... +} + +Component: { + hostname: string | *"localhost" + + _#foo: { + hello: "world" + } +} + +hello: #Schema & Component @test(closed) @test(eq, { + hostname: *"localhost" | string + _#foo: {hello: "world"} +}) +-- out/compile -- +--- in.cue +{ + #Schema: { + ... + } + Component: { + hostname: (string|*"localhost") + _#foo: { + hello: "world" + } + } + hello: (〈0;#Schema〉 & 〈0;Component〉) +} diff --git a/internal/core/compile/testdata/sync/definitions/list.txtar b/internal/core/compile/testdata/sync/definitions/list.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/list.txtar @@ -0,0 +1,25 @@ +-- in.cue -- +c: #R & { + w: [{}, {b: int}] +} @test(eq, {w: [{}, {b: int}]}) +#R: { + w: [{}, ...] +} +-- out/compile -- +--- in.cue +{ + c: (〈0;#R〉 & { + w: [ + {}, + { + b: int + }, + ] + }) + #R: { + w: [ + {}, + ..., + ] + } +} diff --git a/internal/core/compile/testdata/sync/definitions/root1.txtar b/internal/core/compile/testdata/sync/definitions/root1.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root1.txtar @@ -0,0 +1,20 @@ +-- in.cue -- +// Test embedding at root of file +root1: 1 +#Root1: x: {} +#Root1 & { } + +@test(eq, { + root1: 1 + #Root1: x: {} + x: {} +}) +-- out/compile -- +--- in.cue +{ + root1: 1 + #Root1: { + x: {} + } + (〈0;#Root1〉 & {}) +} diff --git a/internal/core/compile/testdata/sync/definitions/root2.txtar b/internal/core/compile/testdata/sync/definitions/root2.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root2.txtar @@ -0,0 +1,16 @@ +-- in.cue -- +root2: 1 +#Root2: {} +#Root2 + +@test(eq, { + root2: 1 + #Root2: {} +}) +-- out/compile -- +--- in.cue +{ + root2: 1 + #Root2: {} + 〈0;#Root2〉 +} diff --git a/internal/core/compile/testdata/sync/definitions/root3.txtar b/internal/core/compile/testdata/sync/definitions/root3.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root3.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +x: _ +#D: b: x +#D & { b: _ } + +@test(eq, { + x: _ + #D: b: _ + b: _ +}) +-- out/compile -- +--- in.cue +{ + x: _ + #D: { + b: 〈1;x〉 + } + (〈0;#D〉 & { + b: _ + }) +} diff --git a/internal/core/compile/testdata/sync/definitions/root4.txtar b/internal/core/compile/testdata/sync/definitions/root4.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root4.txtar @@ -0,0 +1,33 @@ +-- in.cue -- +#schema: a!: bool +_hidden & #schema // must fail here, but not elsewhere +_hidden: { + "a": true, + notAllowed: true +} +allowed: true + +@test(eq, { + a: true + #schema: a!: bool + _hidden: { + a: true + notAllowed: true + } + allowed: true + notAllowed: _|_ +}) +@test(err, code=eval, contains="field not allowed", pos=[in.cue:5:2]) +-- out/compile -- +--- in.cue +{ + #schema: { + a!: bool + } + (〈0;_hidden〉 & 〈0;#schema〉) + _hidden: { + a: true + notAllowed: true + } + allowed: true +} diff --git a/internal/core/compile/testdata/sync/definitions/root5.txtar b/internal/core/compile/testdata/sync/definitions/root5.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root5.txtar @@ -0,0 +1,89 @@ +-- in.cue -- +_schema // embed schema through indirections +_schema: #Schema @test(shareID=topSchema) +#Schema: { + @test(shareID=topSchema) + a?: b?: string +} +a: b: "foo" +c: "foo" + + +x: { + _schema // embed schema through indirections + _schema: #Schema @test(shareID=xSchema) + #Schema: { + @test(shareID=xSchema) + a?: b?: string + } + a: b: "foo" + c: "foo" +} + +@test(eq, { + a: b: "foo" + _schema: a?: b?: string + #Schema: a?: b?: string + c: "foo" + x: { + a: b: "foo" + _schema: a?: b?: string + #Schema: a?: b?: string + c: "foo" + } +}) +// TODO(inline): fix sharing detection across hidden fields. +@test(debug, """ + (#struct){ + _schema: ~(#Schema) + #Schema: (#struct){ + a?: (#struct){ + b?: (string){ string } + } + } + a: (#struct){ + b: (string){ "foo" } + } + c: (string){ "foo" } + x: (#struct){ + _schema: ~(x.#Schema) + #Schema: (#struct){ + a?: (#struct){ + b?: (string){ string } + } + } + a: (#struct){ + b: (string){ "foo" } + } + c: (string){ "foo" } + } + } + """) +-- out/compile -- +--- in.cue +{ + 〈0;_schema〉 + _schema: 〈0;#Schema〉 + #Schema: { + a?: { + b?: string + } + } + a: { + b: "foo" + } + c: "foo" + x: { + 〈0;_schema〉 + _schema: 〈0;#Schema〉 + #Schema: { + a?: { + b?: string + } + } + a: { + b: "foo" + } + c: "foo" + } +} diff --git a/internal/core/compile/testdata/sync/definitions/root6.txtar b/internal/core/compile/testdata/sync/definitions/root6.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root6.txtar @@ -0,0 +1,49 @@ +-- in.cue -- +c: "foo" +a: b: int +#Schema +#Schema: close({ a: b: int}) @test(closed) + +x: { + c: "foo" + a: b: int + #Schema + #Schema: close({ a: b: int}) +} @test(closed) + +@test(eq, { + a: b: int + c: "foo" + #Schema: { a: b: int } + x: { + a: b: int + c: "foo" + #Schema: a: b: int + } +}) +-- out/compile -- +--- in.cue +{ + c: "foo" + a: { + b: int + } + 〈0;#Schema〉 + #Schema: close({ + a: { + b: int + } + }) + x: { + c: "foo" + a: { + b: int + } + 〈0;#Schema〉 + #Schema: close({ + a: { + b: int + } + }) + } +} diff --git a/internal/core/compile/testdata/sync/definitions/root7.txtar b/internal/core/compile/testdata/sync/definitions/root7.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root7.txtar @@ -0,0 +1,19 @@ +-- in.cue -- +root: input: #deps: root: {} +{root.input.#deps} + +@test(eq, { root: input: #deps: root: {} }) +-- out/compile -- +--- in.cue +{ + root: { + input: { + #deps: { + root: {} + } + } + } + { + 〈1;root〉.input.#deps + } +} diff --git a/internal/core/compile/testdata/sync/definitions/root8.txtar b/internal/core/compile/testdata/sync/definitions/root8.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/root8.txtar @@ -0,0 +1,44 @@ +-- in.cue -- +root: input: foo: { + metadata: name: *"foo" | string + id: "id-\(metadata.name)" + #deps: [string]: _ + #deps: root: {} + spec: replicas: 1 +} +{root.input.foo.#deps} + +@test(eq, { + root: input: foo: { + metadata: name: *"foo" | string + id: "id-foo" + #deps: root: {} + spec: replicas: 1 + } +}) +-- out/compile -- +--- in.cue +{ + root: { + input: { + foo: { + metadata: { + name: (*"foo"|string) + } + id: "id-\(〈0;metadata〉.name)" + #deps: { + [string]: _ + } + #deps: { + root: {} + } + spec: { + replicas: 1 + } + } + } + } + { + 〈1;root〉.input.foo.#deps + } +} diff --git a/internal/core/compile/testdata/sync/definitions/typocheck.txtar b/internal/core/compile/testdata/sync/definitions/typocheck.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/typocheck.txtar @@ -0,0 +1,2096 @@ +-- in.cue -- +embed: simple: { + #A: b: 1 + a: { #A } + a: err: 1 @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} +embed: andInStruct: { + #Foo: a: int + a: { #Foo & { err: 2 } } + + @test(err, at=a.err, code=eval, contains="field not allowed", pos=[2:16]) +} +embed: embedDefWithEmbedding: { + #Foo: {{a: int}} + a: { #Foo & { err: 2 } } // not allowed + + @test(err, at=a.err, code=eval, contains="field not allowed", pos=[2:16]) +} +embed: embedComprehension: { + #Foo: {if true {a: int}} + a: { #Foo & { err: 2 } } // not allowed + + @test(err, at=a.err, code=eval, contains="field not allowed", pos=[2:16]) +} +embed: fieldWithAnd: { + #A: {} + { a: #A & {err: 3 } } + + @test(err, at=a.err, code=eval, contains="field not allowed", pos=[2:13]) +} +embed: embedAndRecursive: { + #A: a: int + B: x: #A + B & { x: err: 2 } + + @test(err, at=x.err, code=eval, contains="field not allowed", pos=[3:11]) +} +embed: andEmbed: { + #A: b: int + #B: b: int + #D: {#A & #B} + d: #D & {err: 3} + + @test(err, at=d.err, code=eval, contains="field not allowed", pos=[4:11]) +} +and: transitive: ok: { + Z: {a: string} @test(shareID:todo=Z) + #Y: Z @test(shareID:todo=Z) + #X: #Y & Z + out: #X & { + a: "foo" + } + + @test(eq, { + Z: {a: string} + #Y: {a: string} + #X: {a: string} + out: {a: "foo"} + }) +} +and: transitive: err: { + Z: a: string + #Y: Z + #X: #Y & Z + out: #X & { + err: "foo" + } @test(err, at=err, code=eval, contains="field not allowed", pos=[1:3]) +} +and: transitiveWithEmbed: ok: { + Z: a: string + #X: #Y & Z + #Y: {Z} + out: #X & { + a: "foo" + } + + @test(eq, { + Z: {a: string} + #X: {a: string} + #Y: {a: string} + out: {a: "foo"} + }) +} +and: transitiveWithEmbed: err: { + Z: a: string + #X: #Y & Z + #Y: {Z} + out: #X & { + err: "foo" + } + + @test(err, at=out.err, code=eval, contains="field not allowed", pos=[5:3]) +} +embed: nonDef: t1: { + X: a: string + #Y: #Z & X + #Z: { + X + b?: string + } + + @test(eq, { + X: {a: string} + #Y: {b?: string, a: string} + #Z: {b?: string, a: string} + }) +} +embed: defAndHidden: full: { + _stepCommon: Name: string + #Step: #Command & _stepCommon + #Command: { + _stepCommon + Path?: string + } + out: #Step & { + Name: "foo" + } + + @test(eq, { + _stepCommon: {Name: string} + #Step: {Path?: string, Name: string} + #Command: {Path?: string, Name: string} + out: {Name: "foo", Path?: string} + }) +} +embed: withIndirect: { + A: #B + #B: b: int + A & { err: 2 } // not allowed + + @test(err, at=err, code=eval, contains="field not allowed", pos=[3:8]) +} +-- validators.cue -- +import ( + "struct" + "list" +) + +embed: normalValidator: { + #X: { + struct.MaxFields(1) + a?: int + b?: int + } + x: #X + x: err: 1 @test(err, code=eval, contains="field not allowed", pos=[-5:3, 0:5]) +} +embed: openValidator: t1: { + #X: { + matchN(0, []) + a?: int + b?: int + } + x: #X + x: err: 1 + + @test(eq, { + #X: {matchN(0, []), a?: int, b?: int} + x: {err: 1, a?: int, b?: int} + }) +} +embed: openValidator: t2: { + Y: matchN(1, [X]) + X: b?: Y + a: X + a: b: 1 @test(err, suberr=(code=eval, contains="conflicting values"), + suberr=(code=eval, contains="does not satisfy matchN", pos=[-3:5, -3:12, -2:9, 0:8]), + ) +} +disjunction: withErr: t1: { + params: {} + out: #Schema1 & { + b1: b2: b3: params.mayExistLater + } + #Schema1: b1?: null | #Schema2 + #Schema2: b2?: null | {b3?: string} + + @test(eq, { + params: {} + out: {b1: {b2: {b3: _}}} + #Schema1: {b1?: null | {b2?: null | {b3?: string}}} + #Schema2: {b2?: null | {b3?: string}} + }) +} +embed: nestedValidator: { + #types: z?: list.UniqueItems + x: y: z: [1] + x: { + #def + y?: #types + } + #def: {} + + @test(eq, { + #types: _ @test(ignore) + x: {y: {z: [1]}} + #def: {} + }) +} +-- inline.cue -- +embedInline: { + #Schema: { + a: "hello" + // do not close outer struct of 'b', as inlined value is not a schema. + b: { {x: c: "foo"}.x } + b: { + c: string + d: "never printed" + } + } + out: #Schema & __no_sharing + + @test(eq, { + #Schema: {a: "hello", b: {c: "foo", d: "never printed"}} + out: {a: "hello", b: {c: "foo", d: "never printed"}} + }) +} +// evalv3 "field not allowed" regression involving embeddings and selectors; +// accessing a field via selector on an embedded definition should stay open. +// https://cuelang.org/issue/3853 +issue3853: { + #Schema: { + a: "hello" + // do not close outer struct of 'b', as inlined value is not a schema. + b: { {x: c: "foo"}.x } + b: { + c: string + d: "never printed" + } + } + out: {x: (#Schema & {}).a}.x + + @test(eq, { + #Schema: {a: "hello", b: {c: "foo", d: "never printed"}} + out: "hello" + }) +} +-- disjunction.cue -- +import "list" + +// evalv3 regression: closedness errors no longer reported when default values +// are present; disallowed fields in a default disjunct should still be caught. +// https://cuelang.org/issue/3947 +issue3947: full: { + #Schema: allowed?: string + _defaults: disallowed: _ | *"default value" + out: #Schema & _defaults @test(err, code=eval, at=disallowed, contains="field not allowed", pos=[-1:13]) +} +// evalv3 regression: #oneOf pattern disjunction; unifying a closed definition +// disjunction with a default string field caused incorrect field-not-allowed errors. +// https://cuelang.org/issue/3957 +issue3957: reduced: { + c: a: "bar" + c: #B & {a: string | *"foo"} + #B: b?: string + + @test(err, at=c.a, code=eval, contains="field not allowed", pos=[1:5, 2:11]) +} +issue3957: full: { + #oneof: {a: string} | {b?: [...string]} + c: #oneof & {a: string | *"foo"} + c: a: "bar" + + @test(eq, { + #oneof: {a: string} | {b?: []} + c: {a: "bar"} + }) +} +issue3957: derived: t1: { + #Schema: { + in: string | [...string] + out: list.FlattenN([in], 1) + } + x: #Schema & {in: "foo"} + + @test(eq, { + #Schema: {in: string | [], out: [string | []]} + x: {in: "foo", out: ["foo"]} + }) +} +issue3957: derived: t2: { + #Schema: { + in: string | [...string] + let _flat = list.FlattenN([in], 1) + out: _flat + } + out: #Schema & {in: "foo"} + + @test(eq, { + #Schema: {in: string | [], out: [string | []]} + out: {in: "foo", out: ["foo"]} + }) +} +-- issue3833.cue -- +// evalv3 "field not allowed" regression with embeddings; combining a definition +// that has an open field with another definition via embedding should be allowed. +// https://cuelang.org/issue/3833 +issue3833: ok: { + out: { #A & { a: #B } } + #A: { + a: {b: string, ...} + ... + } + #C: c: string + #B: { + #C & {c: "foo"} + b: "foo" + } + + @test(eq, { + out: {a: {b: "foo", c: "foo"}} + #A: {a: {b: string}} + #C: {c: string} + #B: {c: "foo", b: "foo"} + }) +} +issue3833: evalv2Issue:{ + out: { #A & { a: #B } } + #A: { + a: b: string + ... + } + #C: c: string + #B: { + #C & {c: "foo"} + b: "foo" + } + + @test(err, at=out.a.c, code=eval, + contains="field not allowed", pos=[6:6, 8:9], + hint="key positions are missing", + ) +} +-- issue3837.cue -- +// evalv3 regression with embeddings, disjunctions, and extra fields; a struct +// that embeds a definition and adds extra fields should not cause spurious errors. +// https://cuelang.org/issue/3837 +issue3837: reduced: { + A: { + #Embed + extra: "foo" + } + out: {{ x: A & __no_sharing }} + #Embed: {} + + @test(eq, { + A: {extra: "foo"} + out: {x: {extra: "foo"}} + #Embed: {} + }) +} +issue3837: full: { + #Embed: {} + #A: { + #Embed + extra: "foo" + } + #B: (#C | {}) + #C: bar: string + out: #B & { + bar: "baz" + { + #def: (#A & __no_sharing) + } + } + + @test(eq, { + #Embed: {} + #A: {extra: "foo"} + #B: {bar: string} | {} + #C: {bar: string} + out: {bar: "baz", #def: {extra: "foo"}} + }) +} +-- issue3832.cue -- +// evalv3 "field not allowed" regression with a disjunction and a let field; +// a let binding inside a disjunct should not cause closedness errors. +// https://cuelang.org/issue/3832 +issue3832: { + _person: self: firstName: "Sam" + + #T: { + _subject: { + in: _ + out: { + let self = in.self + outFirstName: self.firstName + } + } + _assert: pass: _ + _assert: { + check!: _ + pass: "never" + } | { + invoke!: _ + // TODO: here, the let from _subject.out gets converted to a + // permanent error,instead of incomplete. + pass: (_subject & {in: invoke}).out + } + results: _assert.pass + } + #T & { + _assert: invoke: _person + } + + @test(eq, { + _person: {self: {firstName: "Sam"}} + #T: _ @test(ignore) + _assert: { + invoke: {self: {firstName: "Sam"}} + pass: {outFirstName: "Sam"} + } + _subject: _ @test(ignore) + results: {outFirstName: "Sam"} + }) +} +-- issue3839.cue -- +// evalv3 closedness regression with embeddings and definitions; embedding a +// definition with an ellipsis inside a non-definition should remain open. +// https://cuelang.org/issue/3839 +issue3839: reduced: { + x: { A & __no_sharing } + x: y: 1 + #B: { + // Note: true with both old semantics and explicitopen + @test(closed) + @test(allows=false, string) + } + A: { + #B + ... + + // Note: true with both old semantics and explicitopen + @test(closed) + @test(allows, string) + } + + @test(eq, {x: {y: 1}, #B: {}, A: {}}) +} +issue3839: full: { + _globals: glb: globalField: "" + + #GlobalContext: globalField: string + #Context: { + glb: #GlobalContext + out: glb + } + out: { + ingress: { + #Ingress & { + #def: (#Context & _globals).out + } + } + + ingress?: { + foo: 1234 + bar: "http" + } + } + #Embed: #def: {...} + + #Ingress: { + #Embed + ... + } + + @test(eq, { + _globals: {glb: {globalField: ""}} + #GlobalContext: {globalField: string} + #Context: {glb: {globalField: string}, out: {globalField: string}} + out: {ingress: {#def: {globalField: ""}, foo: 1234, bar: "http"}} + #Embed: {#def: {}} + #Ingress: {#def: {}} + }) +} +-- chaineddef.cue -- +// evalv3 "field not allowed" regression when embedding a chain of definitions; +// chained optional-field definitions embedded in a struct should not be enforced. +// https://cuelang.org/issue/3920 +// chained definitions should be handled correctly within embeddings. +issue3920: { + out: { + #A + a: b: "out" // do not enforce #B + } + #A: a?: #B + #B: c?: string + + @test(eq, { + out: {a: {b: "out", c?: string}} + #A: {a?: {c?: string}} + #B: {c?: string} + }) +} +onlyCloseDirectStruct: { + #foo: {} + x: {y: {{a: #foo}}} + x: y: b: 1 + + @test(eq, {#foo: {}, x: {y: {a: {}, b: 1}}}) +} +closeInEmbed: { + x: {close({{["d"]: f: int}})} + x: d: e: 1 + + @test(eq, {x: {d: {e: 1, f: int}}}) +} +-- embedelim.cue -- +// evalv3 "field not allowed" regression with nested definitions; eliminating +// an embedded top value from a definition should not incorrectly close the struct. +// https://cuelang.org/issue/3921 +issue3921: top: { + #A: #B + #A: b: string + #B: _ + a: {#A & {}} + + @test(eq, {#A: {b: string}, #B: _, a: {b: string}}) +} +issue3921: hidden: { + #A: #B + #A: _hidden: b: string + #B: {} + a: { #A & { _hidden: {} }} + + @test(eq, { + #A: {_hidden: {b: string}} + #B: {} + a: {_hidden: {b: string}} + }) +} +issue3921: full: { + out: #templateList & #defineMap + #templateList: { + #stepMap: [string]: _ + stepList: [for c in #stepMap {c}] + } + #defineMap: { + #stepMap: foo: #Step & { + image: "bar" + #config: {} + } + stepList: _ + } + #Step: #StepInner & { + image: string + #config: version: string + } + #StepInner: image: string + + @test(eq, { + out: { + #stepMap: {foo: { + image: "bar" + #config: {version: string} + }} + stepList: [{ + image: "bar" + #config: {version: string} + }] + } + #templateList: {#stepMap: {}, stepList: []} + #defineMap: { + #stepMap: {foo: { + image: "bar" + #config: {version: string}} + } + stepList: _ + } + #Step: { + image: string + #config: {version: string} + } + #StepInner: {image: string} + }) +} +-- issue3843.cue -- +// evalv3 "field not allowed" regression when a definition is reused at +// multiple levels and pattern constraints are unified more than once. +// https://cuelang.org/issue/3843 +// Pattern is unified twice. Ensure that deduping is handled correctly. +dedupPattern: t1: p1: { + A: { + #Z: [string]: _ + x: #Z + x: y: z: 1 + } + B: A & __no_sharing + out: A.#Z & B.x + + @test(eq, { + A: {#Z: {}, x: {y: {z: 1}}} + B: {#Z: {}, x: {y: {z: 1}}} + out: {y: {z: 1}} + }) +} +dedupPattern: t1: p2: { + A: { + #Z: [string]: _ + x: #Z + x: y: z: 1 + } + B: A & __no_sharing + out: B.x & A.#Z + + @test(eq, { + A: {#Z: {}, x: {y: {z: 1}}} + B: {#Z: {}, x: {y: {z: 1}}} + out: {y: {z: 1}} + }) +} +-- issue3858.cue -- +// evalv3 "field not allowed" regression with embeddings where a definition +// with an embedded field reference was incorrectly rejected. +// https://cuelang.org/issue/3858 +orig: t1: { + #Image: embed: image: "foo:v1" + #JobConfig: { + image: #Image + job: #Job & { + image.embed + } + } + #Job: { + image: string + vcs: "git" + args: [...string] + env: [string]: string + } + + #Output: { + _in: _ + out: (_in & {}) + } + #Output & { + _in: (#JobConfig & {}).job + } + + @test(eq, { + #Image: {embed: {image: "foo:v1"}} + #JobConfig: { + image: {embed: {image: "foo:v1"}} + job: {image: "foo:v1", vcs: "git", args: [], env: {}} + } + #Job: {image: string, vcs: "git", args: [], env: {}} + #Output: {_in: _, out: {}} + _in: {image: "foo:v1", vcs: "git", args: [], env: {}} + out: {image: "foo:v1", vcs: "git", args: [], env: {}} + }) +} +reduced: t1: { + Y: { + a: e: "foo" + b: X & { a } + } + X: { + e: string + f: 1 // fails in `out` + } + #Z: { + _in: _ + out: _in & __no_sharing + } + #Z & { + _in: Y + } + + @test(eq, { + Y: {a: {e: "foo"}, b: {e: "foo", f: 1}} + X: {e: string, f: 1} + #Z: {_in: _, out: _} + _in: {a: {e: "foo"}, b: {e: "foo", f: 1}} + out: {a: {e: "foo"}, b: {e: "foo", f: 1}} + }) +} +orig: t2: { + #JobConfig: { + image: spec: image: "someimage" + job: #Job & { + image.spec + } + } + #Job: { + image: string + env: "FOO" + } + #Output: { + in: _ + out: (in & {}).input + } + out: #Output & { + in: input: (#JobConfig & {}).job + } + + @test(eq, { + #JobConfig: { + image: {spec: {image: "someimage"}} + job: {image: "someimage", env: "FOO"} + } + #Job: {image: string, env: "FOO"} + #Output: { + in: _ + out: _ @test(ignore) + } + out: { + in: {input: {image: "someimage", env: "FOO"}} + out: {image: "someimage", env: "FOO"} + } + }) +} +reduced: t2: { + Y: { + a: e: "foo" + b: X & { a } + } + X: { + e: string + f: 1 // fails + } + #Z: { + _in: _ + out: _in + } + #Z & { _in: Y } + + @test(eq, { + Y: {a: {e: "foo"}, b: {e: "foo", f: 1}} + X: {e: string, f: 1} + #Z: {_in: _, out: _} + _in: {a: {e: "foo"}, b: {e: "foo", f: 1}} + out: {a: {e: "foo"}, b: {e: "foo", f: 1}} + }) +} +-- issue3934.cue -- +// evalv3 "field not allowed" regression with disjunctions and a comprehension; +// a false-branch comprehension inside a disjunct should not trigger closedness errors. +// https://cuelang.org/issue/3934 +issue3934: { + out: #Foo & { + foo: { + if false { + extra: nested: 123 + } + } + } + #Foo: foo?: null | #Bar | *{bar: 3} + #Bar: { + bar?: int + extra?: null | {...} + } + + @test(eq, { + out: {foo: *{bar: 3} | {extra?: null | {}, bar?: int} | null} + #Foo: {foo?: *{bar: 3} | {bar?: int, extra?: null | {}} | null} + #Bar: {bar?: int, extra?: null | {}} + }) +} +-- large.cue -- +full: { + #Resource: { + someMsg: string + obs: {} | *{missing: true} + + let pickMsg = [ + if obs.missing {msg: "\(someMsg)"}, + {msg: "bar"}, + ][0] + patches: [{ + op: "add" + path: "/metadata" + value: pickMsg.msg + }] + } + + #Patches: [string]: _ + #JSONPatch: { + namespace?: string + patch: [...#JSONOp] + output: #Patches & {(namespace): patch} + } + #JSONOp: { + op: "add" + path: string + value: _ + } | { + op: "remove" + path: string + } + + #Main: { + NS=namespace: string + + output: jsonPatch.output + + let jsonPatch = #JSONPatch & { + let base = #Resource & {} + let withMsg = base & {someMsg: "foo"} + + namespace: NS + + patch: withMsg.patches + } + } + out: (#Main & {namespace: "ns1"}).output + + @test(eq, { + #Resource: _ @test(ignore) + #Patches: _ @test(ignore) + #JSONPatch: _ @test(ignore) + #JSONOp: _ @test(ignore) + #Main: _ @test(ignore) + out: {ns1: [{op: "add", path: "/metadata", value: "foo"}]} + }) +} +-- ellipsis.cue -- +nestedEllipsis: minimal: { + out: #Schema & { extra: "foo" } + #Schema: { + #meta + ... + } + #meta: {} + + @test(eq, {out: {extra: "foo"}, #Schema: {}, #meta: {}}) +} +nestedEllipsis: nestedWithPatterns: { + out: #Schema & { + objs: obj1: extra: "foo" + } + #Schema: { + [_]: [_]: { + #meta + ... + } + #meta: name?: int + objs?: _ + } + + @test(eq, { + out: { + objs: {obj1: {extra: "foo", name?: int}} + #meta: {name?: int} + } + #Schema: {#meta: {name?: int}, objs?: {}} + }) +} +// evalv3 "field not allowed" regression with ellipses since v0.13.0; embedding +// a schema with `...` alongside additional fields should not close the struct. +// https://cuelang.org/issue/4015 +issue4015: reduced: { + #X: { ... } + out: { + // Embedded schema allows `a: _`. Adding `a` below should not change that. + #X + a: b: string + } @test(allows, string) @test(closed) + out: { + a: { + c: "h" + b: "x" + } + } + + @test(eq, {#X: {}, out: {a: {b: "x", c: "h"}}}) +} +issue4015: nested: { + #X: { foo: {...} } + out: { + #X + foo: {a: b: string} @test(allows, string) @test(closed) + } + out: { + foo: a: { + c: "h" + b: "x" + } + } + + @test(eq, {#X: {foo: {}}, out: {foo: {a: {b: "x", c: "h"}}}}) +} +issue4015: full: { + #Schema: { + cfg: { + foo: { + enabled: bool | *false + fooField: string + } + bar: barField: string + } + capacity: int | *3 + } + + #MoreCapacity: { + capacity: 30 + ... + } + + out: #Schema + out: { + #MoreCapacity + cfg: foo: enabled: true + } + out: { + cfg: { + foo: fooField: "h" + bar: barField: "x" + } + + // This one is rather confusing, but true. Note that this should no + // longer hold if this is converted to the explicitopen semantics, in + // which case #Schema applies "monotonically" limiting to its fields. + @test(allows, string) + @test(allows:todo=false, string, hint="for explicit open") + @test(closed) + } + + @test(eq, { + #Schema: { + cfg: { + foo: {enabled: *false | bool, fooField: string} + bar: {barField: string} + } + capacity: *3 | int + } + #MoreCapacity: {capacity: 30} + out: { + cfg: {foo: {enabled: true, fooField: "h"}, bar: {barField: "x"}} + capacity: 30 + } + }) +} +-- issue3964.cue -- +// evalv3 closedness regression since v0.13.1; a definition that embeds another +// definition containing a disjunction should correctly allow matching fields. +// https://cuelang.org/issue/3964 +issue3964: reduced: { + #Output: { #Embedded } + #Embedded: { + name: string + #Unused | #Used + } + #Unused: {} + #Used: {} + + @test(eq, { + #Output: {name: string} + #Embedded: {name: string} + #Unused: {} + #Used: {} + }) +} +issue3964: full: { + out: #Output & { + name: "oauth2" + used: "bar" + } + #Output: { #Embedded } + #Embedded: { + name: string + #Unused | #Used + } + #Unused: unused: string + #Used: used: string + + @test(eq, { + out: {name: "oauth2", used: "bar"} + #Output: {name: string, unused: string} | {name: string, used: string} + #Embedded: {name: string, unused: string} | {name: string, used: string} + #Unused: {unused: string} + #Used: {used: string} + }) +} +-- cycle.cue -- +// evalv3 stack overflow due to latest closedness changes; mutually recursive +// definitions that embed each other caused infinite recursion during evaluation. +// https://cuelang.org/issue/4006 +issue4006: { + #A: { + #B + fieldA: string + } + #B: { #A } + #C: #A & {} + out: #C & #B + + @test(eq, { + #A: {fieldA: string} + #B: {fieldA: string} + #C: {fieldA: string} + out: {fieldA: string} + }) +} +-- out/compile -- +--- chaineddef.cue +{ + issue3920: { + out: { + 〈1;#A〉 + a: { + b: "out" + } + } + #A: { + a?: 〈1;#B〉 + } + #B: { + c?: string + } + } + onlyCloseDirectStruct: { + #foo: {} + x: { + y: { + { + a: 〈3;#foo〉 + } + } + } + x: { + y: { + b: 1 + } + } + } + closeInEmbed: { + x: { + close({ + { + ["d"]: { + f: int + } + } + }) + } + x: { + d: { + e: 1 + } + } + } +} +--- cycle.cue +{ + issue4006: { + #A: { + 〈1;#B〉 + fieldA: string + } + #B: { + 〈1;#A〉 + } + #C: (〈0;#A〉 & {}) + out: (〈0;#C〉 & 〈0;#B〉) + } +} +--- disjunction.cue +{ + issue3947: { + full: { + #Schema: { + allowed?: string + } + _defaults: { + disallowed: (_|*"default value") + } + out: (〈0;#Schema〉 & 〈0;_defaults〉) + } + } + issue3957: { + reduced: { + c: { + a: "bar" + } + c: (〈0;#B〉 & { + a: (string|*"foo") + }) + #B: { + b?: string + } + } + } + issue3957: { + full: { + #oneof: ({ + a: string + }|{ + b?: [ + ...string, + ] + }) + c: (〈0;#oneof〉 & { + a: (string|*"foo") + }) + c: { + a: "bar" + } + } + } + issue3957: { + derived: { + t1: { + #Schema: { + in: (string|[ + ...string, + ]) + out: 〈import;list〉.FlattenN([ + 〈1;in〉, + ], 1) + } + x: (〈0;#Schema〉 & { + in: "foo" + }) + } + } + } + issue3957: { + derived: { + t2: { + #Schema: { + in: (string|[ + ...string, + ]) + let _flat#1 = 〈import;list〉.FlattenN([ + 〈1;in〉, + ], 1) + out: 〈0;let _flat#1〉 + } + out: (〈0;#Schema〉 & { + in: "foo" + }) + } + } + } +} +--- ellipsis.cue +{ + nestedEllipsis: { + minimal: { + out: (〈0;#Schema〉 & { + extra: "foo" + }) + #Schema: { + 〈1;#meta〉 + ... + } + #meta: {} + } + } + nestedEllipsis: { + nestedWithPatterns: { + out: (〈0;#Schema〉 & { + objs: { + obj1: { + extra: "foo" + } + } + }) + #Schema: { + [_]: { + [_]: { + 〈2;#meta〉 + ... + } + } + #meta: { + name?: int + } + objs?: _ + } + } + } + issue4015: { + reduced: { + #X: { + ... + } + out: { + 〈1;#X〉 + a: { + b: string + } + } + out: { + a: { + c: "h" + b: "x" + } + } + } + } + issue4015: { + nested: { + #X: { + foo: { + ... + } + } + out: { + 〈1;#X〉 + foo: { + a: { + b: string + } + } + } + out: { + foo: { + a: { + c: "h" + b: "x" + } + } + } + } + } + issue4015: { + full: { + #Schema: { + cfg: { + foo: { + enabled: (bool|*false) + fooField: string + } + bar: { + barField: string + } + } + capacity: (int|*3) + } + #MoreCapacity: { + capacity: 30 + ... + } + out: 〈0;#Schema〉 + out: { + 〈1;#MoreCapacity〉 + cfg: { + foo: { + enabled: true + } + } + } + out: { + cfg: { + foo: { + fooField: "h" + } + bar: { + barField: "x" + } + } + } + } + } +} +--- embedelim.cue +{ + issue3921: { + top: { + #A: 〈0;#B〉 + #A: { + b: string + } + #B: _ + a: { + (〈1;#A〉 & {}) + } + } + } + issue3921: { + hidden: { + #A: 〈0;#B〉 + #A: { + _hidden: { + b: string + } + } + #B: {} + a: { + (〈1;#A〉 & { + _hidden: {} + }) + } + } + } + issue3921: { + full: { + out: (〈0;#templateList〉 & 〈0;#defineMap〉) + #templateList: { + #stepMap: { + [string]: _ + } + stepList: [ + for _, c in 〈1;#stepMap〉 { + 〈1;c〉 + }, + ] + } + #defineMap: { + #stepMap: { + foo: (〈2;#Step〉 & { + image: "bar" + #config: {} + }) + } + stepList: _ + } + #Step: (〈0;#StepInner〉 & { + image: string + #config: { + version: string + } + }) + #StepInner: { + image: string + } + } + } +} +--- in.cue +{ + embed: { + simple: { + #A: { + b: 1 + } + a: { + 〈1;#A〉 + } + a: { + err: 1 + } + } + } + embed: { + andInStruct: { + #Foo: { + a: int + } + a: { + (〈1;#Foo〉 & { + err: 2 + }) + } + } + } + embed: { + embedDefWithEmbedding: { + #Foo: { + { + a: int + } + } + a: { + (〈1;#Foo〉 & { + err: 2 + }) + } + } + } + embed: { + embedComprehension: { + #Foo: { + if true { + a: int + } + } + a: { + (〈1;#Foo〉 & { + err: 2 + }) + } + } + } + embed: { + fieldWithAnd: { + #A: {} + { + a: (〈1;#A〉 & { + err: 3 + }) + } + } + } + embed: { + embedAndRecursive: { + #A: { + a: int + } + B: { + x: 〈1;#A〉 + } + (〈0;B〉 & { + x: { + err: 2 + } + }) + } + } + embed: { + andEmbed: { + #A: { + b: int + } + #B: { + b: int + } + #D: { + (〈1;#A〉 & 〈1;#B〉) + } + d: (〈0;#D〉 & { + err: 3 + }) + } + } + and: { + transitive: { + ok: { + Z: { + a: string + } + #Y: 〈0;Z〉 + #X: (〈0;#Y〉 & 〈0;Z〉) + out: (〈0;#X〉 & { + a: "foo" + }) + } + } + } + and: { + transitive: { + err: { + Z: { + a: string + } + #Y: 〈0;Z〉 + #X: (〈0;#Y〉 & 〈0;Z〉) + out: (〈0;#X〉 & { + err: "foo" + }) + } + } + } + and: { + transitiveWithEmbed: { + ok: { + Z: { + a: string + } + #X: (〈0;#Y〉 & 〈0;Z〉) + #Y: { + 〈1;Z〉 + } + out: (〈0;#X〉 & { + a: "foo" + }) + } + } + } + and: { + transitiveWithEmbed: { + err: { + Z: { + a: string + } + #X: (〈0;#Y〉 & 〈0;Z〉) + #Y: { + 〈1;Z〉 + } + out: (〈0;#X〉 & { + err: "foo" + }) + } + } + } + embed: { + nonDef: { + t1: { + X: { + a: string + } + #Y: (〈0;#Z〉 & 〈0;X〉) + #Z: { + 〈1;X〉 + b?: string + } + } + } + } + embed: { + defAndHidden: { + full: { + _stepCommon: { + Name: string + } + #Step: (〈0;#Command〉 & 〈0;_stepCommon〉) + #Command: { + 〈1;_stepCommon〉 + Path?: string + } + out: (〈0;#Step〉 & { + Name: "foo" + }) + } + } + } + embed: { + withIndirect: { + A: 〈0;#B〉 + #B: { + b: int + } + (〈0;A〉 & { + err: 2 + }) + } + } +} +--- inline.cue +{ + embedInline: { + #Schema: { + a: "hello" + b: { + { + x: { + c: "foo" + } + }.x + } + b: { + c: string + d: "never printed" + } + } + out: (〈0;#Schema〉 & _|_(no sharing)) + } + issue3853: { + #Schema: { + a: "hello" + b: { + { + x: { + c: "foo" + } + }.x + } + b: { + c: string + d: "never printed" + } + } + out: { + x: (〈1;#Schema〉 & {}).a + }.x + } +} +--- issue3832.cue +{ + issue3832: { + _person: { + self: { + firstName: "Sam" + } + } + #T: { + _subject: { + in: _ + out: { + let self#2 = 〈1;in〉.self + outFirstName: 〈0;let self#2〉.firstName + } + } + _assert: { + pass: _ + } + _assert: ({ + check!: _ + pass: "never" + }|{ + invoke!: _ + pass: (〈1;_subject〉 & { + in: 〈1;invoke〉 + }).out + }) + results: 〈0;_assert〉.pass + } + (〈0;#T〉 & { + _assert: { + invoke: 〈2;_person〉 + } + }) + } +} +--- issue3833.cue +{ + issue3833: { + ok: { + out: { + (〈1;#A〉 & { + a: 〈2;#B〉 + }) + } + #A: { + a: { + b: string + ... + } + ... + } + #C: { + c: string + } + #B: { + (〈1;#C〉 & { + c: "foo" + }) + b: "foo" + } + } + } + issue3833: { + evalv2Issue: { + out: { + (〈1;#A〉 & { + a: 〈2;#B〉 + }) + } + #A: { + a: { + b: string + } + ... + } + #C: { + c: string + } + #B: { + (〈1;#C〉 & { + c: "foo" + }) + b: "foo" + } + } + } +} +--- issue3837.cue +{ + issue3837: { + reduced: { + A: { + 〈1;#Embed〉 + extra: "foo" + } + out: { + { + x: (〈2;A〉 & _|_(no sharing)) + } + } + #Embed: {} + } + } + issue3837: { + full: { + #Embed: {} + #A: { + 〈1;#Embed〉 + extra: "foo" + } + #B: (〈0;#C〉|{}) + #C: { + bar: string + } + out: (〈0;#B〉 & { + bar: "baz" + { + #def: (〈2;#A〉 & _|_(no sharing)) + } + }) + } + } +} +--- issue3839.cue +{ + issue3839: { + reduced: { + x: { + (〈1;A〉 & _|_(no sharing)) + } + x: { + y: 1 + } + #B: {} + A: { + 〈1;#B〉 + ... + } + } + } + issue3839: { + full: { + _globals: { + glb: { + globalField: "" + } + } + #GlobalContext: { + globalField: string + } + #Context: { + glb: 〈1;#GlobalContext〉 + out: 〈0;glb〉 + } + out: { + ingress: { + (〈2;#Ingress〉 & { + #def: (〈3;#Context〉 & 〈3;_globals〉).out + }) + } + ingress?: { + foo: 1234 + bar: "http" + } + } + #Embed: { + #def: { + ... + } + } + #Ingress: { + 〈1;#Embed〉 + ... + } + } + } +} +--- issue3843.cue +{ + dedupPattern: { + t1: { + p1: { + A: { + #Z: { + [string]: _ + } + x: 〈0;#Z〉 + x: { + y: { + z: 1 + } + } + } + B: (〈0;A〉 & _|_(no sharing)) + out: (〈0;A〉.#Z & 〈0;B〉.x) + } + } + } + dedupPattern: { + t1: { + p2: { + A: { + #Z: { + [string]: _ + } + x: 〈0;#Z〉 + x: { + y: { + z: 1 + } + } + } + B: (〈0;A〉 & _|_(no sharing)) + out: (〈0;B〉.x & 〈0;A〉.#Z) + } + } + } +} +--- issue3858.cue +{ + orig: { + t1: { + #Image: { + embed: { + image: "foo:v1" + } + } + #JobConfig: { + image: 〈1;#Image〉 + job: (〈1;#Job〉 & { + 〈1;image〉.embed + }) + } + #Job: { + image: string + vcs: "git" + args: [ + ...string, + ] + env: { + [string]: string + } + } + #Output: { + _in: _ + out: (〈0;_in〉 & {}) + } + (〈0;#Output〉 & { + _in: (〈1;#JobConfig〉 & {}).job + }) + } + } + reduced: { + t1: { + Y: { + a: { + e: "foo" + } + b: (〈1;X〉 & { + 〈1;a〉 + }) + } + X: { + e: string + f: 1 + } + #Z: { + _in: _ + out: (〈0;_in〉 & _|_(no sharing)) + } + (〈0;#Z〉 & { + _in: 〈1;Y〉 + }) + } + } + orig: { + t2: { + #JobConfig: { + image: { + spec: { + image: "someimage" + } + } + job: (〈1;#Job〉 & { + 〈1;image〉.spec + }) + } + #Job: { + image: string + env: "FOO" + } + #Output: { + in: _ + out: (〈0;in〉 & {}).input + } + out: (〈0;#Output〉 & { + in: { + input: (〈2;#JobConfig〉 & {}).job + } + }) + } + } + reduced: { + t2: { + Y: { + a: { + e: "foo" + } + b: (〈1;X〉 & { + 〈1;a〉 + }) + } + X: { + e: string + f: 1 + } + #Z: { + _in: _ + out: 〈0;_in〉 + } + (〈0;#Z〉 & { + _in: 〈1;Y〉 + }) + } + } +} +--- issue3934.cue +{ + issue3934: { + out: (〈0;#Foo〉 & { + foo: { + if false { + extra: { + nested: 123 + } + } + } + }) + #Foo: { + foo?: (null|〈1;#Bar〉|*{ + bar: 3 + }) + } + #Bar: { + bar?: int + extra?: (null|{ + ... + }) + } + } +} +--- issue3964.cue +{ + issue3964: { + reduced: { + #Output: { + 〈1;#Embedded〉 + } + #Embedded: { + name: string + (〈1;#Unused〉|〈1;#Used〉) + } + #Unused: {} + #Used: {} + } + } + issue3964: { + full: { + out: (〈0;#Output〉 & { + name: "oauth2" + used: "bar" + }) + #Output: { + 〈1;#Embedded〉 + } + #Embedded: { + name: string + (〈1;#Unused〉|〈1;#Used〉) + } + #Unused: { + unused: string + } + #Used: { + used: string + } + } + } +} +--- large.cue +{ + full: { + #Resource: { + someMsg: string + obs: ({}|*{ + missing: true + }) + let pickMsg#3 = [ + if 〈1;obs〉.missing { + msg: "\(〈2;someMsg〉)" + }, + { + msg: "bar" + }, + ][0] + patches: [ + { + op: "add" + path: "/metadata" + value: 〈2;let pickMsg#3〉.msg + }, + ] + } + #Patches: { + [string]: _ + } + #JSONPatch: { + namespace?: string + patch: [ + ...〈2;#JSONOp〉, + ] + output: (〈1;#Patches〉 & { + 〈1;namespace〉: 〈1;patch〉 + }) + } + #JSONOp: ({ + op: "add" + path: string + value: _ + }|{ + op: "remove" + path: string + }) + #Main: { + namespace: string + output: 〈0;let jsonPatch#4〉.output + let jsonPatch#4 = (〈1;#JSONPatch〉 & { + let base#7 = (〈2;#Resource〉 & {}) + let withMsg#8 = (〈0;let base#7〉 & { + someMsg: "foo" + }) + namespace: 〈1;namespace〉 + patch: 〈0;let withMsg#8〉.patches + }) + } + out: (〈0;#Main〉 & { + namespace: "ns1" + }).output + } +} +--- validators.cue +{ + embed: { + normalValidator: { + #X: { + 〈import;struct〉.MaxFields(1) + a?: int + b?: int + } + x: 〈0;#X〉 + x: { + err: 1 + } + } + } + embed: { + openValidator: { + t1: { + #X: { + matchN(0, []) + a?: int + b?: int + } + x: 〈0;#X〉 + x: { + err: 1 + } + } + } + } + embed: { + openValidator: { + t2: { + Y: matchN(1, [ + 〈1;X〉, + ]) + X: { + b?: 〈1;Y〉 + } + a: 〈0;X〉 + a: { + b: 1 + } + } + } + } + disjunction: { + withErr: { + t1: { + params: {} + out: (〈0;#Schema1〉 & { + b1: { + b2: { + b3: 〈3;params〉.mayExistLater + } + } + }) + #Schema1: { + b1?: (null|〈1;#Schema2〉) + } + #Schema2: { + b2?: (null|{ + b3?: string + }) + } + } + } + } + embed: { + nestedValidator: { + #types: { + z?: 〈import;list〉.UniqueItems + } + x: { + y: { + z: [ + 1, + ] + } + } + x: { + 〈1;#def〉 + y?: 〈1;#types〉 + } + #def: {} + } + } +} diff --git a/internal/core/compile/testdata/sync/definitions/visibility.txtar b/internal/core/compile/testdata/sync/definitions/visibility.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/definitions/visibility.txtar @@ -0,0 +1,28 @@ +-- in.cue -- +#foo: { + name: string +} +foo: #foo & { + // These should all be allowed. + _name: "foo" + _#name: "bar" + + #name: "baz" +} @test(closed) @test(eq, { + _name: "foo" + _#name: "bar" + #name: "baz" + name: string +}) +-- out/compile -- +--- in.cue +{ + #foo: { + name: string + } + foo: (〈0;#foo〉 & { + _name: "foo" + _#name: "bar" + #name: "baz" + }) +} diff --git a/internal/core/compile/testdata/sync/disjunctions/019_ips.txtar b/internal/core/compile/testdata/sync/disjunctions/019_ips.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/019_ips.txtar @@ -0,0 +1,67 @@ +#name: ips +#evalFull +-- in.cue -- +import "list" + +IP: list.Repeat([uint8], 4) + +Private: + *[ 192, 168, uint8, uint8] | + [ 10, uint8, uint8, uint8] | + [ 172, >=16 & <=32, uint8, uint8] + +Inst: Private & [ _, 10, ...] + +MyIP: Inst & [_, _, 10, 10] @test(eq, [10, 10, 10, 10]) +@test(eq, { + IP: [ + >=0 & <=255 & int, + >=0 & <=255 & int, + >=0 & <=255 & int, + >=0 & <=255 & int + ] + Private: *[192, 168, >=0 & <=255 & int, >=0 & <=255 & int] | + [10, >=0 & <=255 & int, >=0 & <=255 & int, >=0 & <=255 & int] | + [172, >=16 & <=32, >=0 & <=255 & int, >=0 & <=255 & int] + Inst: [ + 10, + 10, + >=0 & <=255 & int, + >=0 & <=255 & int + ] + MyIP: [10, 10, 10, 10] +}) +-- out/compile -- +--- in.cue +{ + IP: 〈import;list〉.Repeat([ + &(int, >=0, <=255), + ], 4) + Private: (*[ + 192, + 168, + &(int, >=0, <=255), + &(int, >=0, <=255), + ]|[ + 10, + &(int, >=0, <=255), + &(int, >=0, <=255), + &(int, >=0, <=255), + ]|[ + 172, + (>=16 & <=32), + &(int, >=0, <=255), + &(int, >=0, <=255), + ]) + Inst: (〈0;Private〉 & [ + _, + 10, + ..., + ]) + MyIP: (〈0;Inst〉 & [ + _, + _, + 10, + 10, + ]) +} diff --git a/internal/core/compile/testdata/sync/disjunctions/confluence.txtar b/internal/core/compile/testdata/sync/disjunctions/confluence.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/confluence.txtar @@ -0,0 +1,53 @@ +-- in.cue -- +import ( + "net" + "strings" +) +// evalv3 regression: disjunctions with conditionals depending on the +// disjunction's own value were left unresolved. +// https://cuelang.org/issue/3993 +issue3993: reduced: { + x: net.IPv4 | =~"fail" + x: { if net.IPv4(x) {=~"^10\\." } } + x: "10.10.10.10" + @test(eq, {x: "10.10.10.10"}) +} + +issue3993: full: { + addr!: string & (net.IPv4 | net.IPv6) + if net.IPv4(addr) { + addr: strings.HasPrefix("10.") + } + if net.IPv6(addr) { + addr: strings.HasPrefix("2a02:") + } + addr: "10.10.10.10" + @test(eq, {addr: "10.10.10.10"}) +} +-- out/compile -- +--- in.cue +{ + issue3993: { + reduced: { + x: (〈import;net〉.IPv4|=~"fail") + x: { + if 〈import;net〉.IPv4(〈1;x〉) { + =~"^10\\." + } + } + x: "10.10.10.10" + } + } + issue3993: { + full: { + addr!: (string & (〈import;net〉.IPv4|〈import;net〉.IPv6)) + if 〈import;net〉.IPv4(〈0;addr〉) { + addr: 〈import;strings〉.HasPrefix("10.") + } + if 〈import;net〉.IPv6(〈0;addr〉) { + addr: 〈import;strings〉.HasPrefix("2a02:") + } + addr: "10.10.10.10" + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/crossembed.txtar b/internal/core/compile/testdata/sync/disjunctions/crossembed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/crossembed.txtar @@ -0,0 +1,38 @@ +# Cross-package embedded disjunction of definitions should correctly +# eliminate branches when unified with a concrete field. +# From issue #4197. +-- cue.mod/module.cue -- +module: "foo.test/main" +language: version: "v0.14.0" +-- in.cue -- +package main + +import "foo.test/main/imported" + +out: imported +out: either: foo: "world" + +@test(eq, { + out: { + either: {foo: "world"} + #Foo: {foo: _} + #Bar: {bar: _} + } +}) +-- imported/imported.cue -- +package imported + +#Foo: foo: _ +#Bar: bar: _ + +{either: #Foo | #Bar} +-- out/compile -- +--- in.cue +{ + out: 〈import;"foo.test/main/imported"〉 + out: { + either: { + foo: "world" + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/defaults.txtar b/internal/core/compile/testdata/sync/disjunctions/defaults.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/defaults.txtar @@ -0,0 +1,60 @@ +-- in.cue -- +passToSingleValue: p1: _ | *((_ | *"x") & "y") @test(eq, *"y" | _) +passToSingleValue: p2: _ | *((*"x" | _) & "y") @test(eq, *"y" | _) +passToSingleValue: p3: *((_ | *"x") & "y") | _ @test(eq, *"y" | _) +passToSingleValue: p4: *((*"x" | _) & "y") | _ @test(eq, *"y" | _) + +// eval: "incomplete value" regression with defaults involving multiple +// definitions; default values that depend on other fields should resolve. +// https://cuelang.org/issue/3779 +issue3779: { + out: #Foo & { + fieldFoo: "foo" + } + #Foo: #Bar & { + fieldFoo: string | *"foo-default" + } + #Bar: { + fieldFoo: _ + fieldBar: string | *fieldFoo + } + @test(eq, { + out: { + fieldFoo: "foo" + fieldBar: *"foo" | string + } + #Foo: { + fieldFoo: *"foo-default" | string + fieldBar: *"foo-default" | string + } + #Bar: {fieldFoo: _, fieldBar: *_ | string} + }) +} +-- out/compile -- +--- in.cue +{ + passToSingleValue: { + p1: (_|*((_|*"x") & "y")) + } + passToSingleValue: { + p2: (_|*((*"x"|_) & "y")) + } + passToSingleValue: { + p3: (*((_|*"x") & "y")|_) + } + passToSingleValue: { + p4: (*((*"x"|_) & "y")|_) + } + issue3779: { + out: (〈0;#Foo〉 & { + fieldFoo: "foo" + }) + #Foo: (〈0;#Bar〉 & { + fieldFoo: (string|*"foo-default") + }) + #Bar: { + fieldFoo: _ + fieldBar: (string|*〈0;fieldFoo〉) + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/defembed.txtar b/internal/core/compile/testdata/sync/disjunctions/defembed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/defembed.txtar @@ -0,0 +1,98 @@ +Interaction between defaults, embedding and disjunctions. + +// TODO: at the moment, using a default will select it. +-- in.cue -- +x: { + // All of these resolve to *2 | 3 + m1: (1 | (*2 | 3)) & (>=2 & <=3) + m2: (1 | (*2 | 3)) & (2 | 3) + m3: (*1 | *(*2 | 3)) & (2 | 3) + @test(eq, {m1: *2 | 3, m2: *2 | 3, m3: *2 | 3}) +} +y1: x & { + {m4: x.m1 + x.m2 + x.m3} +} @test(eq, { + m4: 6 + m1: *2 | 3 + m2: *2 | 3 + m3: *2 | 3 +}) +y2: { + x + {m4: y2.m1 + y2.m2 + y2.m3} + @test(eq, { + m4: 6 + m1: *2 | 3 + m2: *2 | 3 + m3: *2 | 3 + }) +} +Y=y3: { + x + {m4: Y.m1 + Y.m2 + Y.m3} +} +@test(eq, { + m4: 6 + m1: *2 | 3 + m2: *2 | 3 + m3: *2 | 3 +}, at=y3) + +y4: x & { + {m4: y4.m1 + y4.m2 + y4.m3} +} @test(eq, { + m4: 6 + m1: *2 | 3 + m2: *2 | 3 + m3: *2 | 3 +}) + +// Second disjunct in embedding is not possible because of previous declaration +// of `b`, so it should be resolved to {a: 1}. +z: { + b: (*"a" | "b") | "c" + {a: b} | {b: int} + @test(eq, { + b: *"a" | "b" | "c" + a: *"a" | "b" | "c" + }) +} +-- out/compile -- +--- in.cue +{ + x: { + m1: ((1|(*2|3)) & (>=2 & <=3)) + m2: ((1|(*2|3)) & (2|3)) + m3: ((*1|*(*2|3)) & (2|3)) + } + y1: (〈0;x〉 & { + { + m4: ((〈2;x〉.m1 + 〈2;x〉.m2) + 〈2;x〉.m3) + } + }) + y2: { + 〈1;x〉 + { + m4: ((〈2;y2〉.m1 + 〈2;y2〉.m2) + 〈2;y2〉.m3) + } + } + y3: { + 〈1;x〉 + { + m4: ((〈2;y3〉.m1 + 〈2;y3〉.m2) + 〈2;y3〉.m3) + } + } + y4: (〈0;x〉 & { + { + m4: ((〈2;y4〉.m1 + 〈2;y4〉.m2) + 〈2;y4〉.m3) + } + }) + z: { + b: ((*"a"|"b")|"c") + ({ + a: 〈1;b〉 + }|{ + b: int + }) + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/discriminator.txtar b/internal/core/compile/testdata/sync/disjunctions/discriminator.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/discriminator.txtar @@ -0,0 +1,234 @@ +-- in.cue -- +// Important that the test cases below fail with more than just +// an incomplete error, as we want to track the quality of errors. + +// Disjunctions where multiple (or zero) disjuncts match by kind, +// so we cannot discriminate. +noKind: { + manyWithStructEmbed: { + #Def: {<10, _hidden: "field"} | >200 | string + + // The data is an int, but the struct embeds a matching scalar kind too. + out: #Def & 123 @test(err, + suberr=(code=eval, contains="conflicting values", args=[123, string]), + suberr=(code=eval, contains="invalid value", args=[123, <10]), + suberr=(code=eval, contains="invalid value", args=[123, >200]), + pos=[]) + } + manyStructsEmpty: { + #Def: {f1!: int} | {f2!: int} | string + + // The data is a struct, which matches multiple disjunct struct kinds. + out: #Def & {} @test(eq, {f1!: int} | {f2!: int}) + } + manyScalars: { + #Def: 1 | 2 | 3 + + // The data is an int, which matches all of the disjunct kinds. + out: #Def & 123 @test(err, + suberr=(code=eval, contains="conflicting values", args=[1, 123], pos=[-3:9, 0:8, 0:15]), + suberr=(code=eval, contains="conflicting values", args=[2, 123], pos=[-3:13, 0:8, 0:15]), + suberr=(code=eval, contains="conflicting values", args=[3, 123], pos=[-3:17, 0:8, 0:15])) + } + zeroScalars: { + #Def: int | string | null + + // The data is a bool, which matches none of the disjunct scalar kinds. + out: #Def & true @test(err, + suberr=(code=eval, contains="conflicting values", args=[true, int]), + suberr=(code=eval, contains="conflicting values", args=[true, null]), + suberr=(code=eval, contains="conflicting values", args=[true, string]), + pos=[]) + } +} + +// Disjunctions where just one disjunct matches by kind, +// so we can discriminate. +byKind: { + nullableStructRegular: { + #Def1: {f1: null | #Def2} + #Def2: {f2: null | #Def3} + #Def3: {f3: null | int} + + // The data is a struct, not a null. + out: #Def1 & {f1: f2: f3: "not an int"} @test(err, code=eval, + contains="6 errors in empty disjunction", + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:15, 0:8, 0:21]), + suberr=(code=eval, contains="4 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:22, -4:15, 0:8, 0:25]), + suberr=(code=eval, contains="2 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=["not an int", int], pos=[-5:22, -4:22, -3:22, 0:8, 0:29]), + suberr=(code=eval, contains="conflicting values", args=["not an int", null], pos=[-5:22, -4:22, -3:15, 0:8, 0:29]), + pos=[]) + } + + nullableStructRequired: { + #Def1: {f1!: null | #Def2} + #Def2: {f2!: null | #Def3} + #Def3: {f3!: null | int} + + // The data is a struct, not a null. + out: #Def1 & {f1: f2: f3: "not an int"} @test(err, code=eval, + contains="6 errors in empty disjunction", + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:16, 0:8, 0:21]), + suberr=(code=eval, contains="4 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:23, -4:16, 0:8, 0:25]), + suberr=(code=eval, contains="2 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=["not an int", int], pos=[-5:23, -4:23, -3:23, 0:8, 0:29]), + suberr=(code=eval, contains="conflicting values", args=["not an int", null], pos=[-5:23, -4:23, -3:16, 0:8, 0:29]), + pos=[]) + } + + nullableStructOptional: { + #Def1: {f1?: null | #Def2} + #Def2: {f2?: null | #Def3} + #Def3: {f3?: null | int} + + // The data is a struct, not a null. + out: #Def1 & {f1: f2: f3: "not an int"} @test(err, code=eval, + contains="6 errors in empty disjunction", + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:16, 0:8, 0:21]), + suberr=(code=eval, contains="4 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:23, -4:16, 0:8, 0:25]), + suberr=(code=eval, contains="2 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=["not an int", int], pos=[-5:23, -4:23, -3:23, 0:8, 0:29]), + suberr=(code=eval, contains="conflicting values", args=["not an int", null], pos=[-5:23, -4:23, -3:16, 0:8, 0:29]), + pos=[]) + } + + nullableList: { + #Def1: [...null | #Def2] + #Def2: [...null | #Def3] + #Def3: [...null | int] + + // The data is a list, not a null. + out: #Def1 & [[["not an int"]]] @test(err, code=eval, + contains="6 errors in empty disjunction", + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:14, 0:8, 0:17]), + suberr=(code=eval, contains="4 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=[null], pos=[-5:21, -4:14, 0:8, 0:18]), + suberr=(code=eval, contains="2 errors in empty disjunction"), + suberr=(code=eval, contains="conflicting values", args=["not an int", int], pos=[-5:21, -4:21, -3:21, 0:8, 0:19]), + suberr=(code=eval, contains="conflicting values", args=["not an int", null], pos=[-5:21, -4:21, -3:14, 0:8, 0:19]), + pos=[]) + } + + scalarConstraints: { + #Def: >10 | "" | null | false + + // The data is an integer, not any other scalar type. + out: #Def & 5 @test(err, + suberr=(code=eval, contains="conflicting values", args=[5, ""]), + suberr=(code=eval, contains="conflicting values", args=[5, false]), + suberr=(code=eval, contains="conflicting values", args=[5, null]), + suberr=(code=eval, contains="invalid value", args=[5, >10]), + pos=[]) + } +} +-- out/compile -- +--- in.cue +{ + noKind: { + manyWithStructEmbed: { + #Def: ({ + <10 + _hidden: "field" + }|>200|string) + out: (〈0;#Def〉 & 123) + } + manyStructsEmpty: { + #Def: ({ + f1!: int + }|{ + f2!: int + }|string) + out: (〈0;#Def〉 & {}) + } + manyScalars: { + #Def: (1|2|3) + out: (〈0;#Def〉 & 123) + } + zeroScalars: { + #Def: (int|string|null) + out: (〈0;#Def〉 & true) + } + } + byKind: { + nullableStructRegular: { + #Def1: { + f1: (null|〈1;#Def2〉) + } + #Def2: { + f2: (null|〈1;#Def3〉) + } + #Def3: { + f3: (null|int) + } + out: (〈0;#Def1〉 & { + f1: { + f2: { + f3: "not an int" + } + } + }) + } + nullableStructRequired: { + #Def1: { + f1!: (null|〈1;#Def2〉) + } + #Def2: { + f2!: (null|〈1;#Def3〉) + } + #Def3: { + f3!: (null|int) + } + out: (〈0;#Def1〉 & { + f1: { + f2: { + f3: "not an int" + } + } + }) + } + nullableStructOptional: { + #Def1: { + f1?: (null|〈1;#Def2〉) + } + #Def2: { + f2?: (null|〈1;#Def3〉) + } + #Def3: { + f3?: (null|int) + } + out: (〈0;#Def1〉 & { + f1: { + f2: { + f3: "not an int" + } + } + }) + } + nullableList: { + #Def1: [ + ...(null|〈1;#Def2〉), + ] + #Def2: [ + ...(null|〈1;#Def3〉), + ] + #Def3: [ + ...(null|int), + ] + out: (〈0;#Def1〉 & [ + [ + [ + "not an int", + ], + ], + ]) + } + scalarConstraints: { + #Def: (>10|""|null|false) + out: (〈0;#Def〉 & 5) + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/edge.txtar b/internal/core/compile/testdata/sync/disjunctions/edge.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/edge.txtar @@ -0,0 +1,319 @@ +# This file mostly contains edge cases of disjunction semantics. +# We should ensure that all these cases can be derived from thee spec. +# +# Many of these cases were discovered as part of the development of the new +# evaluator that started at v0.7 and do not pass for that version. +-- in.cue -- +cyclicalInsertInDisjunction: { + // We do not allow lookups across unresolved disjunctions. As such, the + // references across disjunctions are not allowed to disambiguate a + // disjunction. + // + // Algorithmically, the distinction between allowing this or not is + // achieved by allowing dereferencing of the node in which a disjunction + // occurs to the disjunct under evaluation. Effectively this is what the + // v0.6 evaluator does. + + ok1: { + // In this case, unifying the comprehension into the processing of the + // disjunctions would _not_ case the reference to cross disjunction + // boundaries. + c: {d: e, e: _} + c: {d: 1, e: 2} | {d : 2, e: 2} + @test(eq, {c: {d: 2, e: 2}}) + } + maybe1: { + // In this case, the reference c.e crosses a disjunction boundary. + // However, since the reference starts from within a disjunction, this + // could be allowed, if we define it to be. + c: d: c.e + c: {d: 1, e: 2} | {d : 2, e: 2} + @test(eq, {c: {d: 2, e: 2}}) + } + err1: { + // This should be an error: to resolve x in c.d, we need to first + // resolve x to a concrete value. As `x` is defined outside the + // disjunction, and the disjunction cannot be resolved without it, `x` + // cannot be evaluated to a concrete value, resulting in an error. + @test(permute, count=6) + x: c.e + c: d: x + c: {d: 1, e: 2} | {d : 2, e: 2} + @test(eq, {x: 2, c: {d: 2, e: 2}}) + } + err2: { + // This is a more obviously erroneous variant of err1. The div in x + // requires a concrete value for c.e. However, the disjunction can only + // be disambiguated as a result of computing x. This means c.e cannot + // be concrete at the time of evaluation. + // NOTE: not so obvious. It clearly works, and arguably it should. + @test(permute, count=6) + x: div(c.e, 2) + c: d: x + c: {d: 1, e: 2} | {d : 2, e: 3} + @test(eq, {x: 1, c: {d: 1, e: 2}}) + } + err3: { + // Here it is clear that d will not disambiguate the disjunction at c. + // So c.e. cannot be resolved. + @test(permute, count=6) + x: c.e @test(err, code=incomplete, contains="unresolved disjunction", pos=[0:6]) + c: d: 1 | 2 | x + c: {d: 1, e: 2} | {d : 2, e: 3} + @test(eq, { + x: _|_ @test(err, code=incomplete, contains="unresolved disjunction", pos=[54:6]) + c: {d: 1, e: 2} | {d: 2, e: 3} + }) + } + @test(eq, { + ok1: {c: {d: 2, e: 2}} + maybe1: {c: {d: 2, e: 2}} + err1: {x: 2, c: {d: 2, e: 2}} + err2: {x: 1, c: {d: 1, e: 2}} + err3: { + x: _|_ @test(err, code=incomplete, contains="unresolved disjunction {d:1,e:2} | {d:2,e:3} (type struct)", pos=[54:6]) + c: {d: 1, e: 2} | {d: 2, e: 3} + } + }) +} + +preseveBottomSemantics: ok: { + // `a: a`, which just says that `a` is `a`, is logically equivalent to + // `a: _`. Consequently, the disjunction `a: a | X` is equivalent to + // `a: _ | X`. As we do not simplify disjunctions, the result is `a: _ | X`. + // However, we could consider simplifying in this case to `a: _` if we can + // come up with a good general mechanism for subsumption. + #x: { #x | {} } + @test(eq, {#x: {}}) +} + +eliminateOpenVariant: ok: { + // We have two structs in the disjunction that are identical in every way + // except openness. TODO: should we disambiguate those? + c: {a: 1} | #b + #b: {a: 1} + @test(eq, {c: {a: 1} | {a: 1}, #b: {a: 1}}) +} + +cyclicSelfElimination: ok: { + // This should resolve to {y: 1} (works for new evaluator) + y: 1 | {y: 1} + y + @test(eq, {y: 1}) +} + +// Value aliases must resolve to the specific disjunct arm's value, +// not the original unresolved disjunction. +issue4251_notC: { + #NotC: x={ + string + _must: true & x != "c" @test(err, code=incomplete, contains="non-concrete value string in operand to !=", pos=[0:17, -2:11, -1:3]) + } + @test(err, at=#NotC._must, =incomplete, contains="non-concrete value string in operand to !=", pos=[3:17, 1:11, 2:3]) + + a: #NotC + a: "a" | "b" + a: "a" @test(eq, {"a", _must: true}) +} +issue4251_notB: { + #NotB: x={ + string + _must: true & x != "b" @test(err, code=incomplete, contains="non-concrete value string in operand to !=", pos=[0:17, -2:11, -1:3]) + } + @test(err, at=#NotB._must, code=incomplete, contains="non-concrete value string in operand to !=", pos=[3:17, 1:11, 2:3]) + a: #NotB + a: "a" | "b" + a: "a" @test(eq, {"a", _must: true}) +} +issue4251_notB_reversed: { + #NotB: x={ + string + _must: true & x != "b" @test(err, code=incomplete, contains="non-concrete value string in operand to !=", pos=[0:17, -2:11, -1:3]) + } + @test(err, at=#NotB._must, code=incomplete, contains="non-concrete value string in operand to !=", pos=[3:17, 1:11, 2:3]) + a: #NotB + a: "b" | "a" + a: "a" @test(eq, {"a", _must: true}) +} +-- panic.cue -- +// This used to cause a panic with evalv3. +panic1: { + #TypeFoo: { + name: "foo" + // Make foo_field here optional and master panics too! + foo_field: string + } + #TypeBar: { + #TypeBar2 + bar_field?: string + } + + #TypeBar2: name: "bar" + + objs: obj1: { + type: #TypeFoo | #TypeBar + type: *objs["missing"] | #TypeFoo | #TypeBar + } @test(eq, { + type: {name: "foo", foo_field: string} | {bar_field?: string, name: "bar"} + }) + + out: #TypeFoo | #TypeBar + out: objs["obj1"].type + @test(eq, { + #TypeFoo: {name: "foo", foo_field: string} + #TypeBar: {bar_field?: string, name: "bar"} + #TypeBar2: {name: "bar"} + objs: { + obj1: { + type: {name: "foo", foo_field: string} | {bar_field?: string, name: "bar"} + } + } + out: {name: "foo", foo_field: string} | {bar_field?: string, name: "bar"} + }) +} +-- out/compile -- +--- in.cue +{ + cyclicalInsertInDisjunction: { + ok1: { + c: { + d: 〈0;e〉 + e: _ + } + c: ({ + d: 1 + e: 2 + }|{ + d: 2 + e: 2 + }) + } + maybe1: { + c: { + d: 〈1;c〉.e + } + c: ({ + d: 1 + e: 2 + }|{ + d: 2 + e: 2 + }) + } + err1: { + x: 〈0;c〉.e + c: { + d: 〈1;x〉 + } + c: ({ + d: 1 + e: 2 + }|{ + d: 2 + e: 2 + }) + } + err2: { + x: div(〈0;c〉.e, 2) + c: { + d: 〈1;x〉 + } + c: ({ + d: 1 + e: 2 + }|{ + d: 2 + e: 3 + }) + } + err3: { + x: 〈0;c〉.e + c: { + d: (1|2|〈1;x〉) + } + c: ({ + d: 1 + e: 2 + }|{ + d: 2 + e: 3 + }) + } + } + preseveBottomSemantics: { + ok: { + #x: { + (〈1;#x〉|{}) + } + } + } + eliminateOpenVariant: { + ok: { + c: ({ + a: 1 + }|〈0;#b〉) + #b: { + a: 1 + } + } + } + cyclicSelfElimination: { + ok: { + y: (1|{ + y: 1 + }) + 〈0;y〉 + } + } + issue4251_notC: { + #NotC: { + string + _must: (true & (〈1〉 != "c")) + } + a: 〈0;#NotC〉 + a: ("a"|"b") + a: "a" + } + issue4251_notB: { + #NotB: { + string + _must: (true & (〈1〉 != "b")) + } + a: 〈0;#NotB〉 + a: ("a"|"b") + a: "a" + } + issue4251_notB_reversed: { + #NotB: { + string + _must: (true & (〈1〉 != "b")) + } + a: 〈0;#NotB〉 + a: ("b"|"a") + a: "a" + } +} +--- panic.cue +{ + panic1: { + #TypeFoo: { + name: "foo" + foo_field: string + } + #TypeBar: { + 〈1;#TypeBar2〉 + bar_field?: string + } + #TypeBar2: { + name: "bar" + } + objs: { + obj1: { + type: (〈2;#TypeFoo〉|〈2;#TypeBar〉) + type: (*〈2;objs〉["missing"]|〈2;#TypeFoo〉|〈2;#TypeBar〉) + } + } + out: (〈0;#TypeFoo〉|〈0;#TypeBar〉) + out: 〈0;objs〉["obj1"].type + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/elimination.txtar b/internal/core/compile/testdata/sync/disjunctions/elimination.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/elimination.txtar @@ -0,0 +1,2480 @@ +// Ensure that disjunction elimination is not done prematurely. + +// Issue #651 +-- in.cue -- +import "struct" + +// Closedness checks should not be triggered too early, or with an improper +// subset of StructInfos. Blindly finalizing partial disjuncts will end up +// doing a closedness check with not all embeddings present, which can lead to +// a field being rejected prematurely. +// +// It should be recursively disabled. +disambiguateClosed: { + b: #Def & a + a: #Def + #Def: {{x: true} | {y: true}} + @test(eq, { + b: {x: true} | {y: true} + a: {x: true} | {y: true} + #Def: {x: true} | {y: true} + }) +} + +// Checks should never be disabled for field matching. +alwaysCheckMatchers1: { + b: {[=~"^xxxx$"]: int} | null + b: {c: string} | null + b: c: "yyyyy" + @test(eq, {b: {c: "yyyyy"}}) +} + +alwaysCheckPatterns2: { + a: #X + a: b + + b: #X + b: c: "yyyyy" + + #X: string | { + c: string + {[=~"^xxxx$"]: int} + } + @test(eq, { + a: {c: "yyyyy"} + b: {c: "yyyyy"} + #X: string | {c: string} + }) +} + +nestedNonMonotonic: resolved: n1: { + x: {a: struct.MinFields(2)} | null + x: {a: c: 1} | null + x: {a: d: 1} | null + @test(eq, {x: {a: {c: 1, d: 1}} | null}) +} + +nestedNonMonotonic: resolved: n2: { + x: {a: b: struct.MinFields(2)} | null + x: {a: b: c: 1} | null + x: {a: b: d: 1} | null + @test(eq, {x: {a: {b: {c: 1, d: 1}}} | null}) +} + +nestedNonMonotonic: eliminated: n1: p1: { + x: {a: struct.MaxFields(1)} | null + x: {a: c: 1} | null + x: {a: d: 1} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: eliminated: n1: p2: { + x: {a: c: 1} | null + x: {a: struct.MaxFields(1)} | null + x: {a: d: 1} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: eliminated: n1: p2: { + x: {a: c: 1} | null + x: {a: d: 1} | null + x: {a: struct.MaxFields(1)} | null + // TODO: Should be p3, fix. +} + +nestedNonMonotonic: eliminated: n2: p1: { + x: {a: b: struct.MaxFields(1)} | null + x: {a: b: c: 1} | null + x: {a: b: d: 1} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: eliminated: n2: p2: { + x: {a: b: c: 1} | null + x: {a: b: struct.MaxFields(1)} | null + x: {a: b: d: 1} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: eliminated: n2: p2: { + x: {a: b: c: 1} | null + x: {a: b: d: 1} | null + x: {a: b: struct.MaxFields(1)} | null + // TODO: should be p3 +} + +// TODO: should be incomplete. +nestedNonMonotonic: incomplete: a: n1: p1: { + x: {a: struct.MinFields(2)} | null + x: {a: c: 1} | null + @test(eq, {x: null}) + @test(eq:todo, {x: {a: {c: 1} & struct.MinFields(2)} | null}) +} + +// TODO: should be incomplete. +nestedNonMonotonic: incomplete: a: n1: p2: { + x: {a: c: 1} | null + x: {a: struct.MinFields(2)} | null + @test(eq, {x: null}) + @test(eq:todo, {x: {a: {c: 1} & struct.MinFields(2)} | null}) +} + +nestedNonMonotonic: incomplete: a: n2: p1: { + x: {a: b: struct.MinFields(2)} | null + x: {a: b: c: 1} | null + @test(eq, {x: {a: {b: {c: 1}}} | null}) +} + +nestedNonMonotonic: incomplete: a: n2: p2: { + x: {a: b: c: 1} | null + x: {a: b: struct.MinFields(2)} | null + @test(eq, {x: {a: {b: {c: 1}}} | null}) +} + +nestedNonMonotonic: incomplete: b: n1: p1: { + x: {a: struct.MinFields(3)} | null + x: {a: c: 1} | null + x: {a: d: 1} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: incomplete: b: n1: p2: { + x: {a: c: 1} | null + x: {a: struct.MinFields(3)} | null + x: {a: d: 1} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: incomplete: b: n1: p3: { + x: {a: c: 1} | null + x: {a: d: 1} | null + x: {a: struct.MinFields(3)} | null + @test(eq, {x: null}) +} + +nestedNonMonotonic: incomplete: b: n2: p1: { + x: {a: b: struct.MinFields(3)} | null + x: {a: b: c: 1} | null + x: {a: b: d: 1} | null + @test(eq, {x: {a: {b: {c: 1, d: 1}}} | null}) +} + +nestedNonMonotonic: incomplete: b: n2: p1: { + x: {a: b: c: 1} | null + x: {a: b: struct.MinFields(3)} | null + x: {a: b: d: 1} | null + @test(eq) // TODO: rename to p2 +} + +nestedNonMonotonic: incomplete: b: n2: p1: { + x: {a: b: c: 1} | null + x: {a: b: d: 1} | null + x: {a: b: struct.MinFields(3)} | null + @test(eq, {x: {a: {b: {c: 1, d: 1}}} | null}) // TODO: rename to p3 +} + +preserveClosedness: small: p1: { + #A: #B & {a: string} + #B: { + *{} | {a: string} + *{} | {b: int} + } + @test(eq, { + #A: *{a: string} | {a: string, b: int} + #B: *{} | {b: int} | {a: string} | {a: string, b: int} + }) +} + +preserveClosedness: small: p2: { + #A: #B & {a: string} + #B: { + {a: string} | *{} + *{} | {b: int} + } + @test(eq, { + #A: *{a: string} | {a: string, b: int} + #B: *{} | {a: string, b: int} | {a: string} | {b: int} + }) +} + +preserveClosedness: medium: p1: { + #A: #B & {a: string} + #B: { + *{} | {a: string} | {b: string} + *{} | {c: int} | {d: string} + } + @test(eq, { + #A: *{a: string} | {a: string, c: int} | {a: string, d: string} + #B: *{} | {c: int} | {d: string} | {a: string} | {a: string, c: int} | {a: string, d: string} | {b: string} | {b: string, c: int} | {b: string, d: string} + }) +} + +preserveClosedness: medium: p2: { + #A: #B & {a: string} + #B: { + {a: string} | *{} | {b: string} + *{} | {c: int} | {d: string} + } + @test(eq, { + #A: *{a: string} | {a: string, c: int} | {a: string, d: string} + #B: *{} | {a: string, c: int} | {a: string, d: string} | {a: string} | {c: int} | {d: string} | {b: string} | {b: string, c: int} | {b: string, d: string} + }) +} + +preserveClosedness: medium: p3: { + #A: #B & {a: string} + #B: { + {a: string} | {b: string} | *{} + *{} | {c: int} | {d: string} + } + @test(eq, { + #A: *{a: string} | {a: string, c: int} | {a: string, d: string} + #B: *{} | {a: string, c: int} | {a: string, d: string} | {b: string} | {b: string, c: int} | {b: string, d: string} | {a: string} | {c: int} | {d: string} + }) +} + +// If an error occurred in the last disjunction, it may sometimes be propagated +// to parent nodes. This, in turn, could lead to references to such field +// to fail with that error. +noChildError: _ +noChildError: issue1608: { + myValue: #type & {fieldName: "some string"} + #type: fieldName: #subtype + + #subtype: string | {foo: string} | {bar: #subtype} + @test(eq, { + myValue: {fieldName: "some string"} + #type: {fieldName: string | {foo: string}} + #subtype: string | {foo: string} + }) +} + +noChildError: t1: { + #D: {b: string} | {c: #D } + o: #D & {b: "test"} + @test(eq, {#D: {b: string}, o: {b: "test"}}) +} + +noChildError: t2: { + o: #D & {b: "test"} + #D: {b: string} | {c: #D } + @test(eq, {o: {b: "test"}, #D: {b: string}}) +} + +noChildError: t3: { + #D: {a: null} | {b: string} | {c: #D } + o: #D & {b: "test"} + @test(eq, { + #D: {a: null} | {b: string} + o: {b: "test"} + }) +} + +noChildError: t4: { + o: #D & {b: "test"} + #D: {a: null} | {b: string} | {c: #D } + @test(eq, { + o: {b: "test"} + #D: {a: null} | {b: string} + }) +} + + +issue1924: t1: { + m: a: 2 + x: *[m.b] | 2 + @test(eq, {m: {a: 2}, x: 2}) +} +issue1924: t2: { + m: a: 2 + x: *{v: m.b} | 3 + @test(eq, {m: {a: 2}, x: 3}) +} +issue1924: t3: { + m: a: 2 + x: *m.b | 1 + @test(eq, {m: {a: 2}, x: 1}) +} + +// should eliminate erroneous comprehension and pass +issue1838: t1: { + p?: [] + a: [for k in p {k}] | null + @test(eq, {p?: [], a: null}) +} +issue1838: t2: { + p?: [] + a: null | [for k in p {k}] + @test(eq, {p?: [], a: null}) +} + +noHang: { + // This should terminate. + #T: ["a", #T] | ["d", ...#T] + + x: #T + + #X: x + #X: #T + @test(eq, {#T: ["d"], x: ["d"], #X: ["d"]}) +} + +issue1940: { + #T: ["a", #T] | ["b", #T] | ["c", #T] | ["d", [...#T]] + + #A: type: #T + + #B: [string]: #A + + #C: #B & { + x: #A + } + @test(eq, { + #T: ["d", []] + #A: {type: ["d", []]} + #B: {} + #C: {x: {type: ["d", []]}} + }) +} + +-- issue2209full.cue -- +// Evaluator 0.5 regression where disjunctions combined with comprehensions +// produced incorrect results or spurious errors. +// https://cuelang.org/issue/2209 +// TODO: fix + +issue2209: simplified: t1: { + #SpecFoo: foo: min: 1 + #SpecBar: bar: min: 1 + spec: bar: {} + spec: #SpecFoo | #SpecBar + out: { + {nullFoo: null} | {nullBar: null} + {minFoo: int} | {minBar: int} + if X.bar != _|_ { + minBar: X.bar.min + } + X: spec + } + @test(eq, { + #SpecFoo: {foo: {min: 1}} + #SpecBar: {bar: {min: 1}} + spec: {bar: {min: 1}} + out: { + minBar: 1 + X: {bar: {min: 1}} + nullFoo: null + minFoo: int + } | { + minBar: 1 + X: {bar: {min: 1}} + nullFoo: null + } | { + minBar: 1 + X: {bar: {min: 1}} + nullBar: null, + minFoo: int + } | { + minBar: 1 + X: {bar: {min: 1}} + nullBar: null + } + }) +} + +issue2209: simplified: t2: { + #SpecFoo: foo: {} + #SpecBar: bar: x: 1 + spec: bar: {} + spec: *#SpecFoo | #SpecBar + if spec.bar != _|_ { + BAZ: spec.bar.x + } + {f1: int} | {b2: int} + {f2: int} | {b2: int} + @test(eq, { + #SpecFoo: {foo: {}} + #SpecBar: {bar: {x: 1}} + spec: {bar: {x: 1}} + BAZ: 1 + f1: int + f2: int + } | { + #SpecFoo: {foo: {}} + #SpecBar: {bar: {x: 1}} + spec: {bar: {x: 1}} + BAZ: 1 + f1: int + b2: int + } | { + #SpecFoo: {foo: {}} + #SpecBar: {bar: {x: 1}} + spec: {bar: {x: 1}} + BAZ: 1 + b2: int + f2: int + } | { + #SpecFoo: {foo: {}} + #SpecBar: {bar: {x: 1}} + spec: {bar: {x: 1}} + BAZ: 1 + b2: int + }) +} + +// This test fails for 0.4 and 0.5. +issue2209: simplified: t3: { + #A: v: 1 + {f1: int} | {b2: int} + {f2: int} | {b2: int} + BAZ: S.y + S: *#A | #B + #B: {x: 1, y: 1} + S: x: 1 + @test(eq, { + #A: {v: 1} + BAZ: 1 + S: {x: 1, y: 1} + #B: {x: 1, y: 1} + f1: int + f2: int + } | { + #A: {v: 1} + BAZ: 1 + S: {x: 1, y: 1} + #B: {x: 1, y: 1} + f1: int + b2: int + } | { + #A: {v: 1} + BAZ: 1 + S: {x: 1, y: 1} + #B: {x: 1, y: 1} + b2: int + f2: int + } | { + #A: {v: 1} + BAZ: 1 + S: {x: 1, y: 1} + #B: {x: 1, y: 1} + b2: int + }) +} + +issue2209: full: { + Foo: #Abstract & {spec: foo: {}} + @test(shareID=FooSpec, at=Foo.spec) + @test(shareID=FooSpec, at=Foo.resource._X.spec) + @test(eq, at=Foo, { + spec: {foo: {min: *10 | int, max: *20 | int}} + resource: { + _X: spec: {foo: {min: *10 | int, max: *20 | int}} + spec: *{ + minFoo: *10 | int + maxFoo: *20 | int + minBar?: null + maxBar?: null + hoge?: null | bool + fuga?: null + } | { + minFoo: *10 | int + maxFoo: *20 | int + minBar?: null + maxBar?: null + hoge?: null + fuga?: null | bool + } + } + }) + + Bar: #Abstract & {spec: bar: {}} + @test(shareID=BarSpec, at=Bar.spec) + @test(shareID=BarSpec, at=Bar.resource._X.spec) + + #Abstract: X={ + spec: _#Spec + + resource: _Thing & {_X: spec: X.spec} + } + + _#Spec: *_#SpecFoo | _#SpecBar + + _#SpecFoo: { + foo: { + min: int | *10 + max: int | *20 + } + } + + _#SpecBar: { + bar: { + min: int | *30 + max: int | *40 + } + } + + _Thing: #Constrained & { + _X: _ + + spec: { + if _X.spec.foo != _|_ { + minFoo: _X.spec.foo.min + maxFoo: _X.spec.foo.max + } + + if _X.spec.bar != _|_ { + minBar: _X.spec.bar.min + maxBar: _X.spec.bar.max + } + } + } + + #Constrained: #Base & { + spec: { + minFoo: int | *10 + maxFoo: int | *20 + minBar?: null + maxBar?: null + } | { + minBar: int | *30 + maxBar: int | *40 + minFoo?: null + maxFoo?: null + } + + spec: *{ + fuga?: null + } | { + hoge?: null + } + } + + #Base: { + spec: { + minFoo?: null | int + maxFoo?: null | int + minBar?: null | int + maxBar?: null | int + + hoge?: null | bool + fuga?: null | bool + } + } + + @test(eq, at=Bar, { + spec: {bar: {min: *30 | int, max: *40 | int}} + resource: { + _X: spec: {bar: {min: *30 | int, max: *40 | int}} + spec: *{ + minFoo?: null + maxFoo?: null + minBar: *30 | int + maxBar: *40 | int + hoge?: null | bool + fuga?: null + } | { + minFoo?: null + maxFoo?: null + minBar: *30 | int + maxBar: *40 | int + hoge?: null + fuga?: null | bool + } + } + }) + // #Abstract: { + // spec: *{ + // foo: {min: *10 | int, max: *20 | int} + // } | { + // bar: {min: *30 | int, max: *40 | int} + // } + // resource: { + // _X: { + // spec: *{ + // foo: {min: *10 | int, max: *20 | int} + // } | { + // bar: {min: *30 | int, max: *40 | int} + // } + // } + // spec: *{ + // minFoo: *10 | int + // maxFoo: *20 | int + // minBar?: null + // maxBar?: null + // hoge?: null | bool + // fuga?: null + // } | { + // minFoo: *10 | int + // maxFoo: *20 | int + // minBar?: null + // maxBar?: null + // hoge?: null + // fuga?: null | bool + // } + // } + // } + // _#Spec: *{ + // foo: {min: *10 | int, max: *20 | int} + // } | { + // bar: {min: *30 | int, max: *40 | int} + // } + // _#SpecFoo: {foo: {min: *10 | int, max: *20 | int}} + // _#SpecBar: {bar: {min: *30 | int, max: *40 | int}} + // _Thing: { + // _X: _ + // spec: *{ + // minFoo: *10 | int + // maxFoo: *20 | int + // minBar?: null + // maxBar?: null + // hoge?: null | bool + // fuga?: null + // } | *{ + // minFoo?: null + // maxFoo?: null + // minBar: *30 | int + // maxBar: *40 | int + // hoge?: null | bool + // fuga?: null + // } | { + // minFoo: *10 | int + // maxFoo: *20 | int + // minBar?: null + // maxBar?: null + // hoge?: null + // fuga?: null | bool + // } | { + // minFoo?: null + // maxFoo?: null + // minBar: *30 | int + // maxBar: *40 | int + // hoge?: null + // fuga?: null | bool} + // } + // #Constrained: { + // spec: *{minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null | bool, fuga?: null} | *{minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null | bool, fuga?: null + // } | { + // minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null, fuga?: null | bool + // } | { + // minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null, fuga?: null | bool} + // } + // #Base: { + // spec: { + // minFoo?: null | int + // maxFoo?: null | int + // minBar?: null | int + // maxBar?: null | int + // hoge?: null | bool + // fuga?: null | bool + // } + // } + // }) +} + + +-- issue2246.cue -- +// Evaluator regression where repeated use of an embedded disjunction resulted +// in spurious "field not allowed" errors. +// https://cuelang.org/issue/2246 +issue2246: simplified: { + #FormFoo: fooID: string + #FormBar: barID: string + #Form: { #FormFoo | #FormBar } + + data: {fooID: "123"} + out1: #Form & data + out2: #Form & out1 + @test(eq, { + #FormFoo: {fooID: string} + #FormBar: {barID: string} + #Form: {fooID: string} | {barID: string} + data: {fooID: "123"} + out1: {fooID: "123"} + out2: {fooID: "123"} + }) +} +issue2246: full: { + data: forms: [{ + fooID: "00-0000001" + }] + + form1040: (#compute & {in: data}).out + + #K1: { + #_base: common: 3 + #FormFoo: { + #_base + fooID: string + } + #FormBar: { + #_base + barID: string + } + #Form: { + #FormFoo | #FormBar + } + } + + #Input: { + forms: [...#K1.#Form] + } + + #summarizeReturn: { + in: #Input + out: [for k in in.forms { k.common }] + } + + #compute: { + in: #Input + out: (#summarizeReturn & {"in": in}).out + } + @test(eq, { + data: {forms: [{ + fooID: "00-0000001" + }]} + form1040: [3] + #K1: { + #_base: {common: 3} + #FormFoo: {fooID: string, common: 3} + #FormBar: {barID: string, common: 3} + #Form: {fooID: string, common: 3} | {barID: string, common: 3} + } + #Input: {forms: []} + #summarizeReturn: {in: {forms: []}, out: []} + #compute: {in: {forms: []}, out: []} + }) +} + +-- issue2263.cue -- +// Disjunction regression in v0.5.0-beta.5 where multiple embedded disjunctions +// in a definition were not evaluated correctly. +// https://cuelang.org/issue/2263 +issue2263: simplified: { + metrics: #Metric + #Metric: { + #IDSource | {} + #TargetAverage | {} + } + + metrics: { + id: "foo" + avg: 60 + } + + #IDSource: id: string + #TargetAverage: avg: number + @test(eq, { + metrics: {id: "foo", avg: 60} + #Metric: {id: string, avg: number} | {id: string} | {avg: number} | {} + #IDSource: {id: string} + #TargetAverage: {avg: number} + }) +} +issue2263: full: { + metrics: [...#Metric] + + metrics: [{ + id: "foo" + avg: 60 + }, { + id: "bar" + value: 80 + }, { + uri: "baz" + avg: 70 + }, { + uri: "qux" + value: 90 + }] + + #Metric: { + #Source + #Target + } + + #Source: + #IDSource | + #URISource + + #Target: + #TargetAverage | + #TargetValue + + #IDSource: { + id: string + } + + #URISource: { + uri: string + } + + #TargetAverage: { + avg: number + } + + #TargetValue: { + value: number + } + @test(eq, { + metrics: [{ + avg: 60 + id: "foo" + }, { + id: "bar" + value: 80 + }, { + avg: 70 + uri: "baz" + }, { + uri: "qux" + value: 90 + }] + #Metric: {id: string, avg: number} | {id: string, value: number} | {uri: string, avg: number} | {uri: string, value: number} + #Source: {id: string} | {uri: string} + #Target: {avg: number} | {value: number} + #IDSource: {id: string} + #URISource: {uri: string} + #TargetAverage: {avg: number} + #TargetValue: {value: number} + }) +} +-- issue1417.cue -- +// Regression where disjuncts sometimes behaved like conjuncts, causing +// incorrect unification of disjunction members. +// https://cuelang.org/issue/1417 +issue1417: { + #ID: !~"^a" | =~"^ab$" | =~"^aB$" + #ID: =~"^a" | !~"[A-Z]" + ids: [...#ID] & ["xyz", "ab", "aB"] + @test(eq, { + #ID: !~"^a" & =~"^a" | !~"^a" & !~"[A-Z]" | =~"^ab$" & =~"^a" | =~"^ab$" & !~"[A-Z]" | =~"^aB$" & =~"^a" | =~"^aB$" & !~"[A-Z]" + ids: ["xyz", "ab", "aB"] + }) +} +-- issue3149.cue -- +// Evaluator regression where unifying disjunctions incorrectly failed to +// validate a fixed value that satisfied the constraint. +// https://cuelang.org/issue/3149 +issue3149: { + #valid: { + name!: ( (=~"^Foo") | "an exception") & ( (=~"Foo$") | "an exception") + } + list: [...#valid] + list: [ + {name: "FooBarFoo"}, + {name: "FooBazFoo"}, + {name: "FooQuuxFoo"}, + {name: "an exception"}, + ] + @test(eq, { + #valid: { + name!: =~"^Foo" & =~"Foo$" | "an exception" + } + list: [{ + name: "FooBarFoo" + }, { + name: "FooBazFoo" + }, { + name: "FooQuuxFoo" + }, { + name: "an exception" + }] + }) +} +-- issue770.cue -- +// Default value resolution issue where chained pattern constraints with default +// disjunctions did not propagate defaults correctly. +// https://cuelang.org/issue/770 +issue770: { + #A: { + v: "a" | "b" | "c" + } + h: [string]: #A + h: a: { + v: *"a" | string + } + h: [=~"^b"]: { + v: *h.a.v | string + } + h: [=~"^c"]: { + v: *h.b.v | string + } + h: b: _ + h: boo: _ + h: c: _ + h: coo: _ + @test(eq, { + #A: {v: "a" | "b" | "c"} + h: { + a: {v: *"a" | "b" | "c"} + b: {v: *"a" | "b" | "c"} + boo: {v: *"a" | "b" | "c"} + c: {v: *"a" | "b" | "c"} + coo: {v: *"a" | "b" | "c"} + } + }) +} +-- issue3528.cue -- +// evalv3 "incDependent: already closed" panic with repeated disjunctions +// and definitions in workflow container schemas. +// https://cuelang.org/issue/3528 +issue3528: original: { + workflows: [...#Workflow] + workflows: [test] + + test: #Workflow & {} + + #Workflow: { + container: [string]: string | #container + #container: string | {volumes?: [...string]} + } + @test(eq, { + workflows: [ + {container: {}, #container: string | {volumes?: []}}, + ] + test: { + container: {} + #container: string | {volumes?: []} + } + #Workflow: { + container: {} + #container: string | {volumes?: []} + } + }) +} +issue3528: reduced: { + a?: #A + a: #A & {} + #A: { + A: [string]: 1 | #a + #a: 2 | {v: 1} + } + @test(eq, { + a: {A: {}, #a: 2 | {v: 1}} + #A: {A: {}, #a: 2 | {v: 1}} + }) +} +issue3528: counter: { + @test(eq, {}) +} +issue3528: nested: t1: { + {v: 1} | (2 | 3) + {v: 1} | (2 | 3) + {v: 1} | (2 | 3) + {v: 1} | (2 | 3) + @test(eq, {v: 1} | { + 2 + @test(eq) + } | { + 3 + @test(eq) + }) +} +issue3528: nested: t2: { + {v: 1} | 2 + {v: 1} | (2 | 3) + {v: 1} | 2 + {v: 1} | 2 + @test(eq, {v: 1} | { + 2 + @test(eq) + }) +} +-- issue3784.cue -- +// evalv3 regressions with "conflicting values" and "field not allowed" errors +// when evaluating schemas similar to the GitHub Terraform provider schema. +// https://cuelang.org/issue/3784 +issue3784: reduced: { + #Schema: a: { + kind: "A" + b: c?: string + b: {} + } | { + kind: "B" + } + + out: #Schema + out: a: { + kind: "A" + b: c: "x" + } + @test(eq, { + #Schema: { + a: {kind: "A", b: {c?: string}} | {kind: "B"} + } + out: {a: {kind: "A", b: {c: "x"}}} + }) +} +issue3784: full: { + #Schema: { + pages?: { + build_type?: "legacy" | "workflow" + source?: { + branch?: string + path?: string + } + cname?: string + } + pages?: { + build_type!: "legacy" + source!: { + branch!: _ + } + } | close({ + build_type!: "workflow" + cname?: _ + }) + } + out: #Schema & { + pages: { + cname: "foo.com" + build_type: "legacy" + source: { + branch: "main" + path: "/" + } + } + } + @test(eq, { + #Schema: { + pages?: {build_type!: "legacy", source!: {branch!: string, path?: string}, cname?: string} | {build_type!: "workflow", source?: {branch?: string, path?: string}, cname?: string} + } + out: { + pages: { + cname: "foo.com" + build_type: "legacy" + source: {branch: "main", path: "/"} + } + } + }) +} +issue3784: variant1: { + #Schema: { + pages: { + build_type?: "legacy" | "workflow" + source: { + branch?: string + path?: string + } + cname?: string + } + pages?: { + build_type!: "legacy" + source!: { + branch!: _ + } + } | close({ + build_type!: "workflow" + cname?: _ + }) + } + @test(eq, { + #Schema: { + pages: { + build_type!: "legacy" + source: {branch!: string, path?: string} + cname?: string + } + } + }) +} +issue3784: variant2: { + #Schema: { + build_type!: "legacy" + source!: { + branch!: _ + } + } | close({ + build_type!: "workflow" + cname?: _ + }) + a: #Schema + a: { + build_type?: "legacy" | "workflow" + source: { + branch?: string + path?: string + } + cname?: string + } + @test(eq, { + #Schema: {build_type!: "legacy", source!: {branch!: _}} | {build_type!: "workflow", cname?: _} + a: { + build_type!: "legacy" + source: { + branch!: string + path?: _|_ @test(err, code=eval, contains="issue3784.variant2.a.source.path: field not allowed", pos=[113:4]) + } + cname?: _|_ @test(err, code=eval, contains="issue3784.variant2.a.cname: field not allowed", pos=[115:3]) + } + }) +} +-- issue3958.cue -- +// evalv3 regression where unifying an odd number of default disjunctions no +// longer produced an error as expected. +// https://cuelang.org/issue/3958 +issue3958: t1: { + #schema: int | *1 + #schema: int | *3 + + test1: #schema & {int | *2} + test2: #schema & {int | *4} + @test(eq, { + #schema: int | 3 | 1 + test1: int | 3 | 1 | 2 + test2: int | 3 | 1 | 4 + }) +} +issue3958: t2: { + a: (int | *4) & (int | *1) & (int | *3) & (int | *8) + b: (int | *4) & (int | *1) & (int | *3) + @test(eq, { + a: int | 8 | 3 | 1 | 4 + b: int | 3 | 1 | 4 + }) +} +-- issue2685.cue -- +// Nested definition with a default value incorrectly took the default value +// even when a concrete value was provided via unification. +// https://cuelang.org/issue/2685 +issue2685: { + #Foo: { + bar: int + opt?: int + } | *{ + opt: int + } + + foo: #Foo + foo: bar: 0 + + { + foo: #Foo + } + @test(eq, { + #Foo: *{opt: int} | {bar: int, opt?: int} + foo: {bar: 0, opt?: int} + }) +} +-- out/compile -- +--- in.cue +{ + disambiguateClosed: { + b: (〈0;#Def〉 & 〈0;a〉) + a: 〈0;#Def〉 + #Def: { + ({ + x: true + }|{ + y: true + }) + } + } + alwaysCheckMatchers1: { + b: ({ + [=~"^xxxx$"]: int + }|null) + b: ({ + c: string + }|null) + b: { + c: "yyyyy" + } + } + alwaysCheckPatterns2: { + a: 〈0;#X〉 + a: 〈0;b〉 + b: 〈0;#X〉 + b: { + c: "yyyyy" + } + #X: (string|{ + c: string + { + [=~"^xxxx$"]: int + } + }) + } + nestedNonMonotonic: { + resolved: { + n1: { + x: ({ + a: 〈import;struct〉.MinFields(2) + }|null) + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: { + d: 1 + } + }|null) + } + } + } + nestedNonMonotonic: { + resolved: { + n2: { + x: ({ + a: { + b: 〈import;struct〉.MinFields(2) + } + }|null) + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + } + } + } + nestedNonMonotonic: { + eliminated: { + n1: { + p1: { + x: ({ + a: 〈import;struct〉.MaxFields(1) + }|null) + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: { + d: 1 + } + }|null) + } + } + } + } + nestedNonMonotonic: { + eliminated: { + n1: { + p2: { + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: 〈import;struct〉.MaxFields(1) + }|null) + x: ({ + a: { + d: 1 + } + }|null) + } + } + } + } + nestedNonMonotonic: { + eliminated: { + n1: { + p2: { + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: { + d: 1 + } + }|null) + x: ({ + a: 〈import;struct〉.MaxFields(1) + }|null) + } + } + } + } + nestedNonMonotonic: { + eliminated: { + n2: { + p1: { + x: ({ + a: { + b: 〈import;struct〉.MaxFields(1) + } + }|null) + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + } + } + } + } + nestedNonMonotonic: { + eliminated: { + n2: { + p2: { + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: 〈import;struct〉.MaxFields(1) + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + } + } + } + } + nestedNonMonotonic: { + eliminated: { + n2: { + p2: { + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + x: ({ + a: { + b: 〈import;struct〉.MaxFields(1) + } + }|null) + } + } + } + } + nestedNonMonotonic: { + incomplete: { + a: { + n1: { + p1: { + x: ({ + a: 〈import;struct〉.MinFields(2) + }|null) + x: ({ + a: { + c: 1 + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + a: { + n1: { + p2: { + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: 〈import;struct〉.MinFields(2) + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + a: { + n2: { + p1: { + x: ({ + a: { + b: 〈import;struct〉.MinFields(2) + } + }|null) + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + a: { + n2: { + p2: { + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: 〈import;struct〉.MinFields(2) + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + b: { + n1: { + p1: { + x: ({ + a: 〈import;struct〉.MinFields(3) + }|null) + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: { + d: 1 + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + b: { + n1: { + p2: { + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: 〈import;struct〉.MinFields(3) + }|null) + x: ({ + a: { + d: 1 + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + b: { + n1: { + p3: { + x: ({ + a: { + c: 1 + } + }|null) + x: ({ + a: { + d: 1 + } + }|null) + x: ({ + a: 〈import;struct〉.MinFields(3) + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + b: { + n2: { + p1: { + x: ({ + a: { + b: 〈import;struct〉.MinFields(3) + } + }|null) + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + b: { + n2: { + p1: { + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: 〈import;struct〉.MinFields(3) + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + } + } + } + } + } + nestedNonMonotonic: { + incomplete: { + b: { + n2: { + p1: { + x: ({ + a: { + b: { + c: 1 + } + } + }|null) + x: ({ + a: { + b: { + d: 1 + } + } + }|null) + x: ({ + a: { + b: 〈import;struct〉.MinFields(3) + } + }|null) + } + } + } + } + } + preserveClosedness: { + small: { + p1: { + #A: (〈0;#B〉 & { + a: string + }) + #B: { + (*{}|{ + a: string + }) + (*{}|{ + b: int + }) + } + } + } + } + preserveClosedness: { + small: { + p2: { + #A: (〈0;#B〉 & { + a: string + }) + #B: { + ({ + a: string + }|*{}) + (*{}|{ + b: int + }) + } + } + } + } + preserveClosedness: { + medium: { + p1: { + #A: (〈0;#B〉 & { + a: string + }) + #B: { + (*{}|{ + a: string + }|{ + b: string + }) + (*{}|{ + c: int + }|{ + d: string + }) + } + } + } + } + preserveClosedness: { + medium: { + p2: { + #A: (〈0;#B〉 & { + a: string + }) + #B: { + ({ + a: string + }|*{}|{ + b: string + }) + (*{}|{ + c: int + }|{ + d: string + }) + } + } + } + } + preserveClosedness: { + medium: { + p3: { + #A: (〈0;#B〉 & { + a: string + }) + #B: { + ({ + a: string + }|{ + b: string + }|*{}) + (*{}|{ + c: int + }|{ + d: string + }) + } + } + } + } + noChildError: _ + noChildError: { + issue1608: { + myValue: (〈0;#type〉 & { + fieldName: "some string" + }) + #type: { + fieldName: 〈1;#subtype〉 + } + #subtype: (string|{ + foo: string + }|{ + bar: 〈1;#subtype〉 + }) + } + } + noChildError: { + t1: { + #D: ({ + b: string + }|{ + c: 〈1;#D〉 + }) + o: (〈0;#D〉 & { + b: "test" + }) + } + } + noChildError: { + t2: { + o: (〈0;#D〉 & { + b: "test" + }) + #D: ({ + b: string + }|{ + c: 〈1;#D〉 + }) + } + } + noChildError: { + t3: { + #D: ({ + a: null + }|{ + b: string + }|{ + c: 〈1;#D〉 + }) + o: (〈0;#D〉 & { + b: "test" + }) + } + } + noChildError: { + t4: { + o: (〈0;#D〉 & { + b: "test" + }) + #D: ({ + a: null + }|{ + b: string + }|{ + c: 〈1;#D〉 + }) + } + } + issue1924: { + t1: { + m: { + a: 2 + } + x: (*[ + 〈1;m〉.b, + ]|2) + } + } + issue1924: { + t2: { + m: { + a: 2 + } + x: (*{ + v: 〈1;m〉.b + }|3) + } + } + issue1924: { + t3: { + m: { + a: 2 + } + x: (*〈0;m〉.b|1) + } + } + issue1838: { + t1: { + p?: [] + a: ([ + for _, k in 〈1;p〉 { + 〈1;k〉 + }, + ]|null) + } + } + issue1838: { + t2: { + p?: [] + a: (null|[ + for _, k in 〈1;p〉 { + 〈1;k〉 + }, + ]) + } + } + noHang: { + #T: ([ + "a", + 〈1;#T〉, + ]|[ + "d", + ...〈1;#T〉, + ]) + x: 〈0;#T〉 + #X: 〈0;x〉 + #X: 〈0;#T〉 + } + issue1940: { + #T: ([ + "a", + 〈1;#T〉, + ]|[ + "b", + 〈1;#T〉, + ]|[ + "c", + 〈1;#T〉, + ]|[ + "d", + [ + ...〈2;#T〉, + ], + ]) + #A: { + type: 〈1;#T〉 + } + #B: { + [string]: 〈1;#A〉 + } + #C: (〈0;#B〉 & { + x: 〈1;#A〉 + }) + } +} +--- issue1417.cue +{ + issue1417: { + #ID: (!~"^a"|=~"^ab$"|=~"^aB$") + #ID: (=~"^a"|!~"[A-Z]") + ids: ([ + ...〈1;#ID〉, + ] & [ + "xyz", + "ab", + "aB", + ]) + } +} +--- issue2209full.cue +{ + issue2209: { + simplified: { + t1: { + #SpecFoo: { + foo: { + min: 1 + } + } + #SpecBar: { + bar: { + min: 1 + } + } + spec: { + bar: {} + } + spec: (〈0;#SpecFoo〉|〈0;#SpecBar〉) + out: { + ({ + nullFoo: null + }|{ + nullBar: null + }) + ({ + minFoo: int + }|{ + minBar: int + }) + if (〈0;X〉.bar != _|_(explicit error (_|_ literal) in source)) { + minBar: 〈1;X〉.bar.min + } + X: 〈1;spec〉 + } + } + } + } + issue2209: { + simplified: { + t2: { + #SpecFoo: { + foo: {} + } + #SpecBar: { + bar: { + x: 1 + } + } + spec: { + bar: {} + } + spec: (*〈0;#SpecFoo〉|〈0;#SpecBar〉) + if (〈0;spec〉.bar != _|_(explicit error (_|_ literal) in source)) { + BAZ: 〈1;spec〉.bar.x + } + ({ + f1: int + }|{ + b2: int + }) + ({ + f2: int + }|{ + b2: int + }) + } + } + } + issue2209: { + simplified: { + t3: { + #A: { + v: 1 + } + ({ + f1: int + }|{ + b2: int + }) + ({ + f2: int + }|{ + b2: int + }) + BAZ: 〈0;S〉.y + S: (*〈0;#A〉|〈0;#B〉) + #B: { + x: 1 + y: 1 + } + S: { + x: 1 + } + } + } + } + issue2209: { + full: { + Foo: (〈0;#Abstract〉 & { + spec: { + foo: {} + } + }) + Bar: (〈0;#Abstract〉 & { + spec: { + bar: {} + } + }) + #Abstract: { + spec: 〈1;_#Spec〉 + resource: (〈1;_Thing〉 & { + _X: { + spec: 〈3〉.spec + } + }) + } + _#Spec: (*〈0;_#SpecFoo〉|〈0;_#SpecBar〉) + _#SpecFoo: { + foo: { + min: (int|*10) + max: (int|*20) + } + } + _#SpecBar: { + bar: { + min: (int|*30) + max: (int|*40) + } + } + _Thing: (〈0;#Constrained〉 & { + _X: _ + spec: { + if (〈1;_X〉.spec.foo != _|_(explicit error (_|_ literal) in source)) { + minFoo: 〈2;_X〉.spec.foo.min + maxFoo: 〈2;_X〉.spec.foo.max + } + if (〈1;_X〉.spec.bar != _|_(explicit error (_|_ literal) in source)) { + minBar: 〈2;_X〉.spec.bar.min + maxBar: 〈2;_X〉.spec.bar.max + } + } + }) + #Constrained: (〈0;#Base〉 & { + spec: ({ + minFoo: (int|*10) + maxFoo: (int|*20) + minBar?: null + maxBar?: null + }|{ + minBar: (int|*30) + maxBar: (int|*40) + minFoo?: null + maxFoo?: null + }) + spec: (*{ + fuga?: null + }|{ + hoge?: null + }) + }) + #Base: { + spec: { + minFoo?: (null|int) + maxFoo?: (null|int) + minBar?: (null|int) + maxBar?: (null|int) + hoge?: (null|bool) + fuga?: (null|bool) + } + } + } + } +} +--- issue2246.cue +{ + issue2246: { + simplified: { + #FormFoo: { + fooID: string + } + #FormBar: { + barID: string + } + #Form: { + (〈1;#FormFoo〉|〈1;#FormBar〉) + } + data: { + fooID: "123" + } + out1: (〈0;#Form〉 & 〈0;data〉) + out2: (〈0;#Form〉 & 〈0;out1〉) + } + } + issue2246: { + full: { + data: { + forms: [ + { + fooID: "00-0000001" + }, + ] + } + form1040: (〈0;#compute〉 & { + in: 〈1;data〉 + }).out + #K1: { + #_base: { + common: 3 + } + #FormFoo: { + 〈1;#_base〉 + fooID: string + } + #FormBar: { + 〈1;#_base〉 + barID: string + } + #Form: { + (〈1;#FormFoo〉|〈1;#FormBar〉) + } + } + #Input: { + forms: [ + ...〈2;#K1〉.#Form, + ] + } + #summarizeReturn: { + in: 〈1;#Input〉 + out: [ + for _, k in 〈1;in〉.forms { + 〈1;k〉.common + }, + ] + } + #compute: { + in: 〈1;#Input〉 + out: (〈1;#summarizeReturn〉 & { + in: 〈1;in〉 + }).out + } + } + } +} +--- issue2263.cue +{ + issue2263: { + simplified: { + metrics: 〈0;#Metric〉 + #Metric: { + (〈1;#IDSource〉|{}) + (〈1;#TargetAverage〉|{}) + } + metrics: { + id: "foo" + avg: 60 + } + #IDSource: { + id: string + } + #TargetAverage: { + avg: number + } + } + } + issue2263: { + full: { + metrics: [ + ...〈1;#Metric〉, + ] + metrics: [ + { + id: "foo" + avg: 60 + }, + { + id: "bar" + value: 80 + }, + { + uri: "baz" + avg: 70 + }, + { + uri: "qux" + value: 90 + }, + ] + #Metric: { + 〈1;#Source〉 + 〈1;#Target〉 + } + #Source: (〈0;#IDSource〉|〈0;#URISource〉) + #Target: (〈0;#TargetAverage〉|〈0;#TargetValue〉) + #IDSource: { + id: string + } + #URISource: { + uri: string + } + #TargetAverage: { + avg: number + } + #TargetValue: { + value: number + } + } + } +} +--- issue2685.cue +{ + issue2685: { + #Foo: ({ + bar: int + opt?: int + }|*{ + opt: int + }) + foo: 〈0;#Foo〉 + foo: { + bar: 0 + } + { + foo: 〈1;#Foo〉 + } + } +} +--- issue3149.cue +{ + issue3149: { + #valid: { + name!: ((=~"^Foo"|"an exception") & (=~"Foo$"|"an exception")) + } + list: [ + ...〈1;#valid〉, + ] + list: [ + { + name: "FooBarFoo" + }, + { + name: "FooBazFoo" + }, + { + name: "FooQuuxFoo" + }, + { + name: "an exception" + }, + ] + } +} +--- issue3528.cue +{ + issue3528: { + original: { + workflows: [ + ...〈1;#Workflow〉, + ] + workflows: [ + 〈1;test〉, + ] + test: (〈0;#Workflow〉 & {}) + #Workflow: { + container: { + [string]: (string|〈1;#container〉) + } + #container: (string|{ + volumes?: [ + ...string, + ] + }) + } + } + } + issue3528: { + reduced: { + a?: 〈0;#A〉 + a: (〈0;#A〉 & {}) + #A: { + A: { + [string]: (1|〈1;#a〉) + } + #a: (2|{ + v: 1 + }) + } + } + } + issue3528: { + counter: {} + } + issue3528: { + nested: { + t1: { + ({ + v: 1 + }|(2|3)) + ({ + v: 1 + }|(2|3)) + ({ + v: 1 + }|(2|3)) + ({ + v: 1 + }|(2|3)) + } + } + } + issue3528: { + nested: { + t2: { + ({ + v: 1 + }|2) + ({ + v: 1 + }|(2|3)) + ({ + v: 1 + }|2) + ({ + v: 1 + }|2) + } + } + } +} +--- issue3784.cue +{ + issue3784: { + reduced: { + #Schema: { + a: ({ + kind: "A" + b: { + c?: string + } + b: {} + }|{ + kind: "B" + }) + } + out: 〈0;#Schema〉 + out: { + a: { + kind: "A" + b: { + c: "x" + } + } + } + } + } + issue3784: { + full: { + #Schema: { + pages?: { + build_type?: ("legacy"|"workflow") + source?: { + branch?: string + path?: string + } + cname?: string + } + pages?: ({ + build_type!: "legacy" + source!: { + branch!: _ + } + }|close({ + build_type!: "workflow" + cname?: _ + })) + } + out: (〈0;#Schema〉 & { + pages: { + cname: "foo.com" + build_type: "legacy" + source: { + branch: "main" + path: "/" + } + } + }) + } + } + issue3784: { + variant1: { + #Schema: { + pages: { + build_type?: ("legacy"|"workflow") + source: { + branch?: string + path?: string + } + cname?: string + } + pages?: ({ + build_type!: "legacy" + source!: { + branch!: _ + } + }|close({ + build_type!: "workflow" + cname?: _ + })) + } + } + } + issue3784: { + variant2: { + #Schema: ({ + build_type!: "legacy" + source!: { + branch!: _ + } + }|close({ + build_type!: "workflow" + cname?: _ + })) + a: 〈0;#Schema〉 + a: { + build_type?: ("legacy"|"workflow") + source: { + branch?: string + path?: string + } + cname?: string + } + } + } +} +--- issue3958.cue +{ + issue3958: { + t1: { + #schema: (int|*1) + #schema: (int|*3) + test1: (〈0;#schema〉 & { + (int|*2) + }) + test2: (〈0;#schema〉 & { + (int|*4) + }) + } + } + issue3958: { + t2: { + a: ((((int|*4) & (int|*1)) & (int|*3)) & (int|*8)) + b: (((int|*4) & (int|*1)) & (int|*3)) + } + } +} +--- issue770.cue +{ + issue770: { + #A: { + v: ("a"|"b"|"c") + } + h: { + [string]: 〈1;#A〉 + } + h: { + a: { + v: (*"a"|string) + } + } + h: { + [=~"^b"]: { + v: (*〈2;h〉.a.v|string) + } + } + h: { + [=~"^c"]: { + v: (*〈2;h〉.b.v|string) + } + } + h: { + b: _ + } + h: { + boo: _ + } + h: { + c: _ + } + h: { + coo: _ + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/embed.txtar b/internal/core/compile/testdata/sync/disjunctions/embed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/embed.txtar @@ -0,0 +1,223 @@ +-- in.cue -- +// Given the existence of this field, embedDefault is a struct. This +// means that embedding this conjunction into `embedDefault` itself should +// make it resolve to `{a: 2}`. + +default: { + y: *1 | {a: 2} + y + @test(eq, {y: *1 | {a: 2}, a: 2}) +} + +unambiguous: { + y: 1 | {a: 2} + y + @test(eq, {y: 1 | {a: 2}, a: 2}) +} + +forDefault: { + y: *1 | {a: 2} + for x in [1] {y} + @test(eq, {y: *1 | {a: 2}, a: 2}) +} + +// Carry over default to first disjunct. +openDefault: { + #y: *1 | {a: 2} + #y + @test(eq, *{1, #y: *1 | {a: 2}} | {#y: *1 | {a: 2}, a: 2}) +} + +openAmbiguous: { + #y: 1 | {a: 2} + #y + @test(eq, {1, #y: 1 | {a: 2}} | {#y: 1 | {a: 2}, a: 2}) +} + +forceStruct: { + #y: 1 | {a: 2} + #y + {} + @test(eq, {#y: 1 | {a: 2}, a: 2}) +} + +defaultsMulti: { + a: { + #def: { + *{} | {a: string} | {b: string} + *{} | {c: string} | {d: string} + } + + a: #def & {a: "foo"} + } + + b: { + #def: { + *{} | {a: string} | {b: string} + *{} | {c: string} | {d: string} + *{} | {d: string} | {e: string} + } + + a: #def & {a: "foo", e: "bar"} + } + @test(eq, { + a: { + #def: *{} | {c: string} | {d: string} | {a: string} | {a: string, c: string} | {a: string, d: string} | {b: string} | {b: string, c: string} | {b: string, d: string} + a: *{a: "foo"} | {a: "foo", c: string} | {a: "foo", d: string} + } + b: { + #def: *{} | {d: string} | {e: string} | {c: string} | {c: string, d: string} | {c: string, e: string} | {d: string, e: string} | {a: string} | {a: string, d: string} | {a: string, e: string} | {a: string, c: string} | {a: string, c: string, d: string} | {a: string, c: string, e: string} | {a: string, d: string, e: string} | {b: string} | {b: string, d: string} | {b: string, e: string} | {b: string, c: string} | {b: string, c: string, d: string} | {b: string, c: string, e: string} | {b: string, d: string, e: string} + a: *{a: "foo", e: "bar"} | {a: "foo", e: "bar", c: string} | {a: "foo", e: "bar", d: string} + } + }) +} + +nested: { + a: 1 | 2 | *( + (3 | 4 | *( 5 | 6 | *7)) & ( 3 | 4 | ( *7 | 8 ))) + @test(eq, {a: *7 | 2 | 3 | 4 | 1}) +} +-- issue3415.cue -- +// evalv3: calculated embedded scalars with a default value disagree with v2 +// when co-located with a hidden field; embedded scalar addition should work. +// https://cuelang.org/issue/3415 +issue3415: full: { + A: #A & { + i: { + _a + _b + _a: 1 + _b: 10 + } + } + #A: { + i: *0 | number + } + @test(eq, { + A: {i: {11, _a: 1, _b: 10}} + #A: {i: *0 | number} + }) +} +issue3415: reduced: { + a: { + 1 + #b + #b: 10 + } + a: *0 | number + @test(eq, {a: {11, #b: 10}}) +} +-- out/compile -- +--- in.cue +{ + default: { + y: (*1|{ + a: 2 + }) + 〈0;y〉 + } + unambiguous: { + y: (1|{ + a: 2 + }) + 〈0;y〉 + } + forDefault: { + y: (*1|{ + a: 2 + }) + for _, x in [ + 1, + ] { + 〈2;y〉 + } + } + openDefault: { + #y: (*1|{ + a: 2 + }) + 〈0;#y〉 + } + openAmbiguous: { + #y: (1|{ + a: 2 + }) + 〈0;#y〉 + } + forceStruct: { + #y: (1|{ + a: 2 + }) + 〈0;#y〉 + {} + } + defaultsMulti: { + a: { + #def: { + (*{}|{ + a: string + }|{ + b: string + }) + (*{}|{ + c: string + }|{ + d: string + }) + } + a: (〈0;#def〉 & { + a: "foo" + }) + } + b: { + #def: { + (*{}|{ + a: string + }|{ + b: string + }) + (*{}|{ + c: string + }|{ + d: string + }) + (*{}|{ + d: string + }|{ + e: string + }) + } + a: (〈0;#def〉 & { + a: "foo" + e: "bar" + }) + } + } + nested: { + a: (1|2|*((3|4|*(5|6|*7)) & (3|4|(*7|8)))) + } +} +--- issue3415.cue +{ + issue3415: { + full: { + A: (〈0;#A〉 & { + i: { + (〈0;_a〉 + 〈0;_b〉) + _a: 1 + _b: 10 + } + }) + #A: { + i: (*0|number) + } + } + } + issue3415: { + reduced: { + a: { + (1 + 〈0;#b〉) + #b: 10 + } + a: (*0|number) + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/errors.txtar b/internal/core/compile/testdata/sync/disjunctions/errors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/errors.txtar @@ -0,0 +1,479 @@ +-- in.cue -- +// cmd/cue: misleading "field not allowed" error when a type clash occurs inside +// a disjunction; the actual conflict should be reported instead. +// https://cuelang.org/issue/570 +issue570: { + results: #DecodeOutput + results: result: "hello" + + #Output: { + result: _ + } | { + error: string + } + + #DecodeOutput: #Output & { + result?: [... string] + ... + } + @test(err, code=eval, at=results.result, contains="conflicting values", args=["hello", [...string]], pos=[1:11, 2:19, 11:12]) +} + +// Clarify when an error resulted from a failed disjunction; error messages +// should indicate which disjunct failed rather than showing a generic error. +// https://cuelang.org/issue/516 +issue516: { + #Def: { + match: metrics: string: {} + } | {} + + x: #Def + x: match: metrics: "foo": {} + @test(err, code=eval, at=x, contains="2 errors in empty disjunction", pos=[]) +} + +// issue #465 +explicitDefaultError: { + a: string | *_|_ + + if a != "" { + } + @test(err, code=incomplete, contains="non-concrete value string in operand to !=", pos=[3:5, 1:5]) +} + +// evaluator: export as YAML vs JSON emits different templated data when +// pattern constraints with defaults produce different disjunction results. +// https://cuelang.org/issue/2916 +issue2916: { + b: _ + [_]: c: uint | *1 + [string]: c: >=3 | *3 + @test(eq, {b: {c: *3 | >=3 & int}}) +} +// evaluator: inconsistent export output for different formats based on which +// default is selected when multiple defaults are unified. +// https://cuelang.org/issue/3157 +issue3157: { + foo: *42 | _ + foo: *43 | bool + @test(eq, {foo: *43 | bool}) +} +-- issue3581.cue -- +// evalv3: tools/flow unexpected error when a flow task result field is used as +// a list item; string interpolation in a list element caused a spurious error. +// https://cuelang.org/issue/3581 +issue3581: reduced: { + list: [...] | *[] + list: ["\(c)" ] @test(err, code=incomplete, contains="2 errors in empty disjunction", + suberr=(code=incomplete, contains="incompatible list lengths", args=[0, 1], pos=[-1:17]), + suberr=(code=incomplete, contains="invalid interpolation: non-concrete value", pos=[0:9]), + ) + c: _ + @test(eq, {list: _|_, c: _}) +} +-- issue3576.cue -- +// evalv3: disjunct of definitions with identical optional fields results in +// incomplete evaluation; the resolved disjunct should be fully evaluated. +// https://cuelang.org/issue/3576 +issue3576: reduced: { + #A: a!: string + #B: { + if false { + dummy: {} + } + } + foo: #B | #A + foo: a: "1" + @test(eq, { + #A: {a!: string} + #B: {} + foo: {a: "1"} + }) +} +issue3576: full: { + #Run: { + run!: string + options?: #Option | [#Option, ...] + if options != _|_ { + optionsValue: options + } + } + + #Copy: { + copy!: string + options?: #Option | [#Option, ...] + if options != _|_ { + optionsValue: options + } + } + + #Option: {} + + foo: #Run | #Copy + foo: run: "make" + @test(eq, { + #Run: {run!: string, options?: {} | [{}]} + #Copy: {copy!: string, options?: {} | [{}]} + #Option: {} + foo: {run: "make", options?: {} | [{}]} + }) +} +-- issue3599.cue -- +// evalv3: "explicit error in source" regression when using bottom (_|_) in +// repeating disjunctions; errors in optional/let fields should be ignored. +// https://cuelang.org/issue/3599 +// Ignore errors for irrelevant fields like let and optional fields. +issue3599: full: { + #Action: { + action: { + read!: string + write?: _|_ + } | { + write!: string + read?: _|_ + } + } + + #Minio: { + container: #Action & { + action: { + read!: string + write?: _|_ + } | { + write!: string + read?: _|_ + } + } + doWrite: bool | *true + container: action: defaultAction + defaultAction: { + if doWrite { write: "somefile.txt" } + if !doWrite { read: "somefile.txt" } + } + } + @test(skip, hint="somehow this test doesn't work. Fix it.") + @test(eq:todo, { + #Action: { + action: {read!: string, write?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[])} | {write!: string, read?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[])} + } + #Minio: { + container: { + action: { + write: "somefile.txt" + read?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source (and 1 more errors)", pos=[23:13]) + } + } + doWrite: *true | bool + defaultAction: {write: "somefile.txt"} + } + }) +} +issue3599: reduced: p1: { + { a?: 1&2 } | { a: string, b?: 1&2 } + { } | { } + @test(eq, {a?: _|_ @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[49:25, 50:2, 50:9, 50:11])} | {a: string, b?: _|_ @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[49:25, 50:2, 50:35, 50:37])}) +} +issue3599: reduced: p2: { + { } | { } + { a?: 1&2 } | { a: string, b?: 1&2 } + @test(eq, {a?: _|_ @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[54:25, 56:2, 56:9, 56:11])} | {a: string, b?: _|_ @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[54:25, 56:2, 56:35, 56:37])}) +} +issue3599: let: { + { } | { a: B | 1, let B = 1&2 } + { } | { } + @test(eq, {} | {a: 1}) +} +-- optionalerror.cue -- +// evalv3 closedness regression with disjunctions and ellipses; a definition +// using _|_ in an optional field inside a disjunction caused spurious errors. +// https://cuelang.org/issue/4022 +issue4022: reduced: { + #NonNamespaced: metadata: namespace?: _|_ + #NullOrNonNamespaced: int | #NonNamespaced + out: #NullOrNonNamespaced + out: #NonNamespaced + out: metadata: {} + @test(eq, { + #NonNamespaced: { + metadata: { + namespace?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[5:40]) + } + } + #NullOrNonNamespaced: int | {metadata: { + namespace?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[5:40]) + }} + out: { + metadata: { + namespace?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[5:40]) + } + } + }) +} +issue4022: full: { + #NonNamespaced: { + metadata: { + name!: string + namespace?: _|_ + ... + } + ... + } + + #NullOrNonNamespaced: null | #NonNamespaced + + out: #NullOrNonNamespaced + out: #NonNamespaced + out: { + metadata: name: "foo" + apiVersion: "v1" + } + @test(eq, { + #NonNamespaced: { + metadata: { + name!: string + namespace?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[30:16]) + } + } + #NullOrNonNamespaced: null | {metadata: { + name!: string + namespace?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[30:16]) + }} + out: { + metadata: { + name: "foo" + namespace?: _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[30:16]) + } + apiVersion: "v1" + } + }) +} +-- out/compile -- +--- in.cue +{ + issue570: { + results: 〈0;#DecodeOutput〉 + results: { + result: "hello" + } + #Output: ({ + result: _ + }|{ + error: string + }) + #DecodeOutput: (〈0;#Output〉 & { + result?: [ + ...string, + ] + ... + }) + } + issue516: { + #Def: ({ + match: { + metrics: { + string: {} + } + } + }|{}) + x: 〈0;#Def〉 + x: { + match: { + metrics: { + foo: {} + } + } + } + } + explicitDefaultError: { + a: (string|*_|_(explicit error (_|_ literal) in source)) + if (〈0;a〉 != "") {} + } + issue2916: { + b: _ + [_]: { + c: (&(int, >=0)|*1) + } + [string]: { + c: (>=3|*3) + } + } + issue3157: { + foo: (*42|_) + foo: (*43|bool) + } +} +--- issue3576.cue +{ + issue3576: { + reduced: { + #A: { + a!: string + } + #B: { + if false { + dummy: {} + } + } + foo: (〈0;#B〉|〈0;#A〉) + foo: { + a: "1" + } + } + } + issue3576: { + full: { + #Run: { + run!: string + options?: (〈1;#Option〉|[ + 〈2;#Option〉, + ..., + ]) + if (〈0;options〉 != _|_(explicit error (_|_ literal) in source)) { + optionsValue: 〈1;options〉 + } + } + #Copy: { + copy!: string + options?: (〈1;#Option〉|[ + 〈2;#Option〉, + ..., + ]) + if (〈0;options〉 != _|_(explicit error (_|_ literal) in source)) { + optionsValue: 〈1;options〉 + } + } + #Option: {} + foo: (〈0;#Run〉|〈0;#Copy〉) + foo: { + run: "make" + } + } + } +} +--- issue3581.cue +{ + issue3581: { + reduced: { + list: ([ + ..., + ]|*[]) + list: [ + "\(〈1;c〉)", + ] + c: _ + } + } +} +--- issue3599.cue +{ + issue3599: { + full: { + #Action: { + action: ({ + read!: string + write?: _|_(explicit error (_|_ literal) in source) + }|{ + write!: string + read?: _|_(explicit error (_|_ literal) in source) + }) + } + #Minio: { + container: (〈1;#Action〉 & { + action: ({ + read!: string + write?: _|_(explicit error (_|_ literal) in source) + }|{ + write!: string + read?: _|_(explicit error (_|_ literal) in source) + }) + }) + doWrite: (bool|*true) + container: { + action: 〈1;defaultAction〉 + } + defaultAction: { + if 〈1;doWrite〉 { + write: "somefile.txt" + } + if !〈1;doWrite〉 { + read: "somefile.txt" + } + } + } + } + } + issue3599: { + reduced: { + p1: { + ({ + a?: (1 & 2) + }|{ + a: string + b?: (1 & 2) + }) + ({}|{}) + } + } + } + issue3599: { + reduced: { + p2: { + ({}|{}) + ({ + a?: (1 & 2) + }|{ + a: string + b?: (1 & 2) + }) + } + } + } + issue3599: { + let: { + ({}|{ + a: (〈0;let B#1〉|1) + let B#1 = (1 & 2) + }) + ({}|{}) + } + } +} +--- optionalerror.cue +{ + issue4022: { + reduced: { + #NonNamespaced: { + metadata: { + namespace?: _|_(explicit error (_|_ literal) in source) + } + } + #NullOrNonNamespaced: (int|〈0;#NonNamespaced〉) + out: 〈0;#NullOrNonNamespaced〉 + out: 〈0;#NonNamespaced〉 + out: { + metadata: {} + } + } + } + issue4022: { + full: { + #NonNamespaced: { + metadata: { + name!: string + namespace?: _|_(explicit error (_|_ literal) in source) + ... + } + ... + } + #NullOrNonNamespaced: (null|〈0;#NonNamespaced〉) + out: 〈0;#NullOrNonNamespaced〉 + out: 〈0;#NonNamespaced〉 + out: { + metadata: { + name: "foo" + } + apiVersion: "v1" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/incomplete.txtar b/internal/core/compile/testdata/sync/disjunctions/incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/incomplete.txtar @@ -0,0 +1,176 @@ +-- in.cue -- +import "encoding/yaml" + +// Defaults don't resolve struct values; a default that selects a missing +// field in a struct should fall back to the other disjunct. +// https://cuelang.org/issue/700 +issue700: { + a: y: "y" + test1: *a.x | 1 + test2: *a.y | 1 + @test(eq, {a: {y: "y"}, test1: 1, test2: *"y" | 1}) +} + +lookup: { + x: { + name: "Hello" + } + y: x.a @test(err, code=incomplete, contains="undefined field: a", pos=[0:14]) + ok1: *x.a | x @test(eq, {name: "Hello"}) + ok2: x | *x.a @test(eq, {name: "Hello"}) + ok3: x.a | *x @test(eq, {name: "Hello"}) + ok4: *x | x.a @test(eq, {name: "Hello"}) + ok5: x | x.a @test(eq) + ok5: x.a | x @test(eq, {name: "Hello"}) + allFail1: x.a | x.b @test(err, code=incomplete, contains="2 errors in empty disjunction", + suberr=(code=incomplete, contains="undefined field: a", pos=[0:14]), + suberr=(code=incomplete, contains="undefined field: b", pos=[0:20]), + ) + allFail2: x.a | x.b @test(err, code=incomplete, contains="2 errors in empty disjunction", + suberr=(code=incomplete, contains="undefined field: a", pos=[0:14]), + suberr=(code=incomplete, contains="undefined field: b", pos=[0:20]), + ) +} + +func: { + s: string + ok1: yaml.MarshalStream(s) | yaml.Marshal(s) @test(err, code=incomplete, + contains="2 errors in empty disjunction", + suberr=(code=incomplete, contains="non-concrete argument 0", pos=[0:7]), + suberr=(code=incomplete, contains="non-concrete argument 0", pos=[0:31]), + ) +} + +// Default mark on interpolated string; a concrete override should suppress +// a default interpolation regardless of whether it is left or right in the disjunction. +// https://cuelang.org/issue/782 +issue782: { + a: { + inner: string + interpolation: *"\(inner)" | string + interpolation: "override" + @test(eq, { + inner: string + interpolation: "override" + }) + } + b: { + inner: string + interpolation: string | *"\(inner)" + interpolation: "override" + @test(eq, { + inner: string + interpolation: "override" + }) + } + c: { + inner: string + interpolation: "\(inner)" | string + interpolation: "override" + @test(eq, { + inner: string + interpolation: "override" + }) + } + d: { + inner: string + interpolation: string | "\(inner)" + interpolation: "override" + @test(eq, { + inner: string + interpolation: "override" + }) + } +} +-- issue3680.cue -- +// evalv3: "unexpected uninitialized node" regression with bottom optional fields; +// optional fields set to _|_ in a disjunct should not cause a crash. +// https://cuelang.org/issue/3680 +issue3680: t1: { + {} | { + a?: _|_ + b?: _|_ + } + {} | {} + @test(eq, {} | {a?: _|_, b?: _|_}) +} +issue3680: t2: { + x: {} | { + a?: _|_ + b?: _|_ + } + x: {} | {} + @test(eq, {x: {} | {a?: _|_, b?: _|_}}) +} +-- out/compile -- +--- in.cue +{ + issue700: { + a: { + y: "y" + } + test1: (*〈0;a〉.x|1) + test2: (*〈0;a〉.y|1) + } + lookup: { + x: { + name: "Hello" + } + y: 〈0;x〉.a + ok1: (*〈0;x〉.a|〈0;x〉) + ok2: (〈0;x〉|*〈0;x〉.a) + ok3: (〈0;x〉.a|*〈0;x〉) + ok4: (*〈0;x〉|〈0;x〉.a) + ok5: (〈0;x〉|〈0;x〉.a) + ok5: (〈0;x〉.a|〈0;x〉) + allFail1: (〈0;x〉.a|〈0;x〉.b) + allFail2: (〈0;x〉.a|〈0;x〉.b) + } + func: { + s: string + ok1: (〈import;"encoding/yaml"〉.MarshalStream(〈0;s〉)|〈import;"encoding/yaml"〉.Marshal(〈0;s〉)) + } + issue782: { + a: { + inner: string + interpolation: (*"\(〈0;inner〉)"|string) + interpolation: "override" + } + b: { + inner: string + interpolation: (string|*"\(〈0;inner〉)") + interpolation: "override" + } + c: { + inner: string + interpolation: ("\(〈0;inner〉)"|string) + interpolation: "override" + } + d: { + inner: string + interpolation: (string|"\(〈0;inner〉)") + interpolation: "override" + } + } +} +--- issue3680.cue +{ + issue3680: { + t1: { + ({}|{ + a?: _|_(explicit error (_|_ literal) in source) + b?: _|_(explicit error (_|_ literal) in source) + }) + ({}|{}) + } + } + issue3680: { + t2: { + x: ({}|{ + a?: _|_(explicit error (_|_ literal) in source) + b?: _|_(explicit error (_|_ literal) in source) + }) + x: ({}|{}) + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/issue2209.txtar b/internal/core/compile/testdata/sync/disjunctions/issue2209.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/issue2209.txtar @@ -0,0 +1,297 @@ +# Tests that complex configurations with disjunctions and comprehensions evaluate +# correctly. A regression in v0.5.0 caused "empty disjunction" errors for code +# involving nested definitions with spec disjunctions and if-guard comprehensions. +# https://cuelang.org/issue/2209 +-- input.cue -- +full: { + Foo: #Abstract & {spec: foo: {}} + Bar: #Abstract & {spec: bar: {}} + + #Abstract: X={ + spec: _#Spec + + resource: _Thing & {_X: spec: X.spec} + } + + _#Spec: *_#SpecFoo | _#SpecBar + + _#SpecFoo: { + foo: { + min: int | *10 + max: int | *20 + } + } + + _#SpecBar: { + bar: { + min: int | *30 + max: int | *40 + } + } + + _Thing: #Constrained & { + _X: _ + + spec: { + if _X.spec.foo != _|_ { + minFoo: _X.spec.foo.min + maxFoo: _X.spec.foo.max + } + + if _X.spec.bar != _|_ { + minBar: _X.spec.bar.min + maxBar: _X.spec.bar.max + } + } + } + + #Constrained: #Base & { + spec: { + minFoo: int | *10 + maxFoo: int | *20 + minBar?: null + maxBar?: null + } | { + minBar: int | *30 + maxBar: int | *40 + minFoo?: null + maxFoo?: null + } + + spec: *{ + fuga?: null + } | { + hoge?: null + } + } + + #Base: { + spec: { + minFoo?: null | int + maxFoo?: null | int + minBar?: null | int + maxBar?: null | int + + hoge?: null | bool + fuga?: null | bool + } + } + @test(eq, { + Foo: { + spec: {foo: {min: *10 | int, max: *20 | int}} + resource: { + _X: { + spec: {foo: {min: *10 | int, max: *20 | int}} + } + spec: *{minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null | bool, fuga?: null} | {minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null, fuga?: null | bool} + } + } + Bar: { + spec: {bar: {min: *30 | int, max: *40 | int}} + resource: { + _X: { + spec: {bar: {min: *30 | int, max: *40 | int}} + } + spec: *{minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null | bool, fuga?: null} | {minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null, fuga?: null | bool} + } + } + #Abstract: { + spec: *{foo: {min: *10 | int, max: *20 | int}} | {bar: {min: *30 | int, max: *40 | int}} + resource: { + _X: { + spec: *{foo: {min: *10 | int, max: *20 | int}} | {bar: {min: *30 | int, max: *40 | int}} + } + spec: *{minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null | bool, fuga?: null} | {minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null, fuga?: null | bool} + } + } + _#Spec: *{foo: {min: *10 | int, max: *20 | int}} | {bar: {min: *30 | int, max: *40 | int}} + _#SpecFoo: {foo: {min: *10 | int, max: *20 | int}} + _#SpecBar: {bar: {min: *30 | int, max: *40 | int}} + _Thing: { + _X: _ + spec: *{minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null | bool, fuga?: null} | *{minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null | bool, fuga?: null} | {minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null, fuga?: null | bool} | {minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null, fuga?: null | bool} + } + #Constrained: { + spec: *{minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null | bool, fuga?: null} | *{minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null | bool, fuga?: null} | {minFoo: *10 | int, maxFoo: *20 | int, minBar?: null, maxBar?: null, hoge?: null, fuga?: null | bool} | {minFoo?: null, maxFoo?: null, minBar: *30 | int, maxBar: *40 | int, hoge?: null, fuga?: null | bool} + } + #Base: { + spec: { + minFoo?: null | int + maxFoo?: null | int + minBar?: null | int + maxBar?: null | int + hoge?: null | bool + fuga?: null | bool + } + } + }) +} + +reduced: { + Foo: #Obj & {spec: foo: {}} + Bar: #Obj & {spec: bar: {}} + + #Obj: X={ + spec: *#SpecFoo | #SpecBar + + out: #Out & { + _Xspec: X.spec + if _Xspec.foo != _|_ { + minFoo: _Xspec.foo.min + } + if _Xspec.bar != _|_ { + minBar: _Xspec.bar.min + } + } + } + + #SpecFoo: foo: min: int | *10 + #SpecBar: bar: min: int | *20 + + #Out: { + {minFoo: int} | {minBar: int} + + *{nullFoo: null} | {nullBar: null} + } + @test(eq, { + Foo: { + spec: {foo: {min: *10 | int}} + out: *{_Xspec: {foo: {min: *10 | int}}, minFoo: *10 | int, nullFoo: null} | {_Xspec: {foo: {min: *10 | int}}, minFoo: *10 | int, nullBar: null} + } + Bar: { + spec: {bar: {min: *20 | int}} + out: *{_Xspec: {bar: {min: *20 | int}}, minBar: *20 | int, nullFoo: null} | {_Xspec: {bar: {min: *20 | int}}, minBar: *20 | int, nullBar: null} + } + #Obj: { + spec: *{foo: {min: *10 | int}} | {bar: {min: *20 | int}} + out: *{_Xspec: *{foo: {min: *10 | int}} | {bar: {min: *20 | int}}, minFoo: *10 | int, nullFoo: null} | {_Xspec: *{foo: {min: *10 | int}} | {bar: {min: *20 | int}}, minFoo: *10 | int, nullBar: null} + } + #SpecFoo: {foo: {min: *10 | int}} + #SpecBar: {bar: {min: *20 | int}} + #Out: *{minFoo: int, nullFoo: null} | *{minBar: int, nullFoo: null} | {minFoo: int, nullBar: null} | {minBar: int, nullBar: null} + }) +} +-- out/compile -- +--- input.cue +{ + full: { + Foo: (〈0;#Abstract〉 & { + spec: { + foo: {} + } + }) + Bar: (〈0;#Abstract〉 & { + spec: { + bar: {} + } + }) + #Abstract: { + spec: 〈1;_#Spec〉 + resource: (〈1;_Thing〉 & { + _X: { + spec: 〈3〉.spec + } + }) + } + _#Spec: (*〈0;_#SpecFoo〉|〈0;_#SpecBar〉) + _#SpecFoo: { + foo: { + min: (int|*10) + max: (int|*20) + } + } + _#SpecBar: { + bar: { + min: (int|*30) + max: (int|*40) + } + } + _Thing: (〈0;#Constrained〉 & { + _X: _ + spec: { + if (〈1;_X〉.spec.foo != _|_(explicit error (_|_ literal) in source)) { + minFoo: 〈2;_X〉.spec.foo.min + maxFoo: 〈2;_X〉.spec.foo.max + } + if (〈1;_X〉.spec.bar != _|_(explicit error (_|_ literal) in source)) { + minBar: 〈2;_X〉.spec.bar.min + maxBar: 〈2;_X〉.spec.bar.max + } + } + }) + #Constrained: (〈0;#Base〉 & { + spec: ({ + minFoo: (int|*10) + maxFoo: (int|*20) + minBar?: null + maxBar?: null + }|{ + minBar: (int|*30) + maxBar: (int|*40) + minFoo?: null + maxFoo?: null + }) + spec: (*{ + fuga?: null + }|{ + hoge?: null + }) + }) + #Base: { + spec: { + minFoo?: (null|int) + maxFoo?: (null|int) + minBar?: (null|int) + maxBar?: (null|int) + hoge?: (null|bool) + fuga?: (null|bool) + } + } + } + reduced: { + Foo: (〈0;#Obj〉 & { + spec: { + foo: {} + } + }) + Bar: (〈0;#Obj〉 & { + spec: { + bar: {} + } + }) + #Obj: { + spec: (*〈1;#SpecFoo〉|〈1;#SpecBar〉) + out: (〈1;#Out〉 & { + _Xspec: 〈2〉.spec + if (〈0;_Xspec〉.foo != _|_(explicit error (_|_ literal) in source)) { + minFoo: 〈1;_Xspec〉.foo.min + } + if (〈0;_Xspec〉.bar != _|_(explicit error (_|_ literal) in source)) { + minBar: 〈1;_Xspec〉.bar.min + } + }) + } + #SpecFoo: { + foo: { + min: (int|*10) + } + } + #SpecBar: { + bar: { + min: (int|*20) + } + } + #Out: { + ({ + minFoo: int + }|{ + minBar: int + }) + (*{ + nullFoo: null + }|{ + nullBar: null + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/issue3850.txtar b/internal/core/compile/testdata/sync/disjunctions/issue3850.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/issue3850.txtar @@ -0,0 +1,192 @@ +# Tests that struct fields referencing hidden variables inside disjunctions +# evaluate correctly. A regression in evalv3 caused incomplete fields and +# panics when combining disjunctions with hidden-field lookups and definitions. +# https://cuelang.org/issue/3850 +-- issue3850.cue -- +issue3850: full: { + global: glb1: glb2: "123" + out: {foo?: _} | {} + out: {foo?: _} | {} + out: #WithFoo + + #WithFoo: { + _global: global + foo: _global.glb1.glb2 + } + @test(eq, { + global: {glb1: {glb2: "123"}} + out: { + _global: {glb1: {glb2: "123"}} + foo: "123" + } + #WithFoo: { + _global: {glb1: {glb2: "123"}} + foo: "123" + } + }) +} +issue3850: incomplete: { + global: glb1: glb2: "123" + out: {foo?: _} | {} + out: {foo?: _} | {} + out: #WithFoo + + #WithFoo: { + _global: global + foo: _global.glb1.glb2 + ... + } + @test(eq, { + global: {glb1: {glb2: "123"}} + out: { + _global: {glb1: {glb2: "123"}} + foo: "123" + } + #WithFoo: { + _global: {glb1: {glb2: "123"}} + foo: "123" + } + }) +} +issue3850: p2p: { + out: *{} | _ + out: *{} | _ + out: { + reg: #def + #def: foo: _global + @test(eq, { + reg: {foo: "global value"} + #def: {foo: "global value"} + }) + } + + _global: "global value" +} +-- issue3875.cue -- +issue3875: full: { + _global: name: "foo" + + out: desc: { + _hidden: _global.name + name: _hidden + } + out: #Schema | "never" + + #Schema: desc: {...} + @test(eq, { + _global: {name: "foo"} + out: {desc: {_hidden: "foo", name: "foo"}} + #Schema: {desc: {}} + }) +} +issue3875: reduced: { + global: a: "foo" + + out: desc: { + a: b + b: global.a + } + out: S | null + + S: {} + @test(eq, { + global: {a: "foo"} + out: {desc: {a: "foo", b: "foo"}} + S: {} + }) +} +-- out/compile -- +--- issue3850.cue +{ + issue3850: { + full: { + global: { + glb1: { + glb2: "123" + } + } + out: ({ + foo?: _ + }|{}) + out: ({ + foo?: _ + }|{}) + out: 〈0;#WithFoo〉 + #WithFoo: { + _global: 〈1;global〉 + foo: 〈0;_global〉.glb1.glb2 + } + } + } + issue3850: { + incomplete: { + global: { + glb1: { + glb2: "123" + } + } + out: ({ + foo?: _ + }|{}) + out: ({ + foo?: _ + }|{}) + out: 〈0;#WithFoo〉 + #WithFoo: { + _global: 〈1;global〉 + foo: 〈0;_global〉.glb1.glb2 + ... + } + } + } + issue3850: { + p2p: { + out: (*{}|_) + out: (*{}|_) + out: { + reg: 〈0;#def〉 + #def: { + foo: 〈2;_global〉 + } + } + _global: "global value" + } + } +} +--- issue3875.cue +{ + issue3875: { + full: { + _global: { + name: "foo" + } + out: { + desc: { + _hidden: 〈2;_global〉.name + name: 〈0;_hidden〉 + } + } + out: (〈0;#Schema〉|"never") + #Schema: { + desc: { + ... + } + } + } + } + issue3875: { + reduced: { + global: { + a: "foo" + } + out: { + desc: { + a: 〈0;b〉 + b: 〈2;global〉.a + } + } + out: (〈0;S〉|null) + S: {} + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/issue3857.txtar b/internal/core/compile/testdata/sync/disjunctions/issue3857.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/issue3857.txtar @@ -0,0 +1,175 @@ +# Tests that disjunctions combined with comprehensions and pattern constraints +# do not cause panics in the v3 evaluator. The issue reported crashes in +# Vertex.DerefValue and Environment.up for code that worked correctly in evalv2. +# https://cuelang.org/issue/3857 +-- in.cue -- +reduced: t1: { + S: { if true { a: U } } + x: S + x: { + ["a"]: b: 1 | T + d: b: x.a + } + T: 1 + U: b: 1 | 1 + @test(eq, { + S: {a: {b: 1}} + x: {d: {b: {b: 1}}, a: {b: 1}} + T: 1 + U: {b: 1} + }) +} +// issue3851: evalv3 incorrectly rejects a let field nested under multiple +// disjunctions with "field not allowed", a regression not present in evalv2. +// https://cuelang.org/issue/3851 +issue3851: t1: { + #Top: _ + #Config: { + disj: _ | *"default" + shared: _ + } + + #Schema: { + [string]: #Config + if true { + one: shared: "foo" + } + } + + out: #Schema + out: { + ["one"]: disj: _ | #Top + two: shared: out.one.shared + } + @test(eq, { + #Top: _ + #Config: {disj: *"default" | _, shared: _} + #Schema: { + one: {shared: "foo", disj: *"default" | _} + } + out: { + two: {shared: "foo", disj: *"default" | _} + one: {shared: "foo", disj: *"default" | _} + } + }) +} +issue3851: t2: { + #Top: _ + #Config: { + disj: _ | *{} + shared: _ + } + + #Env: { + conf: [string]: #Config + if true { + conf: one: shared: "foo" + } + } + + env1: #Env + + [string]: { + conf: ["one"]: disj: {} | #Top + conf: two: shared: conf.one.shared + } + @test(eq, { + #Top: _ + #Config: {disj: *{} | _, shared: _} + #Env: { + conf: {one: {shared: "foo", disj: *{} | _}} + } + env1: { + conf: { + two: {shared: "foo", disj: *{} | _} + one: {shared: "foo", disj: *{} | _} + } + } + }) +} +-- out/compile -- +--- in.cue +{ + reduced: { + t1: { + S: { + if true { + a: 〈2;U〉 + } + } + x: 〈0;S〉 + x: { + ["a"]: { + b: (1|〈2;T〉) + } + d: { + b: 〈2;x〉.a + } + } + T: 1 + U: { + b: (1|1) + } + } + } + issue3851: { + t1: { + #Top: _ + #Config: { + disj: (_|*"default") + shared: _ + } + #Schema: { + [string]: 〈1;#Config〉 + if true { + one: { + shared: "foo" + } + } + } + out: 〈0;#Schema〉 + out: { + ["one"]: { + disj: (_|〈2;#Top〉) + } + two: { + shared: 〈2;out〉.one.shared + } + } + } + } + issue3851: { + t2: { + #Top: _ + #Config: { + disj: (_|*{}) + shared: _ + } + #Env: { + conf: { + [string]: 〈2;#Config〉 + } + if true { + conf: { + one: { + shared: "foo" + } + } + } + } + env1: 〈0;#Env〉 + [string]: { + conf: { + ["one"]: { + disj: ({}|〈3;#Top〉) + } + } + conf: { + two: { + shared: 〈2;conf〉.one.shared + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/issue4339.txtar b/internal/core/compile/testdata/sync/disjunctions/issue4339.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/issue4339.txtar @@ -0,0 +1,30 @@ +# Tests that a default disjunct which embeds a struct referencing a sibling +# field, combined with an if-comprehension gated on a default boolean, does +# not panic. See: https://cuelang.org/issue/4339 +-- in.cue -- +_withExtra: extra: out.one + +out: { + *_withExtra | {} + + one: 1 + + enable: *true | false + if enable {} +} @test(eq, + // TODO: we should be able to use @test(final) here, avoiding the defaults. + *{one: 1, enable: *true | false, extra: 1} | {one: 1, enable: *true | false}, +) +-- out/compile -- +--- in.cue +{ + _withExtra: { + extra: 〈1;out〉.one + } + out: { + (*〈1;_withExtra〉|{}) + one: 1 + enable: (*true|false) + if 〈0;enable〉 {} + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/nested.txtar b/internal/core/compile/testdata/sync/disjunctions/nested.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/nested.txtar @@ -0,0 +1,156 @@ +-- issue3635.cue -- +import "list" +// evalv3: `incDependent: already closed` panic with a builtin and a disjunction; +// using list.Concat to satisfy a disjunction of map or list should not crash. +// https://cuelang.org/issue/3635 +issue3635: case1: { + Run: { + env: *{[string]: string} | [...string] + } + + command: Run & { + env: list.Concat([["foo"], ["bar"]]) + } + @test(eq, { + Run: {env: *{} | []} + command: {env: ["foo", "bar"]} + }) +} + +issue3635: case2: { + out: [...#Schema] + out: [#Schema & { + name: "x" + }] + + #Schema: { + name?: string + container?: [string]: string | #container + + #container: string | { + env?: #env + } + + #env: [string]: bool | string + } + @test(eq, { + out: [{ + name: "x" + container?: {} + #container: string | {env?: {}} + #env: [string]: bool | string + }] + #Schema: { + name?: string + container?: {} + #container: string | {env?: {}} + #env: [string]: bool | string + + } + }) +} + +issue3635: reduced: { + out: {X} & X + X: { + b: int | c + c: int | { e: d } + } + d: 1 + @test(eq, { + out: {b: int | {e: 1}, c: int | {e: 1}} + X: {b: int | {e: 1}, c: int | {e: 1}} + d: 1 + }) +} + +issue3635: reduced_noshare: { + out: {X} & X + X: { + b: int | c + c: int | { e: d & __no_sharing } + } + d: 1 + @test(eq, { + out: {b: int | {e: 1}, c: int | {e: 1}} + X: {b: int | {e: 1}, c: int | {e: 1}} + d: 1 + }) +} +-- out/compile -- +--- issue3635.cue +{ + issue3635: { + case1: { + Run: { + env: (*{ + [string]: string + }|[ + ...string, + ]) + } + command: (〈0;Run〉 & { + env: 〈import;list〉.Concat([ + [ + "foo", + ], + [ + "bar", + ], + ]) + }) + } + } + issue3635: { + case2: { + out: [ + ...〈1;#Schema〉, + ] + out: [ + (〈1;#Schema〉 & { + name: "x" + }), + ] + #Schema: { + name?: string + container?: { + [string]: (string|〈1;#container〉) + } + #container: (string|{ + env?: 〈1;#env〉 + }) + #env: { + [string]: (bool|string) + } + } + } + } + issue3635: { + reduced: { + out: ({ + 〈1;X〉 + } & 〈0;X〉) + X: { + b: (int|〈0;c〉) + c: (int|{ + e: 〈2;d〉 + }) + } + d: 1 + } + } + issue3635: { + reduced_noshare: { + out: ({ + 〈1;X〉 + } & 〈0;X〉) + X: { + b: (int|〈0;c〉) + c: (int|{ + e: (〈2;d〉 & _|_(no sharing)) + }) + } + d: 1 + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/operands.txtar b/internal/core/compile/testdata/sync/disjunctions/operands.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/operands.txtar @@ -0,0 +1,83 @@ +# This file tests disjunctions used as operands. +-- in.cue -- +list: *[1] | [2] @test(eq, *[1] | [2]) +condition: *true | false @test(eq, *true | false) +num: *1 | 2 @test(eq, *1 | 2) +object: *{a: 1} | {a: 2} @test(eq, *{a: 1} | {a: 2}) + +forLoop: [ + for e in list { + "count: \(e)" + }, +] @test(eq, ["count: 1"]) + +conditional: { + if condition { + a: 3 + } + if num < 5 { + b: 3 + } + @test(eq, {a: 3, b: 3}) +} + +selector: { + a: object.a + @test(eq, {a: 1}) +} + +index: { + a: list[0] + @test(eq, {a: 1}) +} + +binOp: { + a: num + 4 + @test(eq, {a: 5}) +} + +unaryOp: { + a: -num + @test(eq, {a: -1}) +} +-- out/compile -- +--- in.cue +{ + list: (*[ + 1, + ]|[ + 2, + ]) + condition: (*true|false) + num: (*1|2) + object: (*{ + a: 1 + }|{ + a: 2 + }) + forLoop: [ + for _, e in 〈1;list〉 { + "count: \(〈1;e〉)" + }, + ] + conditional: { + if 〈1;condition〉 { + a: 3 + } + if (〈1;num〉 < 5) { + b: 3 + } + } + selector: { + a: 〈1;object〉.a + } + index: { + a: 〈1;list〉[0] + } + binOp: { + a: (〈1;num〉 + 4) + } + unaryOp: { + a: -〈1;num〉 + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/propagate_err.txtar b/internal/core/compile/testdata/sync/disjunctions/propagate_err.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/propagate_err.txtar @@ -0,0 +1,77 @@ +// Issue 4055: crash variant +// Issue 4056 +-- issue4056.cue -- +import "strings" + +// cmd/cue: "unresolved disjunction" when error() disjuncts are added inside +// a conditional that depends on the same field; the concrete value should win. +// https://cuelang.org/issue/4056 +issue4056: full: { + a: "foo-bar" + a: _ | error("error message 1") + if strings.HasPrefix(a, "foo") { + a: _ | error("error message 2") + } + @test(eq, {a: "foo-bar"}) +} +issue4056: reduced: { + a: "x" + a: _ | error("a") + if len(a) > 0 { + a: _ | error("b") + } + @test(eq, {a: "x"}) +} +variant: { + a: "x" + a: string | int + if len(a) > 0 { + a: _ + } + @test(eq, {a: "x"}) +} +-- pending.cue -- +// Be sure to emit errors for uncompleted pending arcs. +err: { + A: "forty two" + if A < 100 {B: true} + @test(err, code=eval, contains="invalid operands", pos=[2:5, 1:5, 2:9]) +} +-- out/compile -- +--- issue4056.cue +{ + issue4056: { + full: { + a: "foo-bar" + a: (_|error("error message 1")) + if 〈import;strings〉.HasPrefix(〈0;a〉, "foo") { + a: (_|error("error message 2")) + } + } + } + issue4056: { + reduced: { + a: "x" + a: (_|error("a")) + if (len(〈0;a〉) > 0) { + a: (_|error("b")) + } + } + } + variant: { + a: "x" + a: (string|int) + if (len(〈0;a〉) > 0) { + a: _ + } + } +} +--- pending.cue +{ + err: { + A: "forty two" + if (〈0;A〉 < 100) { + B: true + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/resolve.txtar b/internal/core/compile/testdata/sync/disjunctions/resolve.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/resolve.txtar @@ -0,0 +1,48 @@ +// Ensure that references are resolved on the boundaries of disjunctions. +-- in.cue -- +resolveAcrossDisjunct: t1: { + {} | { #B: 1} // d resolves to 1 in the second case. + {d: #B} | {} + #B: int + @test(eq, {#B: int, d: int} | {#B: int} | {#B: 1, d: 1} | {#B: 1}) +} +resolveAcrossDisjunct: nested: { + {} | { a: b: #B: 1} // d resolves to 1 in the second case. + {d: a.b.#B} | {} + a: b: #B: int + @test(eq, {a: {b: {#B: int}}, d: int} | {a: {b: {#B: int}}} | {a: {b: {#B: 1}}, d: 1} | {a: {b: {#B: 1}}}) +} +-- out/compile -- +--- in.cue +{ + resolveAcrossDisjunct: { + t1: { + ({}|{ + #B: 1 + }) + ({ + d: 〈1;#B〉 + }|{}) + #B: int + } + } + resolveAcrossDisjunct: { + nested: { + ({}|{ + a: { + b: { + #B: 1 + } + } + }) + ({ + d: 〈1;a〉.b.#B + }|{}) + a: { + b: { + #B: int + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/disjunctions/specdeviation.txtar b/internal/core/compile/testdata/sync/disjunctions/specdeviation.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/disjunctions/specdeviation.txtar @@ -0,0 +1,127 @@ +It turns out the semantics of the spec is somewhat awkward, +though theoretically nicer. It seems like we do need to change +the definition somewhat to make it less awkward, or at least +come up with a good workaround before adopting the spec. + +We have introduce a small hack to mimic the old behavior for scalar +values. + +Note that the value of p below is now 2 (default), but should +be the non-concrete 2 | int. + +Proof: + p: *((*1 | int) & 2) | int // substitution of both P conjuncts in p + p: *(*_|_ | 2) | int // U1: distribute conjuncts + p: *_|_ | 2 | int // M2: remove mark + p: 2 | int // value after removing default. +-- in.cue -- +Q: *1 | int @test(eq, *1 | int) +q: *Q | int @test(eq, *1 | int) // 1 as expected + +P: *1 | int +P: 2 +p: *P | int @test(eq, *2 | int) // now 2, but should be (2 | int), according to the spec: + +// Here the inner default may not be used as it is masked by the outer default. +r: (*3 | (*1 | 2)) & (1 | 2) @test(eq, 1 | 2) + +// Here the inner default is used, as there are no defaults marked in the +// outer disjunction. +s: (3 | (*1 | 2)) & (1 | 2) @test(eq, *1 | 2) + +s1: #Size & {min: 5} @test(eq, { + min: 5 + max: *5 | >5 + res: *0 | >=0 & int +}) + +#Size: { + max: >min | *min + res: uint | *0 + min: >res | *(1 + res) + @test(eq, { + max: *1 | >0 | >1 + res: *0 | >=0 & int + min: *1 | >0 + }) +} + +staged: { + c: ("a" | "b") & (*(*"a" | string) | string) + d: (*(*"a" | string) | string) & ("a" | "b") + @test(eq, {c: *"a" | *"b", d: *"a" | "b"}) +} + +issue763a: { + #A: { + v: "a" | "b" | "c" // change to string to fix + } + + h: [string]: #A + + h: [=~"^b"]: #A & { + v: *h.a.v | string + } + + h: a: { + v: *"a" | string + } + + h: baa: _ + h: boo: _ + @test(eq, { + #A: {v: "a" | "b" | "c"} + h: { + a: {v: *"a" | "b" | "c"} + baa: {v: *"a" | "b" | "c"} + boo: {v: *"a" | "b" | "c"} + } + }) +} +-- out/compile -- +--- in.cue +{ + Q: (*1|int) + q: (*〈0;Q〉|int) + P: (*1|int) + P: 2 + p: (*〈0;P〉|int) + r: ((*3|(*1|2)) & (1|2)) + s: ((3|(*1|2)) & (1|2)) + s1: (〈0;#Size〉 & { + min: 5 + }) + #Size: { + max: (>〈0;min〉|*〈0;min〉) + res: (&(int, >=0)|*0) + min: (>〈0;res〉|*(1 + 〈0;res〉)) + } + staged: { + c: (("a"|"b") & (*(*"a"|string)|string)) + d: ((*(*"a"|string)|string) & ("a"|"b")) + } + issue763a: { + #A: { + v: ("a"|"b"|"c") + } + h: { + [string]: 〈1;#A〉 + } + h: { + [=~"^b"]: (〈1;#A〉 & { + v: (*〈2;h〉.a.v|string) + }) + } + h: { + a: { + v: (*"a"|string) + } + } + h: { + baa: _ + } + h: { + boo: _ + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/basictypes.txtar b/internal/core/compile/testdata/sync/eval/basictypes.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/basictypes.txtar @@ -0,0 +1,78 @@ +#inlinetest:exclude skip: compile errors. TODO: investigates +-- cue.mod/module.cue -- +module: "test.com" +language: version: "v0.15.0" +-- in.cue -- +top: { + a: {_} + b: _ +} + +scalar: { + a: {string} + b: string + c: {{{number}}} + d: number +} + +// StructCmp works with accepted experiment status +comparison: { + basicEquality: t: 42 == 42 + typeComparison: err: string == number // error for non-concrete + structEquality: t: {name: "test"} == {name: "test"} + nestedComparison: t: {data: {value: 1}} == {data: {value: 1}} +} +-- out/compile -- +comparison.typeComparison.err: invalid operand string ('==' requires concrete value): + ./in.cue:16:23 +comparison.typeComparison.err: invalid operand number ('==' requires concrete value): + ./in.cue:16:33 +--- in.cue +{ + top: { + a: { + _ + } + b: _ + } + scalar: { + a: { + string + } + b: string + c: { + { + { + number + } + } + } + d: number + } + comparison: { + basicEquality: { + t: (42 == 42) + } + typeComparison: { + err: (string == number) + } + structEquality: { + t: ({ + name: "test" + } == { + name: "test" + }) + } + nestedComparison: { + t: ({ + data: { + value: 1 + } + } == { + data: { + value: 1 + } + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/bounds.txtar b/internal/core/compile/testdata/sync/eval/bounds.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/bounds.txtar @@ -0,0 +1,614 @@ +// Tests bound expression evaluation and simplification including binary bound +// simplification (incompatible bounds), simplifyExpr with non-concrete bound +// arguments, and struct equality bounds (== / !=). Also covers issue 4142 +// (struct equality in definitions) and issue 4251 (SimplifyBounds panic on == +// bounds combined with other bound types). +-- cue.mod/module.cue -- +module: "x.test" +language: version: "v0.14.0" +-- in.cue -- +x0: 5 @test(eq, 5) +x1: b5 & 30 @test(eq, 30) + +b0: 0 @test(eq, >0 & <5) +b1: b0 & int @test(eq, >0 & <5 & int) +b2: int & <5.5 @test(eq, <5.5 & int) +b3: <10 & <=5 @test(eq, <=5) +b4: >=20 & >20 @test(eq, >20) +b5: >=21 & >20 @test(eq, >=21) +b6: int & >5 & <=6 @test(eq, >5 & <=6 & int) + +simplifyExpr: { + // TODO: fill out later. + less1: <(<3) @test(err, code=incomplete, contains="non-concrete value <3", pos=[0:11]) + less2: <(<=3) @test(err, code=incomplete, contains="non-concrete value <=3", pos=[0:11]) + less3: <=(<3) @test(err, code=incomplete, contains="non-concrete value <3", pos=[0:12]) + less4: <=(<=3) @test(err, code=incomplete, contains="non-concrete value <=3", pos=[0:12]) + less5: <(!=3) @test(err, code=incomplete, contains="non-concrete value !=3", pos=[0:11]) + less6: <=(!=3) @test(err, code=incomplete, contains="non-concrete value !=3", pos=[0:12]) + + gtr1: >(>3) @test(err, code=incomplete, contains="non-concrete value >3", pos=[0:10]) + gtr2: >(>=3) @test(err, code=incomplete, contains="non-concrete value >=3", pos=[0:10]) + gtr3: >=(>3) @test(err, code=incomplete, contains="non-concrete value >3", pos=[0:11]) + gtr4: >=(>=3) @test(err, code=incomplete, contains="non-concrete value >=3", pos=[0:11]) + gtr5: >(!=3) @test(err, code=incomplete, contains="non-concrete value !=3", pos=[0:10]) + gtr6: >=(!=3) @test(err, code=incomplete, contains="non-concrete value !=3", pos=[0:11]) + + lg1: <(>3) @test(err, code=incomplete, contains="non-concrete value >3", pos=[0:9]) + lg2: <(>=3) @test(err, code=incomplete, contains="non-concrete value >=3", pos=[0:9]) + lg3: <=(>3) @test(err, code=incomplete, contains="non-concrete value >3", pos=[0:10]) + lg4: <=(>=3) @test(err, code=incomplete, contains="non-concrete value >=3", pos=[0:10]) + + gl1: >(<3) @test(err, code=incomplete, contains="non-concrete value <3", pos=[0:9]) + gl2: >(<=3) @test(err, code=incomplete, contains="non-concrete value <=3", pos=[0:9]) + gl3: >=(<3) @test(err, code=incomplete, contains="non-concrete value <3", pos=[0:10]) + gl4: >=(<=3) @test(err, code=incomplete, contains="non-concrete value <=3", pos=[0:10]) + + ne1: !=(!=3) @test(err, code=incomplete, contains="non-concrete value !=3", pos=[0:10]) + ne2: !=(<3) @test(err, code=incomplete, contains="non-concrete value <3", pos=[0:10]) + ne3: !=(<=3) @test(err, code=incomplete, contains="non-concrete value <=3", pos=[0:10]) + ne4: !=(>3) @test(err, code=incomplete, contains="non-concrete value >3", pos=[0:10]) + ne5: !=(>=3) @test(err, code=incomplete, contains="non-concrete value >=3", pos=[0:10]) + + s: string + n: number + i: int + f: float + b: bytes + basic1: <(i) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[i, <], pos=[0:12]) + basic2: >(n) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[n, >], pos=[0:12]) + basic3: >=(s) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[s, >=], pos=[0:13]) + basic4: <=(f) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[f, <=], pos=[0:13]) + basic5: <=(b) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[b, <=], pos=[0:13]) + + // Do NOT interpret this the same as `!= type`. + bne1: !=(s) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[s, !=], pos=[0:11]) + bne2: !=(n) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[n, !=], pos=[0:11]) + bne3: !=(n) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[n, !=], pos=[0:11]) + bne4: !=(i) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[i, !=], pos=[0:11]) + bne5: !=(b) @test(err, code=incomplete, contains="non-concrete value %s for bound %s", args=[b, !=], pos=[0:11]) + + e1: <(=~"foo") @test(err, code=incomplete, contains="non-concrete value =~", pos=[0:8]) + e2: >(null) @test(err, code=eval, contains="cannot use null for bound", pos=[0:8]) +} +-- binarystring.cue -- +simplifyBinary: strings: { + err1: { + p1: <"a" & >"b" @test(err, code=eval, contains="incompatible string bounds", pos=[0:16, 0:9]) + p2: >"b" & <"a" @test(err, code=eval, contains="incompatible string bounds", pos=[0:16, 0:9]) + } + err2: { + p1: >"b" & <="a" @test(err, code=eval, contains="incompatible string bounds", pos=[0:16, 0:9]) + p2: <="a" & >"b" @test(err, code=eval, contains="incompatible string bounds", pos=[0:17, 0:9]) + } + err3: { + p1: >="b" & <"b" @test(err, code=eval, contains="incompatible string bounds", pos=[0:17, 0:9]) + p2: <"b" & >="b" @test(err, code=eval, contains="incompatible string bounds", pos=[0:16, 0:9]) + p3: >"b" & <="b" @test(err, code=eval, contains="incompatible string bounds", pos=[0:16, 0:9]) + p4: <="b" & >"b" @test(err, code=eval, contains="incompatible string bounds", pos=[0:17, 0:9]) + } + ok1: { + p1: >"a" & <"b" @test(eq, >"a" & <"b") + p2: <"b" & >"a" @test(eq, >"a" & <"b") + } + ok2: { + p1: >"a" & <="b" @test(eq, >"a" & <="b") + p2: <="b" & >"a" @test(eq, >"a" & <="b") + p3: >="a" & <"b" @test(eq, >="a" & <"b") + p4: <"b" & >="a" @test(eq, >="a" & <"b") + } + ok3: { + p1: >="b" & <="c" @test(eq, >="b" & <="c") + p2: <="c" & >="b" @test(eq, >="b" & <="c") + } + ok4: { + p1: >="b" & <="b" @test(eq, >="b" & <="b") + } +} +simplifyBinary: byte: { + err1: { + p1: <'a' & >'b' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:16, 0:9]) + p2: >'b' & <'a' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:16, 0:9]) + } + err2: { + p1: >'b' & <='a' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:16, 0:9]) + p2: <='a' & >'b' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:17, 0:9]) + } + err3: { + p1: >='b' & <'b' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:17, 0:9]) + p2: <'b' & >='b' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:16, 0:9]) + p3: >'b' & <='b' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:16, 0:9]) + p4: <='b' & >'b' @test(err, code=eval, contains="incompatible bytes bounds", pos=[0:17, 0:9]) + } + ok1: { + p1: >'a' & <'b' @test(eq, >'a' & <'b') + p2: <'b' & >'a' @test(eq, >'a' & <'b') + } + ok2: { + p1: >'a' & <='b' @test(eq, >'a' & <='b') + p2: <='b' & >'a' @test(eq, >'a' & <='b') + p3: >='a' & <'b' @test(eq, >='a' & <'b') + p4: <'b' & >='a' @test(eq, >='a' & <'b') + } + ok3: { + p1: >='b' & <='c' @test(eq, >='b' & <='c') + p2: <='c' & >='b' @test(eq, >='b' & <='c') + } + ok4: { + p1: >='b' & <='b' @test(eq, >='b' & <='b') + } +} +-- binary.cue -- +simplifyBinary: float: { + err1: { + p1: <1 & >2 @test(err, code=eval, contains="incompatible number bounds", pos=[0:14, 0:9]) + p2: >2 & <1 @test(err, code=eval, contains="incompatible number bounds", pos=[0:14, 0:9]) + } + err2: { + p1: >2 & <=1 @test(err, code=eval, contains="incompatible number bounds", pos=[0:14, 0:9]) + p2: <=1 & >2 @test(err, code=eval, contains="incompatible number bounds", pos=[0:15, 0:9]) + } + err3: { + p1: >=2 & <2 @test(err, code=eval, contains="incompatible number bounds", pos=[0:15, 0:9]) + p2: <2 & >=2 @test(err, code=eval, contains="incompatible number bounds", pos=[0:14, 0:9]) + p3: >2 & <=2 @test(err, code=eval, contains="incompatible number bounds", pos=[0:14, 0:9]) + p4: <=2 & >2 @test(err, code=eval, contains="incompatible number bounds", pos=[0:15, 0:9]) + } + ok1: { + p1: >1 & <2 @test(eq, >1 & <2) + p2: <2 & >1 @test(eq, >1 & <2) + } + ok2: { + p1: >=2 & <=2 @test(eq, >=2 & <=2) + p2: <=2 & >=2 @test(eq, >=2 & <=2) + } +} + +simplifyBinary: integer: { + [_]: [_]: int + err1: { + p1: <1 & >2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + p2: >2 & <1 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + } + err2: { + p1: >2 & <=1 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + p2: <=1 & >2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:15, 0:9]) + } + err3: { + p1: >=2 & <2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:15, 0:9]) + p2: <2 & >=2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + p3: >2 & <=2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + p4: <=2 & >2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:15, 0:9]) + } + err4: { + p1: >1 & <2 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + p2: <2 & >1 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:14, 0:9]) + } + ok1: { + p1: >=2 & <=3 @test(eq, >=2 & <=3 & int) + p2: <=3 & >=2 @test(eq, >=2 & <=3 & int) + } + ok2: { + p1: >=2 & <=2 @test(eq, >=2 & <=2 & int) + p2: <=2 & >=2 @test(eq, >=2 & <=2 & int) + } + ok3: { + p1: >=2 & <3 @test(eq, >=2 & <3 & int) + p2: >2 & <=3 @test(eq, >2 & <=3 & int) + p3: <3 & >=2 @test(eq, >=2 & <3 & int) + p4: <=3 & >2 @test(eq, >2 & <=3 & int) + } +} +-- equals.cue -- +@experiment(structcmp) + +equalScalar: { + ok1: ==1 @test(eq, 1) + ok1: 1 + + ok2: [1, 2] + ok2: ==[1, 2] @test(eq, [1, 2]) + + err1: ==1 + err1: 2 @test(err, code=eval, contains="out of bound ==1", pos=[-1:8, 0:8]) + + err2: [1, 2] + err2: !=[1, 2] @test(err, code=eval, contains="out of bound !=", pos=[0:8, -1:8]) +} +equalStruct: { + ok1: =={} @test(eq, {}) + ok1: {} + + ok2: {a: 1, b: 2} + ok2: =={a: 1, b: 2} @test(eq, {a: 1, b: 2}) + + err1: =={} + err1: {a: 1, b: 2} @test(err, code=eval, contains="out of bound ==", pos=[-1:8, 0:8]) + + err2: {a: 1, b: 2} + err2: !={a: 1, b: 2} @test(err, code=eval, contains="out of bound !=", pos=[0:8, -1:8]) +} +nonConcrete: { + ok0: =="foo" @test(eq, =="foo") + + _int: int + + iErr1: ==_int @test(err, code=incomplete, contains="non-concrete value", pos=[0:11]) + + iErr2: !=_int @test(err, code=incomplete, contains="non-concrete value", pos=[0:11]) + + iErr3: ==_int + iErr3: == 1 @test(err, code=incomplete, contains="non-concrete value", pos=[-1:11]) + + ok4: ==1 + ok4: _int @test(eq, ==1 & int) // v3: ==1 & int is not an error + + eErr5: =="foo" + eErr5: _int @test(err, code=eval, contains="conflicting values", pos=[-13:8, -1:9, 0:9]) + + eErr6: ==_int + eErr6: "foo" @test(err, code=incomplete|eval, + hint="incompatible types, so this SHOULD be a permanent error", + contains="non-concrete value", pos=[-1:11]) @test(err:todo, code=eval) +} +-- issue4142.cue -- +@experiment(structcmp) + +inDefinitions: ok1: { + #X: =={ name: "X" } + x: #X & { name: "X" } + @test(eq, {#X: {=={ name: "X" }}, x: {name: "X"}}) +} +inDefinitions: ok2: { + x: #X & { name: "Y" } + #X: !={ name: "X" } + @test(eq, {x: {name: "Y"}, #X: {!={name: "X"}}}) +} +inDefinitions: err1: { + #X: =={ name: "X" } + x: #X & { name: "Y" } + @test(err, code=eval, at=x, contains="out of bound ==", pos=[1:6, 2:5]) +} +inDefinitions: err2: { + #X: !={ name: "X" } + x: #X & { name: "X" } + @test(err, code=eval, at=x, contains="out of bound !=", pos=[1:6, 2:5]) +} +-- issue4251-panic.cue -- +@experiment(structcmp) + +// SimplifyBounds should handle EqualOp bounds +// without panicking, including in combination +// with other bound types. +// Regression: SimplifyBounds panicked on == bounds combined with other bound types. +// https://cuelang.org/issue/4251 +issue4251: ok: { + a: !="c" & =="a" & "a" @test(eq, "a") + b: =="b" & !="c" & "b" @test(eq, "b") + c: =="x" & >="a" & "x" @test(eq, "x") + d: <="z" & =="y" & "y" @test(eq, "y") +} +issue4251: fail: { + b: =="b" & !="b" & "b" @test(err, code=eval, contains="out of bound !=", pos=[0:13, 0:5, 0:21]) +} +-- out/compile -- +--- binary.cue +{ + simplifyBinary: { + float: { + err1: { + p1: (<1 & >2) + p2: (>2 & <1) + } + err2: { + p1: (>2 & <=1) + p2: (<=1 & >2) + } + err3: { + p1: (>=2 & <2) + p2: (<2 & >=2) + p3: (>2 & <=2) + p4: (<=2 & >2) + } + ok1: { + p1: (>1 & <2) + p2: (<2 & >1) + } + ok2: { + p1: (>=2 & <=2) + p2: (<=2 & >=2) + } + } + } + simplifyBinary: { + integer: { + [_]: { + [_]: int + } + err1: { + p1: (<1 & >2) + p2: (>2 & <1) + } + err2: { + p1: (>2 & <=1) + p2: (<=1 & >2) + } + err3: { + p1: (>=2 & <2) + p2: (<2 & >=2) + p3: (>2 & <=2) + p4: (<=2 & >2) + } + err4: { + p1: (>1 & <2) + p2: (<2 & >1) + } + ok1: { + p1: (>=2 & <=3) + p2: (<=3 & >=2) + } + ok2: { + p1: (>=2 & <=2) + p2: (<=2 & >=2) + } + ok3: { + p1: (>=2 & <3) + p2: (>2 & <=3) + p3: (<3 & >=2) + p4: (<=3 & >2) + } + } + } +} +--- binarystring.cue +{ + simplifyBinary: { + strings: { + err1: { + p1: (<"a" & >"b") + p2: (>"b" & <"a") + } + err2: { + p1: (>"b" & <="a") + p2: (<="a" & >"b") + } + err3: { + p1: (>="b" & <"b") + p2: (<"b" & >="b") + p3: (>"b" & <="b") + p4: (<="b" & >"b") + } + ok1: { + p1: (>"a" & <"b") + p2: (<"b" & >"a") + } + ok2: { + p1: (>"a" & <="b") + p2: (<="b" & >"a") + p3: (>="a" & <"b") + p4: (<"b" & >="a") + } + ok3: { + p1: (>="b" & <="c") + p2: (<="c" & >="b") + } + ok4: { + p1: (>="b" & <="b") + } + } + } + simplifyBinary: { + byte: { + err1: { + p1: (<'a' & >'b') + p2: (>'b' & <'a') + } + err2: { + p1: (>'b' & <='a') + p2: (<='a' & >'b') + } + err3: { + p1: (>='b' & <'b') + p2: (<'b' & >='b') + p3: (>'b' & <='b') + p4: (<='b' & >'b') + } + ok1: { + p1: (>'a' & <'b') + p2: (<'b' & >'a') + } + ok2: { + p1: (>'a' & <='b') + p2: (<='b' & >'a') + p3: (>='a' & <'b') + p4: (<'b' & >='a') + } + ok3: { + p1: (>='b' & <='c') + p2: (<='c' & >='b') + } + ok4: { + p1: (>='b' & <='b') + } + } + } +} +--- equals.cue +{ + equalScalar: { + ok1: ==1 + ok1: 1 + ok2: [ + 1, + 2, + ] + ok2: ==[ + 1, + 2, + ] + err1: ==1 + err1: 2 + err2: [ + 1, + 2, + ] + err2: !=[ + 1, + 2, + ] + } + equalStruct: { + ok1: =={} + ok1: {} + ok2: { + a: 1 + b: 2 + } + ok2: =={ + a: 1 + b: 2 + } + err1: =={} + err1: { + a: 1 + b: 2 + } + err2: { + a: 1 + b: 2 + } + err2: !={ + a: 1 + b: 2 + } + } + nonConcrete: { + ok0: =="foo" + _int: int + iErr1: ==〈0;_int〉 + iErr2: !=〈0;_int〉 + iErr3: ==〈0;_int〉 + iErr3: ==1 + ok4: ==1 + ok4: 〈0;_int〉 + eErr5: =="foo" + eErr5: 〈0;_int〉 + eErr6: ==〈0;_int〉 + eErr6: "foo" + } +} +--- in.cue +{ + x0: 5 + x1: (〈0;b5〉 & 30) + b0: (<〈0;x0〉 & >0) + b1: (〈0;b0〉 & int) + b2: (int & <5.5) + b3: (<10 & <=5) + b4: (>=20 & >20) + b5: (>=21 & >20) + b6: ((int & >5) & <=6) + simplifyExpr: { + less1: <<3 + less2: <<=3 + less3: <=<3 + less4: <=<=3 + less5: >3 + gtr2: >>=3 + gtr3: >=>3 + gtr4: >=>=3 + gtr5: >!=3 + gtr6: >=!=3 + lg1: <>3 + lg2: <>=3 + lg3: <=>3 + lg4: <=>=3 + gl1: ><3 + gl2: ><=3 + gl3: >=<3 + gl4: >=<=3 + ne1: !=!=3 + ne2: !=<3 + ne3: !=<=3 + ne4: !=>3 + ne5: !=>=3 + s: string + n: number + i: int + f: float + b: bytes + basic1: <〈0;i〉 + basic2: >〈0;n〉 + basic3: >=〈0;s〉 + basic4: <=〈0;f〉 + basic5: <=〈0;b〉 + bne1: !=〈0;s〉 + bne2: !=〈0;n〉 + bne3: !=〈0;n〉 + bne4: !=〈0;i〉 + bne5: !=〈0;b〉 + e1: <=~"foo" + e2: >null + } +} +--- issue4142.cue +{ + inDefinitions: { + ok1: { + #X: =={ + name: "X" + } + x: (〈0;#X〉 & { + name: "X" + }) + } + } + inDefinitions: { + ok2: { + x: (〈0;#X〉 & { + name: "Y" + }) + #X: !={ + name: "X" + } + } + } + inDefinitions: { + err1: { + #X: =={ + name: "X" + } + x: (〈0;#X〉 & { + name: "Y" + }) + } + } + inDefinitions: { + err2: { + #X: !={ + name: "X" + } + x: (〈0;#X〉 & { + name: "X" + }) + } + } +} +--- issue4251-panic.cue +{ + issue4251: { + ok: { + a: ((!="c" & =="a") & "a") + b: ((=="b" & !="c") & "b") + c: ((=="x" & >="a") & "x") + d: ((<="z" & =="y") & "y") + } + } + issue4251: { + fail: { + b: ((=="b" & !="b") & "b") + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/bulk.txtar b/internal/core/compile/testdata/sync/eval/bulk.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/bulk.txtar @@ -0,0 +1,493 @@ +// Tests bulk pattern constraints including pattern cycles, multiple pattern +// constraints, and field-not-allowed errors from pattern constraint closedness. +// Also covers regressions: issue 2109 (pattern cycle detection), issue 3638 +// (closedness/default markers erased in multiple contexts), and issue 3670 +// (int pattern incorrectly allowing non-int fields). +-- in.cue -- +a: { + foo: a: 1 + [X = =~"foo"]: { + b: 1 + name: X + } + + @test(eq, { + [=~"foo"]: { b: 1, name: string } + foo: {a: 1, b: 1, name: "foo"} + }) + @test(allows, foo) + @test(allows, foobar) + @test(allows, string) + // TODO(eval): struct isn't closed, so this should be true. + @test(allows:todo=false, bar) +} +d: a & { + "foobar": { + c: 2 + } +} @test(eq, { + foobar: {c: 2, b: 1, name: "foobar"} + foo: {a: 1, b: 1, name: "foo"} +}) + +t1: { + #a: { + [>"e" & <"z"]: int + } + // TODO(inline): support allow on fields. + b: #a & {f: 4} @test(eq, {f: 4}) @test(allows, f) @test(allows=false, a) @test(allows=false, string) + c: #a & {z: 4} @test(err, code=eval, at=z, contains="field not allowed", pos=[0:11]) +} + +t2: { + #a: { + ["x" | "y"]: int + } + // TODO(inline): support allow on fields. + b: #a & {x: 4} @test(eq, {x: 4}) @test(allows, x) @test(allows=false, z) @test(allows=false, string) + c: #a & {z: 4} @test(err, code=eval, at=z, contains="field not allowed", pos=[0:11]) +} + +-- issue2109.cue -- +// Detect cycle: +// The pattern constraint of FlagsURLS is applied to countries (because +// FlagsURLs is embedded. But the pattern constraint itself refers to +// countries. So countries -> or(countries) -> countries. +// +// Theoretically, or(countries) can be resolved without a cycle. And then we +// could see it does not apply to countries. For now we stick with this +// approach understanding that it is easier to relax later. +patternCycle: issue2109: p1: { + // TODO(inline: permute doesn't permute embeddings, so the permute count + // here is 2, not 6. Fix this. + countries: ["US", "GB", "AU"] + FlagsURLs: {[or(countries)]: string} + FlagsURLs + @test(eq, { + countries: ["US", "GB", "AU"] + FlagsURLs: {} + }) +} +patternCycle: issue2109: p2: { + FlagsURLs: {[or(countries)]: string} + FlagsURLs + countries: ["US", "GB", "AU"] + @test(eq, { + FlagsURLs: {} + countries: ["US", "GB", "AU"] + }) +} +patternCycle: issue2109: p3: { + FlagsURLs + FlagsURLs: {[or(countries)]: string} + countries: ["US", "GB", "AU"] + @test(eq, { + FlagsURLs: {} + countries: ["US", "GB", "AU"] + }) +} + +patternCycle: t1: p1: { + countries: "US" | "GB" | "AU" + FlagsURLs: {[countries]: string} + FlagsURLs + @test(eq, { + countries: "US" | "GB" | "AU" + FlagsURLs: {} + }) +} +patternCycle: t1: p2: { + FlagsURLs + countries: "US" | "GB" | "AU" + FlagsURLs: {[countries]: string} + @test(eq, { + countries: "US" | "GB" | "AU" + FlagsURLs: {} + }) +} +patternCycle: t1: p3: { + FlagsURLs + FlagsURLs: {[countries]: string} + countries: "US" | "GB" | "AU" + @test(eq, { + FlagsURLs: {} + countries: "US" | "GB" | "AU" + }) +} + +-- intpattern.cue -- +// evalv3 regression: a pattern constraint definition with int key incorrectly +// allowed a non-matching (non-int) field. +// https://cuelang.org/issue/3670 +issue3670: { + #X: [int]: string + a: #X + a: "not_int": "c" @test(err, code=eval, contains="field not allowed", pos=[0:5]) +} +dual: { + _ + // As long as it is undecided whether this is a struct or list, this should + // not be a conflict. Note that the spec does not allow int patterns, but + // both v2 and v3 allow it, and we soon will, so it seems gratuitous to + // break it now. + [string]: _ + [int]: _ + + @test(eq, {_, [int]: _, [string]: _}) + + // TODO: test allows once we know what it means in this case. +} +-- multi.cue -- +// evalv3 regression: closedness values and default markers were incorrectly +// erased, causing order-dependent "incomplete value" errors. +// https://cuelang.org/issue/3638 +// Ensure that if the same pattern is added multiple times in different +// contexts, it is added to all contexts to preserve closedness information. +issue3638: full: { + routes: default: {} + routes: [string]: spec: [{ + + refs: [{"default"}] + }] + #Fields: { + input: _ + output: [for x in input { x }] @test(err, code=incomplete, contains="cannot range over input (incomplete type _)", pos=[0:21]) + ... + } + #Kubernetes: { + #Fields & { + Routes: route: [_]: spec!: HTTPROUTESPEC.#x + } + #Fields // Commenting out this line also fixes evalv3. + Routes: _ + input: res1: Routes + } + let HTTPROUTESPEC = { + #x: [...{ + refs: [...{string}] + }] | *[{ + other: [] + }] + } + + // Order dependent! Breaks if the lines below are moved to the top of the file. + entrypoint: used.output + used: #Kubernetes & { + Routes: route: routes + } + @test(eq, { + routes: default: {spec: [{ refs: ["default"] }]} + #Fields: { + input: _ + output: _|_ + } + #Kubernetes: { + Routes: route: {} + input: res1: route: {} + output: [{ route: {} }] + } + entrypoint: [{ route: default: spec: [{ refs: ["default"] }] }] + used: { + Routes: route: default: spec: [{ refs: ["default"] }] + input: res1: route: default: spec: [{ refs: ["default"] }] + output: [{ + route: default: spec: [{ refs: ["default"] }] + }] + } + }) +} +issue3638: reduced: { + input: k1: [string]: a: 1 + input: k1: foo: #x + out: { + for x in input { x } + for x in input { x } + } + #x: { a: int } | *{ b: 2 } + @test(eq, { + input: k1: foo: {a: 1} + out: foo: a: 1 + #x: *{b: 2} | {a: int} + }) +} +// We expect that changing the pattern constraint into a field should give +// not materially change the outcome. +issue3638: compare: { + input: k1: foo: a: 1 + input: k1: foo: #x + out: { + for x in input { x } + for x in input { x } + } + #x: { a: int } | *{ b: 2 } + @test(eq, { + input: k1: foo: {a: 1} + out: foo: a: 1 + #x: *{b: 2} | {a: int} + }) +} +-- out/compile -- +--- in.cue +{ + a: { + foo: { + a: 1 + } + [=~"foo"]: { + b: 1 + name: 〈1;-〉 + } + } + d: (〈0;a〉 & { + foobar: { + c: 2 + } + }) + t1: { + #a: { + [(>"e" & <"z")]: int + } + b: (〈0;#a〉 & { + f: 4 + }) + c: (〈0;#a〉 & { + z: 4 + }) + } + t2: { + #a: { + [("x"|"y")]: int + } + b: (〈0;#a〉 & { + x: 4 + }) + c: (〈0;#a〉 & { + z: 4 + }) + } +} +--- intpattern.cue +{ + issue3670: { + #X: { + [int]: string + } + a: 〈0;#X〉 + a: { + not_int: "c" + } + } + dual: { + _ + [string]: _ + [int]: _ + } +} +--- issue2109.cue +{ + patternCycle: { + issue2109: { + p1: { + countries: [ + "US", + "GB", + "AU", + ] + FlagsURLs: { + [or(〈1;countries〉)]: string + } + 〈0;FlagsURLs〉 + } + } + } + patternCycle: { + issue2109: { + p2: { + FlagsURLs: { + [or(〈1;countries〉)]: string + } + 〈0;FlagsURLs〉 + countries: [ + "US", + "GB", + "AU", + ] + } + } + } + patternCycle: { + issue2109: { + p3: { + 〈0;FlagsURLs〉 + FlagsURLs: { + [or(〈1;countries〉)]: string + } + countries: [ + "US", + "GB", + "AU", + ] + } + } + } + patternCycle: { + t1: { + p1: { + countries: ("US"|"GB"|"AU") + FlagsURLs: { + [〈1;countries〉]: string + } + 〈0;FlagsURLs〉 + } + } + } + patternCycle: { + t1: { + p2: { + 〈0;FlagsURLs〉 + countries: ("US"|"GB"|"AU") + FlagsURLs: { + [〈1;countries〉]: string + } + } + } + } + patternCycle: { + t1: { + p3: { + 〈0;FlagsURLs〉 + FlagsURLs: { + [〈1;countries〉]: string + } + countries: ("US"|"GB"|"AU") + } + } + } +} +--- multi.cue +{ + issue3638: { + full: { + routes: { + default: {} + } + routes: { + [string]: { + spec: [ + { + refs: [ + { + "default" + }, + ] + }, + ] + } + } + #Fields: { + input: _ + output: [ + for _, x in 〈1;input〉 { + 〈1;x〉 + }, + ] + ... + } + #Kubernetes: { + (〈1;#Fields〉 & { + Routes: { + route: { + [_]: { + spec!: 〈5;let HTTPROUTESPEC#1〉.#x + } + } + } + }) + 〈1;#Fields〉 + Routes: _ + input: { + res1: 〈1;Routes〉 + } + } + let HTTPROUTESPEC#1 = { + #x: ([ + ...{ + refs: [ + ...{ + string + }, + ] + }, + ]|*[ + { + other: [] + }, + ]) + } + entrypoint: 〈0;used〉.output + used: (〈0;#Kubernetes〉 & { + Routes: { + route: 〈2;routes〉 + } + }) + } + } + issue3638: { + reduced: { + input: { + k1: { + [string]: { + a: 1 + } + } + } + input: { + k1: { + foo: 〈2;#x〉 + } + } + out: { + for _, x in 〈1;input〉 { + 〈1;x〉 + } + for _, x in 〈1;input〉 { + 〈1;x〉 + } + } + #x: ({ + a: int + }|*{ + b: 2 + }) + } + } + issue3638: { + compare: { + input: { + k1: { + foo: { + a: 1 + } + } + } + input: { + k1: { + foo: 〈2;#x〉 + } + } + out: { + for _, x in 〈1;input〉 { + 〈1;x〉 + } + for _, x in 〈1;input〉 { + 〈1;x〉 + } + } + #x: ({ + a: int + }|*{ + b: 2 + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/closed_disjunction.txtar b/internal/core/compile/testdata/sync/eval/closed_disjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/closed_disjunction.txtar @@ -0,0 +1,40 @@ +-- in.cue -- +#A: { + b?: int + *{} | {c?: int} | {d?: int} | {e?: int} +} @test(eq, *{b?: int} | {b?: int, c?: int} | {b?: int, d?: int} | {b?: int, e?: int}) + +a: #A & { + b: 3 + c: 3 +} @test(eq, {b: 3, c: 3}) @test(closed) + +b: #A & { + c: 3 + d: 4 +} @test(err, code=eval, contains="2 errors in empty disjunction",, + suberr=(code=eval, contains="field not allowed", pos=[1:2]), + suberr=(code=eval, contains="field not allowed", pos=[2:2]) +) +-- out/compile -- +--- in.cue +{ + #A: { + b?: int + (*{}|{ + c?: int + }|{ + d?: int + }|{ + e?: int + }) + } + a: (〈0;#A〉 & { + b: 3 + c: 3 + }) + b: (〈0;#A〉 & { + c: 3 + d: 4 + }) +} diff --git a/internal/core/compile/testdata/sync/eval/closedness.txtar b/internal/core/compile/testdata/sync/eval/closedness.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/closedness.txtar @@ -0,0 +1,2290 @@ +// Issue #852 +-- in.cue -- +#E: { + c: int +} +#A: { + b: int + q: { + #E + d: int + } +} +a: #A & { + b: 3 + q: { + c: 2 + e: 43 + } +} @test(err, code=eval, contains="field not allowed", pos=[4:3]) + +// A constraint validation error fails to trigger when a field violating a +// regex pattern constraint is duplicated via a for-loop comprehension. +// https://cuelang.org/issue/852 +// `a` is evaluated through the comprehension first. Ensure that +// this does not bypass closedness checks. +issue852: { + #A: { + [=~"^a-z$"]: string + } + + a: #A + + a: Foo: "foo" + + for k, v in a { + b: "\(k)": v + } +} @test(err, code=eval, contains="field not allowed", pos=[7:5]) + +dynamic: { + #D: { + key: "foo" + (key): int + } + d: #D & {foo: 3} + @test(eq, { + #D: {key: "foo", foo: int} + d: {foo: 3, key: "foo"} + }) +} + +// Closedness appeared to be lost when using a comprehension: CUE incorrectly +// produced "incomplete value" errors for disjunctions inside if/for blocks. +// https://cuelang.org/issue/4180 +// The `if true` comprehension would lead to ambiguity in out.iter.FooOrBar, +// even though {foo: "is foo"} does not unify with `#Bar & {...}`. +issue4180: { + out: { + if true { + iter: #Schema & { + FooOrBar: foo: "is foo" + } + } + } + + #Foo: foo: string + #Bar: bar: string + #Schema: { + FooOrBar: {...} + FooOrBar: #Foo | #Bar + } + @test(eq, { + out: {iter: {FooOrBar: {foo: "is foo"}}} + #Foo: {foo: string} + #Bar: {bar: string} + #Schema: { + FooOrBar: {foo: string} | {bar: string} + } + }) +} +-- embed.cue -- +// evalv3: ordering of embedded structs affects template definition evaluation, +// causing validation errors that shouldn't occur when structs are reordered. +// https://cuelang.org/issue/3325 +issue3325: ok: { + #Items: [Name=string]: { + name: Name + } + + #Base: { + name: "base" + type: string + + items: #Items + } + + #Extended: #Base & { + type: "extended" + items: "my-item": {} + } + + broken: { + #Base + #Extended + } + + works: { + #Extended + #Base + } + @test(eq, { + #Items: {} + #Base: {name: "base", type: string, items: {}} + #Extended: { + type: "extended" + items: {"my-item": {name: "my-item"}} + name: "base" + } + broken: { + name: "base" + type: "extended" + items: {"my-item": {name: "my-item"}} + } + works: { + type: "extended" + items: {"my-item": {name: "my-item"}} + name: "base" + } + }) +} + +patterns: shallow: { + #a: [>="k"]: int + #b: [<="m"]: int + #c: [>="w"]: int + #d: [<="y"]: int + + single: { + X: #a // "k" <= x + err: X @test(err, code=eval, path=j, contains="field not allowed", pos=[1:8]) + err: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + and: p1: { + X: #a & #b // "k" <= x && x <= "m" + + err: X @test(err, code=eval, path=j, contains="field not allowed", pos=[-16:6, 1:8]) + err: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + and: p2: { + X: #b & #a // "k" <= x && x <= "m" + err: X @test(err, code=eval, path=j, contains="field not allowed", pos=[-25:6, 1:8]) + err: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + andEmbed: p1: { + X: { #a & #b } // "k" <= x && x <= "m" + + err: X @test(err, code=eval, path=j, contains="field not allowed", pos=[-35:6, 1:8]) + err: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + andEmbed: p2: { + X: { #b & #a } // "k" <= x && x <= "m" + err: X @test(err, code=eval, path=j, contains="field not allowed", pos=[-44:6, 1:8]) + err: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + orEmbed: p1: { + X: { #a, #b } // "k" <= x && x <= "m" + + ok1: X @test(eq, {j: 3}) + ok1: j: 3 + + ok2: X @test(eq, {k: 3}) + ok2: k: 3 + } + + orEmbed: p2: { + X: { #b, #a } // "k" <= x && x <= "m" + ok1: X @test(eq, {j: 3}) + ok1: j: 3 + + ok2: X @test(eq, {k: 3}) + ok2: k: 3 + } + + andOrEmbed: t1: p1: { + // ("k" <= x && x <= "m") || ("w" <= x && x <= "y") + X: { + #a & #b + #c & #d + } + err1: X @test(eq, {j: 3}) + err1: j: 3 + + ok1: X @test(eq, {k: 3}) + ok1: k: 3 + } + + andOrEmbed: t1: p2: { + // ("k" <= x && x <= "m") || ("w" <= x && x <= "y") + X: { + #c & #d + #a & #b + } + err1: X @test(eq, {j: 3}) + err1: j: 3 + + ok1: X @test(eq, {k: 3}) + ok1: k: 3 + } + + andOrEmbed: t2: { + // ("k" <= x && x <= "m") || ("w" <= x && x <= "y") || x == "p" + X: { + #a & #b + #c & #d + ["p"]: int + } + err1: X @test(eq, {j: 3}) + err1: j: 3 + + ok1: X @test(eq, {k: 3}) + ok1: k: 3 + + ok2: X @test(eq, {p: 3}) + ok2: p: 3 + } + + // The last indirection is not a definition. + indirect: { + a: [>="k"]: int + #a: a + + p1: { // XXX // link to code + X: #a + err1: X @test(err, code=eval, path=j, contains="field not allowed", pos=[1:10]) + err1: j: 3 + + err2: X & __no_sharing + err2: j: 3 @test(err, code=eval, contains="field not allowed", pos=[0:10]) + + ok: X + ok:k: 3 @test(eq, 3) + } + + p2: { + #a: a & __no_sharing + X: #a + + err1: X + err1: j: 3 @test(err, code=eval, contains="field not allowed", pos=[0:10]) + + err2: X & __no_sharing @test(err, code=eval, path=j, contains="field not allowed", pos=[1:10]) + err2: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + p3: { + X: #a & __no_sharing + + err1: X @test(err, code=eval, path=j, contains="field not allowed", pos=[1:10]) + err1: j: 3 + + err2: X & __no_sharing @test(err, code=eval, path=j, contains="field not allowed", pos=[1:10]) + err2: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + + p4: { + #a: a & __no_sharing + X: #a + X: #a & __no_sharing + + err1: X @test(err, code=eval, path=j, contains="field not allowed", pos=[1:10]) + err1: j: 3 + + err2: X & __no_sharing @test(err, code=eval, path=j, contains="field not allowed", pos=[1:10]) + err2: j: 3 + + ok: X @test(eq, {k: 3}) + ok: k: 3 + } + } +} + +patterns: nested: { + #a: x: y: [>="k"]: int + #b: x: y: [<="m"]: int + #c: x: y: [>="w"]: int + #d: x: y: [<="y"]: int + + single: { + X: #a // "k" <= x + err: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:14]) + err: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + and: p1: { + X: #a & #b // "k" <= x && x <= "m" + + err: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[-16:12, 1:14]) + err: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + and: p2: { + X: #b & #a // "k" <= x && x <= "m" + err: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[-25:12, 1:14]) + err: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + andEmbed: p1: { + X: { #a & #b } // "k" <= x && x <= "m" + + err: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[-35:12, 1:14]) + err: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + andEmbed: p2: { + X: { #b & #a } // "k" <= x && x <= "m" + err: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[-44:12, 1:14]) + err: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + orEmbed: p1: { + X: { #a, #b } // "k" <= x && x <= "m" + + ok1: X @test(eq, {x: {y: {j: 3}}}) + ok1: x: y: j: 3 + + ok2: X @test(eq, {x: {y: {k: 3}}}) + ok2: x: y: k: 3 + } + + orEmbed: p2: { + X: { #b, #a } // "k" <= x && x <= "m" + ok1: X @test(eq, {x: {y: {j: 3}}}) + ok1: x: y: j: 3 + + ok2: X @test(eq, {x: {y: {k: 3}}}) + ok2: x: y: k: 3 + } + + andOrEmbed: t1: p1: { + // ("k" <= x && x <= "m") || ("w" <= x && x <= "y") + X: { + #a & #b + #c & #d + } + err1: X @test(eq, {x: {y: {j: 3}}}) + err1: x: y: j: 3 + + ok1: X @test(eq, {x: {y: {k: 3}}}) + ok1: x: y: k: 3 + } + + andOrEmbed: t1: p2: { + // ("k" <= x && x <= "m") || ("w" <= x && x <= "y") + X: { + #c & #d + #a & #b + } + err1: X @test(eq, {x: {y: {j: 3}}}) + err1: x: y: j: 3 + + ok1: X @test(eq, {x: {y: {k: 3}}}) + ok1: x: y: k: 3 + } + + andOrEmbed: t2: { + // ("k" <= x && x <= "m") || ("w" <= x && x <= "y") || x == "p" + X: { + #a & #b + #c & #d + ["p"]: int + } + err1: X @test(eq, {x: {y: {j: 3}}}) + err1: x: y: j: 3 + + ok1: X @test(eq, {x: {y: {k: 3}}}) + ok1: x: y: k: 3 + + ok2: X @test(eq, {x: {y: {p: 3}}}) + ok2: x: y: p: 3 + } + + // The last indirection is not a definition. + indirect: { + a: x: y: [>="k"]: int + #a: a + + p1: { + X: #a + err1: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err1: x: y: j: 3 + + err2: X & __no_sharing @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err2: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + p2: { + #a: a & __no_sharing + X: #a + + err1: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err1: x: y: j: 3 + + err2: X & __no_sharing @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err2: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + p3: { + X: #a & __no_sharing + + err1: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err1: x: y: j: 3 + + err2: X & __no_sharing @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err2: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + + p4: { + #a: a & __no_sharing + X: #a + X: #a & __no_sharing + + err1: X @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err1: x: y: j: 3 + + err2: X & __no_sharing @test(err, code=eval, path=x.y.j, contains="field not allowed", pos=[1:16]) + err2: x: y: j: 3 + + ok: X @test(eq, {x: {y: {k: 3}}}) + ok: x: y: k: 3 + } + } +} @test(err, code=eval, contains="field not allowed", pos=[168:16]) + +// Embedding a definition doesn't recursively close the embedder: closedness +// is not propagated correctly when a definition is embedded in an open struct. +// https://cuelang.org/issue/2241 +issue2241: { + #close: {} + + a: { + x: q: 2 + #close + } + + b: a + b: x: r: 4 +} @test(err, code=eval, path=b.x.r, contains="field not allowed", pos=[9:8]) + +-- ellipsis.cue -- +// evalv3 regression: unification with {...} allowed extra fields where evalv2 +// correctly rejected them as "field not allowed". +// https://cuelang.org/issue/3778 +issue3778: full: { + #x: a?: string + #y: #x & { ... } + z: #y & { + a: "ok" + b: "something" + } + @test(err, code=eval, path=z.b, contains="field not allowed", pos=[5:3]) +} +issue3778: { + keepOpen: { + #x: { a?: string, ... } + #y: #x & { ... } + z: #y & { + a: "ok" + b: "something" + } + @test(eq, { + #x: {a?: string} + #y: {a?: string} + z: {a: "ok", b: "something"} + }) + } +} + +// Unification of a closed struct in a subfield does not close it: the evaluator +// incorrectly allows adding fields to a closed struct unified with ellipsis. +// https://cuelang.org/issue/1867 +// All three reproducers below should fail with "field not allowed". +issue1867: one: { + #T: close({}) + #T: {...} + x: #T + x: foo: "foo" + @test(err, code=eval, path=x.foo, contains="field not allowed", pos=[4:5]) +} +issue1867: two: { + #S: {} + #T: s: #S + #T: s: {...} + x: #T.s + x: foo: "foo" + @test(err, code=eval, path=x.foo, contains="field not allowed", pos=[5:5]) +} +// This third version used to not fail as expected on evalv2. +issue1867: three: { + #T: s: close({}) + #T: s: {...} + x: #T.s + x: foo: "foo" + @test(err, code=eval, contains="field not allowed", pos=[4:5]) +} +// evalv3 regression in detecting closedness: "field not allowed" errors were +// incorrectly suppressed when validating nested structures with closedness constraints. +// https://cuelang.org/issue/3924 +issue3924: one: { + #Schema: { + ... + {[string]: #SchemaInner} + } + #SchemaInner: allowed?: string + + out: #Schema & {foo: disallowed: "foo"} // should fail + @test(err, code=eval, path=out.foo.disallowed, contains="field not allowed", pos=[7:23]) +} +issue3924: two: { + #Schema: { + {[string]: #job} + + #job: matchN(1, [{ + other?: string + ... + }]) & close({ + allowed?: string + }) + } + out: #Schema & {foo: disallowed: "bar"} // should fail + @test(err, code=eval, path=out.foo.disallowed, contains="field not allowed", pos=[4:9, 11:23]) +} +issue3924: three: t1: { + {foo: #job & {disallowed: "bar"}} + #job: { other?: string } + #job: #def + #def: allowed?: string + @test(err, code=eval, path=foo.disallowed, contains="field not allowed", pos=[1:16]) +} +issue3924: three: t2: { + {foo: #job & {disallowed: "bar"}} + #job: { other?: string, ... } + #job: #def + #def: allowed?: string + @test(err, code=eval, path=foo.disallowed, contains="field not allowed", pos=[1:16]) +} +issue3924: three: t3: { + #job: { ... } + #job: #def + #def: {} + foo: #job & {disallowed: "bar"} + @test(err, code=eval, path=foo.disallowed, contains="field not allowed", pos=[4:15]) +} +issue3924: four: { + A: { {foo: #B} } + #B: allowed?: string + out: A & {foo: disallowed: "foo"} // should fail + @test(err, code=eval, contains="field not allowed", pos=[3:17]) +} +-- reroot.cue -- +import "list" + +// evalv3 panic "unexpected uninitialized node" while processing certain +// config files using list.Concat with definitions. +// https://cuelang.org/issue/3330 +issue3330: { + let: ok: { + #struct: { + let empty = {} + + field: null | { n: int } + field: empty & { n: 3 } + } + + out: list.Concat([[#struct]]) + @test(eq, { + #struct: {field: {n: 3}} + out: [{ + field: n: 3 + }] + }) + } + matthew: ok1: { + #struct: { + field: { n: 3 } & g + g: {} + } + + out: #struct & {} + @test(eq, { + #struct: {field: {n: 3}, g: {}} + out: {field: {n: 3}, g: {}} + }) + } + matthew: ok2: { + #struct: { + field: { n: 3 } & g + g: {} + } + + out: #struct + out2: out & {} + @test(eq, { + #struct: {field: {n: 3}, g: {}} + out: {field: {n: 3}, g: {}} + out2: {field: {n: 3}, g: {}} + }) + } +} +// evalv3 "field not allowed" regression: a valid struct with a let binding and +// field unification incorrectly produces "field not allowed". +// https://cuelang.org/issue/3331 +issue3331: { + original: ok: { + #A: { + let b = {} + c: b & { + d: 1 + } + } + list.Concat([[#A]]) + @test(eq, { + #A: {c: {d: 1}} + [{c: {d: 1}}] + }) + } + variant1: ok: { + #A: { + let b = {} + c: b & { + d: 1 + } + } + [[#A]] + @test(eq, { + #A: {c: {d: 1}} + [[{c: {d: 1}}]] + }) + } + @test(eq, { + original: {ok: { + #A: {c: {d: 1}} + [{c: {d: 1}}] + }} + variant1: {ok: { + #A: {c: {d: 1}} + [[{c: {d: 1}}]] + }} + }) +} + +// indirect tests cases where a reference indirectly crosses a node that +// references a definition, thereby indirectly referencing it. +indirect: { + embed: err1: { + #A: { + x: {#x, #y} + zx: x.a + } + + #x: {a: b: 1} + #y: {a: c: 2} + + b: #A + + b1: b.zx + b1: d: 1 // This should fail as b.zx crosses a reference to definition. + @test(err:todo) + @test(eq, { + #A: {x: {a: {b: 1, c: 2}}, zx: {b: 1, c: 2}} + #x: {a: {b: 1}} + #y: {a: {c: 2}} + b: {x: {a: {b: 1, c: 2}}, zx: {b: 1, c: 2}} + b1: {d: 1, b: 1, c: 2} + }) + } + closed: err1: { + X: { + // refer to a value that will be closed after unification in another struct. + a: b + b: {} + a: e: 1 + } + Y: X + Y: { + b: c + c: #X + } + #X: {} + @test(err, at=Y.a.e, code=eval, contains="field not allowed", pos=[5:7]) + } +} +// nested.a +nested: ok1: { + #A: { + b: {} + + #B: { + c: b & { + d: 1 + } + } + } + x: #A + @test(eq, { + #A: {b: {}, #B: {c: {d: 1}}} + x: {b: {}, #B: {c: {d: 1}}} + }) +} +nested: embed: ok: { + x: #A + #A: { + k + } + k: { + d: b & {e: int} + b: {} + } + @test(eq, { + x: {d: {e: int}, b: {}} + #A: {d: {e: int}, b: {}} + k: {d: {e: int}, b: {}} + }) +} +// nested.b tests insertion of a field (b) that has a conjunct rooted within +// the tree it is referred in as well as a conjunct outside of it that refers +// to a definition. +nested: err1: { + x: #A + #A: { + b: f: 1 + v: #V + #V: { + c: b & { // Fails as #B is not compatible. + d: 1 + } + } + } + x: b: #B + #B: g: 1 + @test(err, at=x.#V.c.d, code=eval, contains="field not allowed", pos=[7:5]) +} + +nested: err2: { + #A: { + b: {} // error only reported here. + c: b & { + // error (g not allowed) not reported here, as it would be okay if b + // were valid. Instead, it is reported at b only. This is conform + // the spec. + d: 1 + } + } + x: #A + x: b: g: 1 + @test(err, at=x.b.g, code=eval, contains="field not allowed", pos=[11:8]) +} + +inline: { + #x: y: z?: name: string + + // TODO: not an error!? + err1: (#x & {y: z: _}).y.z & { + name: "a" + age1: 5 // not allowed + } @test(err:todo, code=eval, contains="field not allowed") + err2: (#x.y & {z: _}).z & { + name: "a" + age2: 5 // not allowed + } @test(err:todo, code=eval, contains="field not allowed") + @test(eq, { + #x: {y: {z?: {name: string}}} + err1: {name: "a", age1: 5} + err2: {name: "a", age2: 5} + }) +} + +// minInDef defines examples where a definition is mixed into an open struct, +// where then this struct refers to a field that is closed by the definition. +mixInDef: { + refInside: { + #x: b: c: {d: {}, e: f: {} } + a: #x + a: b: c: d: {} + a: b: c: e: c.d + @test(eq, { + #x: {b: {c: {d: {}, e: {f: {}}}}} + a: {b: {c: {d: {}, e: {f: {}}}}} + }) + } + refEdge: { + #x: c: {d: {}, e: f: {} } + a: #x + a: c: d: {} + a: c: e: c.d + @test(eq, { + #x: {c: {d: {}, e: {f: {}}}} + a: {c: {d: {}, e: {f: {}}}} + }) + } + refOutside: { + #x: c: {d: {}, e: f: {} } + a: #x + a: c: d: {} + a: c: e: a.c.d // crosses definition + @test(eq, { + #x: {c: {d: {}, e: {f: {}}}} + a: {c: {d: {}, e: {f: {}}}} + }) + } +} + +// evalv3 "field not allowed" regression: out.foo.final.version incorrectly +// rejected when embedding a definition's output through a transformed struct. +// https://cuelang.org/issue/3601 +issue3601: original: { + out: { + #Transform.output + } + #Transform: output: (#Patch & {}).output + #Patch: { + target: {} + output: foo: { + final: target + final: version: "v1" + } + } + @test(eq, { + out: {foo: {final: {version: "v1"}}} + #Transform: { + output: {foo: {final: {version: "v1"}}} + } + #Patch: { + target: {} + output: {foo: {final: {version: "v1"}}} + } + }) +} +issue3601: originalNoShare: { + // Like the original, but with explicit no sharing. + out: { + #Transform.output + } + #Transform: output: (#Patch & __no_sharing).output + #Patch: { + target: {} + output: foo: { + final: target + final: version: "v1" + } + } + @test(eq, { + out: {foo: {final: {version: "v1"}}} + #Transform: { + output: {foo: {final: {version: "v1"}}} + } + #Patch: { + target: {} + output: {foo: {final: {version: "v1"}}} + } + }) +} +issue3601: reduced: { + #X: { + a: b: c: "v1" + a: b: empty + empty: {} + } + + original: { + Y: (#X & __no_sharing).a + out: Y & __no_sharing + } + moreInlining: { + out: (#X & {}).a & {} + } + noInline: { + Y: #X & __no_sharing + Z: Y & __no_sharing + out: Z.a & __no_sharing + } + moreNesting: { + #X: { + a: b: c: d: "v1" + a: b: c: empty + empty: {} + } + Y: (#X.a & __no_sharing).b + Z: Y & __no_sharing + } + @test(eq, { + #X: {a: {b: {c: "v1"}}, empty: {}} + original: {Y: {b: {c: "v1"}}, out: {b: {c: "v1"}}} + moreInlining: {out: {b: {c: "v1"}}} + noInline: { + Y: {a: {b: {c: "v1"}}, empty: {}} + Z: {a: {b: {c: "v1"}}, empty: {}} + out: {b: {c: "v1"}} + } + moreNesting: { + #X: {a: {b: {c: {d: "v1"}}}, empty: {}} + Y: {c: {d: "v1"}} + Z: {c: {d: "v1"}} + } + }) +} + +-- validation.cue -- +import "list" + +// evalv3: struct with only list.MinItems does not allow a valid list field to +// exist, reporting "field not allowed" instead of accepting it. +// https://cuelang.org/issue/3332 +issue3332: { + #def: field: list.MinItems(1) + use: #def & { + field: ["value"] + } + @test(eq, { + #def: {field: list.MinItems(1)} + use: {field: ["value"]} + }) +} + +-- out/compile -- +--- ellipsis.cue +{ + issue3778: { + full: { + #x: { + a?: string + } + #y: (〈0;#x〉 & { + ... + }) + z: (〈0;#y〉 & { + a: "ok" + b: "something" + }) + } + } + issue3778: { + keepOpen: { + #x: { + a?: string + ... + } + #y: (〈0;#x〉 & { + ... + }) + z: (〈0;#y〉 & { + a: "ok" + b: "something" + }) + } + } + issue1867: { + one: { + #T: close({}) + #T: { + ... + } + x: 〈0;#T〉 + x: { + foo: "foo" + } + } + } + issue1867: { + two: { + #S: {} + #T: { + s: 〈1;#S〉 + } + #T: { + s: { + ... + } + } + x: 〈0;#T〉.s + x: { + foo: "foo" + } + } + } + issue1867: { + three: { + #T: { + s: close({}) + } + #T: { + s: { + ... + } + } + x: 〈0;#T〉.s + x: { + foo: "foo" + } + } + } + issue3924: { + one: { + #Schema: { + ... + { + [string]: 〈2;#SchemaInner〉 + } + } + #SchemaInner: { + allowed?: string + } + out: (〈0;#Schema〉 & { + foo: { + disallowed: "foo" + } + }) + } + } + issue3924: { + two: { + #Schema: { + { + [string]: 〈1;#job〉 + } + #job: (matchN(1, [ + { + other?: string + ... + }, + ]) & close({ + allowed?: string + })) + } + out: (〈0;#Schema〉 & { + foo: { + disallowed: "bar" + } + }) + } + } + issue3924: { + three: { + t1: { + { + foo: (〈1;#job〉 & { + disallowed: "bar" + }) + } + #job: { + other?: string + } + #job: 〈0;#def〉 + #def: { + allowed?: string + } + } + } + } + issue3924: { + three: { + t2: { + { + foo: (〈1;#job〉 & { + disallowed: "bar" + }) + } + #job: { + other?: string + ... + } + #job: 〈0;#def〉 + #def: { + allowed?: string + } + } + } + } + issue3924: { + three: { + t3: { + #job: { + ... + } + #job: 〈0;#def〉 + #def: {} + foo: (〈0;#job〉 & { + disallowed: "bar" + }) + } + } + } + issue3924: { + four: { + A: { + { + foo: 〈2;#B〉 + } + } + #B: { + allowed?: string + } + out: (〈0;A〉 & { + foo: { + disallowed: "foo" + } + }) + } + } +} +--- embed.cue +{ + issue3325: { + ok: { + #Items: { + [string]: { + name: 〈1;-〉 + } + } + #Base: { + name: "base" + type: string + items: 〈1;#Items〉 + } + #Extended: (〈0;#Base〉 & { + type: "extended" + items: { + "my-item": {} + } + }) + broken: { + 〈1;#Base〉 + 〈1;#Extended〉 + } + works: { + 〈1;#Extended〉 + 〈1;#Base〉 + } + } + } + patterns: { + shallow: { + #a: { + [>="k"]: int + } + #b: { + [<="m"]: int + } + #c: { + [>="w"]: int + } + #d: { + [<="y"]: int + } + single: { + X: 〈1;#a〉 + err: 〈0;X〉 + err: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + and: { + p1: { + X: (〈2;#a〉 & 〈2;#b〉) + err: 〈0;X〉 + err: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + } + and: { + p2: { + X: (〈2;#b〉 & 〈2;#a〉) + err: 〈0;X〉 + err: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + } + andEmbed: { + p1: { + X: { + (〈3;#a〉 & 〈3;#b〉) + } + err: 〈0;X〉 + err: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + } + andEmbed: { + p2: { + X: { + (〈3;#b〉 & 〈3;#a〉) + } + err: 〈0;X〉 + err: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + } + orEmbed: { + p1: { + X: { + 〈3;#a〉 + 〈3;#b〉 + } + ok1: 〈0;X〉 + ok1: { + j: 3 + } + ok2: 〈0;X〉 + ok2: { + k: 3 + } + } + } + orEmbed: { + p2: { + X: { + 〈3;#b〉 + 〈3;#a〉 + } + ok1: 〈0;X〉 + ok1: { + j: 3 + } + ok2: 〈0;X〉 + ok2: { + k: 3 + } + } + } + andOrEmbed: { + t1: { + p1: { + X: { + (〈4;#a〉 & 〈4;#b〉) + (〈4;#c〉 & 〈4;#d〉) + } + err1: 〈0;X〉 + err1: { + j: 3 + } + ok1: 〈0;X〉 + ok1: { + k: 3 + } + } + } + } + andOrEmbed: { + t1: { + p2: { + X: { + (〈4;#c〉 & 〈4;#d〉) + (〈4;#a〉 & 〈4;#b〉) + } + err1: 〈0;X〉 + err1: { + j: 3 + } + ok1: 〈0;X〉 + ok1: { + k: 3 + } + } + } + } + andOrEmbed: { + t2: { + X: { + (〈3;#a〉 & 〈3;#b〉) + (〈3;#c〉 & 〈3;#d〉) + ["p"]: int + } + err1: 〈0;X〉 + err1: { + j: 3 + } + ok1: 〈0;X〉 + ok1: { + k: 3 + } + ok2: 〈0;X〉 + ok2: { + p: 3 + } + } + } + indirect: { + a: { + [>="k"]: int + } + #a: 〈0;a〉 + p1: { + X: 〈1;#a〉 + err1: 〈0;X〉 + err1: { + j: 3 + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + p2: { + #a: (〈1;a〉 & _|_(no sharing)) + X: 〈0;#a〉 + err1: 〈0;X〉 + err1: { + j: 3 + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + p3: { + X: (〈1;#a〉 & _|_(no sharing)) + err1: 〈0;X〉 + err1: { + j: 3 + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + p4: { + #a: (〈1;a〉 & _|_(no sharing)) + X: 〈0;#a〉 + X: (〈0;#a〉 & _|_(no sharing)) + err1: 〈0;X〉 + err1: { + j: 3 + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + j: 3 + } + ok: 〈0;X〉 + ok: { + k: 3 + } + } + } + } + } + patterns: { + nested: { + #a: { + x: { + y: { + [>="k"]: int + } + } + } + #b: { + x: { + y: { + [<="m"]: int + } + } + } + #c: { + x: { + y: { + [>="w"]: int + } + } + } + #d: { + x: { + y: { + [<="y"]: int + } + } + } + single: { + X: 〈1;#a〉 + err: 〈0;X〉 + err: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + and: { + p1: { + X: (〈2;#a〉 & 〈2;#b〉) + err: 〈0;X〉 + err: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + } + and: { + p2: { + X: (〈2;#b〉 & 〈2;#a〉) + err: 〈0;X〉 + err: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + } + andEmbed: { + p1: { + X: { + (〈3;#a〉 & 〈3;#b〉) + } + err: 〈0;X〉 + err: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + } + andEmbed: { + p2: { + X: { + (〈3;#b〉 & 〈3;#a〉) + } + err: 〈0;X〉 + err: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + } + orEmbed: { + p1: { + X: { + 〈3;#a〉 + 〈3;#b〉 + } + ok1: 〈0;X〉 + ok1: { + x: { + y: { + j: 3 + } + } + } + ok2: 〈0;X〉 + ok2: { + x: { + y: { + k: 3 + } + } + } + } + } + orEmbed: { + p2: { + X: { + 〈3;#b〉 + 〈3;#a〉 + } + ok1: 〈0;X〉 + ok1: { + x: { + y: { + j: 3 + } + } + } + ok2: 〈0;X〉 + ok2: { + x: { + y: { + k: 3 + } + } + } + } + } + andOrEmbed: { + t1: { + p1: { + X: { + (〈4;#a〉 & 〈4;#b〉) + (〈4;#c〉 & 〈4;#d〉) + } + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + ok1: 〈0;X〉 + ok1: { + x: { + y: { + k: 3 + } + } + } + } + } + } + andOrEmbed: { + t1: { + p2: { + X: { + (〈4;#c〉 & 〈4;#d〉) + (〈4;#a〉 & 〈4;#b〉) + } + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + ok1: 〈0;X〉 + ok1: { + x: { + y: { + k: 3 + } + } + } + } + } + } + andOrEmbed: { + t2: { + X: { + (〈3;#a〉 & 〈3;#b〉) + (〈3;#c〉 & 〈3;#d〉) + ["p"]: int + } + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + ok1: 〈0;X〉 + ok1: { + x: { + y: { + k: 3 + } + } + } + ok2: 〈0;X〉 + ok2: { + x: { + y: { + p: 3 + } + } + } + } + } + indirect: { + a: { + x: { + y: { + [>="k"]: int + } + } + } + #a: 〈0;a〉 + p1: { + X: 〈1;#a〉 + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + p2: { + #a: (〈1;a〉 & _|_(no sharing)) + X: 〈0;#a〉 + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + p3: { + X: (〈1;#a〉 & _|_(no sharing)) + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + p4: { + #a: (〈1;a〉 & _|_(no sharing)) + X: 〈0;#a〉 + X: (〈0;#a〉 & _|_(no sharing)) + err1: 〈0;X〉 + err1: { + x: { + y: { + j: 3 + } + } + } + err2: (〈0;X〉 & _|_(no sharing)) + err2: { + x: { + y: { + j: 3 + } + } + } + ok: 〈0;X〉 + ok: { + x: { + y: { + k: 3 + } + } + } + } + } + } + } + issue2241: { + #close: {} + a: { + x: { + q: 2 + } + 〈1;#close〉 + } + b: 〈0;a〉 + b: { + x: { + r: 4 + } + } + } +} +--- in.cue +{ + #E: { + c: int + } + #A: { + b: int + q: { + 〈2;#E〉 + d: int + } + } + a: (〈0;#A〉 & { + b: 3 + q: { + c: 2 + e: 43 + } + }) + issue852: { + #A: { + [=~"^a-z$"]: string + } + a: 〈0;#A〉 + a: { + Foo: "foo" + } + for k, v in 〈0;a〉 { + b: { + "\(〈2;k〉)": 〈2;v〉 + } + } + } + dynamic: { + #D: { + key: "foo" + 〈0;key〉: int + } + d: (〈0;#D〉 & { + foo: 3 + }) + } + issue4180: { + out: { + if true { + iter: (〈2;#Schema〉 & { + FooOrBar: { + foo: "is foo" + } + }) + } + } + #Foo: { + foo: string + } + #Bar: { + bar: string + } + #Schema: { + FooOrBar: { + ... + } + FooOrBar: (〈1;#Foo〉|〈1;#Bar〉) + } + } +} +--- reroot.cue +{ + issue3330: { + let: { + ok: { + #struct: { + let empty#1 = {} + field: (null|{ + n: int + }) + field: (〈0;let empty#1〉 & { + n: 3 + }) + } + out: 〈import;list〉.Concat([ + [ + 〈2;#struct〉, + ], + ]) + } + } + matthew: { + ok1: { + #struct: { + field: ({ + n: 3 + } & 〈0;g〉) + g: {} + } + out: (〈0;#struct〉 & {}) + } + } + matthew: { + ok2: { + #struct: { + field: ({ + n: 3 + } & 〈0;g〉) + g: {} + } + out: 〈0;#struct〉 + out2: (〈0;out〉 & {}) + } + } + } + issue3331: { + original: { + ok: { + #A: { + let b#2 = {} + c: (〈0;let b#2〉 & { + d: 1 + }) + } + 〈import;list〉.Concat([ + [ + 〈2;#A〉, + ], + ]) + } + } + variant1: { + ok: { + #A: { + let b#3 = {} + c: (〈0;let b#3〉 & { + d: 1 + }) + } + [ + [ + 〈2;#A〉, + ], + ] + } + } + } + indirect: { + embed: { + err1: { + #A: { + x: { + 〈2;#x〉 + 〈2;#y〉 + } + zx: 〈0;x〉.a + } + #x: { + a: { + b: 1 + } + } + #y: { + a: { + c: 2 + } + } + b: 〈0;#A〉 + b1: 〈0;b〉.zx + b1: { + d: 1 + } + } + } + closed: { + err1: { + X: { + a: 〈0;b〉 + b: {} + a: { + e: 1 + } + } + Y: 〈0;X〉 + Y: { + b: 〈0;c〉 + c: 〈1;#X〉 + } + #X: {} + } + } + } + nested: { + ok1: { + #A: { + b: {} + #B: { + c: (〈1;b〉 & { + d: 1 + }) + } + } + x: 〈0;#A〉 + } + } + nested: { + embed: { + ok: { + x: 〈0;#A〉 + #A: { + 〈1;k〉 + } + k: { + d: (〈0;b〉 & { + e: int + }) + b: {} + } + } + } + } + nested: { + err1: { + x: 〈0;#A〉 + #A: { + b: { + f: 1 + } + v: 〈0;#V〉 + #V: { + c: (〈1;b〉 & { + d: 1 + }) + } + } + x: { + b: 〈1;#B〉 + } + #B: { + g: 1 + } + } + } + nested: { + err2: { + #A: { + b: {} + c: (〈0;b〉 & { + d: 1 + }) + } + x: 〈0;#A〉 + x: { + b: { + g: 1 + } + } + } + } + inline: { + #x: { + y: { + z?: { + name: string + } + } + } + err1: ((〈0;#x〉 & { + y: { + z: _ + } + }).y.z & { + name: "a" + age1: 5 + }) + err2: ((〈0;#x〉.y & { + z: _ + }).z & { + name: "a" + age2: 5 + }) + } + mixInDef: { + refInside: { + #x: { + b: { + c: { + d: {} + e: { + f: {} + } + } + } + } + a: 〈0;#x〉 + a: { + b: { + c: { + d: {} + } + } + } + a: { + b: { + c: { + e: 〈1;c〉.d + } + } + } + } + refEdge: { + #x: { + c: { + d: {} + e: { + f: {} + } + } + } + a: 〈0;#x〉 + a: { + c: { + d: {} + } + } + a: { + c: { + e: 〈1;c〉.d + } + } + } + refOutside: { + #x: { + c: { + d: {} + e: { + f: {} + } + } + } + a: 〈0;#x〉 + a: { + c: { + d: {} + } + } + a: { + c: { + e: 〈2;a〉.c.d + } + } + } + } + issue3601: { + original: { + out: { + 〈1;#Transform〉.output + } + #Transform: { + output: (〈1;#Patch〉 & {}).output + } + #Patch: { + target: {} + output: { + foo: { + final: 〈2;target〉 + final: { + version: "v1" + } + } + } + } + } + } + issue3601: { + originalNoShare: { + out: { + 〈1;#Transform〉.output + } + #Transform: { + output: (〈1;#Patch〉 & _|_(no sharing)).output + } + #Patch: { + target: {} + output: { + foo: { + final: 〈2;target〉 + final: { + version: "v1" + } + } + } + } + } + } + issue3601: { + reduced: { + #X: { + a: { + b: { + c: "v1" + } + } + a: { + b: 〈1;empty〉 + } + empty: {} + } + original: { + Y: (〈1;#X〉 & _|_(no sharing)).a + out: (〈0;Y〉 & _|_(no sharing)) + } + moreInlining: { + out: ((〈1;#X〉 & {}).a & {}) + } + noInline: { + Y: (〈1;#X〉 & _|_(no sharing)) + Z: (〈0;Y〉 & _|_(no sharing)) + out: (〈0;Z〉.a & _|_(no sharing)) + } + moreNesting: { + #X: { + a: { + b: { + c: { + d: "v1" + } + } + } + a: { + b: { + c: 〈2;empty〉 + } + } + empty: {} + } + Y: (〈0;#X〉.a & _|_(no sharing)).b + Z: (〈0;Y〉 & _|_(no sharing)) + } + } + } +} +--- validation.cue +{ + issue3332: { + #def: { + field: 〈import;list〉.MinItems(1) + } + use: (〈0;#def〉 & { + field: [ + "value", + ] + }) + } +} diff --git a/internal/core/compile/testdata/sync/eval/comprehensions.txtar b/internal/core/compile/testdata/sync/eval/comprehensions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/comprehensions.txtar @@ -0,0 +1,311 @@ +// Tests comprehension evaluation including for-loop filters, let bindings in +// comprehensions, if-conditioned field insertions, and field-match ordering +// in structs. Also covers panic fixes for nested comprehensions with pattern +// constraints (issue 3691). +-- in.cue -- +import "strings" + +a: {x: 10, y: 100, z: 50} @test(eq, {x: 10, y: 100, z: 50}) +b: { + for k, v in a if v <= 50 { + "\(k)": v + } + x: int + if x > 3 { + k: 20 + } + k: int + if k > 0 { + l: 40 + } + @test(eq, {x: 10, k: 20, l: 40, z: 50}) +} + +c: { + for k, v in a let y = v + 10 if y > 50 { + "\(k)": y + } + @test(eq, {y: 110, z: 60}) +} + +A: { + X: run: "dfoo" + @test(eq, {X: {run: "dfoo", files: "dfoo"}}) +} + +if true { + A: X: { + run: string + files: "\(strings.Join([ run], "\n"))" + } +} + +matchOrder: { + a1: { + out: [string]: Val: 1 + out: in.a + + in: a: { + if true { + b: {} + } + } + @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}}) + } + a2: { + out: [string]: Val: 1 + + in: a: { + if true { + b: {} + } + } + + out: in.a + @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}}) + } + a3: { + + in: a: { + if true { + b: {} + } + } + + out: [string]: Val: 1 + out: in.a + @test(eq, {in: {a: {b: {}}}, out: {b: {Val: 1}}}) + } + a4: { + out: in.a + out: [string]: Val: 1 + + in: a: { + if true { + b: {} + } + } + @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}}) + } + a5: { + out: in.a + + in: a: { + if true { + b: {} + } + } + + out: [string]: Val: 1 + @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}}) + } + a6: { + in: a: { + if true { + b: {} + } + } + + out: in.a + out: [string]: Val: 1 + @test(eq, {in: {a: {b: {}}}, out: {b: {Val: 1}}}) + } +} +-- issue3691.cue -- +// evalv3 panic: incDependent "already closed" when processing conditional +// field definitions inside a comprehension with nested object structures. +// https://cuelang.org/issue/3691 +// Ensure that parent nodes are properly processed, even when a pending arc +// is evaluated early. +issue3691: original: { + X: [string]: string + a: [string]: X + a: { + if true { + b: c: 1 + } + } + @test(err, code=eval, at=a.b.c, contains="conflicting values", args=[string, 1], pos=[1:15, 2:15, 3:5, 4:3, 5:10]) +} +// Structural cycles follow a different code path. +issue3691: structuralCycle: { + X: [string]: string + a: [string]: X + a: { + if true { + b: c: a + } + } + @test(err, code=eval, at=a.b.c, contains="conflicting values", pos=[1:15, 2:5, 2:15, 3:5, 4:3, 5:10]) +} +-- out/compile -- +--- in.cue +{ + a: { + x: 10 + y: 100 + z: 50 + } + b: { + for k, v in 〈1;a〉 if (〈0;v〉 <= 50) { + "\(〈1;k〉)": 〈1;v〉 + } + x: int + if (〈0;x〉 > 3) { + k: 20 + } + k: int + if (〈0;k〉 > 0) { + l: 40 + } + } + c: { + for k, v in 〈1;a〉 let y = (〈0;v〉 + 10) if (〈0;y〉 > 50) { + "\(〈2;k〉)": 〈1;y〉 + } + } + A: { + X: { + run: "dfoo" + } + } + if true { + A: { + X: { + run: string + files: "\(〈import;strings〉.Join([ + 〈1;run〉, + ], "\n"))" + } + } + } + matchOrder: { + a1: { + out: { + [string]: { + Val: 1 + } + } + out: 〈0;in〉.a + in: { + a: { + if true { + b: {} + } + } + } + } + a2: { + out: { + [string]: { + Val: 1 + } + } + in: { + a: { + if true { + b: {} + } + } + } + out: 〈0;in〉.a + } + a3: { + in: { + a: { + if true { + b: {} + } + } + } + out: { + [string]: { + Val: 1 + } + } + out: 〈0;in〉.a + } + a4: { + out: 〈0;in〉.a + out: { + [string]: { + Val: 1 + } + } + in: { + a: { + if true { + b: {} + } + } + } + } + a5: { + out: 〈0;in〉.a + in: { + a: { + if true { + b: {} + } + } + } + out: { + [string]: { + Val: 1 + } + } + } + a6: { + in: { + a: { + if true { + b: {} + } + } + } + out: 〈0;in〉.a + out: { + [string]: { + Val: 1 + } + } + } + } +} +--- issue3691.cue +{ + issue3691: { + original: { + X: { + [string]: string + } + a: { + [string]: 〈1;X〉 + } + a: { + if true { + b: { + c: 1 + } + } + } + } + } + issue3691: { + structuralCycle: { + X: { + [string]: string + } + a: { + [string]: 〈1;X〉 + } + a: { + if true { + b: { + c: 〈3;a〉 + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/conflicts.txtar b/internal/core/compile/testdata/sync/eval/conflicts.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/conflicts.txtar @@ -0,0 +1,54 @@ +-- in.cue -- +i: int +s: string + +t0: { + @test(err, code=eval, at=v, + contains="conflicting values", + args=[int, string], + pos=[-3:4, -2:4, 5:5, 5:9]) + v: i & s +} + +t1: { + @test(err, code=eval, at=x.a.b, + contains="conflicting values", + args=[3, 4], + pos=[6:9, 10:9, 13:5, 13:11]) + #d1: { + a: b: 3 + } + + #d2: { + a: b: 4 + } + + x: #d1 & #d2 + @test(eq, { + #d1: a: b: 3 + #d2: a: b: 4 + x: a: b: _|_ + }) +} +-- out/compile -- +--- in.cue +{ + i: int + s: string + t0: { + v: (〈1;i〉 & 〈1;s〉) + } + t1: { + #d1: { + a: { + b: 3 + } + } + #d2: { + a: { + b: 4 + } + } + x: (〈0;#d1〉 & 〈0;#d2〉) + } +} diff --git a/internal/core/compile/testdata/sync/eval/conjuncts.txtar b/internal/core/compile/testdata/sync/eval/conjuncts.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/conjuncts.txtar @@ -0,0 +1,189 @@ +// These tests are related to issue 2351. +// Tests conjunct unification with disjunctions and comprehensions, including +// regression fixes for undefined field errors (issue 2351) and cycle errors +// (issue 2355) in the v3 evaluator. +-- in.cue -- + +conjunct: t1: ({ + #early: *"X" | string + #early +} & { + #early: *"X" | string + string +}) @test(eq, *{"X", #early: *"X" | string} | {string, #early: *"X" | string}) + +conjunct: t2: { + #early: *"X" | string + #early +} +conjunct: t2: { + #early: *"X" | string + string +} @test(eq, *{"X", #early: *"X" | string} | {string, #early: *"X" | string}) + +conjunct: t3: (conjunct.t1 & conjunct.t2) @test(eq, *{"X", #early: *"X" | string} | {string, #early: *"X" | string}) + +handleComprehensions: { + if false { + subs: #sub2 & 2 + } + #sub2: 2 + @test(eq, {#sub2: 2}) +} + +-- issue2351.cue -- +// Regression between v0.4.3 and v0.5.0: "undefined field" error when embedding +// a for comprehension, caused by incorrect error reporting for let/hidden fields. +// https://cuelang.org/issue/2351 +issue2351: let: { + let _param = "foo" + ({ + param: _param & [{}] + gen: [for p in param {p}] + }).gen + @test(err, code=eval, contains="conflicting values", pos=[0:17, 1:15, 2:2, 3:10, 3:19]) +} + +issue2351: hidden: { + _in1: ["foo"] + { + in2: _in1 + out: [for x in in2 {x}] + }.out + @test(skip, hint="TODO(inline): allow ignoring hidden values.") + @test(eq:todo, { + @test(final) + ["foo"] + }) +} + +-- issue2355.cue -- +// Regression v0.4.3→v0.5.0: cycle error when using let fields within nested +// struct embeddings, breaking previously working code. +// https://cuelang.org/issue/2355 +issue2355: { + #GetF1: { + in: _ + out: in.f1 @test(err, code=incomplete, contains="%s undefined as %s is incomplete (type %s)", args=[in.f1, in, _], pos=[0:8]) + } + + #PutOut1: { + in: _ + out: out1: "\(in)" @test(err, code=incomplete, contains="invalid interpolation", pos=[0:14]) + } + + export: { + let data = {f1: "foo"} + (#PutOut1 & { + in: (#GetF1 & { + in: data + }).out + }).out + } + @test(eq, { + #GetF1: { + in: _ + out: _|_ + } + #PutOut1: { + in: _ + out: { + out1: _|_ + } + } + export: {out1: "foo"} + }) +} + +-- out/compile -- +--- in.cue +{ + conjunct: { + t1: ({ + #early: (*"X"|string) + 〈0;#early〉 + } & { + #early: (*"X"|string) + string + }) + } + conjunct: { + t2: { + #early: (*"X"|string) + 〈0;#early〉 + } + } + conjunct: { + t2: { + #early: (*"X"|string) + string + } + } + conjunct: { + t3: (〈1;conjunct〉.t1 & 〈1;conjunct〉.t2) + } + handleComprehensions: { + if false { + subs: (〈1;#sub2〉 & 2) + } + #sub2: 2 + } +} +--- issue2351.cue +{ + issue2351: { + let: { + let _param#1 = "foo" + { + param: (〈1;let _param#1〉 & [ + {}, + ]) + gen: [ + for _, p in 〈1;param〉 { + 〈1;p〉 + }, + ] + }.gen + } + } + issue2351: { + hidden: { + _in1: [ + "foo", + ] + { + in2: 〈1;_in1〉 + out: [ + for _, x in 〈1;in2〉 { + 〈1;x〉 + }, + ] + }.out + } + } +} +--- issue2355.cue +{ + issue2355: { + #GetF1: { + in: _ + out: 〈0;in〉.f1 + } + #PutOut1: { + in: _ + out: { + out1: "\(〈1;in〉)" + } + } + export: { + let data#2 = { + f1: "foo" + } + (〈1;#PutOut1〉 & { + in: (〈2;#GetF1〉 & { + in: 〈2;let data#2〉 + }).out + }).out + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/counters.txtar b/internal/core/compile/testdata/sync/eval/counters.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/counters.txtar @@ -0,0 +1,316 @@ +// Tests various evaluator stability fixes: panic in recursive disjunctions with +// list.FlattenN (issue3750), negative reference counter panic with pattern +// constraints and comprehensions (issue3780), fields dropped by for loop in let +// binding with disjunction (issue3770), and unexpected uninitialized node panic +// with if comprehensions and list comprehensions (issue3824). +-- issue3750.cue -- +package p + +import "list" + +// evalv3 panic "incDependent: already closed" triggered by recursive +// disjunctions combined with list.FlattenN comprehensions. +// https://cuelang.org/issue/3750 +issue3750: original: { + out: #Foo & { + sub: #Foo + } + + #Foo: { + sub: #Foo | #Bar + meta: { + strs: [...string] + for _, w in list.FlattenN([strs], 1) {} + } + } + + + #Bar: { + kind: "bar" + meta: strs: [...string] + } + @test(eq, { + out: { + sub: { + sub: { + sub: { + sub: {kind: "bar", meta: {strs: []}} + meta: {strs: []} + } |{kind: "bar", meta: {strs: []}} + meta: {strs: []} + } | {kind: "bar", meta: {strs: []}} + meta: {strs: []} + } + meta: {strs: []} + } + #Foo: { + sub: {kind: "bar", meta: {strs: []}} + meta: {strs: []} + } + #Bar: {kind: "bar", meta: {strs: []}} + }) +} + +issue3750: reduced: { + out: Foo & { sub: Foo } + + Foo: { + sub: Foo | {a: b: _} + a: { + b: _ + for _, w in list.FlattenN([b], 1) {} + } + } + @test(eq, { + out: { + sub: { + sub: {sub: {sub: {a: {b: _}}, a: {b: _}} | {a: {b: _}}, a: {b: _}} | {a: {b: _}} + a: {b: _} + } + a: {b: _} + } + Foo: {sub: {a: {b: _}}, a: {b: _}} + }) +} +-- issue3780.cue -- +import "strings" + +// evalv3 "negative reference counter" panic when combining pattern +// constraints with comprehensions and conditional logic. +// https://cuelang.org/issue/3780 +issue3780: panic1: { + objs: #Objects & {} + param!: bool + if param { + objs: obj1: { + one: 1 + two: 2 + } + } + #Objects: [strings.HasPrefix("obj")]: { + kind: "object" + ... + } + @test(err, code=incomplete, hint="required field missing: param") +} +issue3780: panic2: { + parent: { + objs: #Objects & {} + param?: bool + if param != _|_ { + objs: obj1: { + one: 1 + two: 2 + } + } + #Objects: [strings.HasPrefix("obj")]: { + kind: "object" + ... + } + } + @test(eq, { + parent: {objs: {}, param?: bool, #Objects: {}} + }) +} +-- issue3770.cue -- +// evalv3 regression: fields generated by a for loop in a let binding were +// dropped after unifying with a disjunctive type constraint. +// https://cuelang.org/issue/3770 +issue3770: task: { + m: { + let t = ["x"] + for m in t { + (m): a: 1 + } + x: b: 1 + } + m: null | { } + out: m.x.a + @test(eq, {m: {x: {b: 1, a: 1}}, out: 1}) +} +-- issue3824.cue -- +// evalv3 panic: "unexpected uninitialized node" when combining if comprehensions +// with list comprehensions and disjunctive type constraints. +// https://cuelang.org/issue/3824 +issue3824: panic: { + thing: { + spec: name: string + outputField: string + } + + val: string + things: [_]: thing + + things: [_]: { + spec: *{ + name: "self-signed" + } | {...} + } + + if true { + things: "name": {} + val: things["name"].outputField + } + @test(eq, { + thing: { + spec: {name: string} + outputField: string + } + val: string + things: { + name: { + spec: *{name: "self-signed"} | {name: string} + outputField: string + } + } + }) +} +-- out/compile -- +--- issue3750.cue +{ + issue3750: { + original: { + out: (〈0;#Foo〉 & { + sub: 〈1;#Foo〉 + }) + #Foo: { + sub: (〈1;#Foo〉|〈1;#Bar〉) + meta: { + strs: [ + ...string, + ] + for _, w in 〈import;list〉.FlattenN([ + 〈1;strs〉, + ], 1) {} + } + } + #Bar: { + kind: "bar" + meta: { + strs: [ + ...string, + ] + } + } + } + } + issue3750: { + reduced: { + out: (〈0;Foo〉 & { + sub: 〈1;Foo〉 + }) + Foo: { + sub: (〈1;Foo〉|{ + a: { + b: _ + } + }) + a: { + b: _ + for _, w in 〈import;list〉.FlattenN([ + 〈1;b〉, + ], 1) {} + } + } + } + } +} +--- issue3770.cue +{ + issue3770: { + task: { + m: { + let t#1 = [ + "x", + ] + for _, m in 〈0;let t#1〉 { + 〈1;m〉: { + a: 1 + } + } + x: { + b: 1 + } + } + m: (null|{}) + out: 〈0;m〉.x.a + } + } +} +--- issue3780.cue +{ + issue3780: { + panic1: { + objs: (〈0;#Objects〉 & {}) + param!: bool + if 〈0;param〉 { + objs: { + obj1: { + one: 1 + two: 2 + } + } + } + #Objects: { + [〈import;strings〉.HasPrefix("obj")]: { + kind: "object" + ... + } + } + } + } + issue3780: { + panic2: { + parent: { + objs: (〈0;#Objects〉 & {}) + param?: bool + if (〈0;param〉 != _|_(explicit error (_|_ literal) in source)) { + objs: { + obj1: { + one: 1 + two: 2 + } + } + } + #Objects: { + [〈import;strings〉.HasPrefix("obj")]: { + kind: "object" + ... + } + } + } + } + } +} +--- issue3824.cue +{ + issue3824: { + panic: { + thing: { + spec: { + name: string + } + outputField: string + } + val: string + things: { + [_]: 〈1;thing〉 + } + things: { + [_]: { + spec: (*{ + name: "self-signed" + }|{ + ... + }) + } + } + if true { + things: { + name: {} + } + val: 〈0;things〉["name"].outputField + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/cycles_ref.txtar b/internal/core/compile/testdata/sync/eval/cycles_ref.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/cycles_ref.txtar @@ -0,0 +1,24 @@ +-- in.cue -- +a: b + 100 @test(eq, 200) +b: a - 100 @test(eq, 100) +a: 200 + +c: d & {b: 2} @test(eq, {a: 1, b: 2}) +d: e @test(eq, {a: 1, b: 2}) +e: {a: 1} @test(eq, {a: 1, b: 2}) +e: c +-- out/compile -- +--- in.cue +{ + a: (〈0;b〉 + 100) + b: (〈0;a〉 - 100) + a: 200 + c: (〈0;d〉 & { + b: 2 + }) + d: 〈0;e〉 + e: { + a: 1 + } + e: 〈0;c〉 +} diff --git a/internal/core/compile/testdata/sync/eval/deref.txtar b/internal/core/compile/testdata/sync/eval/deref.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/deref.txtar @@ -0,0 +1,89 @@ +-- in.cue -- +issue4011: full: { + let _hugoEnvironments = { + default: "_default" + production: "production" + } + + site: cls: _ + site: [_]: { + fs: { + Create: { + for envID, envName in _hugoEnvironments + let envConfig = hugo[envID] + if envConfig != _|_ { + config: Contents: envConfig + } + } + } + + hugo: _ + } + + site: [_]: hugo: production: {} + @test(eq, {site: cls: { + fs: Create: config: Contents: {} + hugo: production: {} + }}) +} +issue4011: reduced: { + @test(eq, {result: foo: true, envs: foo: {}}) + result: { + for envName in ["foo"] + let env = envs[envName] + if env != _|_ { + (envName): true + } + } + envs: foo: {} +} +-- out/compile -- +--- in.cue +{ + issue4011: { + full: { + let _hugoEnvironments#1 = { + default: "_default" + production: "production" + } + site: { + cls: _ + } + site: { + [_]: { + fs: { + Create: { + for envID, envName in 〈4;let _hugoEnvironments#1〉 let envConfig = 〈3;hugo〉[〈0;envID〉] if (〈0;envConfig〉 != _|_(explicit error (_|_ literal) in source)) { + config: { + Contents: 〈2;envConfig〉 + } + } + } + } + hugo: _ + } + } + site: { + [_]: { + hugo: { + production: {} + } + } + } + } + } + issue4011: { + reduced: { + result: { + for _, envName in [ + "foo", + ] let env = 〈2;envs〉[〈0;envName〉] if (〈0;env〉 != _|_(explicit error (_|_ literal) in source)) { + 〈2;envName〉: true + } + } + envs: { + foo: {} + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/discontinuous.txtar b/internal/core/compile/testdata/sync/eval/discontinuous.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/discontinuous.txtar @@ -0,0 +1,51 @@ +This test tests a case where a child node needs to be evaluated +before evaluating a parent has completed. +-- in.cue -- +a: [for c in foo.bar.baz { + c +}] + +a: [{name: "http"}] @test(eq, [{name: "http", port: 8080}]) + +foo: { + x.D + + bar: baz: [{port: 8080}] + @test(eq, {bar: {baz: [{port: 8080}]}}) +} + +x: { + D: bar: DSpec + DSpec: {} + @test(eq, {D: bar: {}, DSpec: {}}) +} +-- out/compile -- +--- in.cue +{ + a: [ + for _, c in 〈1;foo〉.bar.baz { + 〈1;c〉 + }, + ] + a: [ + { + name: "http" + }, + ] + foo: { + 〈1;x〉.D + bar: { + baz: [ + { + port: 8080 + }, + ] + } + } + x: { + D: { + bar: 〈1;DSpec〉 + } + DSpec: {} + } +} diff --git a/internal/core/compile/testdata/sync/eval/disjselfcycle.txtar b/internal/core/compile/testdata/sync/eval/disjselfcycle.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/disjselfcycle.txtar @@ -0,0 +1,174 @@ +-- in.cue -- +-- comprehensions.cue -- +// Panic "vertex not initialized" in v0.14.0+ with recursive comprehensions +// referencing a field being defined, particularly across subdirectories. +// https://cuelang.org/issue/4119 +issue4119: reduced: { + x: [...] + x: _ | *[{f: 123}] + x: [ + for i in x { + f: i.f + } + ] + @test(eq, {x: *[{ + f: 123 + }] | []}) +} +// This test is added to test the memory management bug isn't triggered +// one level deeper. This test is expected to fail, as it now triggers +// a structural cycle in the right disjunct, leaving an incomplete error +// on the left disjunct. +issue4119: reducedNested: { + x: {y: [...]} + x: {y: _} | *{y: [{f: 123}]} + x: {y: [ + for i in x { + f: i.f + } + ]} + @test(err, code=eval, path=x.y.0.f, contains="undefined field: %s", args=[f], pos=[5:9]) +} +issue4119: full: { + _img: img={ + val: string + accounts: { + groups: img.accounts.groups | *[{gid: 65532}] + + // Recursive comprehension - this triggers the bug + groups: [ + for g in groups + let _gid = g.gid { + gid: [ + if _gid != _|_ {_gid}, + 65532, + ][0] + }, + ] + } + } + + art: { + images: [string]: #Image + for k, v in images { + images: (k): _img & v + } + } + #Image: { + val: string + accounts?: { + groups?: [...] + } + } + art: images: ko: { + val: "test" + } + @test(eq, { + _img: { + val: string + accounts: {groups: [{ gid: 65532 }]} + } + art: images: ko: { + val: "test" + accounts: {groups: *[{ gid: 65532 }] | []} + } + #Image: {val: string, accounts?: groups?: []} + }) +} +-- out/compile -- +--- comprehensions.cue +{ + issue4119: { + reduced: { + x: [ + ..., + ] + x: (_|*[ + { + f: 123 + }, + ]) + x: [ + for _, i in 〈1;x〉 { + f: 〈1;i〉.f + }, + ] + } + } + issue4119: { + reducedNested: { + x: { + y: [ + ..., + ] + } + x: ({ + y: _ + }|*{ + y: [ + { + f: 123 + }, + ] + }) + x: { + y: [ + for _, i in 〈2;x〉 { + f: 〈1;i〉.f + }, + ] + } + } + } + issue4119: { + full: { + _img: { + val: string + accounts: { + groups: (〈2〉.accounts.groups|*[ + { + gid: 65532 + }, + ]) + groups: [ + for _, g in 〈1;groups〉 let _gid = 〈0;g〉.gid { + gid: [ + if (〈2;_gid〉 != _|_(explicit error (_|_ literal) in source)) { + 〈3;_gid〉 + }, + 65532, + ][0] + }, + ] + } + } + art: { + images: { + [string]: 〈2;#Image〉 + } + for k, v in 〈0;images〉 { + images: { + 〈2;k〉: (〈4;_img〉 & 〈2;v〉) + } + } + } + #Image: { + val: string + accounts?: { + groups?: [ + ..., + ] + } + } + art: { + images: { + ko: { + val: "test" + } + } + } + } + } +} +--- in.cue +{} diff --git a/internal/core/compile/testdata/sync/eval/disjunctioncross.txtar b/internal/core/compile/testdata/sync/eval/disjunctioncross.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/disjunctioncross.txtar @@ -0,0 +1,306 @@ +-- in.cue -- +#OneOrTwo: #One | #Two +#One: { + kind: "one" + one: oneField: "value" +} +#Two: { + kind: "two" + two: optional?: string +} +_appDefaults: two: two: optional: *"optional set" | string + +// Use a discriminator field to disambiguation additional per-disjunct +// information. +valueDiscriminator: crossing: { + out: #Application & { oneOrTwo: kind: "two" } + #Application: { + oneOrTwo: #OneOrTwo + // oneOrTwo.kind resolves will resolve to "two" regardless of whether + // it resolves to the original oneOrTwo or the disjunct that is being + // processed. + oneOrTwo: *_appDefaults[oneOrTwo.kind] | _ + } + @test(eq, { + out: { + oneOrTwo: + *{kind: "two", two: {optional: *"optional set" | string}} | + {kind: "two", two: {optional?: string}} + } + #Application: { + oneOrTwo: + *{kind: "two", two: {optional: *"optional set" | string}} | + {kind: "one", one: {oneField: "value"}} | + {kind: "two", two: {optional?: string}} + } + }) +} + +valueDiscriminator: local: { + out: #Application & { oneOrTwo: kind: "two" } + #Application: { + oneOrTwo: #OneOrTwo + // oneOrTwo.kind always resolves to the value of the disjunct. + // Alternative writing for future features based on various proposals: + // oneOrTwo~X: *_appDefaults[X.kind] | _ + // oneOrTwo: *_appDefaults[self.kind] | _ + // try { oneOrTwo: _appDefaults.(self.kind)? } + oneOrTwo: X={ *_appDefaults[X.kind] | _ } + } + @test(eq, { + out: oneOrTwo: + *{kind: "two", two: {optional: *"optional set" | string}} | + {kind: "two", two: {optional?: string}} + #Application: oneOrTwo: + *{kind: "two", two: {optional: *"optional set" | string}} | + {kind: "one", one: {oneField: "value"}} | + {kind: "two", two: {optional?: string}} + }) +} + +// Use a value that is available AFTER a disjunction is resolved to augment +// values. We may not want to support this in perpetuity, as this relies on +// closedness to discrimnate the disjuncts. But for now, as there is no +// alternative to discriminating based on fields, we will support it. +fieldDiscriminator: crossing:{ + out: #Application & { oneOrTwo: two: {} } + #Application: { + oneOrTwo: #OneOrTwo + // The value of oneOrTwo.kind depends on whether oneOrTwo resolves + // to the disjunct currently being processed, the original before + // a disjunct has been selected, or a disjunct after it has been + // selected. + oneOrTwo: *_appDefaults[oneOrTwo.kind] | _ + } + @test(eq, { + out: oneOrTwo: + *{two: {optional: *"optional set" | string}, kind: "two"} | + {two: {optional?: string}, kind: "two"} + #Application: oneOrTwo: + *{kind: "two", two: {optional: *"optional set" | string}} | + {kind: "one", one: {oneField: "value"}} | + {kind: "two", two: {optional?: string}} + }) +} + +fieldDiscriminator: local:{ + out: #Application & { oneOrTwo: two: {} } + #Application: { + oneOrTwo: #OneOrTwo + // oneOrTwo.kind always resolves to the value of the disjunct. + oneOrTwo: X={ *_appDefaults[X.kind] | _ } + } + @test(eq, { + out: { + oneOrTwo: + *{two: {optional: *"optional set" | string}, kind: "two"} | + {two: {optional?: string}, kind: "two"} + } + #Application: { + oneOrTwo: + *{kind: "two", two: {optional: *"optional set" | string}} | + {kind: "one", one: {oneField: "value"}} | + {kind: "two", two: {optional?: string}} + } + }) +} + +// Do not hide error messages. Here, the inner failure of both disjuncts means +// that an enclosing field cannot be resolved as it needs to look up a value +// inside the disjunction. The failure to do this lookup is not the underlying +// cause, though: the inner failure is. For this reason, we should report all +// errors. +// evalv3 regression: misleading "undefined field" error instead of the expected +// circular dependency error when processing disjunctions with cyclic conditionals. +// https://cuelang.org/issue/3967 +issue3967: error: nested: { + out: #Application & { + oneOrTwo: two: {} + } + #Application: X={ + oneOrTwo: #OneOrTwo & { + if X.oneOrTwo.kind == "two" { + two: { + if X.oneOrTwo.two.optional == _|_ { + optional: "optional set" + } + } + } + if X.oneOrTwo.kind == "never" { + } + } + if X.oneOrTwo.kind == "never" { + } + } + @test(eq, { + out: {oneOrTwo: {two: {}}} + #Application: { + oneOrTwo: {kind: "one", one: {oneField: "value"}} + } + }) +} +issue3967: { + error: local: { + out: #Application & { + oneOrTwo: two: {} + } + #Application: { + oneOrTwo: X= { #OneOrTwo & { + if X.kind == "two" { + two: { + if X.two.optional == _|_ { + optional: "optional set" + } + } + } + if X.kind == "never" { + } + }} + } + } + @test(eq, { + error: { + nested: { + out: {oneOrTwo: {two: {}}} + #Application: { + oneOrTwo: {kind: "one", one: {oneField: "value"}} + } + } + local: { + out: {oneOrTwo: {two: {}}} + #Application: { + oneOrTwo: {kind: "one", one: {oneField: "value"}} + } + } + } + }) +} +-- out/compile -- +--- in.cue +{ + #OneOrTwo: (〈0;#One〉|〈0;#Two〉) + #One: { + kind: "one" + one: { + oneField: "value" + } + } + #Two: { + kind: "two" + two: { + optional?: string + } + } + _appDefaults: { + two: { + two: { + optional: (*"optional set"|string) + } + } + } + valueDiscriminator: { + crossing: { + out: (〈0;#Application〉 & { + oneOrTwo: { + kind: "two" + } + }) + #Application: { + oneOrTwo: 〈3;#OneOrTwo〉 + oneOrTwo: (*〈3;_appDefaults〉[〈0;oneOrTwo〉.kind]|_) + } + } + } + valueDiscriminator: { + local: { + out: (〈0;#Application〉 & { + oneOrTwo: { + kind: "two" + } + }) + #Application: { + oneOrTwo: 〈3;#OneOrTwo〉 + oneOrTwo: { + (*〈4;_appDefaults〉[〈1〉.kind]|_) + } + } + } + } + fieldDiscriminator: { + crossing: { + out: (〈0;#Application〉 & { + oneOrTwo: { + two: {} + } + }) + #Application: { + oneOrTwo: 〈3;#OneOrTwo〉 + oneOrTwo: (*〈3;_appDefaults〉[〈0;oneOrTwo〉.kind]|_) + } + } + } + fieldDiscriminator: { + local: { + out: (〈0;#Application〉 & { + oneOrTwo: { + two: {} + } + }) + #Application: { + oneOrTwo: 〈3;#OneOrTwo〉 + oneOrTwo: { + (*〈4;_appDefaults〉[〈1〉.kind]|_) + } + } + } + } + issue3967: { + error: { + nested: { + out: (〈0;#Application〉 & { + oneOrTwo: { + two: {} + } + }) + #Application: { + oneOrTwo: (〈4;#OneOrTwo〉 & { + if (〈2〉.oneOrTwo.kind == "two") { + two: { + if (〈4〉.oneOrTwo.two.optional == _|_(explicit error (_|_ literal) in source)) { + optional: "optional set" + } + } + } + if (〈2〉.oneOrTwo.kind == "never") {} + }) + if (〈1〉.oneOrTwo.kind == "never") {} + } + } + } + } + issue3967: { + error: { + local: { + out: (〈0;#Application〉 & { + oneOrTwo: { + two: {} + } + }) + #Application: { + oneOrTwo: { + (〈5;#OneOrTwo〉 & { + if (〈2〉.kind == "two") { + two: { + if (〈4〉.two.optional == _|_(explicit error (_|_ literal) in source)) { + optional: "optional set" + } + } + } + if (〈2〉.kind == "never") {} + }) + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/disjunctions.txtar b/internal/core/compile/testdata/sync/eval/disjunctions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/disjunctions.txtar @@ -0,0 +1,1097 @@ +-- in.cue -- +a: *1 | int @test(eq, *1 | int) +aa: *1 | *2 | int @test(eq, *1 | *2 | int) + +b: { + name: "int" + val: int +} | { + name: "str" + val: string +} @test(eq, {name: "int", val: int} | {name: "str", val: string}) + +d: b & {val: 3} @test(eq, {val: 3, name: "int"}) +c: b & {name: "int", val: 3} @test(eq, {name: "int", val: 3}) +e: b & {val: "foo"} @test(eq, {val: "foo", name: "str"}) +f: b & {name: "str", val: 3} @test(err, + suberr=(code=eval, contains="conflicting values", pos=[-10:8, 0:4, 0:15]), + suberr=(code=eval, contains="conflicting values", pos=[-6:8, 0:4, 0:27])) + +// Disjunct elimination based on type. +e1: { + a: null | {bar: 2} + b: (a & {}).bar + @test(eq, {a: null | {bar: 2}, b: 2}) +} + +d1: { + a: (null | {c: 1}) & {} + b: {} & (null | {c: 1}) + @test(eq, {a: {c: 1}, b: {c: 1}}) +} + +d2: { + a: ([...] | {c: 1}) & {} + b: {} & ([...] | {c: 1}) + @test(eq, {a: {c: 1}, b: {c: 1}}) +} + +d3: { + a: (string | {c: 1}) & {} + b: {} & (string | {c: 1}) + @test(eq, {a: {c: 1}, b: {c: 1}}) +} + +d4: { + a: (string | {c: 1}) & {} + b: {} & (string | {c: 1}) + @test(eq, {a: {c: 1}, b: {c: 1}}) +} + +d5: { + a: (number | {c: 1}) & {} + b: {} & (number | {c: 1}) + @test(eq, {a: {c: 1}, b: {c: 1}}) +} + +d6: { + a: (int | {c: 1}) & {} + b: {} & (int | {c: 1}) + @test(eq, {a: {c: 1}, b: {c: 1}}) +} + +t10: p1: { + // @test(permute, count=120) // TODO(inline): we could reduce this by grouping fields. + schema: test + schema: string | {name: string} + #A: {string | {name: string}} + + test: name: "Test" + test: #A + @test(eq, { + schema: {name: "Test"} + #A: string | {name: string} + test: {name: "Test"} + }) +} + +t10: p2: { + schema: string | {name: string} + schema: test + #A: {string | {name: string}} + + test: name: "Test" + test: #A + @test(eq, { + schema: {name: "Test"} + #A: string | {name: string} + test: {name: "Test"} + }) +} + +t10: p3: { + #A: {string | {name: string}} + + test: name: "Test" + test: #A + + schema: string | {name: string} + schema: test + @test(eq, { + #A: string | {name: string} + test: {name: "Test"} + schema: {name: "Test"} + }) +} + +t11: p1: { + a: #A + a: b + + b: #A & ["b"] + #A: ["a" | "b"] | {} + @test(eq, { + a: ["b"] + b: ["b"] + #A: ["a" | "b"] | {} + }) +} + +t11: p2: { + b: #A & ["b"] + #A: ["a" | "b"] | {} + + a: b + a: #A + @test(eq, { + b: ["b"] + #A: ["a" | "b"] | {} + a: ["b"] + }) +} + +cross: { + a: *"word" | string + a: string | *"word" + @test(eq, {a: *"word" | string}) +} + +d100: { + // Should we allow a selector to imply a struct or list? Would be convenient. + // This would be a spec change. Disallow for now. + i: null | {bar: 2} + j: i.bar + @test(eq, { + i: null | {bar: 2} + j: _|_ @test(err, code=incomplete, contains="d100.j: unresolved disjunction null | {bar:2} (type (null|struct))", pos=[142:5]) + }) +} + +// Regression test for empty disjunction with combined definitions and +// template constraints where valid unification was incorrectly rejected. +// https://cuelang.org/issue/641 +issue641: { + #A: { + type: "a" + x: "" + } + + #B: { + type: "b" + x: string + } + + #C: { + b: #A | #B + } + + e: [string]: #C & { + b: #A | #B + } + + e: foobar: #C & { + b: #B & { + x: "foobar" + } + } + @test(eq, { + #A: {type: "a", x: ""} + #B: {type: "b", x: string} + #C: { + b: {type: "a", x: ""} | {type: "b", x: string} + } + e: {foobar: {b: {x: "foobar", type: "b"}}} + }) +} +-- issue3406.cue -- +// evalv3 panic with inconsistent state when unifying a struct with itself +// embedded via a disjunction field. +// https://cuelang.org/issue/3406 +issue3406: { + out: d & { d } + d: kind: "foo" | "bar" + d: { kind: "foo" } | { kind: "bar" } + @test(eq, { + out: {kind: "foo"} | {kind: "bar"} + d: {kind: "foo"} | {kind: "bar"} + }) +} +-- issue3411.cue -- +// evalv3 nil pointer dereference when unifying optional fields with defaults. +// https://cuelang.org/issue/3411 +issue3411: { + x: y?: [...string] + x: {y: ["foo"]} | *{y: ["bar"]} + @test(eq, {x: *{y: ["bar"]} | {y: ["foo"]}}) +} +-- issue3490.cue -- +// evalv3 "incDependent: already closed" panic regression involving disjunctions. +// https://cuelang.org/issue/3490 +issue3490: nested: p1: { + ("a"|"b") | "b" + "a"|"b" + @test(eq, { + "a" + @test(eq) + } | { + "b" + @test(eq) + }) +} +issue3490: nested: p2: { + "a"|"b" + ("a"|"b") | "b" + @test(eq, { + "a" + @test(eq) + } | { + "b" + @test(eq) + }) +} +issue3490: full: { + data: [...#Schema] + data: [#Schema & {}] + #Schema: { + runs?: "foo" | ([#D1] | [#D1, #D2]) + #D1: "d1" + #D2: "d2" + } + @test(eq, { + data: [{ + runs?: "foo" | ["d1"] | ["d1", "d2"] + #D1: "d1" + #D2: "d2" + }] + #Schema: { + runs?: "foo" | ["d1"] | ["d1", "d2"] + #D1: "d1" + #D2: "d2" + } + }) +} +-- issue3434.cue -- +// evalv3 panic "unexpected overlay in next" with disjunctions inside definitions. +// https://cuelang.org/issue/3434 +issue3434: t1: { + ({} | {}) + {["x"]: 1} + {["y"]: 2} + @test(eq, {["x"]: 1, ["y"]: 2}) +} +issue3434: full: { + out: #Schema & { + steps: [{run: "example"}] + } + #Schema: { + steps: [...{run: string}] + #matrixConfig: string | [...#matrixConfig] + matrix?: ({...} | string) & { + {[=~"^foo"]: [...{[string]: #matrixConfig}]} + {[=~"^bar"]: [...#matrixConfig] | string} + } + } + @test(eq, { + out: { + steps: [{ run: "example" }] + #matrixConfig: string | [] + matrix?: {} + } + #Schema: { + steps: [] + #matrixConfig: string | [] + matrix?: {} + } + }) +} +-- issue3597.cue -- +// evalv3 index out of range panic in overlayContext.allocCC with let inside +// a disjunction within a definition applied via a pattern constraint. +// https://cuelang.org/issue/3597 +issue3597: t1: { + #Schema: { + _ok: bool + {} | { + _ok: true + let Ok = _ok + {} | {x: Ok} + } + } + + [string]: #Schema + + foo: bar + bar: {} + @test(eq, { + #Schema: {_ok: bool} | {_ok: true} | {_ok: true, x: true} + foo: {_ok: bool} | {_ok: true} | {_ok: true, x: true} + bar: {_ok: bool} | {_ok: true} | {_ok: true, x: true} + }) +} +issue3597: t2: { + ok: true + X: _ | { + let Ok = ok + _ | {x: Ok} + } + foo: X & {X} + @test(eq, { + ok: true + X: _ | _ | {x: true} + foo: _ | _ | {x: true} + }) +} +-- dependencies.cue -- +// evalv3 incorrectly allowed a field inside a struct disjunction that should +// have been rejected as "field not allowed". +// https://cuelang.org/issue/3606 +issue3606: { + data: { + notAllowed: true + } & #S + + #S: string | {} + + @test(err, code=eval, + suberr=(code=eval, path=data, contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[{notAllowed:true}, string, struct, string], pos=[1:8, 3:6, 5:6]), + suberr=(code=eval, path=data.notAllowed, contains="field not allowed", pos=[2:3])) +} + +// evalv3 gives a different result vs evalv2 when openinline is enabled; list +// element count is wrong after unifying nested disjunctions through definitions. +// https://cuelang.org/issue/3672 +issue3672: { + #A: string | {y: true} + #B: #A | {a: "append"} | {b: "prepend"} + + #fn: { + #C: #B + #out: x: [...#C] + } + + // The unification inline appears to be critical + #def: (#fn & {}).#out + + v: #def + v: x: [{y: true}] // Should be one element + @test(eq, { + #A: string | {y: true} + #B: string | {y: true} | {a: "append"} | {b: "prepend"} + #fn: { + #C: string | {y: true} | {a: "append"} | {b: "prepend"} + #out: {x: []} + } + #def: {x: []} + v: {x: [{ + y: true + }]} + }) +} +// Regression giving "non-concrete value _ (type _)" error when interpolating +// a string default from a disjunction via a definition alias. +// https://cuelang.org/issue/3681 +issue3681: { + // Order dependent! These two fields need to go first. + out: one: #strDefaultDef + out: two: "\(strDefault)" + + strDefault: *"fallback" | string + #strDefaultDef: strDefault + @test(eq, { + out: { + one: *"fallback" | string + two: "fallback" + } + strDefault: *"fallback" | string + #strDefaultDef: *"fallback" | string + }) +} +// evalv3 "undefined field" regression when a comprehension condition references +// a field whose default is provided by a disjunction. +// https://cuelang.org/issue/3699 +issue3699: { + reduced: p1: { + y: { if x.z { 1 } } + x: *{z: true} | {} + } + reduced: p2: { + y: { if x.z { 1 } } + x: *{z: true} | {} + } + reduced: full: { + _res: { + _fooTrue: {} | *{foo: true} + _msgSwitch: [ + if _fooTrue.foo { msg: "foo" }, + { msg: "bar" }, + ][0] + out: _msgSwitch.msg + } + let res = { + out: (_res & {}).out + } + out: res.out + } + @test(eq, { + reduced: { + p1: {y: 1, x: *{z: true} | {}} + p2: {y: 1, x: *{z: true} | {}} + full: { + _res: { + _fooTrue: *{foo: true} | {} + _msgSwitch: {msg: "foo"} + out: "foo" + } + out: "foo" + } + } + }) +} +-- indexelim.cue -- +import "math/bits" + +indexElimination: { + inStruct: x: { a: *x[0] | 0 }.a @test(eq, 0) + inList1: x: [x[0]][0] @test(eq, _) + inList2: x: [*x[0] | 0][0] @test(eq, 0) + // evalv3 strange behavior with chaining of list comprehensions, + // incorrect results when indexing the output of a for loop. + // https://cuelang.org/issue/3124 + issue3124: full: { + x: [...bool] + x: [true, false, true, true] + y: [for _, v in x {[if v {1}, 0][0]}] + z: [for i, v in y {bits.Set(*z[i-1] | 0, len(y)-i-1, v)}][3] + @test(eq, { + x: [true, false, true, true] + y: [1, 0, 1, 1] + z: 1 + }) + } +} +-- issue3899.cue -- +// evalv3 "invalid type _" regression that is order-dependent, triggered when +// a string interpolation references an optional field inside a disjunction. +// https://cuelang.org/issue/3899 +issue3899: reduced: { + @test(permute, count=2) + b: c + "" | string + c?: string + @test(eq, {b: string, c?: string}) +} +issue3899: full: { + out: #Schema & { + name: "foo" + } + #Schema: { + _versions: foo: "123" + spec: limits: true + name!: string + spec: image: string | *"\(name)" + deployImage: _versions[spec.image] @test(err, code=incomplete, + contains="invalid non-ground value %s (must be concrete %s)", + args=[string, string], pos=[-1:18]) + } + @test(eq, { + out: { + name: "foo" + _versions: {foo: "123"} + spec: {limits: true, image: *"foo" | string} + deployImage: "123" + } + #Schema: { + _versions: {foo: "123"} + spec: {limits: true, image: string} + name!: string + deployImage: _|_ + } + }) +} +-- issue3891.cue -- +// evalv3 "incomplete value" regression with repeated disjunctions where a +// field referencing a default via another field yields an incomplete error. +// https://cuelang.org/issue/3891 +issue3891: reduced: { + {x: _} | null + {x: _} | null + x: *a.y | _ + a: b @test(shareID=r3891ab) + @test(shareID=r3891ab, at=b) + b: y: 1 + @test(eq, {x: *1 | _, a: {y: 1}, b: {y: 1}}) +} +issue3891: full: { + out: #Foo | "never" + out: #Foo | "never" + out: _fooTemplate & { + _input: (_transform & {in: sub1: sub2: "bar"}).out + } + _transform: { + in: _ + out: in + } + #Foo: foo?: _ + _fooTemplate: { + _input: _ + foo: *_input.sub1.sub2 | _ + } + @test(eq, { + out: { + _input: {sub1: {sub2: "bar"}} + foo: *"bar" | _ + } + _transform: {in: _, out: _} + #Foo: {foo?: _} + _fooTemplate: {_input: _, foo: _} + }) +} +-- out/compile -- +--- dependencies.cue +{ + issue3606: { + data: ({ + notAllowed: true + } & 〈0;#S〉) + #S: (string|{}) + } + issue3672: { + #A: (string|{ + y: true + }) + #B: (〈0;#A〉|{ + a: "append" + }|{ + b: "prepend" + }) + #fn: { + #C: 〈1;#B〉 + #out: { + x: [ + ...〈2;#C〉, + ] + } + } + #def: (〈0;#fn〉 & {}).#out + v: 〈0;#def〉 + v: { + x: [ + { + y: true + }, + ] + } + } + issue3681: { + out: { + one: 〈1;#strDefaultDef〉 + } + out: { + two: "\(〈1;strDefault〉)" + } + strDefault: (*"fallback"|string) + #strDefaultDef: 〈0;strDefault〉 + } + issue3699: { + reduced: { + p1: { + y: { + if 〈1;x〉.z { + 1 + } + } + x: (*{ + z: true + }|{}) + } + } + reduced: { + p2: { + y: { + if 〈1;x〉.z { + 1 + } + } + x: (*{ + z: true + }|{}) + } + } + reduced: { + full: { + _res: { + _fooTrue: ({}|*{ + foo: true + }) + _msgSwitch: [ + if 〈1;_fooTrue〉.foo { + msg: "foo" + }, + { + msg: "bar" + }, + ][0] + out: 〈0;_msgSwitch〉.msg + } + let res#1 = { + out: (〈1;_res〉 & {}).out + } + out: 〈0;let res#1〉.out + } + } + } +} +--- in.cue +{ + a: (*1|int) + aa: (*1|*2|int) + b: ({ + name: "int" + val: int + }|{ + name: "str" + val: string + }) + d: (〈0;b〉 & { + val: 3 + }) + c: (〈0;b〉 & { + name: "int" + val: 3 + }) + e: (〈0;b〉 & { + val: "foo" + }) + f: (〈0;b〉 & { + name: "str" + val: 3 + }) + e1: { + a: (null|{ + bar: 2 + }) + b: (〈0;a〉 & {}).bar + } + d1: { + a: ((null|{ + c: 1 + }) & {}) + b: ({} & (null|{ + c: 1 + })) + } + d2: { + a: (([ + ..., + ]|{ + c: 1 + }) & {}) + b: ({} & ([ + ..., + ]|{ + c: 1 + })) + } + d3: { + a: ((string|{ + c: 1 + }) & {}) + b: ({} & (string|{ + c: 1 + })) + } + d4: { + a: ((string|{ + c: 1 + }) & {}) + b: ({} & (string|{ + c: 1 + })) + } + d5: { + a: ((number|{ + c: 1 + }) & {}) + b: ({} & (number|{ + c: 1 + })) + } + d6: { + a: ((int|{ + c: 1 + }) & {}) + b: ({} & (int|{ + c: 1 + })) + } + t10: { + p1: { + schema: 〈0;test〉 + schema: (string|{ + name: string + }) + #A: { + (string|{ + name: string + }) + } + test: { + name: "Test" + } + test: 〈0;#A〉 + } + } + t10: { + p2: { + schema: (string|{ + name: string + }) + schema: 〈0;test〉 + #A: { + (string|{ + name: string + }) + } + test: { + name: "Test" + } + test: 〈0;#A〉 + } + } + t10: { + p3: { + #A: { + (string|{ + name: string + }) + } + test: { + name: "Test" + } + test: 〈0;#A〉 + schema: (string|{ + name: string + }) + schema: 〈0;test〉 + } + } + t11: { + p1: { + a: 〈0;#A〉 + a: 〈0;b〉 + b: (〈0;#A〉 & [ + "b", + ]) + #A: ([ + ("a"|"b"), + ]|{}) + } + } + t11: { + p2: { + b: (〈0;#A〉 & [ + "b", + ]) + #A: ([ + ("a"|"b"), + ]|{}) + a: 〈0;b〉 + a: 〈0;#A〉 + } + } + cross: { + a: (*"word"|string) + a: (string|*"word") + } + d100: { + i: (null|{ + bar: 2 + }) + j: 〈0;i〉.bar + } + issue641: { + #A: { + type: "a" + x: "" + } + #B: { + type: "b" + x: string + } + #C: { + b: (〈1;#A〉|〈1;#B〉) + } + e: { + [string]: (〈1;#C〉 & { + b: (〈2;#A〉|〈2;#B〉) + }) + } + e: { + foobar: (〈1;#C〉 & { + b: (〈2;#B〉 & { + x: "foobar" + }) + }) + } + } +} +--- indexelim.cue +{ + indexElimination: { + inStruct: { + x: { + a: (*〈1;x〉[0]|0) + }.a + } + inList1: { + x: [ + 〈1;x〉[0], + ][0] + } + inList2: { + x: [ + (*〈1;x〉[0]|0), + ][0] + } + issue3124: { + full: { + x: [ + ...bool, + ] + x: [ + true, + false, + true, + true, + ] + y: [ + for _, v in 〈1;x〉 { + [ + if 〈2;v〉 { + 1 + }, + 0, + ][0] + }, + ] + z: [ + for i, v in 〈1;y〉 { + 〈import;"math/bits"〉.Set((*〈3;z〉[(〈1;i〉 - 1)]|0), ((len(〈3;y〉) - 〈1;i〉) - 1), 〈1;v〉) + }, + ][3] + } + } + } +} +--- issue3406.cue +{ + issue3406: { + out: (〈0;d〉 & { + 〈1;d〉 + }) + d: { + kind: ("foo"|"bar") + } + d: ({ + kind: "foo" + }|{ + kind: "bar" + }) + } +} +--- issue3411.cue +{ + issue3411: { + x: { + y?: [ + ...string, + ] + } + x: ({ + y: [ + "foo", + ] + }|*{ + y: [ + "bar", + ] + }) + } +} +--- issue3434.cue +{ + issue3434: { + t1: { + ({}|{}) + { + ["x"]: 1 + } + { + ["y"]: 2 + } + } + } + issue3434: { + full: { + out: (〈0;#Schema〉 & { + steps: [ + { + run: "example" + }, + ] + }) + #Schema: { + steps: [ + ...{ + run: string + }, + ] + #matrixConfig: (string|[ + ...〈1;#matrixConfig〉, + ]) + matrix?: (({ + ... + }|string) & { + { + [=~"^foo"]: [ + ...{ + [string]: 〈4;#matrixConfig〉 + }, + ] + } + { + [=~"^bar"]: ([ + ...〈3;#matrixConfig〉, + ]|string) + } + }) + } + } + } +} +--- issue3490.cue +{ + issue3490: { + nested: { + p1: { + (("a"|"b")|"b") + ("a"|"b") + } + } + } + issue3490: { + nested: { + p2: { + ("a"|"b") + (("a"|"b")|"b") + } + } + } + issue3490: { + full: { + data: [ + ...〈1;#Schema〉, + ] + data: [ + (〈1;#Schema〉 & {}), + ] + #Schema: { + runs?: ("foo"|([ + 〈1;#D1〉, + ]|[ + 〈1;#D1〉, + 〈1;#D2〉, + ])) + #D1: "d1" + #D2: "d2" + } + } + } +} +--- issue3597.cue +{ + issue3597: { + t1: { + #Schema: { + _ok: bool + ({}|{ + _ok: true + let Ok#2 = 〈0;_ok〉 + ({}|{ + x: 〈1;let Ok#2〉 + }) + }) + } + [string]: 〈0;#Schema〉 + foo: 〈0;bar〉 + bar: {} + } + } + issue3597: { + t2: { + ok: true + X: (_|{ + let Ok#3 = 〈1;ok〉 + (_|{ + x: 〈1;let Ok#3〉 + }) + }) + foo: (〈0;X〉 & { + 〈1;X〉 + }) + } + } +} +--- issue3891.cue +{ + issue3891: { + reduced: { + ({ + x: _ + }|null) + ({ + x: _ + }|null) + x: (*〈0;a〉.y|_) + a: 〈0;b〉 + b: { + y: 1 + } + } + } + issue3891: { + full: { + out: (〈0;#Foo〉|"never") + out: (〈0;#Foo〉|"never") + out: (〈0;_fooTemplate〉 & { + _input: (〈1;_transform〉 & { + in: { + sub1: { + sub2: "bar" + } + } + }).out + }) + _transform: { + in: _ + out: 〈0;in〉 + } + #Foo: { + foo?: _ + } + _fooTemplate: { + _input: _ + foo: (*〈0;_input〉.sub1.sub2|_) + } + } + } +} +--- issue3899.cue +{ + issue3899: { + reduced: { + b: ((〈0;c〉 + "")|string) + c?: string + } + } + issue3899: { + full: { + out: (〈0;#Schema〉 & { + name: "foo" + }) + #Schema: { + _versions: { + foo: "123" + } + spec: { + limits: true + } + name!: string + spec: { + image: (string|*"\(〈1;name〉)") + } + deployImage: 〈0;_versions〉[〈0;spec〉.image] + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/dynamic_field.txtar b/internal/core/compile/testdata/sync/eval/dynamic_field.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/dynamic_field.txtar @@ -0,0 +1,222 @@ +// Tests dynamic field key resolution including string interpolations, chained +// resolution, and comprehension with let bindings. Covers panic fix for issue799 +// (struct used in string interpolation) and issue3828 (let inside comprehension +// with dynamic field key). +-- in.cue -- +a: "foo" +"\(a)": b: c: d: e +e: 2 @test(eq, 2) + +b: "bar" +X="\(b)": { + a: 1 +} +c: X @test(eq, {a: 1}) + +withError: { + // Panic when running cue eval with a struct used in a string interpolation. + // https://cuelang.org/issue/799 + issue799: {key: int32} & {"\(1 & 2)": 123} + // TODO(inline): access _wrapped_ error somehow: underlying error is + // "conflicting values 2 and 1". + @test(err, code=eval, contains="invalid interpolation", pos=[3:28, 3:31, 3:35]) +} + +parenExprRefParent: { + a: (x): {} + x: "foo" + @test(eq, {a: {foo: {}}, x: "foo"}) +} +parenExprRefEqual: { + (x): {} + x: "foo" + @test(eq, {x: "foo", foo: {}}) +} +chainedResolution: x: { + @test(permute, count=6) + (x.baz): "bar" + (x.foo): "baz" + baz: "foo" + @test(eq, { + baz: "foo", foo: "bar", bar: "baz" + }) +} + +// A dynamic field key that references an incomplete value (string interpolation +// using abstract string) must produce an "incomplete" error, not a spurious +// "cycle error". The error should also include path and position information. +// https://cuelang.org/issue/1407 +noCycleError: { + foo: [_]: { + #ID: "\(string)" + } + foo: bar: entries: (foo.baz.#ID): true + foo: baz: {} + @test(err, at=foo.bar.entries, code=incomplete, + suberr=(code=incomplete, contains="dynamic field must be concrete", pos=[4:22]), + suberr=(code=incomplete, contains="non-concrete value string", pos=[2:8, 2:11]), + ) + @test(err, at=foo.bar.#ID, code=incomplete, contains="non-concrete value string", pos=[2:8, 2:11]) + @test(err, at=foo.baz.#ID, code=incomplete, contains="non-concrete value string", pos=[2:8, 2:11]) + + @test(eq, { + foo: { + bar: { + entries: _|_ + #ID: _|_ + } + baz: { #ID: _|_ } + } + }) +} + +-- constraints.cue -- +constraints: { + t1: "foo" + t2: "bar" + (t1)?: (t2)!: 3 + @test(eq, {t1: "foo", t2: "bar", foo?: {bar!: 3}}) +} +-- issue3828.cue -- +// evalv3 regression: a let inside a comprehension with a dynamic field key +// failed to produce the correct output due to a "cycle with field" error. +// https://cuelang.org/issue/3828 +issue3828: reduced: { + a: b: {} + a: [_]: { + if true let x=str { + (x): true + } + } + str: "foobot1" + @test(eq, {a: {b: {foobot1: true}}, str: "foobot1"}) +} +issue3828: full: { + orgs: org1: { + repos: repo1: {} + } + botUser: "bot1" + orgs: [_]: config={ + for repo_name, _ in config.repos + let orgBotUser = botUser { + collaborators: (repo_name): (orgBotUser): true + } + } + @test(eq, { + orgs: org1: { + repos: {repo1: {}} + collaborators: {repo1: {bot1: true}} + } + botUser: "bot1" + }) +} +-- out/compile -- +--- constraints.cue +{ + constraints: { + t1: "foo" + t2: "bar" + 〈0;t1〉?: { + 〈1;t2〉!: 3 + } + } +} +--- in.cue +{ + a: "foo" + "\(〈0;a〉)": { + b: { + c: { + d: 〈3;e〉 + } + } + } + e: 2 + b: "bar" + "\(〈0;b〉)": { + a: 1 + } + c: 〈0;("\(〈0;b〉)")〉 + withError: { + issue799: ({ + key: &(int, >=-2147483648, <=2147483647) + } & { + "\((1 & 2))": 123 + }) + } + parenExprRefParent: { + a: { + 〈1;x〉: {} + } + x: "foo" + } + parenExprRefEqual: { + 〈0;x〉: {} + x: "foo" + } + chainedResolution: { + x: { + 〈1;x〉.baz: "bar" + 〈1;x〉.foo: "baz" + baz: "foo" + } + } + noCycleError: { + foo: { + [_]: { + #ID: "\(string)" + } + } + foo: { + bar: { + entries: { + 〈3;foo〉.baz.#ID: true + } + } + } + foo: { + baz: {} + } + } +} +--- issue3828.cue +{ + issue3828: { + reduced: { + a: { + b: {} + } + a: { + [_]: { + if true let x = 〈2;str〉 { + 〈1;x〉: true + } + } + } + str: "foobot1" + } + } + issue3828: { + full: { + orgs: { + org1: { + repos: { + repo1: {} + } + } + } + botUser: "bot1" + orgs: { + [_]: { + for repo_name, _ in 〈1〉.repos let orgBotUser = 〈3;botUser〉 { + collaborators: { + 〈3;repo_name〉: { + 〈3;orgBotUser〉: true + } + } + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/embed.txtar b/internal/core/compile/testdata/sync/eval/embed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/embed.txtar @@ -0,0 +1,354 @@ +// Tests struct embedding behavior including comprehension-based embeddings and +// closedness enforcement. Verifies that "field not allowed" errors are correctly +// raised when embedding adds fields disallowed by a closed definition, and that +// closedness inversion with open fields works correctly. +-- in.cue -- +#A: { + Common + ... +} + +Common: { + a: int + b: int +} + +x: #A +x: { + c: int + @test(eq, {c: int, a: int, b: int}) +} + +#B: { + if true { + a: int + } + ... +} + +y: #B +y: { + c: int + @test(eq, {c: int, a: int}) +} +-- noclose.cue -- +double: { + a: b?: c: d: "c" + a: {{ + b: {{ + c: e: "member" + }} + }} + @test(eq, {a: {b: {c: {d: "c", e: "member"}}}}) +} +doubleAsComprehension: { + a: b?: c: d: "c" + a: { + if true { + b: { + if true { + c: e: "member" + } + } + } + } + @test(eq, {a: {b: {c: {d: "c", e: "member"}}}}) +} +fieldNotAllowed: { + // This was not correctly enforced in evalv2. + t1: { + #X: { + objs: { + extra: unused: "foo" + ... + } + ... + } + #Y: unused: {} + addTwo: #X & { + #Y + objs: name: "Two" + } + @test(err, at=addTwo.objs.extra, code=eval, contains="field not allowed", pos=[3:5]) + } + t2: { + #AddObjsExtra: { + objs: [string]: { + extra: unused: "foo" + ... + } + ... + } + #EmbedUnused: unused: {} + #AddTwo: #AddObjsExtra & { + #EmbedUnused + objs: two: { + name: "Two" + labels: app: objs.one.name + } + } + out: #AddTwo & { + objs: one: { + name: "One" + } + } + @test(err, at=#AddTwo.objs.two.labels.app, code=incomplete, contains="undefined field: one", pos=[13:23]) + + @test(err, at=#AddTwo.objs.two.extra, code=eval, contains="field not allowed", pos=[3:5]) + @test(err, at=#AddTwo.objs.two.extra.unused, code=eval, contains="field not allowed", pos=[3:12]) + @test(err, at=out.objs.one.extra.unused, code=eval, contains="field not allowed", pos=[3:12]) + @test(err, at=out.objs.one.extra, code=eval, contains="field not allowed", pos=[3:5]) + @test(err, at=out.objs.one.name, code=eval, contains="field not allowed", pos=[18:5]) + @test(err, at=out.objs.two.extra.unused, code=eval, contains="field not allowed", pos=[3:12]) + + // This error is perculated up. + @test(err, code=eval, + hint="the error chosen here is somewhat arbitrary, okay to ignore as long as the others are good", + suberr=(code=eval, path=out.objs.one.name, contains="field not allowed", pos=[18:5]), + suberr=(code=eval, path=out.objs.one.extra, contains="field not allowed", pos=[3:5])) + } + t3: { + x: #X + #X: y: { + z: { + a: [string]: string + b: E: "1" + } + ... + } + + @test(shareID=YY, at=#Y) + @test(shareID=YY, at=x1.y) + x1: y: #Y + #Y: port?: string + + x: y: { + z: b: E: string + port: z.b.E + z: a: c?: string + } @test(eq, { + z: {b: E: "1", a: c?: string} + port: "1" + }) + + if true { + w: x & { + y: x1.y + } + } + @test(err, at=w.y.z.b.E, code=eval, contains="field not allowed", pos=[5:8, 16:10]) + @test(err, at=w.y.z.a, code=eval, contains="field not allowed", pos=[4:5, 18:7]) + @test(err, at=w.y.z.b, code=eval, contains="field not allowed", pos=[5:5, 16:7]) + @test(err, code=eval, + suberr=(code=eval, path=w.y.z.b, contains="field not allowed", pos=[5:5, 16:7]), + suberr=(code=eval, path=w.y.z.a, contains="field not allowed", pos=[4:5, 18:7])) + } +} +closednessInversion: { + base: #X + base: x: #Y + #X: x: {...} + #Y: y: string | *"default" + out: { + base.x + a: b: c: "d" + } + @test(eq, { + base: {x: {y: *"default" | string}} + #X: {x: {}} + #Y: {y: *"default" | string} + out: { + a: {b: {c: "d"}} + y: *"default" | string + } + }) +} +-- out/compile -- +--- in.cue +{ + #A: { + 〈1;Common〉 + ... + } + Common: { + a: int + b: int + } + x: 〈0;#A〉 + x: { + c: int + } + #B: { + if true { + a: int + } + ... + } + y: 〈0;#B〉 + y: { + c: int + } +} +--- noclose.cue +{ + double: { + a: { + b?: { + c: { + d: "c" + } + } + } + a: { + { + b: { + { + c: { + e: "member" + } + } + } + } + } + } + doubleAsComprehension: { + a: { + b?: { + c: { + d: "c" + } + } + } + a: { + if true { + b: { + if true { + c: { + e: "member" + } + } + } + } + } + } + fieldNotAllowed: { + t1: { + #X: { + objs: { + extra: { + unused: "foo" + } + ... + } + ... + } + #Y: { + unused: {} + } + addTwo: (〈0;#X〉 & { + 〈1;#Y〉 + objs: { + name: "Two" + } + }) + } + t2: { + #AddObjsExtra: { + objs: { + [string]: { + extra: { + unused: "foo" + } + ... + } + } + ... + } + #EmbedUnused: { + unused: {} + } + #AddTwo: (〈0;#AddObjsExtra〉 & { + 〈1;#EmbedUnused〉 + objs: { + two: { + name: "Two" + labels: { + app: 〈3;objs〉.one.name + } + } + } + }) + out: (〈0;#AddTwo〉 & { + objs: { + one: { + name: "One" + } + } + }) + } + t3: { + x: 〈0;#X〉 + #X: { + y: { + z: { + a: { + [string]: string + } + b: { + E: "1" + } + } + ... + } + } + x1: { + y: 〈1;#Y〉 + } + #Y: { + port?: string + } + x: { + y: { + z: { + b: { + E: string + } + } + port: 〈0;z〉.b.E + z: { + a: { + c?: string + } + } + } + } + if true { + w: (〈1;x〉 & { + y: 〈2;x1〉.y + }) + } + } + } + closednessInversion: { + base: 〈0;#X〉 + base: { + x: 〈1;#Y〉 + } + #X: { + x: { + ... + } + } + #Y: { + y: (string|*"default") + } + out: { + 〈1;base〉.x + a: { + b: { + c: "d" + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/errunifiy.txtar b/internal/core/compile/testdata/sync/eval/errunifiy.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/errunifiy.txtar @@ -0,0 +1,15 @@ +Incomplete errors should not unify with values. +-- in.cue -- +a: or([]) @test(err, code=incomplete, contains="empty list", pos=[0:4]) +a: "t" + +b: _|_ @test(err, code=user, contains="explicit error", pos=[0:4]) +b: "t" +-- out/compile -- +--- in.cue +{ + a: or([]) + a: "t" + b: _|_(explicit error (_|_ literal) in source) + b: "t" +} diff --git a/internal/core/compile/testdata/sync/eval/expressions.txtar b/internal/core/compile/testdata/sync/eval/expressions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/expressions.txtar @@ -0,0 +1,56 @@ +-- cue.mod/module.cue -- +module: "test.com" +language: version: "v0.15.0" +-- in.cue -- +a: 1 @test(eq, 1) +b: 1 + 2 @test(eq, 3) +c: 3 - 1 @test(eq, 2) +d: rem(5, 3) @test(eq, 2) + +// StructCmp examples - now that the experiment is accepted +structComparison: { + equalStructs: {a: 1, b: 2} == {a: 1, b: 2} @test(eq, true) + differentStructs: {a: 1} == {a: 2} @test(eq, false) + emptyStructs: {} == {} @test(eq, true) +} + +mixedComparison: { + structVsNumber: {a: 1} == 1 @test(eq, false) + listVsStruct: [1, 2] == {a: 1} @test(eq, false) + stringVsNumber: "hello" == 42 @test(eq, false) +} +-- out/compile -- +--- in.cue +{ + a: 1 + b: (1 + 2) + c: (3 - 1) + d: rem(5, 3) + structComparison: { + equalStructs: ({ + a: 1 + b: 2 + } == { + a: 1 + b: 2 + }) + differentStructs: ({ + a: 1 + } == { + a: 2 + }) + emptyStructs: ({} == {}) + } + mixedComparison: { + structVsNumber: ({ + a: 1 + } == 1) + listVsStruct: ([ + 1, + 2, + ] == { + a: 1 + }) + stringVsNumber: ("hello" == 42) + } +} diff --git a/internal/core/compile/testdata/sync/eval/fields.txtar b/internal/core/compile/testdata/sync/eval/fields.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/fields.txtar @@ -0,0 +1,28 @@ +-- in.cue -- +bulkToSelf: { + a: { + foo: [string]: int + foo: bar: "3" @test(err, any, code=eval, contains="conflicting values") + } +} +intField: { + @test(err, code=eval, contains="integer fields not supported", pos=[2:3]) + (2): string +} +-- out/compile -- +--- in.cue +{ + bulkToSelf: { + a: { + foo: { + [string]: int + } + foo: { + bar: "3" + } + } + } + intField: { + 2: string + } +} diff --git a/internal/core/compile/testdata/sync/eval/incomplete.txtar b/internal/core/compile/testdata/sync/eval/incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/incomplete.txtar @@ -0,0 +1,115 @@ +# Tests incomplete-error reporting for various expressions: string arithmetic, +# non-concrete bounds, self-referential bounds, mutual dependencies, and +# undefined-field lookups. All produce [incomplete] errors except e2 which +# succeeds because "bar" is concrete. issue1837 checks that incomplete errors +# are correctly preferred over cycle errors in conditional comprehensions. +-- in.cue -- +s: string + +e1: s + s @test(err, code=incomplete, + suberr=(code=incomplete, contains="non-concrete value %v in operand to %s", args=[string, +], pos=[0:6, -2:4]), + suberr=(code=incomplete, contains="non-concrete value %v in operand to %s", args=[string, +], pos=[0:6, -2:4]), +) +e2: >"bar" & s @test(eq, >"bar") // okay: "bar" is concrete, result is a valid bound +e3: >s & "foo" @test(err, code=incomplete, contains="non-concrete value s for bound >", pos=[0:7]) +e3b: >s @test(err, code=incomplete, contains="non-concrete value s for bound >", pos=[0:7]) + +e4: >e1 & s @test(err, code=incomplete, pos=[-8:6, -10:4]) +e5: =5 @test(err, code=incomplete, pos=[-1:5, 0:5, 0:11]) +} + +a: int @test(eq, int) +okay: (>10 & "bar" & 〈0;s〉) + e3: (>〈0;s〉 & "foo") + e3b: >〈0;s〉 + e4: (>〈0;e1〉 & 〈0;s〉) + e5: (<〈0;e5〉 & 〈0;s〉) + E: { + a: (〈0;c〉 - 〈0;b〉) + b: (〈0;c〉 - 〈0;a〉) + c: ((〈0;a〉 + 〈0;b〉) & >=5) + } + a: int + okay: ((>10 & <〈0;a〉) + 3) + issue1837: { + p1: { + context: {} + x: 〈0;context〉.b + if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) { + message: "a" + } + } + p2: { + if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) { + message: "a" + } + x: 〈0;context〉.b + context: {} + } + p3: { + if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) { + message: "a" + } + context: {} + x: 〈0;context〉.b + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/incompleteperm.txtar b/internal/core/compile/testdata/sync/eval/incompleteperm.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/incompleteperm.txtar @@ -0,0 +1,60 @@ +#inlinetest:exclude source contains compile-time error expressions (abstract arithmetic, +# bound comparisons) which prevent the inline runner from compiling the source. +// Issue #742 +// Issue #405 +-- in.cue -- +// Issue #129 +permanentlyIncompleteOperands: { + a: string + ":" + string + a: "golang/go:1.13.5" +} + +permanentlyIncompleteOperandsNested: { + a: (int + 1) + (int + 1) +} + +permanentlyIncompleteOperandsDisjunct: { + a: (int + 1) | (int + 1) +} + +// Wrong result for `meet`: multiplying a bound by a concrete value should +// yield an error when the result contradicts the bound. +// https://cuelang.org/issue/680 +issue680: (>10 * 2) & 0 + +// In a definition, 'size: >=100 <=200' should be a compile error since +// applying <= to a bound (>=100) is not valid arithmetic. +// https://cuelang.org/issue/405 +issue405: >=100 <= 200 +-- out/compile -- +permanentlyIncompleteOperands.a: invalid operand string ('+' requires concrete value): + ./in.cue:3:5 +permanentlyIncompleteOperands.a: invalid operand string ('+' requires concrete value): + ./in.cue:3:20 +permanentlyIncompleteOperandsNested.a: invalid operand int ('+' requires concrete value): + ./in.cue:8:6 +permanentlyIncompleteOperandsNested.a: invalid operand int ('+' requires concrete value): + ./in.cue:8:18 +permanentlyIncompleteOperandsDisjunct.a: invalid operand int ('+' requires concrete value): + ./in.cue:12:6 +permanentlyIncompleteOperandsDisjunct.a: invalid operand int ('+' requires concrete value): + ./in.cue:12:18 +issue680: invalid operand >10 ('*' requires concrete value): + ./in.cue:18:12 +issue405: invalid operand >=100 ('<=' requires concrete value): + ./in.cue:23:11 +--- in.cue +{ + permanentlyIncompleteOperands: { + a: ((string + ":") + string) + a: "golang/go:1.13.5" + } + permanentlyIncompleteOperandsNested: { + a: ((int + 1) + (int + 1)) + } + permanentlyIncompleteOperandsDisjunct: { + a: ((int + 1)|(int + 1)) + } + issue680: ((>10 * 2) & 0) + issue405: (>=100 <= 200) +} diff --git a/internal/core/compile/testdata/sync/eval/insertion.txtar b/internal/core/compile/testdata/sync/eval/insertion.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/insertion.txtar @@ -0,0 +1,254 @@ +# Tests various patterns of insertion of conjuncts. +# See https://cuelang.org/issues/2169 +-- a.cue -- +embeddingDirect: t1: ({ + #a: _ + _ +} & { + #a: "s" + #a +}) @test(eq, {"s", #a: "s"}) + +embeddingExpr: t1: ({ + #a: _ + _ +} & { + #a: "s" + [ #a ][0] +}) @test(eq, {"s", #a: "s"}) + +unifiedDirect: { + t1: { + #a: _ + _ + } + t1: { + #a + #a: _ + } + t1: { + _ + #a: "s" + } +} @test(eq, {t1: {"s", #a: "s"}}) + + +unifiedExpr: { + t1: { + #a: _ + _ + } + t1: { + [ #a ][0] + #a: _ + } + t1: { + #a: "s" + _ + } +} @test(eq, {t1: {"s", #a: "s"}}) + +// These two embeddings both add fields to each other's original source, which +// then, in turn, needs to be added. +cross: t1: { + a: { + b: {v: 1, a: w: 2} + // from b.a: {x: 2, b: y: 5} + } + b: { + a: {x: 2, b: y: 5} + // from a.b: {v: 1, a: v: 2} + } + a + b +} @test(eq, { + a: {b: {v: 1, a: w: 2, y: 5}, x: 2, w: 2} + b: {a: {x: 2, b: y: 5, w: 2}, v: 1, y: 5} + v: 1 + w: 2 + x: 2 + y: 5 +}) + +-- complex.cue -- +// Multiple levels of insertion +recursive: { + t1: { + e: {} + c: d: e: f: 1 + c.d + c: d: + // This part gets embedded within t1, which ends up adding new fields + // to here, when then again need to be embedded in t1, which then + // will add more fields to node e. + c: d: e: g: 1 + } + t2: { + c + c: c: g: 1 + } +} @test(eq, { + t1: { + e: {f: 1, g: 1} + c: d: { + e: {f: 1, g: 1} + c: d: e: g: 1 + } + } + t2: { + c: {c: g: 1, g: 1} + g: 1 + } +}) + +-- issue2169.cue -- +// Evaluator regression where "cannot add field $X: was already used" errors +// appeared incorrectly when a field was referenced before being defined. +// https://cuelang.org/issue/2169 +embeddedFunctionalExpr: { + #fn: { + #in: _ + _ + } & { + #in: "str" + + ({ + #t: _ + #t + } & { + #t: #in + _ + }) + "" + } + #fn +} @test(eq, {"str", #fn: {"str", #in: "str"}, #in: "str"}) +-- out/compile -- +--- a.cue +{ + embeddingDirect: { + t1: ({ + #a: _ + _ + } & { + #a: "s" + 〈0;#a〉 + }) + } + embeddingExpr: { + t1: ({ + #a: _ + _ + } & { + #a: "s" + [ + 〈1;#a〉, + ][0] + }) + } + unifiedDirect: { + t1: { + #a: _ + _ + } + t1: { + 〈0;#a〉 + #a: _ + } + t1: { + _ + #a: "s" + } + } + unifiedExpr: { + t1: { + #a: _ + _ + } + t1: { + [ + 〈1;#a〉, + ][0] + #a: _ + } + t1: { + #a: "s" + _ + } + } + cross: { + t1: { + a: { + b: { + v: 1 + a: { + w: 2 + } + } + } + b: { + a: { + x: 2 + b: { + y: 5 + } + } + } + 〈0;a〉 + 〈0;b〉 + } + } +} +--- complex.cue +{ + recursive: { + t1: { + e: {} + c: { + d: { + e: { + f: 1 + } + } + } + 〈0;c〉.d + c: { + d: { + c: { + d: { + e: { + g: 1 + } + } + } + } + } + } + t2: { + 〈0;c〉 + c: { + c: { + g: 1 + } + } + } + } +} +--- issue2169.cue +{ + embeddedFunctionalExpr: { + #fn: ({ + #in: _ + _ + } & { + #in: "str" + (({ + #t: _ + 〈0;#t〉 + } & { + #t: 〈1;#in〉 + _ + }) + "") + }) + 〈0;#fn〉 + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue1640.txtar b/internal/core/compile/testdata/sync/eval/issue1640.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue1640.txtar @@ -0,0 +1,54 @@ +# Tests that evaluation of multi-file packages is deterministic regardless of +# field declaration order across files. The two input files a1.cue and a2.cue +# define the same fields x and y but in opposite orders; both must yield the same +# result. Also tests that #MCS (MultiCaseString, with uc: lc) correctly propagates +# concrete values when fact1 and fact2 cross-reference each other. +-- a1.cue -- +package bug + +y: fact2.uc @test(eq, "foo") +x: fact1.uc @test(eq, "foo") +-- a2.cue -- +package bug + +x: fact1.uc @test(eq, "foo") +y: fact2.uc @test(eq, "foo") +-- x.cue -- +package bug + +fact1: #MCS & {lc: fact2.lc} @test(eq, {lc: "foo", uc: "foo"}) @test(closed) +fact2: #MCS & {lc: "foo"} @test(eq, {lc: "foo", uc: "foo"}) @test(closed) + +#MCS: #MultiCaseString @test(eq, {lc: string, uc: string}) @test(closed) @test(shareID=MCS) +#MultiCaseString: { + @test(shareID=MCS) + @test(eq, {lc: string, uc: string}) + @test(closed) + lc: string + uc: lc +} +-- out/compile -- +--- a1.cue +{ + y: 〈0;fact2〉.uc + x: 〈0;fact1〉.uc +} +--- a2.cue +{ + x: 〈0;fact1〉.uc + y: 〈0;fact2〉.uc +} +--- x.cue +{ + fact1: (〈0;#MCS〉 & { + lc: 〈1;fact2〉.lc + }) + fact2: (〈0;#MCS〉 & { + lc: "foo" + }) + #MCS: 〈0;#MultiCaseString〉 + #MultiCaseString: { + lc: string + uc: 〈0;lc〉 + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue1886.txtar b/internal/core/compile/testdata/sync/eval/issue1886.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue1886.txtar @@ -0,0 +1,90 @@ +# Tests cycles and incomplete errors. The cycle struct covers resolvable cycles +# (x=200, x=y+100, y=x-100 resolves because x is grounded at 200) and +# unresolvable ones (a=b+100, b=a-100 — cycle error). The incompleteOne and +# incompleteTwo cases verify that string interpolation with an abstract type +# parameter reports "incomplete" errors correctly regardless of whether the +# hidden template field _t appears before or after its usage site. +-- in.cue -- +cycle: { + x: 200 @test(eq, 200) + x: y + 100 + y: x - 100 @test(eq, 100) + + a: b + 100 @test(err, code=cycle, + suberr=(pos=[0:5], args=[b]), + suberr=(pos=[4:5], args=[a]), + ) + b: a - 100 @test(err, code=cycle, + suberr=(pos=[-4:5], args=[b]), + suberr=(pos=[0:5], args=[a]), + ) +} + +incompleteOne: { + @test(err, code=incomplete, pos=[9:5, 3:7, 4:3], at=r) + _t: { + #p: string + """ + hello \(#p) + """ + } + + r: """ + \(_t) + """ + // TODO: we cannot check for errors on hidden fields yet. + @test(debugCheck, """ + (struct){ + _t: (_|_){ + // [incomplete] incompleteOne._t: invalid interpolation: non-concrete value string (type string): + // in.cue:20:3 + // in.cue:19:7 + #p: (string){ string } + } + r: (_|_){ + // [incomplete] incompleteOne._t: invalid interpolation: invalid interpolation: non-concrete value string (type string): + // in.cue:25:5 + // in.cue:19:7 + // in.cue:20:3 + } + } + """) +} + +incompleteTwo: { + r: """ + \(_t) + """ @test(err, code=incomplete) + + _t: { + #p: string + """ + hello \(#p) + """ + } +} +-- out/compile -- +--- in.cue +{ + cycle: { + x: 200 + x: (〈0;y〉 + 100) + y: (〈0;x〉 - 100) + a: (〈0;b〉 + 100) + b: (〈0;a〉 - 100) + } + incompleteOne: { + _t: { + #p: string + "hello \(〈0;#p〉)" + } + r: "\(〈0;_t〉)" + } + incompleteTwo: { + r: "\(〈0;_t〉)" + _t: { + #p: string + "hello \(〈0;#p〉)" + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue2146.txtar b/internal/core/compile/testdata/sync/eval/issue2146.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue2146.txtar @@ -0,0 +1,114 @@ +# Tests that let expressions within disjunctions are uniqued per arc, not just +# per Environment. Without the fix, incorrect results were cached and shared +# across arcs, causing the `all` list to evaluate incorrectly under unification. +# https://cuelang.org/issue/2146 +// Issue #2146 +// +// Ensure that let expressions are uniqued not only per Environment, but also +// per arc. This is relevant for disjunctions. Without it, an incorrect +// result may be cached for an arbitrary Environment. +-- in.cue -- +p1: { + #A: { + x?: int + y?: int + + let list = [x, y] + all: [for v in list if v != _|_ {v}] + + *{ + x?: _|_ + y: 1 + } | _ + } + + a: #A & { x: 3 } + b: #A & a + @test(eq, { + #A: *{ + y: 1, all: [1], x?: _|_ @test(err, code=user, contains="explicit error", pos=[10:8]) + } | { + x?: int, y?: int, all: [] + } + a: {x: 3, y?: int, all: [3]} + b: {x: 3, y?: int, all: [3]} + }) +} +p2: { + #A: { + x?: int + y?: int + + let list = [x, y] + all: [for v in list if v != _|_ {v}] + + _ | *{ + x?: _|_ + y: 1 + } + } + + a: #A & { x: 3, y: 2 } + b: #A & a + @test(eq, { + #A: *{ + y: 1, all: [1], x?: _|_ @test(err, code=user, contains="explicit error") + } | { + x?: int, y?: int, all: [] + } + a: {x: 3, y: 2, all: [3, 2]} + b: {x: 3, y: 2, all: [3, 2]} + }) +} + +-- out/compile -- +--- in.cue +{ + p1: { + #A: { + x?: int + y?: int + let list#1 = [ + 〈1;x〉, + 〈1;y〉, + ] + all: [ + for _, v in 〈1;let list#1〉 if (〈0;v〉 != _|_(explicit error (_|_ literal) in source)) { + 〈1;v〉 + }, + ] + (*{ + x?: _|_(explicit error (_|_ literal) in source) + y: 1 + }|_) + } + a: (〈0;#A〉 & { + x: 3 + }) + b: (〈0;#A〉 & 〈0;a〉) + } + p2: { + #A: { + x?: int + y?: int + let list#2 = [ + 〈1;x〉, + 〈1;y〉, + ] + all: [ + for _, v in 〈1;let list#2〉 if (〈0;v〉 != _|_(explicit error (_|_ literal) in source)) { + 〈1;v〉 + }, + ] + (_|*{ + x?: _|_(explicit error (_|_ literal) in source) + y: 1 + }) + } + a: (〈0;#A〉 & { + x: 3 + y: 2 + }) + b: (〈0;#A〉 & 〈0;a〉) + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue2235.txtar b/internal/core/compile/testdata/sync/eval/issue2235.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue2235.txtar @@ -0,0 +1,268 @@ +# Tests that nested for-loop comprehensions with dynamic field assignments do +# not trigger a nil pointer dereference panic. The issue occurred in the +# evaluator's conjunct handling when processing nested iterations over structs. +# https://cuelang.org/issue/2235 +// Test various orders +// https://cuelang.org/issues/2235 +-- reductions.cue -- +// Each of these tests triggers a slightly different path. + +t1: { + params: x.y + x: y: {} + for _ in x { + if true { + x: y: a: {} + } + } + @test(eq, {params: {a: {}}, x: {y: {a: {}}}}) +} + +t2: { + out: X.y + let X = m.x + m: x: y: {} + for v in m { + if true { + m: x: y: z: {} + } + } + @test(eq, {out: {z: {}}, m: {x: {y: {z: {}}}}}) +} + +t3: { + out: foo.bar + + foo: bar: {} + + for _ in foo { + for name, _ in foo { + foo: (name): _ + } + } + @test(eq, {out: {}, foo: {bar: {}}}) +} + +-- issue2235.cue -- +package kubecluster + +import ( + "strings" + "net" +) + +shorewallParams: close({ + [=~"^[A-Z0-9_]+$"]: [...net.IP] +}) + +#Cluster: { + clusterName: string + shorewallPrefix: "KUBERNETES_\(strings.ToUpper(clusterName))" +} + +clusters: [CLUSTER=string]: #Cluster & { + clusterName: CLUSTER +} + +#Cluster: { + globalIngressControllers: [string]: #GlobalIngressController + globalIngressControllers: admin: #GlobalIngressController & { + class: "admin" + } + for _, c in globalIngressControllers { + objects: c.objects + } +} + +for clusterName, cluster in clusters { + for class, controller in cluster.globalIngressControllers { + let svc = controller.objects.namespaced.ingress.Service["\(class)-nginx-ingress-controller"] + + shorewallParams: "\(cluster.shorewallPrefix)_INGRESS_\(strings.ToUpper(class))": svc.spec.externalIPs + } +} + +#GlobalIngressController: { + class: string + + objects: namespaced: ingress: { + Service: "\(class)-nginx-ingress-controller": { + spec: { + externalIPs: ["127.0.0.1"] + } + } + } + + for kind, objs in objects.namespaced.ingress { + for name, obj in objs { + objects: namespaced: ingress: "\(kind)": "\(name)": metadata: labels: { + "ingress-class": class + stack: "ingress" + ... + } + } + } +} + +clusters: foo: {} + +@test(eq, { + foo: { + clusterName: "foo" + shorewallPrefix: "KUBERNETES_FOO" + globalIngressControllers: admin: { + class: "admin" + objects: namespaced: ingress: Service: { + "admin-nginx-ingress-controller": { + spec: {externalIPs: ["127.0.0.1"]} + metadata: labels: { + "ingress-class": "admin" + stack: "ingress" + } + } + } + } + objects: namespaced: ingress: { + Service: "admin-nginx-ingress-controller": { + spec: {externalIPs: ["127.0.0.1"]} + metadata: labels: { + "ingress-class": "admin" + stack: "ingress" + } + } + } + } +}, at=clusters) + +-- out/compile -- +--- issue2235.cue +{ + shorewallParams: close({ + [=~"^[A-Z0-9_]+$"]: [ + ...〈import;net〉.IP, + ] + }) + #Cluster: { + clusterName: string + shorewallPrefix: "KUBERNETES_\(〈import;strings〉.ToUpper(〈0;clusterName〉))" + } + clusters: { + [string]: (〈1;#Cluster〉 & { + clusterName: 〈1;-〉 + }) + } + #Cluster: { + globalIngressControllers: { + [string]: 〈2;#GlobalIngressController〉 + } + globalIngressControllers: { + admin: (〈2;#GlobalIngressController〉 & { + class: "admin" + }) + } + for _, c in 〈0;globalIngressControllers〉 { + objects: 〈1;c〉.objects + } + } + for clusterName, cluster in 〈0;clusters〉 { + for class, controller in 〈1;cluster〉.globalIngressControllers { + let svc#1multi = 〈1;controller〉.objects.namespaced.ingress.Service["\(〈1;class〉)-nginx-ingress-controller"] + shorewallParams: { + "\(〈4;cluster〉.shorewallPrefix)_INGRESS_\(〈import;strings〉.ToUpper(〈2;class〉))": 〈1;let svc#1〉.spec.externalIPs + } + } + } + #GlobalIngressController: { + class: string + objects: { + namespaced: { + ingress: { + Service: { + "\(〈4;class〉)-nginx-ingress-controller": { + spec: { + externalIPs: [ + "127.0.0.1", + ] + } + } + } + } + } + } + for kind, objs in 〈0;objects〉.namespaced.ingress { + for name, obj in 〈1;objs〉 { + objects: { + namespaced: { + ingress: { + "\(〈6;kind〉)": { + "\(〈5;name〉)": { + metadata: { + labels: { + "ingress-class": 〈11;class〉 + stack: "ingress" + ... + } + } + } + } + } + } + } + } + } + } + clusters: { + foo: {} + } +} +--- reductions.cue +{ + t1: { + params: 〈0;x〉.y + x: { + y: {} + } + for _, _ in 〈0;x〉 { + if true { + x: { + y: { + a: {} + } + } + } + } + } + t2: { + out: 〈0;let X#2〉.y + let X#2 = 〈0;m〉.x + m: { + x: { + y: {} + } + } + for _, v in 〈0;m〉 { + if true { + m: { + x: { + y: { + z: {} + } + } + } + } + } + } + t3: { + out: 〈0;foo〉.bar + foo: { + bar: {} + } + for _, _ in 〈0;foo〉 { + for name, _ in 〈2;foo〉 { + foo: { + 〈2;name〉: _ + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue2337.txtar b/internal/core/compile/testdata/sync/eval/issue2337.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue2337.txtar @@ -0,0 +1,92 @@ +# evalv2 reported "x: was already used" instead of "conflicting values" for the +# simple.x case. The issue2473 cases test that comprehension guards do not prevent +# fields referenced in the guard from being further constrained in the outer scope +# — env2 should remain "prod" even after being used as a comprehension condition. +# The "one" variant broke on v0.6.0; the "two" variant also failed on v0.5.0. +-- in.cue -- +// evalv2 failed with the confusing error "x: was already used" +// rather than a friendlier "conflicting values" error. +simple: { + x: "x" @test(err, code=eval, + contains="conflicting values", + args=["foo", "x"], + pos=[0:7, 5:7]) + + (x): "foo" +} +// Worked on CUE v0.5.0, broke on v0.6.0 with "was already used". +// Should succeed, as the comprehension does not change env2. +issue2473: one: { + c: { + env: "prod" + env: "dev" | "prod" + env2: env + } + + if c.env2 == "prod" { + { + c: env2: string + example: c.env2 + } + } + @test(eq, { + c: {env: "prod", env2: "prod"}, + example: "prod"} + ) +} +// A variant of the above which failed on v0.5.0 as well. +issue2473: two: { + env: "prod" + env: "dev" | "prod" + env2: env + + if env2 == "prod" { + { + env2: string + example: env2 + } + } + @test(eq, { + env: "prod" + env2: "prod" + example: "prod" + }) +} +-- out/compile -- +--- in.cue +{ + simple: { + x: "x" + 〈0;x〉: "foo" + } + issue2473: { + one: { + c: { + env: "prod" + env: ("dev"|"prod") + env2: 〈0;env〉 + } + if (〈0;c〉.env2 == "prod") { + { + c: { + env2: string + } + example: 〈0;c〉.env2 + } + } + } + } + issue2473: { + two: { + env: "prod" + env: ("dev"|"prod") + env2: 〈0;env〉 + if (〈0;env2〉 == "prod") { + { + env2: string + example: 〈0;env2〉 + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue2550.txtar b/internal/core/compile/testdata/sync/eval/issue2550.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue2550.txtar @@ -0,0 +1,24 @@ +# Tests that accessing an undefined field (bar.missing) on a closed empty struct +# (bar: close({})) inside a comprehension guard correctly reports "undefined +# field" rather than panicking or producing a wrong result. The let binding +# (let _bar = bar) inside the comprehension body verifies that let bindings in +# comprehensions interacting with closed structs do not affect the error behavior. +-- in.cue -- +foo: string @test(eq, string) +bar: close({}) @test(eq, {}) @test(closed) + +if bar.missing == "x" { + let _bar = bar + foo: _bar +} +@test(err, code=eval, contains="undefined field", args=[missing], pos=[in.cue:4:8]) +-- out/compile -- +--- in.cue +{ + foo: string + bar: close({}) + if (〈0;bar〉.missing == "x") { + let _bar#1 = 〈1;bar〉 + foo: 〈0;let _bar#1〉 + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue2649.txtar b/internal/core/compile/testdata/sync/eval/issue2649.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue2649.txtar @@ -0,0 +1,14 @@ +# Tests that list.Avg returns a float value (not an integer) when the result +# is mathematically a whole number. Issue: in v0.6.0 the integer representation +# of the float result caused incorrect Int64() reads and panics in Int(). +# https://cuelang.org/issue/2649 +-- in.cue -- +@test(eq, 8.0) +@test(eq:todo, 8) +@test(kind=float) // TODO: should this be a float, or can it also be an int? +(4 + 8 + 12) / 3 +-- out/compile -- +--- in.cue +{ + (((4 + 8) + 12) / 3) +} diff --git a/internal/core/compile/testdata/sync/eval/issue285.txtar b/internal/core/compile/testdata/sync/eval/issue285.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue285.txtar @@ -0,0 +1,41 @@ +# Tests that a definition referencing another definition with a nested pattern +# constraint correctly propagates field constraints through Instance.Fill and +# unification. Issue: filling a field in a closed nested struct failed with +# "field not allowed" when the constraint was inherited via a parent definition +# rather than explicitly re-stated. +# https://cuelang.org/issue/285 +-- in.cue -- +#TopLevel: [name=string]: { + path: string + content: string +} + +#Mid: #TopLevel & { + myoutput: path: "/output" +} @test(closed) @test(eq, { + myoutput: {path: "/output", content: string} +}) + +val: #Mid & {} & {myoutput: {content: "foo"}} @test(closed) @test(eq, { + myoutput: {content: "foo", path: "/output"} +}) // Should work. +-- out/compile -- +--- in.cue +{ + #TopLevel: { + [string]: { + path: string + content: string + } + } + #Mid: (〈0;#TopLevel〉 & { + myoutput: { + path: "/output" + } + }) + val: ((〈0;#Mid〉 & {}) & { + myoutput: { + content: "foo" + } + }) +} diff --git a/internal/core/compile/testdata/sync/eval/issue295.txtar b/internal/core/compile/testdata/sync/eval/issue295.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue295.txtar @@ -0,0 +1,21 @@ +# Tests that a closed struct with an interpolated dynamic field key correctly +# unifies with a regular field of the same name. Issue: `cue vet -c` reported +# "field not allowed in closed struct" when the key was written as `"\("f")":` +# even though the resulting field name is identical to a subsequently declared +# regular field. +# https://cuelang.org/issue/295 +-- in.cue -- +p: close({ + "\("f")": _ +}) @test(eq, {f: 9}) @test(closed) +p: f: 9 +-- out/compile -- +--- in.cue +{ + p: close({ + "\("f")": _ + }) + p: { + f: 9 + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3301.txtar b/internal/core/compile/testdata/sync/eval/issue3301.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3301.txtar @@ -0,0 +1,57 @@ +# Tests that closedness is correctly propagated through multiple levels of +# embedded definitions with optional fields and conditional comprehensions. +# #Leaf embeds #Mid (which embeds #Base), all with optional fields. The nested +# if comprehensions inside #Leaf reference optional fields without triggering +# spurious closedness errors. +-- in.cue -- +object: #Leaf & {} @test(eq, {extra?: {}, more?: int}) @test(closed) + +#Base: { + extra?: {...} + @test(eq, {extra?: {}}) + @test(closed) +} + +#Mid: { + #Base + @test(eq, {extra?: {}}) + @test(closed) +} + +#Leaf: { + #Mid + extra?: {...} + more?: int + if extra.foo != _|_ { + if more != _|_ { + foo: "bar" + } + } + @test(eq, {extra?: {}, more?: int}) + @test(closed) +} +-- out/compile -- +--- in.cue +{ + object: (〈0;#Leaf〉 & {}) + #Base: { + extra?: { + ... + } + } + #Mid: { + 〈1;#Base〉 + } + #Leaf: { + 〈1;#Mid〉 + extra?: { + ... + } + more?: int + if (〈0;extra〉.foo != _|_(explicit error (_|_ literal) in source)) { + if (〈1;more〉 != _|_(explicit error (_|_ literal) in source)) { + foo: "bar" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3330.txtar b/internal/core/compile/testdata/sync/eval/issue3330.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3330.txtar @@ -0,0 +1,77 @@ +-- in.cue -- +import "list" + +// issue3330: out[0] is a list element that shares #A's vertex. +issue3330: { + #A: { + let empty = {} + + // Reference to empty is within the definition that defines it. Closedness + // thus does not trigger. + field: null | { n: int } + field: empty & { n: 3 } + } @test(eq, {field: {n: 3}}) @test(shareID=A) + + out: list.Concat([[#A]]) @test(eq, [{field: {n: 3}}]) @test(shareID=A, at=0) +} + +// eliminated: ensures a definition used only for the empty struct triggers the +// disjunct-elimination code path that caused the original panic in issue3330. +eliminated: { + #empty: {} + x: null | { n: 3 } + x: #empty & { n: 3 } @test(err, code=eval, contains="empty disjunction", + suberr=(pos=[-1:5, 0:5, 0:14], contains="conflicting values", args=[struct, null]), + suberr=(pos=[-1:14, 0:16], contains="not allowed")) + out: len(x) @test(err, code=eval) +} + +// simplified: different take showing the bug is triggered after a definition +// is referenced. +simplified: { + #struct: { + field: { n: 3 } & g + g: {} + } @test(eq, {field: {n: 3}, g: {}}) + + out: #struct & {} @test(eq, {field: {n: 3}, g: {}}) +} +-- out/compile -- +--- in.cue +{ + issue3330: { + #A: { + let empty#1 = {} + field: (null|{ + n: int + }) + field: (〈0;let empty#1〉 & { + n: 3 + }) + } + out: 〈import;list〉.Concat([ + [ + 〈2;#A〉, + ], + ]) + } + eliminated: { + #empty: {} + x: (null|{ + n: 3 + }) + x: (〈0;#empty〉 & { + n: 3 + }) + out: len(〈0;x〉) + } + simplified: { + #struct: { + field: ({ + n: 3 + } & 〈0;g〉) + g: {} + } + out: (〈0;#struct〉 & {}) + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue349.txtar b/internal/core/compile/testdata/sync/eval/issue349.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue349.txtar @@ -0,0 +1,40 @@ +# Tests that field names overlapping with built-in identifiers (e.g. "html", +# "list") are not reordered to the front of the struct during evaluation. +# Issue: `cue eval` placed such fields before others, violating declaration +# order. +# https://cuelang.org/issue/349 +-- in.cue -- +ex: { + @test(eq, { + aaa: "aaa" + list: "list" + zzz: "zzz" + AAA: "AAA" + html: "html" + HTML: "html" + ZZZ: "ZZZ" + Html: "html" + }) + "aaa": "aaa" + "list": "list" + "zzz": "zzz" + "AAA": "AAA" + "html": "html" + "HTML": "html" + "ZZZ": "ZZZ" + "Html": "html" +} +-- out/compile -- +--- in.cue +{ + ex: { + aaa: "aaa" + list: "list" + zzz: "zzz" + AAA: "AAA" + html: "html" + HTML: "html" + ZZZ: "ZZZ" + Html: "html" + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue353.txtar b/internal/core/compile/testdata/sync/eval/issue353.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue353.txtar @@ -0,0 +1,36 @@ +# Tests that unifying a value with a definition that embeds a disjunction +# correctly retains both disjunction branches after concretizing some fields. +# Issue: after setting e.a = "hello" the two-branch disjunction (one with +# value?, one with externalValue?) should survive intact. +# https://cuelang.org/issue/353 +-- in.cue -- +e: #Example +e: { + a: "hello" + @test(eq, {a: "hello", value?: string} | {a: "hello", externalValue?: string}) +} + +#Example: { + a: string + { + value?: string + } | { + externalValue?: string + } +} +-- out/compile -- +--- in.cue +{ + e: 〈0;#Example〉 + e: { + a: "hello" + } + #Example: { + a: string + ({ + value?: string + }|{ + externalValue?: string + }) + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3672.txtar b/internal/core/compile/testdata/sync/eval/issue3672.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3672.txtar @@ -0,0 +1,315 @@ +# Tests that inline unification patterns like `(#mkDef & {}).#Type` evaluate +# correctly in the v3 evaluator. The issue caused evalv3 to include unwanted +# disjunction alternatives, making orgSyntax compute the wrong branch result. +# https://cuelang.org/issue/3672 +-- x.cue -- +import "strings" + +import "encoding/json" + +#FinDefSetElemType: { + #Type!: _ +} +#FinDefSetDefinition: { + #Elem!: #FinDefSetElemType + #Alternatives: { + allBut: { + AllBut: [...#Elem.#Type] + } + only: { + Only: [...#Elem.#Type] + } + } +} + +#mkFinDefSet: { + #Definition!: #FinDefSetDefinition + #Type: or([for _, v in #Definition.#Alternatives {v}]) +} + +#FinDefSetElemType: { + #Type: _ + toString!: { + _input: #Type + _output: string + } +} + +#FinDefSetDefinition: { + #Elem!: #FinDefSetElemType + #Alternatives: { + allBut: { + AllBut: [...#Elem.#Type] + let xs = [for x in AllBut {(#Elem.toString & {_input: x})._output}] + let str = strings.Join(xs, "\",\"") + orgSyntax: "AllBut [\(str)]" + } + only: { + Only: [...#Elem.#Type] + let xs = [for x in Only {(#Elem.toString & {_input: x})._output}] + let str = strings.Join(xs, "\",\"") + orgSyntax: "Only [\(str)]" + } + } +} + +#ConfigText: string | {UseSectionName: true} + +#ConfigTextRule: #ConfigText | {Append: #ConfigText} | {Prepend: #ConfigText} + +#ConfigTextRules: #ConfigTextRule | [#ConfigTextRule, #ConfigTextRule, ...#ConfigTextRule] + +#FinDefSetConfigTextElem: #FinDefSetElemType +#FinDefSetConfigTextElem: { + #Type: #ConfigTextRules +} + +#FinDefSetOfConfigText: ( + #mkFinDefSet & { + #Definition: {#Elem: #FinDefSetConfigTextElem} + }).#Type + +#FinDefSetConfigTextElem: { + toString: { + _input: #ConfigTextRules + _output: (#orgForConfigTextRules & {source: _input}).orgSyntax + } +} + +#orgForConfigText: { + IN=source: #ConfigText + orgSyntax: { + let INS = IN & string + let INO = IN & {UseSectionName: _} + [ + if INS != _|_ { + json.Marshal(INS) + }, + if INO != _|_ { + "UseSectionName" + }, + "Impossible", + ][0] + } +} + +#orgForConfigTextRule: { + IN=source: #ConfigTextRule + orgSyntax: { + let INA = IN & {Append: _} + let INP = IN & {Prepend: _} + [ + if INA != _|_ { + "Append " + (#orgForConfigText & {source: INA.Append}).orgSyntax + }, + if INP != _|_ { + "Prepend " + (#orgForConfigText & {source: INP.Prepend}).orgSyntax + }, + (#orgForConfigText & {source: IN}).orgSyntax, + ][0] + } +} + +#orgForConfigTextRules: { + IN=source: #ConfigTextRules + orgSyntax: { + let INL = IN & [...] + [ + if INL != _|_ { + let elems = [for x in IN {(#orgForConfigTextRule & {source: x}).orgSyntax}] + let result = strings.Join(elems, "\",\"") + "[\(result)]" + }, + (#orgForConfigTextRule & {source: IN}).orgSyntax, + ][0] + } +} + +value0: #FinDefSetOfConfigText +value0: Only: [{UseSectionName: true}] +@test(eq, { + Only: [{ UseSectionName: true }] + orgSyntax: "Only [UseSectionName]" +}, at=value0) + +@test(err, at=#mkFinDefSet.#Type, code=incomplete, contains="error in call to %s", args=[or], pos=[-108:9, -108:25]) +// TODO(inline): test wrapped errors +@test(err, at=#orgForConfigTextRules.orgSyntax, code=incomplete, path=elems, contains="invalid interpolation", pos=[-16:5, -18:18]) +@test(err, at=#FinDefSetConfigTextElem.toString._output, code=incomplete, path=elems, contains="invalid interpolation", pos=[-17:5, -19:18]) + +-- out/compile -- +--- x.cue +{ + #FinDefSetElemType: { + #Type!: _ + } + #FinDefSetDefinition: { + #Elem!: 〈1;#FinDefSetElemType〉 + #Alternatives: { + allBut: { + AllBut: [ + ...〈3;#Elem〉.#Type, + ] + } + only: { + Only: [ + ...〈3;#Elem〉.#Type, + ] + } + } + } + #mkFinDefSet: { + #Definition!: 〈1;#FinDefSetDefinition〉 + #Type: or([ + for _, v in 〈1;#Definition〉.#Alternatives { + 〈1;v〉 + }, + ]) + } + #FinDefSetElemType: { + #Type: _ + toString!: { + _input: 〈1;#Type〉 + _output: string + } + } + #FinDefSetDefinition: { + #Elem!: 〈1;#FinDefSetElemType〉 + #Alternatives: { + allBut: { + AllBut: [ + ...〈3;#Elem〉.#Type, + ] + let xs#1 = [ + for _, x in 〈1;AllBut〉 { + (〈5;#Elem〉.toString & { + _input: 〈2;x〉 + })._output + }, + ] + let str#2 = 〈import;strings〉.Join(〈0;let xs#1〉, "\",\"") + orgSyntax: "AllBut [\(〈0;let str#2〉)]" + } + only: { + Only: [ + ...〈3;#Elem〉.#Type, + ] + let xs#3 = [ + for _, x in 〈1;Only〉 { + (〈5;#Elem〉.toString & { + _input: 〈2;x〉 + })._output + }, + ] + let str#4 = 〈import;strings〉.Join(〈0;let xs#3〉, "\",\"") + orgSyntax: "Only [\(〈0;let str#4〉)]" + } + } + } + #ConfigText: (string|{ + UseSectionName: true + }) + #ConfigTextRule: (〈0;#ConfigText〉|{ + Append: 〈1;#ConfigText〉 + }|{ + Prepend: 〈1;#ConfigText〉 + }) + #ConfigTextRules: (〈0;#ConfigTextRule〉|[ + 〈1;#ConfigTextRule〉, + 〈1;#ConfigTextRule〉, + ...〈1;#ConfigTextRule〉, + ]) + #FinDefSetConfigTextElem: 〈0;#FinDefSetElemType〉 + #FinDefSetConfigTextElem: { + #Type: 〈1;#ConfigTextRules〉 + } + #FinDefSetOfConfigText: (〈0;#mkFinDefSet〉 & { + #Definition: { + #Elem: 〈2;#FinDefSetConfigTextElem〉 + } + }).#Type + #FinDefSetConfigTextElem: { + toString: { + _input: 〈2;#ConfigTextRules〉 + _output: (〈2;#orgForConfigTextRules〉 & { + source: 〈1;_input〉 + }).orgSyntax + } + } + #orgForConfigText: { + source: 〈1;#ConfigText〉 + orgSyntax: { + let INS#5 = (〈1;source〉 & string) + let INO#6 = (〈1;source〉 & { + UseSectionName: _ + }) + [ + if (〈1;let INS#5〉 != _|_(explicit error (_|_ literal) in source)) { + 〈import;"encoding/json"〉.Marshal(〈2;let INS#5〉) + }, + if (〈1;let INO#6〉 != _|_(explicit error (_|_ literal) in source)) { + "UseSectionName" + }, + "Impossible", + ][0] + } + } + #orgForConfigTextRule: { + source: 〈1;#ConfigTextRule〉 + orgSyntax: { + let INA#7 = (〈1;source〉 & { + Append: _ + }) + let INP#8 = (〈1;source〉 & { + Prepend: _ + }) + [ + if (〈1;let INA#7〉 != _|_(explicit error (_|_ literal) in source)) { + ("Append " + (〈4;#orgForConfigText〉 & { + source: 〈3;let INA#7〉.Append + }).orgSyntax) + }, + if (〈1;let INP#8〉 != _|_(explicit error (_|_ literal) in source)) { + ("Prepend " + (〈4;#orgForConfigText〉 & { + source: 〈3;let INP#8〉.Prepend + }).orgSyntax) + }, + (〈3;#orgForConfigText〉 & { + source: 〈3;source〉 + }).orgSyntax, + ][0] + } + } + #orgForConfigTextRules: { + source: 〈1;#ConfigTextRules〉 + orgSyntax: { + let INL#9 = (〈1;source〉 & [ + ..., + ]) + [ + if (〈1;let INL#9〉 != _|_(explicit error (_|_ literal) in source)) { + let elems#A = [ + for _, x in 〈4;source〉 { + (〈7;#orgForConfigTextRule〉 & { + source: 〈2;x〉 + }).orgSyntax + }, + ] + let result#B = 〈import;strings〉.Join(〈0;let elems#A〉, "\",\"") + "[\(〈0;let result#B〉)]" + }, + (〈3;#orgForConfigTextRule〉 & { + source: 〈3;source〉 + }).orgSyntax, + ][0] + } + } + value0: 〈0;#FinDefSetOfConfigText〉 + value0: { + Only: [ + { + UseSectionName: true + }, + ] + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3688.txtar b/internal/core/compile/testdata/sync/eval/issue3688.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3688.txtar @@ -0,0 +1,98 @@ +# Tests that #fun1 with a hidden field _in: #TypeA (where #TypeA: string | +# {foo: int}) correctly computes out using comprehensions that select based on +# whether _in is a string or has field foo. evalv2 had closedness bugs where eg2 +# (input {foo: 5}) failed to select "foo" and eg3 (input {foo: 5, bar: "test"}) +# failed to fall through to "impossible". evalv3 fixed these bugs. +-- x.cue -- +package x + +#TypeA: string | {foo: int} + +#fun1: { + _in: #TypeA + out: [ + // either `in` is a string + if (_in & string) != _|_ { + _in + }, + // or `in` is has field `foo` + if _in.foo != _|_ { + "foo" + }, + "impossible", // in & #TypeA != _|_ !! + ][0] +} + +examples: [string]: { + in: _ + res: (#fun1 & {_in: in, _}).out +} + +examples: eg1: { + in: "test" + @test(eq, {in: "test", res: "test"}) +} +examples: eg2: { + in: { + foo: 5 + } + @test(eq, {in: {foo: 5}, res: "foo"}) +} +examples: eg3: { + in: { + foo: 5 + bar: "test" + } + @test(eq, { + in: {foo: 5, bar: "test"} + res: "impossible" + }) +} +-- out/compile -- +--- x.cue +{ + #TypeA: (string|{ + foo: int + }) + #fun1: { + _in(:x): 〈1;#TypeA〉 + out: [ + if ((〈1;_in(:x)〉 & string) != _|_(explicit error (_|_ literal) in source)) { + 〈2;_in(:x)〉 + }, + if (〈1;_in(:x)〉.foo != _|_(explicit error (_|_ literal) in source)) { + "foo" + }, + "impossible", + ][0] + } + examples: { + [string]: { + in: _ + res: (〈2;#fun1〉 & { + _in(:x): 〈1;in〉 + _ + }).out + } + } + examples: { + eg1: { + in: "test" + } + } + examples: { + eg2: { + in: { + foo: 5 + } + } + } + examples: { + eg3: { + in: { + foo: 5 + bar: "test" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3709.txtar b/internal/core/compile/testdata/sync/eval/issue3709.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3709.txtar @@ -0,0 +1,27 @@ +# Tests that mutually recursive optional definitions across packages do not cause +# the evaluator to hang. Issue: a pattern constraint referencing a type from an +# imported package, where that type and its transitive references form a cycle +# (e.g. #Foo -> #Bar -> #Foo), caused an infinite loop during evaluation. +# https://cuelang.org/issue/3709 +-- cue.mod/module.cue -- +module: "foo.test/bar" +language: version: "v0.11.0" +-- input.cue -- +package p + +import "foo.test/bar/imported" + +out: [string]: imported.#Foo +@test(eq, { out: [string]: {bar?: foo?: _ @test(ignore)} }) +-- imported/imported.cue -- +package imported + +#Foo: bar?: #Bar +#Bar: foo?: #Foo +-- out/compile -- +--- input.cue +{ + out: { + [string]: 〈import;"foo.test/bar/imported"〉.#Foo + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3801.txtar b/internal/core/compile/testdata/sync/eval/issue3801.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3801.txtar @@ -0,0 +1,309 @@ +# This issue addresses evaluation in nested lets. +-- nested.cue -- +issue3801: let: reduced: { + let F = { + base: { + in: string + let X = {a: "\(in)" }.a + out: X + } + filled: base & {in: "foo"} // failure is here + } + z: F.filled.out + @test(eq, {z: "foo"}) +} +issue3801: nonRooted: reduced: { + #Output: output: { + #base: { + val0: string + msgObj: {a: val0}.a + value: msgObj + } + out: #base & {val0: "foo"} + } + out: (#Output & {}).output // non-concrete + @test(eq, { + #Output: { + output: { + #base: { + val0: string + msgObj: string + value: string + } + out: { + val0: "foo" + msgObj: "foo" + value: "foo" + } + } + } + out: { + #base: { + val0: string + msgObj: string + value: string + } + out: { + val0: "foo" + msgObj: "foo" + value: "foo" + } + } + }) +} +issue3801: let: full: { + #Resource: { + someMsg: string + obs: {} | *{missing: true} + + let pickMsg = [ + if obs.missing {msg: "\(someMsg)"}, + {msg: "bar"}, + ][0] + patches: [{ + op: "add" + path: "/metadata" + value: pickMsg.msg + }] + } + + #Patches: [string]: _ + #JSONPatch: { + namespace?: string + patch: [...#JSONOp] + output: #Patches & {(namespace): patch} + } + #JSONOp: { + op: "add" + path: string + value: _ + } | { + op: "remove" + path: string + } + + #Main: { + NS=namespace: string + + output: jsonPatch.output + + let jsonPatch = #JSONPatch & { + let base = #Resource & {} + let withMsg = base & {someMsg: "foo"} + + namespace: NS + + patch: withMsg.patches + } + } + out: (#Main & {namespace: "ns1"}).output + @test(eq, { + #Resource: { + someMsg: string + obs: *{missing: true} | {} + patches: [{op: "add", path: "/metadata", value: _ @test(ignore)}] + } + #Patches: {} + #JSONPatch: { + namespace?: string + patch: [] + output: _|_ @test(err, code=incomplete, contains="key value of dynamic field must be concrete", pos=[72:24]) + } + #JSONOp: {op: "add", path: string, value: _} | {op: "remove", path: string} + #Main: { + namespace: string + output: _|_ @test(err, code=incomplete) + } + out: { + ns1: [{op: "add", path: "/metadata", value: "foo"}] + } + }) +} +issue3801: nonRooted: full: { + #Output: { + NS=namespace: string + output: (#SubOutput & { + namespace: NS + let base2 = { + let base = #Base & {} + output: base & {val0: "foo"} + } + patch: base2.output.value + }).output @test(err, code=incomplete, contains="key value of dynamic field must be concrete, found %v", args=[string], pos=[15:12, 12:15]) + } + out: (#Output & {namespace: "ns1"}).output + + #SubOutput: { + namespace?: string + + patch: _ + output: (namespace): patch + + // TODO(eval): our message is substituted as a string instead of being wrapped as an error. + @test(err, at=output, code=incomplete, + suberr=(code=incomplete, contains="key value of dynamic field must be concrete, found %v", + args=[_|_(issue3801.nonRooted.full.#SubOutput.output: cannot reference optional field: namespace)], pos=[4:12]), + suberr=(code=incomplete, contains="cannot reference optional field: %s", args=[namespace], pos=[4:12])) + } + + #Base: { + val0: string + let msgObj = [val0][0] + value: msgObj + } + @test(eq, { + #Output: { + namespace: string + output: _|_ + } + out: {ns1: "foo"} + #SubOutput: { + namespace?: string + patch: _ + output: _|_ + } + #Base: {val0: string, value: string} + }) +} +-- out/compile -- +--- nested.cue +{ + issue3801: { + let: { + reduced: { + let F#1 = { + base: { + in: string + let X#2 = { + a: "\(〈1;in〉)" + }.a + out: 〈0;let X#2〉 + } + filled: (〈0;base〉 & { + in: "foo" + }) + } + z: 〈0;let F#1〉.filled.out + } + } + } + issue3801: { + nonRooted: { + reduced: { + #Output: { + output: { + #base: { + val0: string + msgObj: { + a: 〈1;val0〉 + }.a + value: 〈0;msgObj〉 + } + out: (〈0;#base〉 & { + val0: "foo" + }) + } + } + out: (〈0;#Output〉 & {}).output + } + } + } + issue3801: { + let: { + full: { + #Resource: { + someMsg: string + obs: ({}|*{ + missing: true + }) + let pickMsg#4 = [ + if 〈1;obs〉.missing { + msg: "\(〈2;someMsg〉)" + }, + { + msg: "bar" + }, + ][0] + patches: [ + { + op: "add" + path: "/metadata" + value: 〈2;let pickMsg#4〉.msg + }, + ] + } + #Patches: { + [string]: _ + } + #JSONPatch: { + namespace?: string + patch: [ + ...〈2;#JSONOp〉, + ] + output: (〈1;#Patches〉 & { + 〈1;namespace〉: 〈1;patch〉 + }) + } + #JSONOp: ({ + op: "add" + path: string + value: _ + }|{ + op: "remove" + path: string + }) + #Main: { + namespace: string + output: 〈0;let jsonPatch#5〉.output + let jsonPatch#5 = (〈1;#JSONPatch〉 & { + let base#8 = (〈2;#Resource〉 & {}) + let withMsg#9 = (〈0;let base#8〉 & { + someMsg: "foo" + }) + namespace: 〈1;namespace〉 + patch: 〈0;let withMsg#9〉.patches + }) + } + out: (〈0;#Main〉 & { + namespace: "ns1" + }).output + } + } + } + issue3801: { + nonRooted: { + full: { + #Output: { + namespace: string + output: (〈1;#SubOutput〉 & { + namespace: 〈1;namespace〉 + let base2#A = { + let base#B = (〈3;#Base〉 & {}) + output: (〈0;let base#B〉 & { + val0: "foo" + }) + } + patch: 〈0;let base2#A〉.output.value + }).output + } + out: (〈0;#Output〉 & { + namespace: "ns1" + }).output + #SubOutput: { + namespace?: string + patch: _ + output: { + 〈1;namespace〉: 〈1;patch〉 + } + } + #Base: { + val0: string + let msgObj#D = [ + 〈1;val0〉, + ][0] + value: 〈0;let msgObj#D〉 + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3805.txtar b/internal/core/compile/testdata/sync/eval/issue3805.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3805.txtar @@ -0,0 +1,330 @@ +# Tests that complex schema definitions with multiple type aliases, comprehensions, +# and nested struct unification evaluate correctly in the v3 evaluator. The issue +# reported that evalv3 produced validation errors for code accepted by evalv2. +# https://cuelang.org/issue/3805 +-- x.cue -- +#PatientViewSections: { + [string]: #PatientViewSection +} + +#PatientViewSection: #PvSection @test(shareID=pvSection) + +#PvSection: { + @test(shareID=pvSection) + Section: { + display?: string + entries: #PatientViewEntries + } + _json: [for k, v in Section.entries {(k): v._json}] +} + +#PatientViewEntries: [string]: #PatientViewEntry + +#PatientViewEntry: { + #PvSingleForm | #PvLink +} + +#PvSingleForm: { + SingleForm: { + formId: string + showNumberOfInstances?: bool + } + _json: [{ + "iDoc": "singleFormIDoc" + "X-FormId": SingleForm.formId + }] +} + +#PvLink: { + Link: { + icon?: string + sections: #PatientViewSections + } + _json: [for k, v in Link.sections {(k): v._json}] +} + +#TabcatsJson: { + config: { + tabcats: #PatientViewSections + ... + } + json: { + //tabcats: #OrgContents + tabcats: [for k, v in config.tabcats {(k): v._json}] + } +} + +tabcatsExample: #TabcatsJson +tabcatsExample: { + _e1: #PatientViewEntry + _e1: { + Link: { + sections: "Formulare": { + Section: entries: "Fotodokumentation": _e2 + } + } + } + _e2: #PatientViewEntry + _e2: { + SingleForm: { + formId: "fotodokumentation" + } + } + _s: #PvSection + _s: Section: entries: "Dokumentation": _e1 + config: { + tabcats: "02": _s + } + @test(eq, { + _e1: { + Link: { + sections: { + Formulare: { + Section: { + entries: { + Fotodokumentation: { + SingleForm: { + formId: "fotodokumentation" + showNumberOfInstances?: bool + } + _json: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + } + } + display?: string + } + _json: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + } + } + icon?: string + } + _json: [{ + Formulare: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + }] + } + _e2: { + SingleForm: { + formId: "fotodokumentation" + showNumberOfInstances?: bool + } + _json: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + } + _s: { + Section: { + entries: Dokumentation: { + Link: { + sections: Formulare: { + Section: { + entries: Fotodokumentation: { + SingleForm: { + formId: "fotodokumentation" + showNumberOfInstances?: bool + } + _json: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + } + display?: string + } + _json: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + } + icon?: string + } + _json: [{ + Formulare: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + }] + } + display?: string + } + _json: [{ + Dokumentation: [{ + Formulare: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + }] + }] + } + config: tabcats: "02": { + Section: { + entries: { + Dokumentation: { + Link: { + sections: Formulare: { + Section: { + entries: Fotodokumentation: { + SingleForm: { + formId: "fotodokumentation" + showNumberOfInstances?: bool + } + _json: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + } + display?: string + } + _json: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + } + icon?: string + } + _json: [{ + Formulare: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + }] + } + } + display?: string + } + _json: [{ + Dokumentation: [{ Formulare: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + }] }] + } + json: tabcats: [{ "02": [{ Dokumentation: [{ Formulare: [{ + Fotodokumentation: [{ + iDoc: "singleFormIDoc" + "X-FormId": "fotodokumentation" + }] + }] + }] }] }] + }) +} +-- out/compile -- +--- x.cue +{ + #PatientViewSections: { + [string]: 〈1;#PatientViewSection〉 + } + #PatientViewSection: 〈0;#PvSection〉 + #PvSection: { + Section: { + display?: string + entries: 〈2;#PatientViewEntries〉 + } + _json: [ + for k, v in 〈1;Section〉.entries { + 〈1;k〉: 〈1;v〉._json + }, + ] + } + #PatientViewEntries: { + [string]: 〈1;#PatientViewEntry〉 + } + #PatientViewEntry: { + (〈1;#PvSingleForm〉|〈1;#PvLink〉) + } + #PvSingleForm: { + SingleForm: { + formId: string + showNumberOfInstances?: bool + } + _json: [ + { + iDoc: "singleFormIDoc" + "X-FormId": 〈2;SingleForm〉.formId + }, + ] + } + #PvLink: { + Link: { + icon?: string + sections: 〈2;#PatientViewSections〉 + } + _json: [ + for k, v in 〈1;Link〉.sections { + 〈1;k〉: 〈1;v〉._json + }, + ] + } + #TabcatsJson: { + config: { + tabcats: 〈2;#PatientViewSections〉 + ... + } + json: { + tabcats: [ + for k, v in 〈2;config〉.tabcats { + 〈1;k〉: 〈1;v〉._json + }, + ] + } + } + tabcatsExample: 〈0;#TabcatsJson〉 + tabcatsExample: { + _e1: 〈1;#PatientViewEntry〉 + _e1: { + Link: { + sections: { + Formulare: { + Section: { + entries: { + Fotodokumentation: 〈6;_e2〉 + } + } + } + } + } + } + _e2: 〈1;#PatientViewEntry〉 + _e2: { + SingleForm: { + formId: "fotodokumentation" + } + } + _s: 〈1;#PvSection〉 + _s: { + Section: { + entries: { + Dokumentation: 〈3;_e1〉 + } + } + } + config: { + tabcats: { + "02": 〈2;_s〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3813.txtar b/internal/core/compile/testdata/sync/eval/issue3813.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3813.txtar @@ -0,0 +1,37 @@ +# Tests that a struct with an open pattern constraint unifies correctly with a +# definition and an embed, producing the expected closed result. Issue: evalv3 +# incorrectly reported "field not allowed" for `y.f` when the struct was opened +# via a pattern constraint `[string]: _` and then closed through unification +# with a definition. +# https://cuelang.org/issue/3813 +-- x.cue -- +x: {[string]: _} @test(closed) @test(eq, { + f: _ + [string]: _ +}) +x: #d +#d: f: _ + +y: { + @test(eq, {f: true}) + @test(closed) + x +} +y: f: true +-- out/compile -- +--- x.cue +{ + x: { + [string]: _ + } + x: 〈0;#d〉 + #d: { + f: _ + } + y: { + 〈1;x〉 + } + y: { + f: true + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3905.txtar b/internal/core/compile/testdata/sync/eval/issue3905.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3905.txtar @@ -0,0 +1,149 @@ +# Tests that dynamic field keys with disjunctive default values evaluate correctly. +# The v3 evaluator incorrectly reported a cycle error for `(parameters.gatewayNamespace)` +# when the value was a disjunction like `string | *"foo"`, working fine in evalv2. +# https://cuelang.org/issue/3905 +-- in.cue -- +issue3905: reduced: { + #Schema: { + params: name: string | *"foo" + + result: (params.name): "bar" + } + + (#Schema).result + @test(eq, { + #Schema: { + params: {name: *"foo" | string} + result: {foo: "bar"} + } + foo: "bar" + }) +} +issue3905: full: { + #ReferenceGrantBuilder: { + parameters: { + namespace: string + gatewayNamespace: string | *"foo" + } + + referenceGrant: (parameters.gatewayNamespace): #ReferenceGrant & { + metadata: name: parameters.gatewayNamespace + metadata: namespace: parameters.namespace + } + } + + (#ReferenceGrantBuilder & { + parameters: namespace: "foo" + }).referenceGrant + + #ReferenceGrant: { + apiVersion: "gateway.networking.k8s.io/v1beta1" + kind: "ReferenceGrant" + metadata!: { + name!: string + namespace!: string + labels?: { + [string]: string + } + annotations?: { + [string]: string + } + } + } + @test(eq, { + #ReferenceGrantBuilder: { + parameters: { + namespace: string + gatewayNamespace: *"foo" | string + } + referenceGrant: { + foo: { + metadata: { + name: *"foo" | string + namespace: string + labels?: {} + annotations?: {} + } + apiVersion: "gateway.networking.k8s.io/v1beta1" + kind: "ReferenceGrant" + } + } + } + #ReferenceGrant: { + apiVersion: "gateway.networking.k8s.io/v1beta1" + kind: "ReferenceGrant" + metadata!: { + name!: string + namespace!: string + labels?: {} + annotations?: {} + } + } + foo: { + metadata: { + name: *"foo" | string + namespace: "foo" + labels?: {} + annotations?: {} + } + apiVersion: "gateway.networking.k8s.io/v1beta1" + kind: "ReferenceGrant" + } + }) +} +-- out/compile -- +--- in.cue +{ + issue3905: { + reduced: { + #Schema: { + params: { + name: (string|*"foo") + } + result: { + 〈1;params〉.name: "bar" + } + } + 〈0;#Schema〉.result + } + } + issue3905: { + full: { + #ReferenceGrantBuilder: { + parameters: { + namespace: string + gatewayNamespace: (string|*"foo") + } + referenceGrant: { + 〈1;parameters〉.gatewayNamespace: (〈2;#ReferenceGrant〉 & { + metadata: { + name: 〈3;parameters〉.gatewayNamespace + } + metadata: { + namespace: 〈3;parameters〉.namespace + } + }) + } + } + (〈0;#ReferenceGrantBuilder〉 & { + parameters: { + namespace: "foo" + } + }).referenceGrant + #ReferenceGrant: { + apiVersion: "gateway.networking.k8s.io/v1beta1" + kind: "ReferenceGrant" + metadata!: { + name!: string + namespace!: string + labels?: { + [string]: string + } + annotations?: { + [string]: string + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue3919.txtar b/internal/core/compile/testdata/sync/eval/issue3919.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue3919.txtar @@ -0,0 +1,234 @@ +# Tests that builtin function calls with arguments depending on later-defined +# default values evaluate correctly in evalv3. The issue caused math.Abs to fail +# with "non-concrete value" when the port field had a default defined after the call. +# https://cuelang.org/issue/3919 +-- in.cue -- +import "math" + +full: { + out: { + env: { + if true { + PORT: math.Abs(out.port) + } + } + if true { + port: int | *30080 + } + } + @test(eq, { + out: {env: {PORT: 30080}, port: *30080 | int} + }) +} +reduced: { + if true { + a: math.Abs(port) + } + port: int | *30080 + @test(eq, {a: 30080, port: *30080 | int}) +} +-- secondary.cue -- +related: { + [string]: { + if true { + shared: all_total: foo.fooData.total + } + } + foo: fooData: { + total: tags: _hidden + _hidden: extra: {} + } + #Tags: [string]: {} + bar: { + shared: { + [string]: tags: #Tags + bar_total: foo.fooData.total + } + } + @test(eq, { + foo: { + fooData: { + total: {tags: {extra: {}}} + _hidden: {extra: {}} + } + shared: {all_total: {tags: {extra: {}}}} + } + #Tags: {} + bar: { + shared: { + bar_total: {tags: {extra: {}}} + all_total: {tags: {extra: {}}} + } + } + }) +} +-- let.cue -- +// issue3931: evalv3 raises "field set was already referenced" when processing +// optional field specs with let bindings that evalv2 accepts without error. +// https://cuelang.org/issue/3931 +issue3931: full: { + bar: [string]: spec?: Spec + if true { + foo: label: "foo" + bar: bar1: spec: selector: foo + } + let Spec = { + selector?: Selector + } + let Selector = { + label?: string + expr?: [...string] + } + @test(eq, { + bar: { + bar1: { + spec: {selector: {label: "foo", expr?: []}} + } + } + foo: {label: "foo"} + }) +} +-- issue3946.cue -- +// issue3946: evalv3 regression reporting a cyclic reference error when a field +// is inserted and then referenced within a comprehension expression. +// https://cuelang.org/issue/3946 +issue3946: reduced:{ + out: [for _, v in _inputs { v }] + _inputs: [_]: { + doExtra?: bool + if doExtra != _|_ { + if true { + extra: "yes" + } + } + } + if true { + _inputs: input1: name: "input1" + } + @test(eq, { + out: [{ + doExtra?: bool + name: "input1" + }] + _inputs: { + input1: {name: "input1", doExtra?: bool} + } + }) +} +-- out/compile -- +--- in.cue +{ + full: { + out: { + env: { + if true { + PORT: 〈import;math〉.Abs(〈3;out〉.port) + } + } + if true { + port: (int|*30080) + } + } + } + reduced: { + if true { + a: 〈import;math〉.Abs(〈1;port〉) + } + port: (int|*30080) + } +} +--- issue3946.cue +{ + issue3946: { + reduced: { + out: [ + for _, v in 〈1;_inputs〉 { + 〈1;v〉 + }, + ] + _inputs: { + [_]: { + doExtra?: bool + if (〈0;doExtra〉 != _|_(explicit error (_|_ literal) in source)) { + if true { + extra: "yes" + } + } + } + } + if true { + _inputs: { + input1: { + name: "input1" + } + } + } + } + } +} +--- let.cue +{ + issue3931: { + full: { + bar: { + [string]: { + spec?: 〈2;let Spec#1〉 + } + } + if true { + foo: { + label: "foo" + } + bar: { + bar1: { + spec: { + selector: 〈3;foo〉 + } + } + } + } + let Spec#1 = { + selector?: 〈1;let Selector#2〉 + } + let Selector#2 = { + label?: string + expr?: [ + ...string, + ] + } + } + } +} +--- secondary.cue +{ + related: { + [string]: { + if true { + shared: { + all_total: 〈3;foo〉.fooData.total + } + } + } + foo: { + fooData: { + total: { + tags: 〈1;_hidden〉 + } + _hidden: { + extra: {} + } + } + } + #Tags: { + [string]: {} + } + bar: { + shared: { + [string]: { + tags: 〈3;#Tags〉 + } + bar_total: 〈2;foo〉.fooData.total + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue494.txtar b/internal/core/compile/testdata/sync/eval/issue494.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue494.txtar @@ -0,0 +1,69 @@ +-- in.cue -- +_Q: [{pos: 0}, {pos: 1}] + +a: [rn=string]: _Q[0:len(a[rn])] +a: ben: [{}] @test(eq, [{pos: 0}]) + +b: [rn=string]: _Q[0:1] +b: ben: [{}] @test(eq, [{pos: 0}]) + +c: [rn=string]: [...{l: len(a[rn])}] +c: ben: [{}] @test(eq, [{l: 1}]) + +#d: {[rn=string]: [...{pos: uint}] & _Q[0:len(#d[rn])]} @test(shareID=D) +#d: ben: [{}] @test(eq, [{pos: 0}]) + +d: #d @test(shareID=D) +-- out/compile -- +--- in.cue +{ + _Q: [ + { + pos: 0 + }, + { + pos: 1 + }, + ] + a: { + [string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])] + } + a: { + ben: [ + {}, + ] + } + b: { + [string]: 〈1;_Q〉[0:1] + } + b: { + ben: [ + {}, + ] + } + c: { + [string]: [ + ...{ + l: len(〈3;a〉[〈2;-〉]) + }, + ] + } + c: { + ben: [ + {}, + ] + } + #d: { + [string]: ([ + ...{ + pos: &(int, >=0) + }, + ] & 〈1;_Q〉[0:len(〈1;#d〉[〈0;-〉])]) + } + #d: { + ben: [ + {}, + ] + } + d: 〈0;#d〉 +} diff --git a/internal/core/compile/testdata/sync/eval/issue500.txtar b/internal/core/compile/testdata/sync/eval/issue500.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue500.txtar @@ -0,0 +1,64 @@ +-- in.cue -- +package x + +import "strings" +import "list" + +a: strings.Join(strings.Split("test", "")[1:], "") @test(eq, "est") + +b: strings.Join(["t", "e", "s", "t"][1:], "") @test(eq, "est") + +c: ["t", "e", "s", "t"][1:] @test(eq, ["e", "s", "t"]) +d: strings.Join(c, "") @test(eq, "est") + +e: strings.Join(list.Concat([["a"], ["b"]]), "") @test(eq, "ab") + +f: list.Concat([["a"], ["b"]]) @test(eq, ["a", "b"]) +g: strings.Join(f, "") @test(eq, "ab") + +h: strings.Join(list.Repeat(["a"], 3), "") @test(eq, "aaa") + +i: list.Repeat(["b"], 3) @test(eq, ["b", "b", "b"]) +j: strings.Join(i, "") @test(eq, "bbb") +-- out/compile -- +--- in.cue +{ + a: 〈import;strings〉.Join(〈import;strings〉.Split("test", "")[1:], "") + b: 〈import;strings〉.Join([ + "t", + "e", + "s", + "t", + ][1:], "") + c: [ + "t", + "e", + "s", + "t", + ][1:] + d: 〈import;strings〉.Join(〈0;c〉, "") + e: 〈import;strings〉.Join(〈import;list〉.Concat([ + [ + "a", + ], + [ + "b", + ], + ]), "") + f: 〈import;list〉.Concat([ + [ + "a", + ], + [ + "b", + ], + ]) + g: 〈import;strings〉.Join(〈0;f〉, "") + h: 〈import;strings〉.Join(〈import;list〉.Repeat([ + "a", + ], 3), "") + i: 〈import;list〉.Repeat([ + "b", + ], 3) + j: 〈import;strings〉.Join(〈0;i〉, "") +} diff --git a/internal/core/compile/testdata/sync/eval/issue545.txtar b/internal/core/compile/testdata/sync/eval/issue545.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue545.txtar @@ -0,0 +1,101 @@ +# Tests that recursive definitions using disjunctions of validators and self-references +# do not produce duplicate constraints. A regression caused nested applications to +# accumulate redundant conjunctions instead of preserving the recursive structure. +# https://cuelang.org/issue/545 +title: Simplification of validators. +-- in.cue -- +package main + +import ( + "strings" + "time" +) + +t1: { + #Test: { + #HTTP: =~"^http://" + #SSH: !~"^ssh://" + #USER: strings.MinRunes(3) + source: #HTTP | #SSH | #USER | #Test + } + + foo: #Test & { + source: "http://blablabla" + } + + bar: #Test & { + source: foo + } + @test(eq, { + #Test: { + #HTTP: =~"^http://" + #SSH: !~"^ssh://" + #USER: strings.MinRunes(3) + source: =~"^http://" | !~"^ssh://" | strings.MinRunes(3) + } + foo: { + source: "http://blablabla" + #HTTP: =~"^http://" + #SSH: !~"^ssh://" + #USER: strings.MinRunes(3) + } + bar: { + source: { + source: "http://blablabla" + #HTTP: =~"^http://" + #SSH: !~"^ssh://" + #USER: strings.MinRunes(3) + } + #HTTP: =~"^http://" + #SSH: !~"^ssh://" + #USER: strings.MinRunes(3) + } + }) +} + +t2: { + str: "foo" + a: =~str + b: =~"foo" + c: a & b & a & b + + d: time.Time + e: time.Time() + f: d & e & d & e + @test(eq, { + str: "foo" + a: =~"foo" + b: =~"foo" + c: =~"foo" + d: time.Time() + e: time.Time() + f: time.Time() + }) +} +-- out/compile -- +--- in.cue +{ + t1: { + #Test: { + #HTTP: =~"^http://" + #SSH: !~"^ssh://" + #USER: 〈import;strings〉.MinRunes(3) + source: (〈0;#HTTP〉|〈0;#SSH〉|〈0;#USER〉|〈1;#Test〉) + } + foo: (〈0;#Test〉 & { + source: "http://blablabla" + }) + bar: (〈0;#Test〉 & { + source: 〈1;foo〉 + }) + } + t2: { + str: "foo" + a: =~〈0;str〉 + b: =~"foo" + c: (((〈0;a〉 & 〈0;b〉) & 〈0;a〉) & 〈0;b〉) + d: 〈import;time〉.Time + e: 〈import;time〉.Time() + f: (((〈0;d〉 & 〈0;e〉) & 〈0;d〉) & 〈0;e〉) + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue599.txtar b/internal/core/compile/testdata/sync/eval/issue599.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue599.txtar @@ -0,0 +1,182 @@ +# Tests that closedness is correctly tracked when combining schemas through +# inheritance and embedding using the & operator. The issue caused CUE to reject +# fields that should be permitted under the merged schema definitions. +# https://cuelang.org/issue/599 +-- in.cue -- +package deps + +a: { + #A: { + n: string + depends_on: [...#AnyA] + } + + #AnyA: { + n: string + depends_on: [...#AnyA] + ... + } + + #A1: { + #A + x: int + y: z: string // Comment to avoid error + } + + #A2: { + #A + i: string + } + + s: [Name=string]: #AnyA & {n: Name} + + s: foo: #A1 & { + x: 10 + y: z: "z" // Comment to avoid error + } + + s: bar: #A2 & { + i: "hello bar" + depends_on: [s.foo] + } + @test(eq, { + #A: {n: string, depends_on: []} + #AnyA: {n: string, depends_on: []} + #A1: { + x: int + y: {z: string} + n: string + depends_on: [] + } + #A2: { + i: string + n: string + depends_on: [] + } + s: { + foo: { + x: 10 + y: {z: "z"} + n: "foo" + depends_on: [] + } + bar: { + i: "hello bar" + depends_on: [{ + x: 10 + y: {z: "z"} + n: "foo" + depends_on: [] + }] + n: "bar" + } + } + }) +} + +b: { + #A: { + f: {...} + } + + #A1: { + #A + // f: {...} // Uncomment to fix + } + + #C: { + d: {...} + } + + s: [string]: #A1 + + s: foo: { + f: #C & { + d: foo: "bar" + } + } + @test(eq, { + #A: {f: {}} + #A1: {f: {}} + #C: {d: {}} + s: {foo: {f: {d: {foo: "bar"}}}} + }) +} +-- out/compile -- +--- in.cue +{ + a: { + #A: { + n: string + depends_on: [ + ...〈2;#AnyA〉, + ] + } + #AnyA: { + n: string + depends_on: [ + ...〈2;#AnyA〉, + ] + ... + } + #A1: { + 〈1;#A〉 + x: int + y: { + z: string + } + } + #A2: { + 〈1;#A〉 + i: string + } + s: { + [string]: (〈1;#AnyA〉 & { + n: 〈1;-〉 + }) + } + s: { + foo: (〈1;#A1〉 & { + x: 10 + y: { + z: "z" + } + }) + } + s: { + bar: (〈1;#A2〉 & { + i: "hello bar" + depends_on: [ + 〈3;s〉.foo, + ] + }) + } + } + b: { + #A: { + f: { + ... + } + } + #A1: { + 〈1;#A〉 + } + #C: { + d: { + ... + } + } + s: { + [string]: 〈1;#A1〉 + } + s: { + foo: { + f: (〈2;#C〉 & { + d: { + foo: "bar" + } + }) + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/issue962.txtar b/internal/core/compile/testdata/sync/eval/issue962.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/issue962.txtar @@ -0,0 +1,24 @@ +# Tests that an indirect reference through a hidden field to a dynamic index +# correctly propagates an "incomplete" error rather than a misleading "cycle" +# error. Issue: indexing foo[_what] via a hidden variable _obj caused a "cycle +# error" instead of "invalid non-ground value" when _what was abstract. +# https://cuelang.org/issue/962 +-- in.cue -- +import "encoding/yaml" + +foo: bar: "something" + +text: yaml.Marshal(_obj) @test(err, code=incomplete, pos=[2:8], contains="invalid non-ground value") + +_what: string +_obj: foo[_what] @test(err, code=incomplete, pos=[-1:8], contains="invalid non-ground value") +-- out/compile -- +--- in.cue +{ + foo: { + bar: "something" + } + text: 〈import;"encoding/yaml"〉.Marshal(〈0;_obj〉) + _what: string + _obj: 〈0;foo〉[〈0;_what〉] +} diff --git a/internal/core/compile/testdata/sync/eval/let.txtar b/internal/core/compile/testdata/sync/eval/let.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/let.txtar @@ -0,0 +1,430 @@ +-- in.cue -- + let A = 3 * 3 +let B = A + A +let C = B + B +let D = C + C +let E = D + D +let F = E + E +b: { + let G = F + F + let H = G + G + let I = H + H + let J = I + I + let K = J + J + let L = K + K + let M = L + L + let N = M + M + let O = N + N + let P = O + O + let Q = P + P + let R = Q + Q + let S = R + R + let T = S + S + + a: T + b: F +} @test(eq, {a: 4718592, b: 288}) + +// Nil pointer in *core/adt.Environment.evalCached caused by a let binding +// that references a list comprehension over another let-bound list. +// https://cuelang.org/issue/1828 +issue1828: { + volumes: L3 + + let L3 = { + for v2 in [for v1 in L2 {}] {} + } + + let L2 = L1 + let L1 = [] + + @test(eq, {volumes: {}}) +} +ignoreErrorInLet: { + let X = 1 & 2 + disjunction: *X | 3 + + @test(eq, {disjunction: 3}) +} +-- incomprehension.cue -- +// for comprehensions in list do not have to split the let as each instance +// is already associated with a separate environment. +list: { + l: [ 1, 2, 3 ] + c: [ + for v in l { + let X = v*4 // can share + X + } + ] + @test(eq, {l: [1, 2, 3], c: [{4}, {8}, {12}]}) +} + +referencesForDirectly: { + l: [ 1, 2, 3 ] + for k, v in l { + let Y = v*4 // multi + "\(k)": Y + } + @test(eq, { + l: [1, 2, 3] + "0": 4 + "1": 8 + "2": 12 + }) +} + +referencesForViaLet: { + l: [ 1, 2, 3 ] + for k, v in l let X = v*4 { + let Y = X // multi + "\(k)": Y + } + @test(eq, { + l: [1, 2, 3] + "0": 4 + "1": 8 + "2": 12 + }) +} + +letClauseReferencesInert: { + x: 2 + l: [ 1, 2, 3 ] + for k, v in l let X = x { + let Y = X // can share + "\(k)": Y + } + @test(eq, { + x: 2 + l: [1, 2, 3] + "0": 2 + "1": 2 + "2": 2 + }) +} + +// for indirect references, it is okay to not "split" a let clause, as the +// it will only fail as a result of not splitting if the referred values +// would fail as well. +indirectReference: { + l: [ 1, 2, 3 ] + for k, v in l { + y: v // fails if v differs for each y. + let X = y*4 // can share, as y fails if let fails. + "\(k)": X + } + @test(err, code=eval, + suberr=(code=eval, path=y, contains="conflicting values %s and %s", args=[2, 1], pos=[0:20, 1:7, 1:10, 2:2, 3:6]), + suberr=(code=eval, path=y, contains="conflicting values %s and %s", args=[3, 1], pos=[0:20, 1:7, 1:13, 2:2, 3:6])) + +} @test(err, code=eval, + suberr=(code=eval, path=y, contains="conflicting values %s and %s", args=[2, 1], pos=[0:20, 1:7, 1:10, 2:2, 3:6]), + suberr=(code=eval, path=y, contains="conflicting values %s and %s", args=[3, 1], pos=[0:20, 1:7, 1:13, 2:2, 3:6])) + +nestedFor: { + for k, y in [ 4, 5 ] { + let X = { + for x in [ 1, 2 ] { + let X = x + "\(X)": X + } + } + "\(k)": X + } + @test(eq, { + "0": {"1": 1, "2": 2} + "1": {"1": 1, "2": 2} + }) +} +-- issue2166.cue -- +// Using a let clause inside a field comprehension to create a dynamic key +// caused an "invalid interpolation: conflicting values" error. +// https://cuelang.org/issue/2166 +letWithDynamicInComprehension: { + _i: { + a: "d" + b: "e" + } + + for k, v in _i { + let T = v + (T): "1" + } + @test(eq, {_i: {a: "d", b: "e"}, e: "1", d: "1"}) +} +-- issue2218.cue -- +// Earlier let evaluation results in the wrong value: a let inside a for +// comprehension picked up an outer binding instead of the loop variable. +// https://cuelang.org/issue/2218 +_parent_configs: { + PARENT: true +} @test(eq) +_configs: { + CHILD1: { + property: true + } + CHILD2: { + property: true + parent: "PARENT" + } +} @test(ignore) +disabled_parent_test: { + for k, v in _configs { + let parent_config = (*_parent_configs[v.parent] | false) + "\(k)": { + "parent_config": parent_config + } + } + @test(eq, { + CHILD1: {parent_config: false} + CHILD2: {parent_config: *true | false} + }) +} + +-- issue2063.cue -- +import ( + "encoding/yaml" + "strings" +) + +// Issue #2063 +// tools/flow: unsupported node import "list" in yaml.Marshal; let bindings +// inside a struct referencing an undefined field must not block descending. +// https://cuelang.org/issue/2063 +keepDescending: t1: { + ec: {} + bs: { + let m = ec.b + if m == _|_ { } + x: y: "" + } + @test(eq, {ec: {}, bs: {x: {y: ""}}}) +} + +keepDescending: t2: { + x: yaml.Marshal(bs) + + ec: {} + bs: { + let m = ec.b + if m.b == _|_ { } + X: Y: strings.Join([], "") + } + @test(eq, { + x: "X:\n \"Y\": \"\"\n" + ec: {} + bs: {X: {Y: ""}} + }) +} +-- interpolation.cue -- +// evalv3 closedness regression with disjunctions and ellipses where a let +// binding shadowed a loop variable inside a for comprehension. +// https://cuelang.org/issue/4022 +issue4022: full: { + envScript: [ for v in _env let v = _env["KEY"] {"\(v)"} ] + _env: { + KEY: *"" | _ + } + @test(eq, {envScript: [""], _env: {KEY: *"" | _}}) +} +-- out/compile -- +--- in.cue +{ + let A#1 = (3 * 3) + let B#2 = (〈0;let A#1〉 + 〈0;let A#1〉) + let C#3 = (〈0;let B#2〉 + 〈0;let B#2〉) + let D#4 = (〈0;let C#3〉 + 〈0;let C#3〉) + let E#5 = (〈0;let D#4〉 + 〈0;let D#4〉) + let F#6 = (〈0;let E#5〉 + 〈0;let E#5〉) + b: { + let G#7 = (〈1;let F#6〉 + 〈1;let F#6〉) + let H#8 = (〈0;let G#7〉 + 〈0;let G#7〉) + let I#9 = (〈0;let H#8〉 + 〈0;let H#8〉) + let J#A = (〈0;let I#9〉 + 〈0;let I#9〉) + let K#B = (〈0;let J#A〉 + 〈0;let J#A〉) + let L#C = (〈0;let K#B〉 + 〈0;let K#B〉) + let M#D = (〈0;let L#C〉 + 〈0;let L#C〉) + let N#E = (〈0;let M#D〉 + 〈0;let M#D〉) + let O#F = (〈0;let N#E〉 + 〈0;let N#E〉) + let P#10 = (〈0;let O#F〉 + 〈0;let O#F〉) + let Q#11 = (〈0;let P#10〉 + 〈0;let P#10〉) + let R#12 = (〈0;let Q#11〉 + 〈0;let Q#11〉) + let S#13 = (〈0;let R#12〉 + 〈0;let R#12〉) + let T#14 = (〈0;let S#13〉 + 〈0;let S#13〉) + a: 〈0;let T#14〉 + b: 〈1;let F#6〉 + } + issue1828: { + volumes: 〈0;let L3#15〉 + let L3#15 = { + for _, v2 in [ + for _, v1 in 〈2;let L2#16〉 {}, + ] {} + } + let L2#16 = 〈0;let L1#17〉 + let L1#17 = [] + } + ignoreErrorInLet: { + let X#18 = (1 & 2) + disjunction: (*〈0;let X#18〉|3) + } +} +--- incomprehension.cue +{ + list: { + l: [ + 1, + 2, + 3, + ] + c: [ + for _, v in 〈1;l〉 { + let X#19 = (〈1;v〉 * 4) + 〈0;let X#19〉 + }, + ] + } + referencesForDirectly: { + l: [ + 1, + 2, + 3, + ] + for k, v in 〈0;l〉 { + let Y#1Amulti = (〈1;v〉 * 4) + "\(〈1;k〉)": 〈0;let Y#1A〉 + } + } + referencesForViaLet: { + l: [ + 1, + 2, + 3, + ] + for k, v in 〈0;l〉 let X = (〈0;v〉 * 4) { + let Y#1Bmulti = 〈1;X〉 + "\(〈2;k〉)": 〈0;let Y#1B〉 + } + } + letClauseReferencesInert: { + x: 2 + l: [ + 1, + 2, + 3, + ] + for k, v in 〈0;l〉 let X = 〈1;x〉 { + let Y#1C = 〈1;X〉 + "\(〈2;k〉)": 〈0;let Y#1C〉 + } + } + indirectReference: { + l: [ + 1, + 2, + 3, + ] + for k, v in 〈0;l〉 { + y: 〈1;v〉 + let X#1D = (〈0;y〉 * 4) + "\(〈1;k〉)": 〈0;let X#1D〉 + } + } + nestedFor: { + for k, y in [ + 4, + 5, + ] { + let X#1Emulti = { + for _, x in [ + 1, + 2, + ] { + let X#1Fmulti = 〈1;x〉 + "\(〈0;let X#1F〉)": 〈0;let X#1F〉 + } + } + "\(〈1;k〉)": 〈0;let X#1E〉 + } + } +} +--- interpolation.cue +{ + issue4022: { + full: { + envScript: [ + for _, v in 〈1;_env〉 let v = 〈2;_env〉["KEY"] { + "\(〈1;v〉)" + }, + ] + _env: { + KEY: (*""|_) + } + } + } +} +--- issue2063.cue +{ + keepDescending: { + t1: { + ec: {} + bs: { + let m#21 = 〈1;ec〉.b + if (〈0;let m#21〉 == _|_(explicit error (_|_ literal) in source)) {} + x: { + y: "" + } + } + } + } + keepDescending: { + t2: { + x: 〈import;"encoding/yaml"〉.Marshal(〈0;bs〉) + ec: {} + bs: { + let m#22 = 〈1;ec〉.b + if (〈0;let m#22〉.b == _|_(explicit error (_|_ literal) in source)) {} + X: { + Y: 〈import;strings〉.Join([], "") + } + } + } + } +} +--- issue2166.cue +{ + letWithDynamicInComprehension: { + _i: { + a: "d" + b: "e" + } + for k, v in 〈0;_i〉 { + let T#23multi = 〈1;v〉 + 〈0;let T#23〉: "1" + } + } +} +--- issue2218.cue +{ + _parent_configs: { + PARENT: true + } + _configs: { + CHILD1: { + property: true + } + CHILD2: { + property: true + parent: "PARENT" + } + } + disabled_parent_test: { + for k, v in 〈1;_configs〉 { + let parent_config#24multi = (*〈3;_parent_configs〉[〈1;v〉.parent]|false) + "\(〈1;k〉)": { + parent_config: 〈1;let parent_config#24〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/letjoin.txtar b/internal/core/compile/testdata/sync/eval/letjoin.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/letjoin.txtar @@ -0,0 +1,339 @@ +-- in.cue -- +// Test that an error in a let that is merged with itself from two different +// origins does not result in an error as long as the error is not referenced +// outside the let. +t1: { + x: { + a: int + y: { + let X = { + b: a + c: 1 + } + v: X.c + } + } + + x1: x + x1: a: 1 + + x2: x + x2: a: 2 + + xy: x1.y & x2.y + @test(eq, { + x: {a: int, y: {v: 1}} + x1: {a: 1, y: {v: 1}} + x2: {a: 2, y: {v: 1}} + xy: {v: 1} + }) +} + +t2: { + x: { + a: {} + y: { + let X = { + b: a + c: 1 + } + v: X.c + } + } + + x1: x + x1: a: q: 1 + + x2: x + x2: a: r: 2 + + xy: x1 & x2 + @test(eq, { + x: {a: {}, y: {v: 1}} + x1: {a: {q: 1}, y: {v: 1}} + x2: {a: {r: 2}, y: {v: 1}} + xy: {a: {q: 1, r: 2}, y: {v: 1}} + }) +} +-- issue3590.cue -- +// Conflicting values in for loop with let expressions: two chained let bindings +// inside a for comprehension incorrectly caused a conflict error. +// https://cuelang.org/issue/3590 +issue3590: reduced: { + result: [_]: [string]: string + + _input: { + A: p: "A" + B: p: "B" + } + + for _, v in _input { + let Var1 = v.p + + // Second let variable required here; just using Var1 with Items not + // sufficient + let Var2 = Var1 + + let Items = { + item: Var2 + } + + result: "conflicting-\(v.p)": Items + } + @test(eq, { + result: { + "conflicting-A": {item: "A"} + "conflicting-B": {item: "B"} + } + _input: {A: {p: "A"}, B: {p: "B"}} + }) +} +issue3590: { + full: { + #Result: [_]: {[string]: string} + + result: #Result + + #Input: { + p: "A" | "B" + } + + _input: [Parm=_]: #Input & { + p: Parm + } + + _input: { + A: {} + B: {} + } + + for _, v in _input { + let Var1 = v.p + let Var2 = Var1 + + let Items = { + "item": Var2 + } + + result: "conflicting-\(v.p)": Items + } + } + @test(eq, { + reduced: { + result: { + "conflicting-A": {item: "A"} + "conflicting-B": {item: "B"} + } + _input: {A: {p: "A"}, B: {p: "B"}} + } + full: { + #Result: {} + result: { + "conflicting-A": {item: "A"} + "conflicting-B": {item: "B"} + } + #Input: {p: "A" | "B"} + _input: {A: {p: "A"}, B: {p: "B"}} + } + }) +} +// Issue #3591 is related +// Missing items in for loop with let expressions: items produced inside a +// for comprehension via let were dropped from the output. +// https://cuelang.org/issue/3591 +issue3591: missing: { + #Result: [_]: {[string]: string} + + result: #Result + + #Input: { + p: "A" | "B" + } + + _input: [Parm=_]: #Input & { + p: Parm + } + + _input: { + A: {} + B: {} + } + + for _, v in _input { + let Var1 = v.p + let Var2 = Var1 + + let Items = { + "item": { + key1: Var2 + } + } + + result: "missing-items-\(v.p)": { + for s, attr in Items { + if attr.key1 != _|_ {(s): attr.key1} + } + } + } + @test(eq, { + #Result: {} + result: { + "missing-items-A": {item: "A"} + "missing-items-B": {item: "B"} + } + #Input: {p: "A" | "B"} + _input: {A: {p: "A"}, B: {p: "B"}} + }) +} +-- out/compile -- +--- in.cue +{ + t1: { + x: { + a: int + y: { + let X#1 = { + b: 〈2;a〉 + c: 1 + } + v: 〈0;let X#1〉.c + } + } + x1: 〈0;x〉 + x1: { + a: 1 + } + x2: 〈0;x〉 + x2: { + a: 2 + } + xy: (〈0;x1〉.y & 〈0;x2〉.y) + } + t2: { + x: { + a: {} + y: { + let X#2 = { + b: 〈2;a〉 + c: 1 + } + v: 〈0;let X#2〉.c + } + } + x1: 〈0;x〉 + x1: { + a: { + q: 1 + } + } + x2: 〈0;x〉 + x2: { + a: { + r: 2 + } + } + xy: (〈0;x1〉 & 〈0;x2〉) + } +} +--- issue3590.cue +{ + issue3590: { + reduced: { + result: { + [_]: { + [string]: string + } + } + _input: { + A: { + p: "A" + } + B: { + p: "B" + } + } + for _, v in 〈0;_input〉 { + let Var1#3multi = 〈1;v〉.p + let Var2#4multi = 〈0;let Var1#3〉 + let Items#5 = { + item: 〈1;let Var2#4〉 + } + result: { + "conflicting-\(〈2;v〉.p)": 〈1;let Items#5〉 + } + } + } + } + issue3590: { + full: { + #Result: { + [_]: { + [string]: string + } + } + result: 〈0;#Result〉 + #Input: { + p: ("A"|"B") + } + _input: { + [_]: (〈1;#Input〉 & { + p: 〈1;-〉 + }) + } + _input: { + A: {} + B: {} + } + for _, v in 〈0;_input〉 { + let Var1#6multi = 〈1;v〉.p + let Var2#7multi = 〈0;let Var1#6〉 + let Items#8 = { + item: 〈1;let Var2#7〉 + } + result: { + "conflicting-\(〈2;v〉.p)": 〈1;let Items#8〉 + } + } + } + } + issue3591: { + missing: { + #Result: { + [_]: { + [string]: string + } + } + result: 〈0;#Result〉 + #Input: { + p: ("A"|"B") + } + _input: { + [_]: (〈1;#Input〉 & { + p: 〈1;-〉 + }) + } + _input: { + A: {} + B: {} + } + for _, v in 〈0;_input〉 { + let Var1#9multi = 〈1;v〉.p + let Var2#Amulti = 〈0;let Var1#9〉 + let Items#B = { + item: { + key1: 〈2;let Var2#A〉 + } + } + result: { + "missing-items-\(〈2;v〉.p)": { + for s, attr in 〈2;let Items#B〉 { + if (〈1;attr〉.key1 != _|_(explicit error (_|_ literal) in source)) { + 〈2;s〉: 〈2;attr〉.key1 + } + } + } + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/lists.txtar b/internal/core/compile/testdata/sync/eval/lists.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/lists.txtar @@ -0,0 +1,40 @@ +-- in.cue -- +a: [...int] +a: [1, 2, 3, 5] +a: [1, 2, 3, d] @test(eq, [1, 2, 3, 5]) + +b: a[3] @test(eq, 5) +d: 5 @test(eq, 5) + +c: [for x in [[1, 2]][0] {x + d}] @test(eq, [6, 7]) +-- out/compile -- +--- in.cue +{ + a: [ + ...int, + ] + a: [ + 1, + 2, + 3, + 5, + ] + a: [ + 1, + 2, + 3, + 〈1;d〉, + ] + b: 〈0;a〉[3] + d: 5 + c: [ + for _, x in [ + [ + 1, + 2, + ], + ][0] { + (〈1;x〉 + 〈3;d〉) + }, + ] +} diff --git a/internal/core/compile/testdata/sync/eval/merge.txtar b/internal/core/compile/testdata/sync/eval/merge.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/merge.txtar @@ -0,0 +1,60 @@ +# TODO: image field is not pre-evaluated (not a huge deal) +# TODO: allow dynamic fields +-- in.cue -- +key: "app01" @test(eq, "app01") +manifests: [ + { + deployment: #map: [string]: {name: string, image: string, desc: string} + deployment: #map: "\(key)": name: "app01" + }, + { + deployment: #map: app01: image: "image01" + // TODO: allow + // deployment: #map: "\("app03")": image: "image01" + }, +] +// unify +results: _ @test(eq, {deployment: #map: { + app01: {image: "image01", name: "app01", desc: string} +}}) +for _, manifest in manifests { + results: manifest +} +-- out/compile -- +--- in.cue +{ + key: "app01" + manifests: [ + { + deployment: { + #map: { + [string]: { + name: string + image: string + desc: string + } + } + } + deployment: { + #map: { + "\(〈4;key〉)": { + name: "app01" + } + } + } + }, + { + deployment: { + #map: { + app01: { + image: "image01" + } + } + } + }, + ] + results: _ + for _, manifest in 〈0;manifests〉 { + results: 〈1;manifest〉 + } +} diff --git a/internal/core/compile/testdata/sync/eval/nonrooted.txtar b/internal/core/compile/testdata/sync/eval/nonrooted.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/nonrooted.txtar @@ -0,0 +1,125 @@ +# Tests non-rooted inline expressions and let bindings where the inline +# expression conflicts with a definition constraint. The evaluation should +# use the local context (overriding the definition's value), even when +# that creates a conflict detectable from the root. +# https://cuelang.org/issue/3977 +-- in.cue -- +issue3977: inlineExpr: { + #NetworkID: 1 + #fn: { + x: #NetworkID + out: x + 1 + } + + err: (#fn & {x: 2}).out @test(err, code=eval, + contains="conflicting values", args=[1, 2]) +} +issue3977: inlineDisj1: { + #NetworkID: "2" | "3" | "4" + #fn: { + x: #NetworkID + out: "value=\(x)" + } + + err: (#fn & {x: "invalid"}).out @test(err, code=eval, + suberr=(code=eval, path=x, contains="conflicting values %s and %s", args=["2", "invalid"], pos=[-6:14, -4:8, 0:8, 0:18]), + suberr=(code=eval, path=x, contains="conflicting values %s and %s", args=["3", "invalid"], pos=[-6:20, -4:8, 0:8, 0:18]), + suberr=(code=eval, path=x, contains="conflicting values %s and %s", args=["4", "invalid"], pos=[-6:26, -4:8, 0:8, 0:18]), + ) +} +issue3977: inlineDisj2: { + #NetworkID: 1 + #fn: { + x: #NetworkID + out: x + 10 + } + + err: (#fn & {x: *2 | 4}).out @test(err, code=eval, + suberr=(contains="conflicting values", args=[1, 2]), + suberr=(contains="conflicting values", args=[4, 1])) +} +issue3977: inlineDisj3: { + #NetworkID: 1 + #fn: { + x: #NetworkID + out: x + 10 + } + + ok: (#fn & {x: *2 | int}).out @test(eq, 11) +} +issue3977: inlineLet: { + #NetworkID: 1 + let p = { + x: #NetworkID + out: x + 10 + } & { + x: 2 + } + + err: p.out @test(eq, 12, incorrect) @test(err:todo, p=1, code=eval, + contains="conflicting values", args=[1, 2]) +} +-- out/compile -- +--- in.cue +{ + issue3977: { + inlineExpr: { + #NetworkID: 1 + #fn: { + x: 〈1;#NetworkID〉 + out: (〈0;x〉 + 1) + } + err: (〈0;#fn〉 & { + x: 2 + }).out + } + } + issue3977: { + inlineDisj1: { + #NetworkID: ("2"|"3"|"4") + #fn: { + x: 〈1;#NetworkID〉 + out: "value=\(〈0;x〉)" + } + err: (〈0;#fn〉 & { + x: "invalid" + }).out + } + } + issue3977: { + inlineDisj2: { + #NetworkID: 1 + #fn: { + x: 〈1;#NetworkID〉 + out: (〈0;x〉 + 10) + } + err: (〈0;#fn〉 & { + x: (*2|4) + }).out + } + } + issue3977: { + inlineDisj3: { + #NetworkID: 1 + #fn: { + x: 〈1;#NetworkID〉 + out: (〈0;x〉 + 10) + } + ok: (〈0;#fn〉 & { + x: (*2|int) + }).out + } + } + issue3977: { + inlineLet: { + #NetworkID: 1 + let p#1 = ({ + x: 〈1;#NetworkID〉 + out: (〈0;x〉 + 10) + } & { + x: 2 + }) + err: 〈0;let p#1〉.out + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/notify.txtar b/internal/core/compile/testdata/sync/eval/notify.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/notify.txtar @@ -0,0 +1,106 @@ +-- in.cue -- +t1: { + @test(permute) + a + a: a: 2|1 + // TODO(inline): fix args passing: match brackets + @test(err, code=eval, contains="empty disjunction", + suberr=(code=eval, contains="conflicting values", pos=[0:5, 2:2, 3:10]), + suberr=(code=eval, contains="conflicting values", pos=[0:5, 2:2, 3:8]), + ) +} +t2: { + @test(permute, count=2) + d: d.a + d: a: a: 2|1 + @test(err, code=eval, contains="empty disjunction", + suberr=(code=eval, contains="conflicting values", pos=[2:5, 3:5, 3:13]), + suberr=(code=eval, contains="conflicting values", pos=[2:5, 3:5, 3:11]), + ) +} +t3: { + @test(permute, count=6) + b: a + b: (1|2) | 2 + a: 1 | 2 + @test(eq, {b: 1 | 2, a: 1 | 2}) +} +-- issue3437.cue -- +// Panic with a structurally recursive disjunction where a field aliases to +// itself via a self-referential disjunction path. +// https://cuelang.org/issue/3437 +issue3437: { + r: L=L.a + d: a: a: a: {b: 4}|d + out: r&d + // TODO(perf): either use structure sharing or stronger pruning. This seems + // disproportional. + @test(eq, { + r: _|_ @test(err, code=incomplete, contains="issue3437.r: undefined field: a", pos=[5:9]) + d: {a: {a: {a: {b: 4}}}} + out: {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}}, b: 4} | {a: {a: { + a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}} + }, b: 4} | {a: { + a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4}, b: 4} | {a: {a: {a: {b: 4}}, b: 4}} + }}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4}, b: 4} | {a: {a: {a: {b: 4}}, b: 4}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}, b: 4} | {a: {a: {a: {b: 4}}, b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}, b: 4} | {a: {a: {a: {b: 4}, b: 4}, b: 4}}}}}}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}}, b: 4} | {a: {a: { + a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}} + }, b: 4} | {a: { + a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4}, b: 4} | {a: {a: {a: {b: 4}}, b: 4}} + }}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}}, b: 4} | {a: { + a: {a: {b: 4}, b: 4} | {a: {a: {a: {b: 4}}, b: 4}} + }}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}}, b: 4} | {a: {a: {a: {b: 4} | {a: {a: {a: {b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}}}}, b: 4} | {a: {a: {a: {b: 4}, b: 4} | {a: {a: {a: {b: 4}}, b: 4}}, b: 4} | {a: {a: {a: {b: 4}, b: 4}, b: 4} | {a: {a: {a: {b: 4}, b: 4}, b: 4}}}}}}}}}} + }) +} +-- out/compile -- +--- in.cue +{ + t1: { + 〈0;a〉 + a: { + a: (2|1) + } + } + t2: { + d: 〈0;d〉.a + d: { + a: { + a: (2|1) + } + } + } + t3: { + b: 〈0;a〉 + b: ((1|2)|2) + a: (1|2) + } +} +--- issue3437.cue +{ + issue3437: { + r: 〈0〉.a + d: { + a: { + a: { + a: ({ + b: 4 + }|〈3;d〉) + } + } + } + out: (〈0;r〉 & 〈0;d〉) + } +} diff --git a/internal/core/compile/testdata/sync/eval/openinline.txtar b/internal/core/compile/testdata/sync/eval/openinline.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/openinline.txtar @@ -0,0 +1,191 @@ +# This test is important in locking in the closedness behavior +# of evalv2, where inline structs cause some closedness errors +# to be ignored. evalv3 mimics this behavior for the sake of +# backwards compatibility and not breaking existing users. +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- in.cue -- +import ( + pkg "foo.com/example" +) + +// This test tests that closeness errors are eliminated that occur within an +// inline struct. +inlineErr: { + #D: {a: 1} + + // Allow a closedness error that occurs within an inline struct. + def: x: (#D & {b: 2}).b + @test(eq, {#D: {a: 1}, def: {x: 2}}) +} + +// These tests test that selecting into an inlined struct recursively opens this +// struct in OpenInline. +outerErr: { + _inToOut: { + in: _ + out: in.foo + } + + // evalv3 regression: when a definition with extra fields allowed (...) + // is unified with the output of an inline function that returns a closed + // definition, evalv3 spuriously reported "field not allowed" where evalv2 + // correctly accepted the value. The closedness of #Inner must be opened + // when used in OpenInline mode so the outer open struct can accept its fields. + // https://cuelang.org/issue/3534 + issue3534: { + #Inner: foo: minor: 2 + #Outer: version: { major: 1, ... } + + t1: #Outer + t1: version: (_inToOut & {in: #Inner}).out + @test(eq, { + #Inner: {foo: {minor: 2}} + #Outer: {version: {major: 1}} + t1: {version: {major: 1, minor: 2}} + }) + } + + // Test that the same principle works with the close builtin. + usingClose: { + // Same as above, but with an additional level of nesting. + #Inner: foo: close({minor: 2}) + #Outer: version: { major: 1, ... } + + t1: #Outer + t1: version: (_inToOut & {in: #Inner}).out + @test(err, code=eval, at=t1.version.major, contains="field not allowed", pos=[3:22]) + } + + // Test that the mechanism still works with extra nesting: the closedness of + // #Inner should be opened recursively in OpenInline mode. + extraNesting: { + // Same as above, but with an additional level of nesting. + #Inner: foo: x: minor: 2 + #Outer: version: x: { major: 1, ... } + + t1: #Outer + t1: version: (_inToOut & {in: #Inner}).out + @test(eq, { + #Inner: {foo: {x: {minor: 2}}} + #Outer: {version: {x: {major: 1}}} + t1: {version: {x: {major: 1, minor: 2}}} + }) + } +} + +// Here OpenInline does _not_ erase the error, as the error is already present +// in the referred definitions. + +// faulty struct referenced from package +refFromPkg: (pkg.#E).b @test(eq, 1) + +refFromLet: { + let X = { + #D: a: 2 + #E: #D & {b: 1} + } + x: (X.#E).b + @test(eq, {x: 1}) +} + +-- cue.mod/pkg/foo.com/example/example.cue -- +package example + +#D: a: 1 +#E: #D & {b: 1} + +-- out/compile -- +--- in.cue +{ + inlineErr: { + #D: { + a: 1 + } + def: { + x: (〈1;#D〉 & { + b: 2 + }).b + } + } + outerErr: { + _inToOut: { + in: _ + out: 〈0;in〉.foo + } + issue3534: { + #Inner: { + foo: { + minor: 2 + } + } + #Outer: { + version: { + major: 1 + ... + } + } + t1: 〈0;#Outer〉 + t1: { + version: (〈2;_inToOut〉 & { + in: 〈2;#Inner〉 + }).out + } + } + usingClose: { + #Inner: { + foo: close({ + minor: 2 + }) + } + #Outer: { + version: { + major: 1 + ... + } + } + t1: 〈0;#Outer〉 + t1: { + version: (〈2;_inToOut〉 & { + in: 〈2;#Inner〉 + }).out + } + } + extraNesting: { + #Inner: { + foo: { + x: { + minor: 2 + } + } + } + #Outer: { + version: { + x: { + major: 1 + ... + } + } + } + t1: 〈0;#Outer〉 + t1: { + version: (〈2;_inToOut〉 & { + in: 〈2;#Inner〉 + }).out + } + } + } + refFromPkg: 〈import;"foo.com/example"〉.#E.b + refFromLet: { + let X#1 = { + #D: { + a: 2 + } + #E: (〈0;#D〉 & { + b: 1 + }) + } + x: 〈0;let X#1〉.#E.b + } +} diff --git a/internal/core/compile/testdata/sync/eval/required.txtar b/internal/core/compile/testdata/sync/eval/required.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/required.txtar @@ -0,0 +1,231 @@ +-- in.cue -- +self: t1: { + a?: int + @test(eq, {a?: int}) +} + +self: t2: { + a!: int + a!: int + @test(eq, {a!: int}) +} + +unify: t1: { + @test(permute, count=2) + a!: int + a: int + @test(eq, {a: int}) +} + +unify: t2: { + @test(permute) + a!: int + a?: int + @test(eq, {a!: int}) +} + +#Def: t1: { + a!: int + @test(eq, {a!: int}) +} + +// Required fields do not cause vet to fail with definitions: a required field +// in one definition should block a disallowed field from another definition. +// https://cuelang.org/issue/2306 +allowed: { + issue2306: { + #A: a!: int + #A: #B @test(err, code=eval, path=a, contains="field not allowed", pos=[-1:7]) + + #B: b!: int + } +} + +reference: { + toWithinDefinition: { + @test(permute, count=2) + #Foo: a!: int + b: #Foo.a @test(err, code=incomplete, contains="required field missing: %s", args=[a], pos=[0:11]) + } + toFieldFromDefinition: { + @test(permute, count=6) + #Foo: a!: int + b: #Foo + c: b.a @test(err, code=incomplete, contains="required field missing: %s", args=[a], pos=[0:8]) + } + toNonDefinition: { + @test(permute, count=2) + x: y!: _ + b: x.y @test(err, code=incomplete, contains="required field missing: %s", args=[y], pos=[0:8]) + } + toConcrete: { + @test(permute, count=2) + a!: 1 + b: a + 1 @test(err, code=incomplete, contains="required field missing: %s", args=[a], pos=[0:6]) + } +} +-- issue3918.cue -- +import "strings" + +// Required fields do not work on the function pattern: a required field used +// as an input to a definition-based function was not satisfied at the call site. +// https://cuelang.org/issue/3918 +issue3918: { + reduced: { + #disjuncts: { + in!: [...string] + out: strings.Join(in, "|") @test(err, code=incomplete, contains="required field missing: %s", args=[in], pos=[0:22]) + } + + x: (#disjuncts & { + in: ["foo", "bar"] + }).out + @test(eq, { + #disjuncts: { + in!: [] + out: _|_ + } + x: "foo|bar" + }) + } + noFunction: { + #disjuncts: { + in!: [...string] + out: in @test(err, code=incomplete, contains="required field missing: %s", args=[in], pos=[0:9]) + } + _foo: #disjuncts & {} @test(err, at=out, code=incomplete, contains="required field missing: %s", args=[in], pos=[-2:9]) + x: _foo.out @test(err, code=incomplete, path=_foo.out, contains="required field missing: %s", args=[in], pos=[-3:9]) + @test(eq, { + #disjuncts: { + in!: [] + out: _|_ + } + _foo: { + in!: [] + out: _|_ + } + x: _|_ + }) + } +} +// A required field error is incomplete error. Ensure that setting a vertex +// to this error does not escalate it to an evaluation error. +doNotEscalateError: { + a: { + in: _ + out: in.self @test(err, code=incomplete, contains="%s undefined as %s is incomplete (type %s)", args=[in.self, in, _], pos=[0:8]) + } + b: { + required!: _ + pass: (a & {in: required}).out @test(err, code=incomplete, contains="undefined field: %s", args=[self], pos=[-4:11]) + } +} +-- out/compile -- +--- in.cue +{ + self: { + t1: { + a?: int + } + } + self: { + t2: { + a!: int + a!: int + } + } + unify: { + t1: { + a!: int + a: int + } + } + unify: { + t2: { + a!: int + a?: int + } + } + #Def: { + t1: { + a!: int + } + } + allowed: { + issue2306: { + #A: { + a!: int + } + #A: 〈0;#B〉 + #B: { + b!: int + } + } + } + reference: { + toWithinDefinition: { + #Foo: { + a!: int + } + b: 〈0;#Foo〉.a + } + toFieldFromDefinition: { + #Foo: { + a!: int + } + b: 〈0;#Foo〉 + c: 〈0;b〉.a + } + toNonDefinition: { + x: { + y!: _ + } + b: 〈0;x〉.y + } + toConcrete: { + a!: 1 + b: (〈0;a〉 + 1) + } + } +} +--- issue3918.cue +{ + issue3918: { + reduced: { + #disjuncts: { + in!: [ + ...string, + ] + out: 〈import;strings〉.Join(〈0;in〉, "|") + } + x: (〈0;#disjuncts〉 & { + in: [ + "foo", + "bar", + ] + }).out + } + noFunction: { + #disjuncts: { + in!: [ + ...string, + ] + out: 〈0;in〉 + } + _foo: (〈0;#disjuncts〉 & {}) + x: 〈0;_foo〉.out + } + } + doNotEscalateError: { + a: { + in: _ + out: 〈0;in〉.self + } + b: { + required!: _ + pass: (〈1;a〉 & { + in: 〈1;required〉 + }).out + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/resolve_basic.txtar b/internal/core/compile/testdata/sync/eval/resolve_basic.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/resolve_basic.txtar @@ -0,0 +1,23 @@ +-- in.cue -- +a: 1 @test(eq, 1) +b: a + 1 @test(eq, 2) +d: { + x: _ + y: b + x @test(err, code=incomplete, contains="non-concrete value", pos=[0:5, -1:5]) +} +e: d & { + x: 5 +} @test(eq, {x: 5, y: 7}) +-- out/compile -- +--- in.cue +{ + a: 1 + b: (〈0;a〉 + 1) + d: { + x: _ + y: (〈1;b〉 + 〈0;x〉) + } + e: (〈0;d〉 & { + x: 5 + }) +} diff --git a/internal/core/compile/testdata/sync/eval/resolve_env.txtar b/internal/core/compile/testdata/sync/eval/resolve_env.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/resolve_env.txtar @@ -0,0 +1,45 @@ +-- in.cue -- +a: { + d: int + b: { + c: d + } + @test(eq, { + d: int + b: c: int + }) +} +x: { + d: 2 @test(eq, 2) + b: a.b.c @test(eq, int) +} +a1: y: 5 +a1: a2: a3: a4: a5: a1.y +b: a1.a2.a3.a4.a5 @test(eq, 5) +-- out/compile -- +--- in.cue +{ + a: { + d: int + b: { + c: 〈1;d〉 + } + } + x: { + d: 2 + b: 〈1;a〉.b.c + } + a1: { + y: 5 + } + a1: { + a2: { + a3: { + a4: { + a5: 〈4;a1〉.y + } + } + } + } + b: 〈0;a1〉.a2.a3.a4.a5 +} diff --git a/internal/core/compile/testdata/sync/eval/selectors.txtar b/internal/core/compile/testdata/sync/eval/selectors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/selectors.txtar @@ -0,0 +1,45 @@ +-- in.cue -- +a: 1 @test(eq, 1) +b: a + 1 @test(eq, 2) +d: { + x: _ + y: b + x @test(err, code=incomplete, pos=[0:5, -1:5], contains="non-concrete value") +} +e: d & { + x: 5 +} @test(eq, {x: 5, y: 7}) +f: { + a: "foo-bar": 3 + b: a."foo-bar" +} @test(eq, {a: {"foo-bar": 3}, b: 3}) +g: { + a: "foo-bar": c: 3 + b: a."foo-bar".c +} @test(eq, {a: {"foo-bar": {c: 3}}, b: 3}) +-- out/compile -- +--- in.cue +{ + a: 1 + b: (〈0;a〉 + 1) + d: { + x: _ + y: (〈1;b〉 + 〈0;x〉) + } + e: (〈0;d〉 & { + x: 5 + }) + f: { + a: { + "foo-bar": 3 + } + b: 〈0;a〉."foo-bar" + } + g: { + a: { + "foo-bar": { + c: 3 + } + } + b: 〈0;a〉."foo-bar".c + } +} diff --git a/internal/core/compile/testdata/sync/eval/sharing.txtar b/internal/core/compile/testdata/sync/eval/sharing.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/sharing.txtar @@ -0,0 +1,704 @@ +-- in.cue -- +// evalv3 "incDependent: already closed" panic on valid CUE involving +// structure sharing between definitions and regular fields. +// https://cuelang.org/issue/3062 +issue3062: ok1: { + #S: "a" + #o: x: #S + o: #o + o: X + X: x: A + A: "a" + + @test(eq, { + #S: "a" + #o: {x: "a"} + o: {x: "a"} + X: {x: "a"} + A: "a" + }) +} + +// evalv3 "field not allowed" regression from v2 involving structure sharing +// when a field is unified with a shared vertex that has a self-referential path. +// https://cuelang.org/issue/3601 +issue3601: ok1: { + Y: (X & __no_sharing).a + X: a: b: a.b + out: Y & __no_sharing + + @test(eq, {Y: {b: _}, X: {a: {b: _}}, out: {b: _}}) +} + +// Test debug facilities to turn of sharing. +debug: { + sharingOn: { + a: b @test(shareID=sharingOn_ab) + b: {c: 1} @test(shareID=sharingOn_ab) + @test(eq, {a: {c: 1}, b: {c: 1}}) + } + sharingOff: t1: { + a: b & __no_sharing + b: c: 1 + @test(eq, {a: {c: 1}, b: {c: 1}}) + } + sharingOff: t2: { + a: b + a: __no_sharing + b: c: 1 + @test(eq, {a: {c: 1}, b: {c: 1}}) + } + sharingOff: t3: { + a: __no_sharing + a: b + b: c: 1 + @test(eq, {a: {c: 1}, b: {c: 1}}) + } +} +-- dupshare.cue -- +// This file contains tests where unifying the same field multiple times into +// a field with different "closedness" history should compute closedness +// correctly. + +// "field not allowed" regression in evalv3 when the same definition is +// unified into a field multiple times with different closedness histories. +// https://cuelang.org/issue/3641 +issue3641: simplified: t1: { + #Context1: {ctx: {}} @test(shareID=t1ctx1) + Context2: {ctx: {}} @test(shareID=t1ctx2) + + // Must both refer to #Context1 + #Config1: {cfg: #Context1 @test(shareID=t1ctx1)} + #Config3: {cfg: #Context1 @test(shareID=t1ctx1)} + + Config2: {cfg: Context2 @test(shareID=t1ctx2)} + + Config: #Config1 & Config2 + + // order matters + out: Config // Indirection necessary. + out: #Config3 + + @test(eq, { + #Context1: {ctx: {}} + Context2: {ctx: {}} + #Config1: {cfg: {ctx: {}}} + #Config3: {cfg: {ctx: {}}} + Config2: {cfg: {ctx: {}}} + Config: {cfg: {ctx: {}}} + out: {cfg: {ctx: {}}} + }) +} +issue3641: simplified: t2: { + #Context1: {ctx: {}} @test(shareID=t2ctx1) + Context2: {ctx: {}} @test(shareID=t2ctx2) + + // Must both refer to #Context1 + #Config1: {cfg: #Context1 @test(shareID=t2ctx1)} + #Config3: {cfg: #Context1 @test(shareID=t2ctx1)} + + Config2: {cfg: Context2 @test(shareID=t2ctx2)} + + Config: #Config1 & Config2 + + // order matters + out: Config // Indirection necessary. + out: #Config3 + + @test(eq, { + #Context1: {ctx: {}} + Context2: {ctx: {}} + #Config1: {cfg: {ctx: {}}} + #Config3: {cfg: {ctx: {}}} + Config2: {cfg: {ctx: {}}} + Config: {cfg: {ctx: {}}} + out: {cfg: {ctx: {}}} + }) +} +// Variant where sharing is explicitly disabled. +issue3641: simplified: t3: { + #Context1: {ctx: {}} @test(shareID=t3ctx1) + Context2: {ctx: {}} @test(shareID=t3ctx2) + + // Must both refer to #Context1 + #Config1: {cfg: #Context1 @test(shareID=t3ctx1)} + #Config3: {cfg: #Context1 @test(shareID=t3ctx1)} + + Config2: {cfg: Context2 @test(shareID=t3ctx2)} + + Config: #Config1 & Config2 + + // order matters + out: __no_sharing + out: Config // Indirection necessary. + out: #Config3 + + @test(eq, { + #Context1: {ctx: {}} + Context2: {ctx: {}} + #Config1: {cfg: {ctx: {}}} + #Config3: {cfg: {ctx: {}}} + Config2: {cfg: {ctx: {}}} + Config: {cfg: {ctx: {}}} + out: {cfg: {ctx: {}}} + }) +} +issue3641: full: { + #Context1: {ctx: {}} @test(shareID=fullctx1) + #Context2: {ctx: {}} @test(shareID=fullctx2) + + #Config1: {cfg: #Context1 @test(shareID=fullctx1)} @test(shareID=fullcfg1) + #Config2: {cfg: #Context2 @test(shareID=fullctx2)} + + #Schema: {sch: #Config1 @test(shareID=fullcfg1)} + + #Config: #Config1 & #Config2 + + let config = #Config + out: #Schema & { + sch: config + } + + @test(eq, { + #Context1: {ctx: {}} + #Context2: {ctx: {}} + #Config1: {cfg: {ctx: {}}} + #Config2: {cfg: {ctx: {}}} + #Schema: {sch: {cfg: {ctx: {}}}} + #Config: {cfg: {ctx: {}}} + out: {sch: {cfg: {ctx: {}}}} + }) +} +// "field not allowed" evalv3 regression with lists: a list value shared from +// a definition constraint was incorrectly rejected in a regular field. +// https://cuelang.org/issue/3546 +issue3546: reduced: { + all: ["a"] + #all: all + + #Network: list: #List + #List: [...string] + + val: #Network + val: list: #all + + out: #Network + out: val + + @test(eq, { + all: ["a"] + #all: ["a"] + #Network: {list: []} + #List: [] + val: {list: ["a"]} + out: {list: ["a"]} + }) +} +-- sharecycle.cue -- +shareCycle: t1: { + #X: {} + Y: { + x: #X & Y + } + @test(err, code=structural_cycle, path=Y.x.x, contains="structural cycle", pos=[]) +} +shareCycle: t2: { + #X: int + Y: { + x: #X & Y + } + @test(err, code=eval, path=Y.x, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[int, {x:(#X & Y)}, int, struct], pos=[1:6, 2:5, 3:6, 3:11]) +} +shareCycle: t3: { + #X: {} + Y: { + x: Y & #X + } + @test(err, code=structural_cycle, at=Y.x.x, contains="structural cycle", pos=[]) +} +-- acrossdisjunction.cue -- +import "list" + +// evalv3 incomplete value regression involving builtin calls: list.Repeat +// result shared across a disjunction boundary was not properly unshared. +// https://cuelang.org/issue/3679 +issue3679: { + // The result of list.Repeat is structure shared in env. This needs to be + // "unshared" within the disjunction. Ensure that unsharing a shared Vertex + // works arcross disjunction boundaries. + b: null | [string] + b: list.Repeat([for k, v in [0] { "bar" }], 1) + + @test(eq, {b: ["bar"]}) +} +-- issue3835.cue -- +// evalv3 regression with "cycle with field" error involving a comprehension +// with a let that references a top-level field via a pattern constraint. +// https://cuelang.org/issue/3835 +issue3835: { + foo: {} + + _global: "global value" + + [string]: { + if true let orgBotUser = _global { + out: "prefix: " + orgBotUser + } + } + + @test(eq, { + foo: {out: "prefix: global value"} + _global: "global value" + }) +} +-- pendingarcs.cue -- +pending: t1: { + a: X + if true { + a: b: c: e: 1 + } + X: {b: Y @test(shareID=pendXbY)} + Y: {c: d: int} @test(shareID=pendXbY) + + @test(eq, { + a: {b: {c: {e: 1, d: int}}} + X: {b: {c: {d: int}}} + Y: {c: {d: int}} + }) +} +// evalv3 "field not allowed" regression with a comprehension that conditionally +// sets a field inside a definition with an optional nested definition. +// https://cuelang.org/issue/3849 +issue3849: { + dep: #Deployment & {} + if true { + dep: metadata: name: app: "mysql" + } + #Deployment: metadata?: #ObjectMeta + #ObjectMeta: name?: [string]: string + + // TODO(inline): investigate why these do not match. Optionals? + // @test(shareID=Meta, at=#Deployment.metadata) + // @test(shareID=Meta, at=#ObjectMeta) + + @test(eq, { + dep: {metadata: {name: {app: "mysql"}}} + #Deployment: {metadata?: {name?: {}}} + #ObjectMeta: {name?: {}} + }) +} +-- let.cue -- +import "list" + +// evalv3 structural cycle regression vs evalv2 when a let binding holds a +// flattened list that is iterated and used to populate a dynamic field. +// https://cuelang.org/issue/3903 +issue3903: full: { + _input: null | *{name: "foo"} + + let _inputList = list.FlattenN([_input], 0) + + _inputByName: { + for input in _inputList { + (input.name): input + } + } + + for name, _input in _inputByName { + (name): _template & { + input: _input + } + } + _template: { + input: name: string + result: "result-\(input.name)" @test(err, code=incomplete, + contains="non-concrete value string (type string)", + pos=[0:11, -1:16]) + } + @test(eq, { + _input: *{name: "foo"} | null + _inputByName: {foo: {name: "foo"}} + _template: { + input: {name: string} + result: _|_ + } + foo: { + input: {name: "foo"} + result: "result-foo" + } + }) +} +issue3903: noshare: { + _input: null | *{name: "foo"} + + let _inputList = list.FlattenN([_input], 0) + + _inputByName: { + for input in (_inputList & __no_sharing) { + (input.name): input + } + } + for name, _input in _inputByName { + (name): _template & { + input: _input + } + } + _template: { + input: name: string + result: "result-\(input.name)" @test(err, code=incomplete, + contains="non-concrete value string (type string)", + pos=[0:11, -1:17]) + } + @test(eq, { + _input: *{name: "foo"} | null + _inputByName: {foo: {name: "foo"}} + _template: { + input: {name: string} + result: _|_ + } + foo: { + input: {name: string} + result: _|_ @test(err, code=incomplete, + contains="non-concrete value string (type string)") + } + }) +} +-- out/compile -- +--- acrossdisjunction.cue +{ + issue3679: { + b: (null|[ + string, + ]) + b: 〈import;list〉.Repeat([ + for k, v in [ + 0, + ] { + "bar" + }, + ], 1) + } +} +--- dupshare.cue +{ + issue3641: { + simplified: { + t1: { + #Context1: { + ctx: {} + } + Context2: { + ctx: {} + } + #Config1: { + cfg: 〈1;#Context1〉 + } + #Config3: { + cfg: 〈1;#Context1〉 + } + Config2: { + cfg: 〈1;Context2〉 + } + Config: (〈0;#Config1〉 & 〈0;Config2〉) + out: 〈0;Config〉 + out: 〈0;#Config3〉 + } + } + } + issue3641: { + simplified: { + t2: { + #Context1: { + ctx: {} + } + Context2: { + ctx: {} + } + #Config1: { + cfg: 〈1;#Context1〉 + } + #Config3: { + cfg: 〈1;#Context1〉 + } + Config2: { + cfg: 〈1;Context2〉 + } + Config: (〈0;#Config1〉 & 〈0;Config2〉) + out: 〈0;Config〉 + out: 〈0;#Config3〉 + } + } + } + issue3641: { + simplified: { + t3: { + #Context1: { + ctx: {} + } + Context2: { + ctx: {} + } + #Config1: { + cfg: 〈1;#Context1〉 + } + #Config3: { + cfg: 〈1;#Context1〉 + } + Config2: { + cfg: 〈1;Context2〉 + } + Config: (〈0;#Config1〉 & 〈0;Config2〉) + out: _|_(no sharing) + out: 〈0;Config〉 + out: 〈0;#Config3〉 + } + } + } + issue3641: { + full: { + #Context1: { + ctx: {} + } + #Context2: { + ctx: {} + } + #Config1: { + cfg: 〈1;#Context1〉 + } + #Config2: { + cfg: 〈1;#Context2〉 + } + #Schema: { + sch: 〈1;#Config1〉 + } + #Config: (〈0;#Config1〉 & 〈0;#Config2〉) + let config#1 = 〈0;#Config〉 + out: (〈0;#Schema〉 & { + sch: 〈1;let config#1〉 + }) + } + } + issue3546: { + reduced: { + all: [ + "a", + ] + #all: 〈0;all〉 + #Network: { + list: 〈1;#List〉 + } + #List: [ + ...string, + ] + val: 〈0;#Network〉 + val: { + list: 〈1;#all〉 + } + out: 〈0;#Network〉 + out: 〈0;val〉 + } + } +} +--- in.cue +{ + issue3062: { + ok1: { + #S: "a" + #o: { + x: 〈1;#S〉 + } + o: 〈0;#o〉 + o: 〈0;X〉 + X: { + x: 〈1;A〉 + } + A: "a" + } + } + issue3601: { + ok1: { + Y: (〈0;X〉 & _|_(no sharing)).a + X: { + a: { + b: 〈1;a〉.b + } + } + out: (〈0;Y〉 & _|_(no sharing)) + } + } + debug: { + sharingOn: { + a: 〈0;b〉 + b: { + c: 1 + } + } + sharingOff: { + t1: { + a: (〈0;b〉 & _|_(no sharing)) + b: { + c: 1 + } + } + } + sharingOff: { + t2: { + a: 〈0;b〉 + a: _|_(no sharing) + b: { + c: 1 + } + } + } + sharingOff: { + t3: { + a: _|_(no sharing) + a: 〈0;b〉 + b: { + c: 1 + } + } + } + } +} +--- issue3835.cue +{ + issue3835: { + foo: {} + _global: "global value" + [string]: { + if true let orgBotUser = 〈1;_global〉 { + out: ("prefix: " + 〈1;orgBotUser〉) + } + } + } +} +--- let.cue +{ + issue3903: { + full: { + _input: (null|*{ + name: "foo" + }) + let _inputList#2 = 〈import;list〉.FlattenN([ + 〈1;_input〉, + ], 0) + _inputByName: { + for _, input in 〈1;let _inputList#2〉 { + 〈1;input〉.name: 〈1;input〉 + } + } + for name, _input in 〈0;_inputByName〉 { + 〈1;name〉: (〈2;_template〉 & { + input: 〈2;_input〉 + }) + } + _template: { + input: { + name: string + } + result: "result-\(〈0;input〉.name)" + } + } + } + issue3903: { + noshare: { + _input: (null|*{ + name: "foo" + }) + let _inputList#3 = 〈import;list〉.FlattenN([ + 〈1;_input〉, + ], 0) + _inputByName: { + for _, input in (〈1;let _inputList#3〉 & _|_(no sharing)) { + 〈1;input〉.name: 〈1;input〉 + } + } + for name, _input in 〈0;_inputByName〉 { + 〈1;name〉: (〈2;_template〉 & { + input: 〈2;_input〉 + }) + } + _template: { + input: { + name: string + } + result: "result-\(〈0;input〉.name)" + } + } + } +} +--- pendingarcs.cue +{ + pending: { + t1: { + a: 〈0;X〉 + if true { + a: { + b: { + c: { + e: 1 + } + } + } + } + X: { + b: 〈1;Y〉 + } + Y: { + c: { + d: int + } + } + } + } + issue3849: { + dep: (〈0;#Deployment〉 & {}) + if true { + dep: { + metadata: { + name: { + app: "mysql" + } + } + } + } + #Deployment: { + metadata?: 〈1;#ObjectMeta〉 + } + #ObjectMeta: { + name?: { + [string]: string + } + } + } +} +--- sharecycle.cue +{ + shareCycle: { + t1: { + #X: {} + Y: { + x: (〈1;#X〉 & 〈1;Y〉) + } + } + } + shareCycle: { + t2: { + #X: int + Y: { + x: (〈1;#X〉 & 〈1;Y〉) + } + } + } + shareCycle: { + t3: { + #X: {} + Y: { + x: (〈1;Y〉 & 〈1;#X〉) + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/shortcircuit.txtar b/internal/core/compile/testdata/sync/eval/shortcircuit.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/shortcircuit.txtar @@ -0,0 +1,48 @@ +# Tests for @experiment(shortcircuit): short-circuit evaluation of && and ||. +# When the left operand alone determines the result, the right operand is not +# evaluated and any error or incomplete value it carries is suppressed. +-- cue.mod/module.cue -- +module: "test.com" +language: version: "v0.17.0" +-- in.cue -- +@experiment(shortcircuit) + +// Incomplete fields used as right operands in short-circuit tests. +incompleteInt: int +incompleteBool: bool + +// Short-circuit && : false && anything = false. +// Right operand not evaluated; errors/incomplete values suppressed. +andFalseBottom: false && _|_ @test(eq, false) +andFalseIncomplete: false && incompleteInt @test(eq, false) +andFalseTrue: false && true @test(eq, false) + +// No short-circuit: && falls through when left is true. +andTrueTrue: true && true @test(eq, true) +andTrueFalse: true && false @test(eq, false) + +// Short-circuit || : true || anything = true. +// Right operand not evaluated; errors/incomplete values suppressed. +orTrueBottom: true || _|_ @test(eq, true) +orTrueIncomplete: true || incompleteBool @test(eq, true) +orTrueTrue: true || true @test(eq, true) + +// No short-circuit: || falls through when left is false. +orFalseFalse: false || false @test(eq, false) +orFalseTrue: false || true @test(eq, true) +-- out/compile -- +--- in.cue +{ + incompleteInt: int + incompleteBool: bool + andFalseBottom: (false && _|_(explicit error (_|_ literal) in source)) + andFalseIncomplete: (false && 〈0;incompleteInt〉) + andFalseTrue: (false && true) + andTrueTrue: (true && true) + andTrueFalse: (true && false) + orTrueBottom: (true || _|_(explicit error (_|_ literal) in source)) + orTrueIncomplete: (true || 〈0;incompleteBool〉) + orTrueTrue: (true || true) + orFalseFalse: (false || false) + orFalseTrue: (false || true) +} diff --git a/internal/core/compile/testdata/sync/eval/shortcircuit_noexp.txtar b/internal/core/compile/testdata/sync/eval/shortcircuit_noexp.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/shortcircuit_noexp.txtar @@ -0,0 +1,16 @@ +# Verifies that without @experiment(shortcircuit), errors on the right operand +# of && and || still propagate (pre-v0.17.0 behavior is unchanged). +-- cue.mod/module.cue -- +module: "test.com" +language: version: "v0.17.0" +-- in.cue -- +// Without @experiment(shortcircuit), both operands are always evaluated. +// Errors on the right side propagate even when left would short-circuit. +noExpAnd: false && _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[0:20]) +noExpOr: true || _|_ @test(err, code=user, contains="explicit error (_|_ literal) in source", pos=[0:20]) +-- out/compile -- +--- in.cue +{ + noExpAnd: (false && _|_(explicit error (_|_ literal) in source)) + noExpOr: (true || _|_(explicit error (_|_ literal) in source)) +} diff --git a/internal/core/compile/testdata/sync/eval/structs.txtar b/internal/core/compile/testdata/sync/eval/structs.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/structs.txtar @@ -0,0 +1,11 @@ +-- in.cue -- +import "struct" + +v: {a: struct.MaxFields(2) & {}}.a @test(eq, {}) @test(eq:todo, struct.MaxFields(2) & {}) +-- out/compile -- +--- in.cue +{ + v: { + a: (〈import;struct〉.MaxFields(2) & {}) + }.a +} diff --git a/internal/core/compile/testdata/sync/eval/unify.txtar b/internal/core/compile/testdata/sync/eval/unify.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/unify.txtar @@ -0,0 +1,39 @@ +-- in.cue -- +a: d: { + #base + #info: {...} + Y: #info.X @test(eq, "foo") @test(closed) +} @test(closed) + +#base: { + #info: {...} +} @test(closed) + +a: [Name=string]: {#info: { + X: "foo" +}} @test(closed=false) +-- out/compile -- +--- in.cue +{ + a: { + d: { + 〈2;#base〉 + #info: { + ... + } + Y: 〈0;#info〉.X + } + } + #base: { + #info: { + ... + } + } + a: { + [string]: { + #info: { + X: "foo" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/v0.7.txtar b/internal/core/compile/testdata/sync/eval/v0.7.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/v0.7.txtar @@ -0,0 +1,843 @@ +# Some new cases specific to v0.7 +-- builtins.cue -- +import "strings" + +mutualBuiltin: t1: ok: { + // Results in incomplete error in v0.6 + s3: strings.ContainsAny(s4) @test(eq, strings.ContainsAny("dd")) + s4: strings.ContainsAny(s3) + s4: "dd" @test(eq, "dd") +} + +mutualBuiltin: t2: ok: { + s3: strings.ContainsAny(s5, "dd") @test(eq, true) + s5: s6 + s6: "dd" +} + +-- comprehensions.cue -- +comprehensions: t1: ok: { + src: ["foo"] + for v in src { "\(v)": v } + @test(eq, {src: ["foo"], foo: "foo"}) +} + +-- dynamic.cue -- +dynamic: t1: ok: { + [X=string]: {name: X} + (x.y): {} + x: y: "foo" + @test(eq, { + x: {y: "foo", name: "x"} + foo: {name: "foo"} + }) +} + +dynamic: t2: ok: { + foo: #X + #X: { + a: b: C: 1 + for _ in a { + a: ("b"): D: 2 + } + } + @test(eq, { + foo: {a: {b: {C: 1, D: 2}}} + #X: {a: {b: {C: 1, D: 2}}} + }) +} + +-- definition.cue -- +definition: t0: err: { + #D1: env: {} + d1: env: c: "C" @test(err, code=eval, contains="field not allowed", pos=[0:11]) + d1: #D1 +} + +definition: t1: err: { + a: #A + a: c: 1 @test(err, code=eval, contains="field not allowed", pos=[0:5]) + // defining after first reference triggers notification mechanism to kick in. + #A: {} +} + +definition: t2: ok: p1: { + #A: { + ... + {a: int} + } + x: #A & { c: int } + @test(eq, {#A: {a: int}, x: {c: int, a: int}}) +} + +definition: t2: ok: p2: { + #A: { + {a: int} + ... + } + x: #A & { c: int } + @test(eq, {#A: {a: int}, x: {c: int, a: int}}) +} + +definition: t2: ok: p3: { + x: #A & { c: int } + #A: { + ... + {a: int} + } + @test(eq, {x: {c: int, a: int}, #A: {a: int}}) +} + +definition: t2: ok: p4: { + x: #A & { c: int } + #A: { + {a: int} + ... + } + @test(eq, {x: {c: int, a: int}, #A: {a: int}}) +} + +-- expr.cue -- +expr: t1: ok: { + a: X + X: 5.0 + X: Y / 2 + Y: a * 2 + @test(eq, {a: 5.0, X: 5.0, Y: 10.0}) +} + +expr: t2: ok: { + A: X + 2 + X: 5 + X: A - 2 + @test(eq, {A: 7, X: 5}) +} + +expr: t3: ok: p1: { + a0: X + X: 5.0 + X: a0 * 1 + @test(eq, {a0: 5.0, X: 5.0}) +} + +expr: t3: ok: p2: { + b: Y * 1 + Y: b * 1 + Y: 5.0 + @test(eq, {b: 5.0, Y: 5.0}) +} + +expr: t4: ok: { + // -> a0 -> X -> b1 -> b0 -> a1 -> a0 + a0: X @test(eq, 5.0) // Need all conjuncts known from X + b0: a1 @test(eq, 7.0) + a1: a0 + 2 @test(eq, 7.0) + b1: b0 - 2 @test(eq, 5.0) + a0: X // defined earlier + X: b1 + X: 5.0 @test(eq, 5.0) +} + +-- in.cue -- +mutual: t0: ok: { + c: e & {b: 2} + e: {a: 1} + e: c + @test(eq, {c: {b: 2, a: 1}, e: {a: 1, b: 2}}) +} + +mutual: t1: ok: { + a: { + b + b: {b: f: 1} + } + a: a.b + a: b: {b: f: 1} + @test(eq, {a: {b: {b: {f: 1}, f: 1}, f: 1}}) +} + +mutual: t2: ok: { + x: a: a: f: 1 + x: y.a + y: a: a: e: 1 + y: x.a + @test(eq, { + x: {a: {a: {f: 1}, e: 1}, f: 1} + y: {a: {a: {e: 1}, f: 1}, e: 1} + }) +} + +mutual: t3: ok: { + d: e: f: 1 + d + d: d: e: g: 1 + @test(eq, { + d: {e: {f: 1, g: 1}, d: {e: {g: 1}}} + e: {f: 1, g: 1} + }) +} + +// This test fails for some permutations in v0.6. +mutual: t4: ok: { + p0: { + z: x.b + x: b: y.c + x: b: {d: b: 2} + y: c: z.d + z: d: {a: 1} + @test(eq, { + z: {d: {a: 1, b: 2}, a: 1, b: 2} + x: {b: {d: {b: 2}, a: 1, b: 2}} + y: {c: {a: 1, b: 2}} + }) + } + + p1: { + x: b: y.c + z: x.b + x: b: {d: b: 2} + y: c: z.d + z: d: {a: 1} + @test(eq, { + x: {b: {d: {b: 2}, a: 1, b: 2}} + z: {d: {a: 1, b: 2}, a: 1, b: 2} + y: {c: {a: 1, b: 2}} + }) + } + + p2: { + x: b: y.c + x: b: {d: b: 2} + y: c: z.d + z: x.b + z: d: {a: 1} + @test(eq, { + x: {b: {d: {b: 2}, a: 1, b: 2}} + y: {c: {a: 1, b: 2}} + z: {d: {a: 1, b: 2}, a: 1, b: 2} + }) + } + + p3: { + x: b: {d: b: 2} + y: c: z.d + z: x.b + x: b: y.c + z: d: {a: 1} + @test(eq, { + x: {b: {d: {b: 2}, a: 1, b: 2}} + y: {c: {a: 1, b: 2}} + z: {d: {a: 1, b: 2}, a: 1, b: 2} + }) + } + + p4: { + z: x.b + x: b: {d: b: 2} + y: c: z.d + x: b: y.c + z: d: {a: 1} + @test(eq, { + z: {d: {a: 1, b: 2}, a: 1, b: 2} + x: {b: {d: {b: 2}, a: 1, b: 2}} + y: {c: {a: 1, b: 2}} + }) + } + + p5: { + x: b: {d: b: 2} + y: c: z.d + x: b: y.c + z: x.b + z: d: {a: 1} + @test(eq, { + x: {b: {d: {b: 2}, a: 1, b: 2}} + y: {c: {a: 1, b: 2}} + z: {d: {a: 1, b: 2}, a: 1, b: 2} + }) + } + + check: p1 & p2 & p3 & p4 & p5 @test(eq, { + x: {b: {d: {b: 2}, a: 1, b: 2}} + z: {d: {a: 1, b: 2}, a: 1, b: 2} + y: {c: {a: 1, b: 2}} + }) +} + +-- equality.cue -- +// evalv3 nil pointer dereference panic in equalTerminal with repeated +// unifications of the same default disjunction inside a close() call. +// https://cuelang.org/issue/3194 +issue3194: reduced: { + A: *0 | >10 + A: *0 | >10 + { + out: close({ b: A }) + out: b: A + }.out + + @test(eq, {A: *0 | >10, b: *0 | >10}) +} + +-- chained.cue -- +import "encoding/yaml" + +// evalv3 "field set was already referenced" regression when a chained field +// lookup resolves through a dynamic field to a yaml.Marshal call. +// https://cuelang.org/issue/3925 +issue3925: reduced: { + out: yaml.Marshal(in.b.actual) + in: { + a: "actual" + a: "actual" | "other" + b: (a): c: "str" + } + + @test(eq, { + out: """ + c: str + + """ + in: {a: "actual", b: {actual: {c: "str"}}} + }) +} +issue3925: full: { + for name, _ in _inputs { + out: (name): early: "early value" + } + _inputs: input1: { + name: "actual" + config: (name): one: "one value" + } + _inputs: [_]: { + name: "actual" | "other" + } + for name, input in _inputs { + out: (name): lateYAML: yaml.Marshal(input.config[input.name]) + } + + @test(eq, { + out: { + input1: { + early: "early value" + lateYAML: """ + one: one value + + """ + } + } + _inputs: { + input1: { + name: "actual" + config: {actual: {one: "one value"}} + } + } + }) +} +-- out/compile -- +--- builtins.cue +{ + mutualBuiltin: { + t1: { + ok: { + s3: 〈import;strings〉.ContainsAny(〈0;s4〉) + s4: 〈import;strings〉.ContainsAny(〈0;s3〉) + s4: "dd" + } + } + } + mutualBuiltin: { + t2: { + ok: { + s3: 〈import;strings〉.ContainsAny(〈0;s5〉, "dd") + s5: 〈0;s6〉 + s6: "dd" + } + } + } +} +--- chained.cue +{ + issue3925: { + reduced: { + out: 〈import;"encoding/yaml"〉.Marshal(〈0;in〉.b.actual) + in: { + a: "actual" + a: ("actual"|"other") + b: { + 〈1;a〉: { + c: "str" + } + } + } + } + } + issue3925: { + full: { + for name, _ in 〈0;_inputs〉 { + out: { + 〈2;name〉: { + early: "early value" + } + } + } + _inputs: { + input1: { + name: "actual" + config: { + 〈1;name〉: { + one: "one value" + } + } + } + } + _inputs: { + [_]: { + name: ("actual"|"other") + } + } + for name, input in 〈0;_inputs〉 { + out: { + 〈2;name〉: { + lateYAML: 〈import;"encoding/yaml"〉.Marshal(〈3;input〉.config[〈3;input〉.name]) + } + } + } + } + } +} +--- comprehensions.cue +{ + comprehensions: { + t1: { + ok: { + src: [ + "foo", + ] + for _, v in 〈0;src〉 { + "\(〈1;v〉)": 〈1;v〉 + } + } + } + } +} +--- definition.cue +{ + definition: { + t0: { + err: { + #D1: { + env: {} + } + d1: { + env: { + c: "C" + } + } + d1: 〈0;#D1〉 + } + } + } + definition: { + t1: { + err: { + a: 〈0;#A〉 + a: { + c: 1 + } + #A: {} + } + } + } + definition: { + t2: { + ok: { + p1: { + #A: { + ... + { + a: int + } + } + x: (〈0;#A〉 & { + c: int + }) + } + } + } + } + definition: { + t2: { + ok: { + p2: { + #A: { + { + a: int + } + ... + } + x: (〈0;#A〉 & { + c: int + }) + } + } + } + } + definition: { + t2: { + ok: { + p3: { + x: (〈0;#A〉 & { + c: int + }) + #A: { + ... + { + a: int + } + } + } + } + } + } + definition: { + t2: { + ok: { + p4: { + x: (〈0;#A〉 & { + c: int + }) + #A: { + { + a: int + } + ... + } + } + } + } + } +} +--- dynamic.cue +{ + dynamic: { + t1: { + ok: { + [string]: { + name: 〈1;-〉 + } + 〈0;x〉.y: {} + x: { + y: "foo" + } + } + } + } + dynamic: { + t2: { + ok: { + foo: 〈0;#X〉 + #X: { + a: { + b: { + C: 1 + } + } + for _, _ in 〈0;a〉 { + a: { + "b": { + D: 2 + } + } + } + } + } + } + } +} +--- equality.cue +{ + issue3194: { + reduced: { + A: (*0|>10) + A: (*0|>10) + { + out: close({ + b: 〈2;A〉 + }) + out: { + b: 〈2;A〉 + } + }.out + } + } +} +--- expr.cue +{ + expr: { + t1: { + ok: { + a: 〈0;X〉 + X: 5.0 + X: (〈0;Y〉 / 2) + Y: (〈0;a〉 * 2) + } + } + } + expr: { + t2: { + ok: { + A: (〈0;X〉 + 2) + X: 5 + X: (〈0;A〉 - 2) + } + } + } + expr: { + t3: { + ok: { + p1: { + a0: 〈0;X〉 + X: 5.0 + X: (〈0;a0〉 * 1) + } + } + } + } + expr: { + t3: { + ok: { + p2: { + b: (〈0;Y〉 * 1) + Y: (〈0;b〉 * 1) + Y: 5.0 + } + } + } + } + expr: { + t4: { + ok: { + a0: 〈0;X〉 + b0: 〈0;a1〉 + a1: (〈0;a0〉 + 2) + b1: (〈0;b0〉 - 2) + a0: 〈0;X〉 + X: 〈0;b1〉 + X: 5.0 + } + } + } +} +--- in.cue +{ + mutual: { + t0: { + ok: { + c: (〈0;e〉 & { + b: 2 + }) + e: { + a: 1 + } + e: 〈0;c〉 + } + } + } + mutual: { + t1: { + ok: { + a: { + 〈0;b〉 + b: { + b: { + f: 1 + } + } + } + a: 〈0;a〉.b + a: { + b: { + b: { + f: 1 + } + } + } + } + } + } + mutual: { + t2: { + ok: { + x: { + a: { + a: { + f: 1 + } + } + } + x: 〈0;y〉.a + y: { + a: { + a: { + e: 1 + } + } + } + y: 〈0;x〉.a + } + } + } + mutual: { + t3: { + ok: { + d: { + e: { + f: 1 + } + } + 〈0;d〉 + d: { + d: { + e: { + g: 1 + } + } + } + } + } + } + mutual: { + t4: { + ok: { + p0: { + z: 〈0;x〉.b + x: { + b: 〈1;y〉.c + } + x: { + b: { + d: { + b: 2 + } + } + } + y: { + c: 〈1;z〉.d + } + z: { + d: { + a: 1 + } + } + } + p1: { + x: { + b: 〈1;y〉.c + } + z: 〈0;x〉.b + x: { + b: { + d: { + b: 2 + } + } + } + y: { + c: 〈1;z〉.d + } + z: { + d: { + a: 1 + } + } + } + p2: { + x: { + b: 〈1;y〉.c + } + x: { + b: { + d: { + b: 2 + } + } + } + y: { + c: 〈1;z〉.d + } + z: 〈0;x〉.b + z: { + d: { + a: 1 + } + } + } + p3: { + x: { + b: { + d: { + b: 2 + } + } + } + y: { + c: 〈1;z〉.d + } + z: 〈0;x〉.b + x: { + b: 〈1;y〉.c + } + z: { + d: { + a: 1 + } + } + } + p4: { + z: 〈0;x〉.b + x: { + b: { + d: { + b: 2 + } + } + } + y: { + c: 〈1;z〉.d + } + x: { + b: 〈1;y〉.c + } + z: { + d: { + a: 1 + } + } + } + p5: { + x: { + b: { + d: { + b: 2 + } + } + } + y: { + c: 〈1;z〉.d + } + x: { + b: 〈1;y〉.c + } + z: 〈0;x〉.b + z: { + d: { + a: 1 + } + } + } + check: ((((〈0;p1〉 & 〈0;p2〉) & 〈0;p3〉) & 〈0;p4〉) & 〈0;p5〉) + } + } + } +} diff --git a/internal/core/compile/testdata/sync/eval/v0.7errorprop.txtar b/internal/core/compile/testdata/sync/eval/v0.7errorprop.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/eval/v0.7errorprop.txtar @@ -0,0 +1,17 @@ +// NOTE: do not add more tests to this file, as it may obfuscate the test case. +-- in.cue -- +a: #A +a: c: 1 @test(err, code=eval, + contains="field not allowed", + pos=[in.cue:2:4], + hint="more positions may be allowed, see out/todo.txt for details") +#A: {} @test(eq, {}) +-- out/compile -- +--- in.cue +{ + a: 〈0;#A〉 + a: { + c: 1 + } + #A: {} +} diff --git a/internal/core/compile/testdata/sync/export/000.txtar b/internal/core/compile/testdata/sync/export/000.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/000.txtar @@ -0,0 +1,8 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +"hello" +-- out/compile -- +--- in.cue +{ + "hello" +} diff --git a/internal/core/compile/testdata/sync/export/001.txtar b/internal/core/compile/testdata/sync/export/001.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/001.txtar @@ -0,0 +1,8 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +'hello' +-- out/compile -- +--- in.cue +{ + 'hello' +} diff --git a/internal/core/compile/testdata/sync/export/002.txtar b/internal/core/compile/testdata/sync/export/002.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/002.txtar @@ -0,0 +1,8 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +'hello\nworld' +-- out/compile -- +--- in.cue +{ + 'hello\nworld' +} diff --git a/internal/core/compile/testdata/sync/export/003.txtar b/internal/core/compile/testdata/sync/export/003.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/003.txtar @@ -0,0 +1,8 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +"hello\nworld" +-- out/compile -- +--- in.cue +{ + "hello\nworld" +} diff --git a/internal/core/compile/testdata/sync/export/004.txtar b/internal/core/compile/testdata/sync/export/004.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/004.txtar @@ -0,0 +1,18 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + $type: 3 + "_": int + "_foo": int + _bar: int +} +-- out/compile -- +--- in.cue +{ + { + $type: 3 + "_": int + "_foo": int + _bar: int + } +} diff --git a/internal/core/compile/testdata/sync/export/005.txtar b/internal/core/compile/testdata/sync/export/005.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/005.txtar @@ -0,0 +1,15 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: 1, b: a + 2, c: null, d: true, e: _, f: string} +-- out/compile -- +--- in.cue +{ + { + a: 1 + b: (〈0;a〉 + 2) + c: null + d: true + e: _ + f: string + } +} diff --git a/internal/core/compile/testdata/sync/export/006.txtar b/internal/core/compile/testdata/sync/export/006.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/006.txtar @@ -0,0 +1,17 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: {b: 2.0, s: "abc"}, b: a.b, c: a.c, d: a["d"], e: a.t[2:3]} +-- out/compile -- +--- in.cue +{ + { + a: { + b: 2.0 + s: "abc" + } + b: 〈0;a〉.b + c: 〈0;a〉.c + d: 〈0;a〉["d"] + e: 〈0;a〉.t[2:3] + } +} diff --git a/internal/core/compile/testdata/sync/export/007.txtar b/internal/core/compile/testdata/sync/export/007.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/007.txtar @@ -0,0 +1,23 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + #a: {b: 2.0, s: "abc"} + b: #a.b + c: #a.c + d: #a["d"] + e: #a.t[2:3] +} +-- out/compile -- +--- in.cue +{ + { + #a: { + b: 2.0 + s: "abc" + } + b: 〈0;#a〉.b + c: 〈0;#a〉.c + d: 〈0;#a〉["d"] + e: 〈0;#a〉.t[2:3] + } +} diff --git a/internal/core/compile/testdata/sync/export/008.txtar b/internal/core/compile/testdata/sync/export/008.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/008.txtar @@ -0,0 +1,12 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: [ 3 & 4]} +-- out/compile -- +--- in.cue +{ + { + a: [ + (3 & 4), + ] + } +} diff --git a/internal/core/compile/testdata/sync/export/009.txtar b/internal/core/compile/testdata/sync/export/009.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/009.txtar @@ -0,0 +1,38 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +import "list" + +{ + a: list.Repeat([int], 5) + a: [1, 2, ...] + e: [...int] + e: [1, 2, ...] + f: [1, 2, ...] +} +-- out/compile -- +--- in.cue +{ + { + a: 〈import;list〉.Repeat([ + int, + ], 5) + a: [ + 1, + 2, + ..., + ] + e: [ + ...int, + ] + e: [ + 1, + 2, + ..., + ] + f: [ + 1, + 2, + ..., + ] + } +} diff --git a/internal/core/compile/testdata/sync/export/010.txtar b/internal/core/compile/testdata/sync/export/010.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/010.txtar @@ -0,0 +1,39 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +import "list" + +{ + a: list.Repeat([int], 5) + a: [1, 2, ...] + e: [...int] + e: [1, 2, ...] + f: [1, 2, ...] +} +-- out/compile -- +--- in.cue +{ + { + a: 〈import;list〉.Repeat([ + int, + ], 5) + a: [ + 1, + 2, + ..., + ] + e: [ + ...int, + ] + e: [ + 1, + 2, + ..., + ] + f: [ + 1, + 2, + ..., + ] + } +} diff --git a/internal/core/compile/testdata/sync/export/011.txtar b/internal/core/compile/testdata/sync/export/011.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/011.txtar @@ -0,0 +1,15 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: {b: []}, c: a.b, d: a["b"]} +-- out/compile -- +--- in.cue +{ + { + a: { + b: [] + } + c: 〈0;a〉.b + d: 〈0;a〉["b"] + } +} diff --git a/internal/core/compile/testdata/sync/export/012.txtar b/internal/core/compile/testdata/sync/export/012.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/012.txtar @@ -0,0 +1,12 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: *"foo" | *"bar" | *string | int, b: a[2:3]} +-- out/compile -- +--- in.cue +{ + { + a: (*"foo"|*"bar"|*string|int) + b: 〈0;a〉[2:3] + } +} diff --git a/internal/core/compile/testdata/sync/export/013.txtar b/internal/core/compile/testdata/sync/export/013.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/013.txtar @@ -0,0 +1,12 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + a: >=0 & <=10 & !=1 +} +-- out/compile -- +--- in.cue +{ + { + a: ((>=0 & <=10) & !=1) + } +} diff --git a/internal/core/compile/testdata/sync/export/014.txtar b/internal/core/compile/testdata/sync/export/014.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/014.txtar @@ -0,0 +1,13 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + a: >=0 & <=10 & !=1 +} +-- out/compile -- +--- in.cue +{ + { + a: ((>=0 & <=10) & !=1) + } +} diff --git a/internal/core/compile/testdata/sync/export/015.txtar b/internal/core/compile/testdata/sync/export/015.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/015.txtar @@ -0,0 +1,18 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + a: (*1 | 2) & (1 | *2) + b: [(*1 | 2) & (1 | *2)] +} +-- out/compile -- +--- in.cue +{ + { + a: ((*1|2) & (1|*2)) + b: [ + ((*1|2) & (1|*2)), + ] + } +} diff --git a/internal/core/compile/testdata/sync/export/016.txtar b/internal/core/compile/testdata/sync/export/016.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/016.txtar @@ -0,0 +1,38 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + u16: int & >=0 & <=65535 + u32: uint32 + u64: uint64 + u128: uint128 + u8: uint8 + ua: uint16 & >0 + us: >=0 & <10_000 & int + i16: >=-32768 & int & <=32767 + i32: int32 & >0 + i64: int64 + i128: int128 + f64: float64 + fi: float64 & int +} +-- out/compile -- +--- in.cue +{ + { + u16: ((int & >=0) & <=65535) + u32: &(int, >=0, <=4294967295) + u64: &(int, >=0, <=18446744073709551615) + u128: &(int, >=0, <=340282366920938463463374607431768211455) + u8: &(int, >=0, <=255) + ua: (&(int, >=0, <=65535) & >0) + us: ((>=0 & <10000) & int) + i16: ((>=-32768 & int) & <=32767) + i32: (&(int, >=-2147483648, <=2147483647) & >0) + i64: &(int, >=-9223372036854775808, <=9223372036854775807) + i128: &(int, >=-170141183460469231731687303715884105728, <=170141183460469231731687303715884105727) + f64: &(>=-1.797693134862315708145274237317043567981E+308, <=1.797693134862315708145274237317043567981E+308) + fi: (&(>=-1.797693134862315708145274237317043567981E+308, <=1.797693134862315708145274237317043567981E+308) & int) + } +} diff --git a/internal/core/compile/testdata/sync/export/017.txtar b/internal/core/compile/testdata/sync/export/017.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/017.txtar @@ -0,0 +1,19 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: [1, 2], b: {for k, v in a if v > 1 {"\(k)": v}}} +-- out/compile -- +--- in.cue +{ + { + a: [ + 1, + 2, + ] + b: { + for k, v in 〈1;a〉 if (〈0;v〉 > 1) { + "\(〈1;k〉)": 〈1;v〉 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/export/018.txtar b/internal/core/compile/testdata/sync/export/018.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/018.txtar @@ -0,0 +1,19 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: [1, 2], b: [for k, v in a {v}]} +-- out/compile -- +--- in.cue +{ + { + a: [ + 1, + 2, + ] + b: [ + for k, v in 〈1;a〉 { + 〈1;v〉 + }, + ] + } +} diff --git a/internal/core/compile/testdata/sync/export/019.txtar b/internal/core/compile/testdata/sync/export/019.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/019.txtar @@ -0,0 +1,12 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: >=0 & <=10, b: "Count: \(a) times"} +-- out/compile -- +--- in.cue +{ + { + a: (>=0 & <=10) + b: "Count: \(〈0;a〉) times" + } +} diff --git a/internal/core/compile/testdata/sync/export/020.txtar b/internal/core/compile/testdata/sync/export/020.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/020.txtar @@ -0,0 +1,12 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{a: "", b: len(a)} +-- out/compile -- +--- in.cue +{ + { + a: "" + b: len(〈0;a〉) + } +} diff --git a/internal/core/compile/testdata/sync/export/021.txtar b/internal/core/compile/testdata/sync/export/021.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/021.txtar @@ -0,0 +1,30 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + b: { + idx: a[str] + str: string + } + b: a: b: 4 + a: b: 3 +} +-- out/compile -- +--- in.cue +{ + { + b: { + idx: 〈1;a〉[〈0;str〉] + str: string + } + b: { + a: { + b: 4 + } + } + a: { + b: 3 + } + } +} diff --git a/internal/core/compile/testdata/sync/export/022.txtar b/internal/core/compile/testdata/sync/export/022.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/022.txtar @@ -0,0 +1,43 @@ +raw: true +eval: true +noOpt: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + job: [Name=_]: { + name: Name + replicas: uint | *1 @protobuf(10) + command: string + } + + job: list: command: "ls" + + job: nginx: { + command: "nginx" + replicas: 2 + } +} +-- out/compile -- +--- in.cue +{ + { + job: { + [_]: { + name: 〈1;-〉 + replicas: (&(int, >=0)|*1) + command: string + } + } + job: { + list: { + command: "ls" + } + } + job: { + nginx: { + command: "nginx" + replicas: 2 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/export/023.txtar b/internal/core/compile/testdata/sync/export/023.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/023.txtar @@ -0,0 +1,54 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + #emb: { + a: 1 + + sub: { + f: 3 + } + } + #def: { + #emb + + b: 2 + } + #f: a: 10 + #e: { + #f + + b: int + {[_]: <100} + {[_]: <300} + } +} +-- out/compile -- +--- in.cue +{ + { + #emb: { + a: 1 + sub: { + f: 3 + } + } + #def: { + 〈1;#emb〉 + b: 2 + } + #f: { + a: 10 + } + #e: { + 〈1;#f〉 + b: int + { + [_]: <100 + } + { + [_]: <300 + } + } + } +} diff --git a/internal/core/compile/testdata/sync/export/024.txtar b/internal/core/compile/testdata/sync/export/024.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/024.txtar @@ -0,0 +1,41 @@ +raw: true +eval: true +noOpt: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + reg: {foo: 1, bar: {baz: 3}} + #def: { + a: 1 + + sub: reg + } + val: #def + #def2: { + a: {b: int} + } + val2: #def2 +} +-- out/compile -- +--- in.cue +{ + { + reg: { + foo: 1 + bar: { + baz: 3 + } + } + #def: { + a: 1 + sub: 〈1;reg〉 + } + val: 〈0;#def〉 + #def2: { + a: { + b: int + } + } + val2: 〈0;#def2〉 + } +} diff --git a/internal/core/compile/testdata/sync/export/025.txtar b/internal/core/compile/testdata/sync/export/025.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/025.txtar @@ -0,0 +1,32 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + b: [{ + {[X=_]: int} + if a > 4 { + f: 4 + } + }][a] + a: int + c: *1 | 2 +} +-- out/compile -- +--- in.cue +{ + { + b: [ + { + { + [_]: int + } + if (〈2;a〉 > 4) { + f: 4 + } + }, + ][〈0;a〉] + a: int + c: (*1|2) + } +} diff --git a/internal/core/compile/testdata/sync/export/026.txtar b/internal/core/compile/testdata/sync/export/026.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/026.txtar @@ -0,0 +1,21 @@ +raw: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + if false { + {a: 1} | {b: 1} + } +} +-- out/compile -- +--- in.cue +{ + { + if false { + ({ + a: 1 + }|{ + b: 1 + }) + } + } +} diff --git a/internal/core/compile/testdata/sync/export/027.txtar b/internal/core/compile/testdata/sync/export/027.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/027.txtar @@ -0,0 +1,22 @@ + +TODO: Should #Bar result in string or #Foo | string? + + +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + #Foo: { + #Bar: #Foo | string + } +} +-- out/compile -- +--- in.cue +{ + { + #Foo: { + #Bar: (〈1;#Foo〉|string) + } + } +} diff --git a/internal/core/compile/testdata/sync/export/028.txtar b/internal/core/compile/testdata/sync/export/028.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/028.txtar @@ -0,0 +1,26 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + #FindInMap: { + #: "Fn::FindInMap": [string | #FindInMap] + } + a: [...string] +} +-- out/compile -- +--- in.cue +{ + { + #FindInMap: { + #: { + "Fn::FindInMap": [ + (string|〈3;#FindInMap〉), + ] + } + } + a: [ + ...string, + ] + } +} diff --git a/internal/core/compile/testdata/sync/export/029.txtar b/internal/core/compile/testdata/sync/export/029.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/029.txtar @@ -0,0 +1,33 @@ +raw: true +eval: true +noOpt: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + #And: { + #: "Fn::And": [...(3 | #And)] + } + #Ands: #And & { + #: "Fn::And": [_] + } +} +-- out/compile -- +--- in.cue +{ + { + #And: { + #: { + "Fn::And": [ + ...(3|〈3;#And〉), + ] + } + } + #Ands: (〈0;#And〉 & { + #: { + "Fn::And": [ + _, + ] + } + }) + } +} diff --git a/internal/core/compile/testdata/sync/export/030.txtar b/internal/core/compile/testdata/sync/export/030.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/030.txtar @@ -0,0 +1,38 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + #Foo: { + sgl: #Bar + ref: null | #Foo + ext: #Bar | null + ref: null | #Foo + ref2: null | #Foo.sgl + ... + } + #Foo: { + "#Foo": 2 + ... + } + #Bar: string +} +-- out/compile -- +--- in.cue +{ + { + #Foo: { + sgl: 〈1;#Bar〉 + ref: (null|〈1;#Foo〉) + ext: (〈1;#Bar〉|null) + ref: (null|〈1;#Foo〉) + ref2: (null|〈1;#Foo〉.sgl) + ... + } + #Foo: { + "#Foo": 2 + ... + } + #Bar: string + } +} diff --git a/internal/core/compile/testdata/sync/export/031.txtar b/internal/core/compile/testdata/sync/export/031.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/031.txtar @@ -0,0 +1,22 @@ +raw: true +eval: true +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + A: [uint] + B: A & ([10] | [192]) +} +-- out/compile -- +--- in.cue +{ + { + A: [ + &(int, >=0), + ] + B: (〈0;A〉 & ([ + 10, + ]|[ + 192, + ])) + } +} diff --git a/internal/core/compile/testdata/sync/export/032.txtar b/internal/core/compile/testdata/sync/export/032.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/032.txtar @@ -0,0 +1,14 @@ +#inlinetest:exclude skip — tests export format, not evaluator semantics +-- in.cue -- +{ + [string]: _ + foo: 3 +} +-- out/compile -- +--- in.cue +{ + { + [string]: _ + foo: 3 + } +} diff --git a/internal/core/compile/testdata/sync/export/issue2119.txtar b/internal/core/compile/testdata/sync/export/issue2119.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/issue2119.txtar @@ -0,0 +1,92 @@ +-- in.cue -- +import ( + "encoding/yaml" + "regexp" +) + +simplified: { + x: d: R={ + ".*" + [R+""][0] + } + out: yaml.Marshal(x) + @test(eq, {x: {d: ".*"}, out: "d: .*\n"}) +} + +original: { + #testableRegexp: R={ + string + + #test: close({ + in: string + out: regexp.FindSubmatch("^"+R+"$", in)[1] + }) + } + + rule: { + #patterns: { + bar: #testableRegexp & { + "(.*)" + #test: {in: "testcontent", out: "testcontent"} + } + } + } + out: yaml.Marshal(rule) + @test(eq, { + #testableRegexp: { + string + #test: { + in: string + out: _|_ @test(err, code=incomplete, contains="original.#testableRegexp.#test.out: non-concrete value string in operand to +", pos=[21:29, 16:21, 17:3]) + } + } + rule: { + #patterns: { + bar: { + "(.*)" + #test: {in: "testcontent", out: "testcontent"} + } + } + } + out: """ + {} + + """ + }) +} +-- out/compile -- +--- in.cue +{ + simplified: { + x: { + d: { + ".*" + [ + (〈2〉 + ""), + ][0] + } + } + out: 〈import;"encoding/yaml"〉.Marshal(〈0;x〉) + } + original: { + #testableRegexp: { + string + #test: close({ + in: string + out: 〈import;regexp〉.FindSubmatch((("^" + 〈2〉) + "$"), 〈0;in〉)[1] + }) + } + rule: { + #patterns: { + bar: (〈2;#testableRegexp〉 & { + "(.*)" + #test: { + in: "testcontent" + out: "testcontent" + } + }) + } + } + out: 〈import;"encoding/yaml"〉.Marshal(〈0;rule〉) + } +} diff --git a/internal/core/compile/testdata/sync/export/issue2244.txtar b/internal/core/compile/testdata/sync/export/issue2244.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/issue2244.txtar @@ -0,0 +1,71 @@ +-- in.cue -- +package x + +import ( + "strings" +) + +_#matchPattern: { + #pattern: string + [ + // can't remove this builtin call + if strings.HasSuffix(#pattern, "*") { + + // this let is required _within_ the if block + // i.e. it can't be "inlined" with the if that + // currently contains it + let prefix = strings.TrimSuffix(#pattern, "*") + + prefix + }, + "'\(#pattern)'", + ][0] +} + +_#isReleaseTag: _#matchPattern & {#pattern: "refs/tags/v*", _} + +#step: { + if: number | string +} + +m: #step & { + if: _#isReleaseTag +} +@test(eq, { + _#matchPattern$x: {_|_, #pattern: string} + _#isReleaseTag$x: { + "refs/tags/v" + #pattern: "refs/tags/v*" + } + #step: {if: number | string} + m: { + if: { + "refs/tags/v" + #pattern: "refs/tags/v*" + } + } +}) +-- out/compile -- +--- in.cue +{ + _#matchPattern(:x): { + #pattern: string + [ + if 〈import;strings〉.HasSuffix(〈1;#pattern〉, "*") { + let prefix#1 = 〈import;strings〉.TrimSuffix(〈2;#pattern〉, "*") + 〈0;let prefix#1〉 + }, + "'\(〈1;#pattern〉)'", + ][0] + } + _#isReleaseTag(:x): (〈0;_#matchPattern(:x)〉 & { + #pattern: "refs/tags/v*" + _ + }) + #step: { + if: (number|string) + } + m: (〈0;#step〉 & { + if: 〈1;_#isReleaseTag(:x)〉 + }) +} diff --git a/internal/core/compile/testdata/sync/export/issue854.txtar b/internal/core/compile/testdata/sync/export/issue854.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/export/issue854.txtar @@ -0,0 +1,26 @@ +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- a.cue -- +package a + +import "mod.test/b" + +theb: b.name @test(err, code=incomplete, path=b, contains="undefined field: %s", args=[c], pos=[b/b.cue:5:6]) +-- b/b.cue -- +package b + +import "mod.test/c" + +b: c.c & { + other: "name" +} + +name: b.other +-- c/c.cue -- +package c +-- out/compile -- +--- a.cue +{ + theb: 〈import;"mod.test/b"〉.name +} diff --git a/internal/core/compile/testdata/sync/fulleval/000_detect_conflicting_value.txtar b/internal/core/compile/testdata/sync/fulleval/000_detect_conflicting_value.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/000_detect_conflicting_value.txtar @@ -0,0 +1,13 @@ +# Tests that a float value conflicting with a disjunction of an int value and int type +# reports an empty disjunction error. Issue: regression test for early evaluator behavior. +-- in.cue -- +a: 8000.9 +a: 7080 | int @test(err, code=eval, + suberr=(code=eval, contains="conflicting values", args=[8000.9, 7080], pos=[in.cue:1:4, in.cue:2:4]), + suberr=(code=eval, contains="conflicting values", args=[8000.9, int], pos=[in.cue:1:4, in.cue:2:11])) +-- out/compile -- +--- in.cue +{ + a: 8000.9 + a: (7080|int) +} diff --git a/internal/core/compile/testdata/sync/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar b/internal/core/compile/testdata/sync/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/001_conflicts_in_optional_fields_are_okay_.txtar @@ -0,0 +1,25 @@ +#name: conflicts in optional fields are okay +#evalFull +-- in.cue -- +d: {a: 1, b?: 3} | {a: 2} @test(eq, {a: 1, b?: 3} | {a: 2}) + +// the following conjunction should not eliminate any disjuncts +c: d & {b?: 4} @test(eq, { + b?: _|_ @test(err, code=eval, contains="conflicting values", args=[3, 4], pos=[1:15, 4:4, 4:13]) + a: 1 +} | { + b?: 4, a: 2 +}) +-- out/compile -- +--- in.cue +{ + d: ({ + a: 1 + b?: 3 + }|{ + a: 2 + }) + c: (〈0;d〉 & { + b?: 4 + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/002_resolve_all_disjunctions.txtar b/internal/core/compile/testdata/sync/fulleval/002_resolve_all_disjunctions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/002_resolve_all_disjunctions.txtar @@ -0,0 +1,40 @@ +-- in.cue -- +service: [Name=string]: { + name: string | *Name + port: int | *7080 +} +service: foo: _ @test(eq, { + name: *"foo" | string + port: *7080 | int +}) +service: bar: {port: 8000} @test(eq, { + port: 8000 + name: *"bar" | string +}) +service: baz: {name: "foobar"} @test(eq, { + name: "foobar" + port: *7080 | int +}) +-- out/compile -- +--- in.cue +{ + service: { + [string]: { + name: (string|*〈1;-〉) + port: (int|*7080) + } + } + service: { + foo: _ + } + service: { + bar: { + port: 8000 + } + } + service: { + baz: { + name: "foobar" + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/003_field_templates.txtar b/internal/core/compile/testdata/sync/fulleval/003_field_templates.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/003_field_templates.txtar @@ -0,0 +1,52 @@ +-- in.cue -- +a: { + {[name=_]: int} + k: 1 + @test(eq, {k: 1}) +} +b: { + {[X=_]: {x: 0, y: *1 | int}} + v: {} @test(eq, {x: 0, y: *1 | int}) + w: {y: 0} @test(eq, {y: 0, x: 0}) +} +b: {[y=_]: {}} // TODO: allow different name +c: { + {[Name=_]: {name: Name, y: 1}} + foo: {} @test(eq, {name: "foo", y: 1}) + bar: _ @test(eq, {name: "bar", y: 1}) +} +-- out/compile -- +--- in.cue +{ + a: { + { + [_]: int + } + k: 1 + } + b: { + { + [_]: { + x: 0 + y: (*1|int) + } + } + v: {} + w: { + y: 0 + } + } + b: { + [_]: {} + } + c: { + { + [_]: { + name: 〈1;-〉 + y: 1 + } + } + foo: {} + bar: _ + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/004_field_comprehension.txtar b/internal/core/compile/testdata/sync/fulleval/004_field_comprehension.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/004_field_comprehension.txtar @@ -0,0 +1,43 @@ +-- in.cue -- +a: { + for k, v in b + if k < "d" + if v > b.a { + "\(k)": v + } + @test(eq, {b: 2, c: 3}) +} +b: { + a: 1 + b: 2 + c: 3 + d: 4 +} +c: { + for k, v in b + if k < "d" + if v > b.a { + "\(k)": v + } + @test(eq, {b: 2, c: 3}) +} +-- out/compile -- +--- in.cue +{ + a: { + for k, v in 〈1;b〉 if (〈0;k〉 < "d") if (〈0;v〉 > 〈2;b〉.a) { + "\(〈1;k〉)": 〈1;v〉 + } + } + b: { + a: 1 + b: 2 + c: 3 + d: 4 + } + c: { + for k, v in 〈1;b〉 if (〈0;k〉 < "d") if (〈0;v〉 > 〈2;b〉.a) { + "\(〈1;k〉)": 〈1;v〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/005_conditional_field.txtar b/internal/core/compile/testdata/sync/fulleval/005_conditional_field.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/005_conditional_field.txtar @@ -0,0 +1,47 @@ +-- in.cue -- +a: { + @test(eq, { + b: true + a: "foo" + }) + if b { + a: "foo" + } + b: true +} +c: { + a: 3 + if a > 1 { + a: 3 + } + @test(eq, { a: 3 }) +} +d: { + a: int + if a > 1 { + a: 3 + } + @test(err, code=(cycle|incomplete)) +} +-- out/compile -- +--- in.cue +{ + a: { + if 〈0;b〉 { + a: "foo" + } + b: true + } + c: { + a: 3 + if (〈0;a〉 > 1) { + a: 3 + } + } + d: { + a: int + if (〈0;a〉 > 1) { + a: 3 + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/006_referencing_field_in_field_comprehension.txtar b/internal/core/compile/testdata/sync/fulleval/006_referencing_field_in_field_comprehension.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/006_referencing_field_in_field_comprehension.txtar @@ -0,0 +1,26 @@ +-- in.cue -- +a: {b: c: 4} +a: { + @test(eq, {b: {c: 4, d: 5}, c: 4, d: 5}) + b: d: 5 + for k, v in b { + "\(k)": v + } +} +-- out/compile -- +--- in.cue +{ + a: { + b: { + c: 4 + } + } + a: { + b: { + d: 5 + } + for k, v in 〈0;b〉 { + "\(〈1;k〉)": 〈1;v〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/007_different_labels_for_templates.txtar b/internal/core/compile/testdata/sync/fulleval/007_different_labels_for_templates.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/007_different_labels_for_templates.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +a: [X=string]: {name: X} +a: [Name=string]: {name: Name} +a: foo: {} @test(eq, {name: "foo"}) +-- out/compile -- +--- in.cue +{ + a: { + [string]: { + name: 〈1;-〉 + } + } + a: { + [string]: { + name: 〈1;-〉 + } + } + a: { + foo: {} + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/008_nested_templates_in_one_field.txtar b/internal/core/compile/testdata/sync/fulleval/008_nested_templates_in_one_field.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/008_nested_templates_in_one_field.txtar @@ -0,0 +1,49 @@ +-- in.cue -- +a: [A=string]: b: [B=string]: { + name: A + kind: B +} +a: "A": b: "B": _ @test(eq, {name: "A", kind: "B"}) +a: "C": b: "D": _ @test(eq, {name: "C", kind: "D"}) +a: "EE": b: "FF": {c: "bar"} @test(eq, { + c: "bar" + name: "EE" + kind: "FF" +}) +-- out/compile -- +--- in.cue +{ + a: { + [string]: { + b: { + [string]: { + name: 〈3;-〉 + kind: 〈1;-〉 + } + } + } + } + a: { + A: { + b: { + B: _ + } + } + } + a: { + C: { + b: { + D: _ + } + } + } + a: { + EE: { + b: { + FF: { + c: "bar" + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/009_template_unification_within_one_struct.txtar b/internal/core/compile/testdata/sync/fulleval/009_template_unification_within_one_struct.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/009_template_unification_within_one_struct.txtar @@ -0,0 +1,41 @@ +-- in.cue -- +a: { + {[A=string]: {name: A}} + + // TODO: allow duplicate alias here + {[X=string]: {kind: X}} +} +a: "A": _ @test(eq, {name: "A", kind: "A"}) +a: "C": _ @test(eq, {name: "C", kind: "C"}) +a: "E": {c: "bar"} @test(eq, { + c: "bar" + name: "E" + kind: "E" +}) +-- out/compile -- +--- in.cue +{ + a: { + { + [string]: { + name: 〈1;-〉 + } + } + { + [string]: { + kind: 〈1;-〉 + } + } + } + a: { + A: _ + } + a: { + C: _ + } + a: { + E: { + c: "bar" + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/010_field_comprehensions_with_multiple_keys.txtar b/internal/core/compile/testdata/sync/fulleval/010_field_comprehensions_with_multiple_keys.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/010_field_comprehensions_with_multiple_keys.txtar @@ -0,0 +1,72 @@ +-- in.cue -- + +for x in [ + {a: "A", b: "B"}, + {a: "C", b: "D"}, + {a: "E", b: "F"}, +] { + a: "\(x.a)": b: "\(x.b)": x +} + +for x in [ + {a: "A", b: "B"}, + {a: "C", b: "D"}, + {a: "E", b: "F"}, +] { + "\(x.a)": "\(x.b)": x +} + +@test(eq, { + a: { + A: b: B: {a: "A", b: "B"} + C: b: D: {a: "C", b: "D"} + E: b: F: {a: "E", b: "F"} + } + A: B: {a: "A", b: "B"} + C: D: {a: "C", b: "D"} + E: F: {a: "E", b: "F"} +}) +-- out/compile -- +--- in.cue +{ + for _, x in [ + { + a: "A" + b: "B" + }, + { + a: "C" + b: "D" + }, + { + a: "E" + b: "F" + }, + ] { + a: { + "\(〈2;x〉.a)": { + b: { + "\(〈4;x〉.b)": 〈4;x〉 + } + } + } + } + for _, x in [ + { + a: "A" + b: "B" + }, + { + a: "C" + b: "D" + }, + { + a: "E" + b: "F" + }, + ] { + "\(〈1;x〉.a)": { + "\(〈2;x〉.b)": 〈2;x〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/011_field_comprehensions_with_templates.txtar b/internal/core/compile/testdata/sync/fulleval/011_field_comprehensions_with_templates.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/011_field_comprehensions_with_templates.txtar @@ -0,0 +1,39 @@ +-- in.cue -- +num: 1 +a: { + if num < 5 { + [A=string]: [B=string]: { + name: A + kind: B + } + } +} @test(eq, { + b: c: { + d: "bar" + name: "b" + kind: "c" + } +}) +a: b: c: d: "bar" +-- out/compile -- +--- in.cue +{ + num: 1 + a: { + if (〈1;num〉 < 5) { + [string]: { + [string]: { + name: 〈2;-〉 + kind: 〈1;-〉 + } + } + } + } + a: { + b: { + c: { + d: "bar" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/012_disjunctions_of_lists.txtar b/internal/core/compile/testdata/sync/fulleval/012_disjunctions_of_lists.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/012_disjunctions_of_lists.txtar @@ -0,0 +1,24 @@ +-- in.cue -- +l: *[int, int] | [string, string] + +t1: { + l & ["c", "d"] + @test(eq, ["c", "d"]) +} +-- out/compile -- +--- in.cue +{ + l: (*[ + int, + int, + ]|[ + string, + string, + ]) + t1: { + (〈1;l〉 & [ + "c", + "d", + ]) + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/013_normalization.txtar b/internal/core/compile/testdata/sync/fulleval/013_normalization.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/013_normalization.txtar @@ -0,0 +1,15 @@ +TODO: the new evaluator currently does not normalize disjuncts. +It needs to be determined under which circumstances is desirable. +The redundancy that remains from not normalizing can be useful. + +-- in.cue -- +a: string | string @test(eq, string) +b: *1 | *int @test(eq, *1 | *int) +c: *1.0 | *float @test(eq, *1.0 | *float) +-- out/compile -- +--- in.cue +{ + a: (string|string) + b: (*1|*int) + c: (*1.0|*float) +} diff --git a/internal/core/compile/testdata/sync/fulleval/014_default_disambiguation_and_elimination.txtar b/internal/core/compile/testdata/sync/fulleval/014_default_disambiguation_and_elimination.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/014_default_disambiguation_and_elimination.txtar @@ -0,0 +1,23 @@ +-- in.cue -- +a: *1 | int @test(eq, *1 | int) +b: *3 | int @test(eq, *3 | int) +e: *1 | *1 @test(eq, 1) + +c: a & b @test(eq, 1 | 3 | int) + +d: { + b & a + @test(eq, 1 | 3 | int) +} + +-- out/compile -- +--- in.cue +{ + a: (*1|int) + b: (*3|int) + e: (*1|*1) + c: (〈0;a〉 & 〈0;b〉) + d: { + (〈1;b〉 & 〈1;a〉) + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/016_struct_comprehension_with_template.txtar b/internal/core/compile/testdata/sync/fulleval/016_struct_comprehension_with_template.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/016_struct_comprehension_with_template.txtar @@ -0,0 +1,64 @@ +-- in.cue -- +result: [for _, v in service {v}] @test(eq, [{ + name: *"foo" | string + type: "service" + port: *7080 | int +}, { + port: 8000 + name: *"bar" | string + type: "service" +}, { + name: "foobar" + type: "service" + port: *7080 | int +}]) + +service: [Name=string]: { + name: *Name | string + type: "service" + port: *7080 | int +} +service: foo: {} @test(eq, { + name: *"foo" | string + type: "service" + port: *7080 | int +}) +service: bar: {port: 8000} @test(eq, { + port: 8000 + name: *"bar" | string + type: "service" +}) +service: baz: {name: "foobar"} @test(eq, { + name: "foobar" + type: "service" + port: *7080 | int +}) +-- out/compile -- +--- in.cue +{ + result: [ + for _, v in 〈1;service〉 { + 〈1;v〉 + }, + ] + service: { + [string]: { + name: (*〈1;-〉|string) + type: "service" + port: (*7080|int) + } + } + service: { + foo: {} + } + service: { + bar: { + port: 8000 + } + } + service: { + baz: { + name: "foobar" + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/017_resolutions_in_struct_comprehension_keys.txtar b/internal/core/compile/testdata/sync/fulleval/017_resolutions_in_struct_comprehension_keys.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/017_resolutions_in_struct_comprehension_keys.txtar @@ -0,0 +1,13 @@ +-- in.cue -- +a: {for _, b in ["c"] {"\(b+".")": "a"}} @test(eq, {"c.": "a"}) +-- out/compile -- +--- in.cue +{ + a: { + for _, b in [ + "c", + ] { + "\((〈1;b〉 + "."))": "a" + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/018_recursive_evaluation_within_list.txtar b/internal/core/compile/testdata/sync/fulleval/018_recursive_evaluation_within_list.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/018_recursive_evaluation_within_list.txtar @@ -0,0 +1,39 @@ +#name: recursive evaluation within list +#evalFull +-- in.cue -- +l: [a] @test(eq, [{c: "t", d: "t"}]) @test(shareID=L, at=0) +a: b & {c: "t"} @test(eq, {c: "t", d: "t"}) @test(shareID=L) +b: { + d: c + c: string +} @test(eq, {d: string, c: string}) +l1: [a1] @test(eq, [{c: "t", d: "st"}]) @test(shareID=L1, at=0) +a1: b1 & {c: "t"} @test(eq, {c: "t", d: "st"}) @test(shareID=L1) +b1: { + d: "s" + c @test(err, code=incomplete) + c: string +} +-- out/compile -- +--- in.cue +{ + l: [ + 〈1;a〉, + ] + a: (〈0;b〉 & { + c: "t" + }) + b: { + d: 〈0;c〉 + c: string + } + l1: [ + 〈1;a1〉, + ] + a1: (〈0;b1〉 & { + c: "t" + }) + b1: { + d: ("s" + 〈0;c〉) + c: string + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/020_complex_interaction_of_groundness.txtar b/internal/core/compile/testdata/sync/fulleval/020_complex_interaction_of_groundness.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/020_complex_interaction_of_groundness.txtar @@ -0,0 +1,44 @@ +-- in.cue -- +res: [for x in a for y in x {y & {d: "b"}}] +res: [ a.b.c & {d: "b"}] + +a: b: [C=string]: {d: string, s: "a" + d} +a: b: c: d: string +@test(eq, { + res: [ {d: "b", s: "ab"} ] + a: b: c: { + d: string + s: _|_ @test(err, code=incomplete, pos=[4:34, 4:23, 5:13]) + } +}) +-- out/compile -- +--- in.cue +{ + res: [ + for _, x in 〈1;a〉 for _, y in 〈0;x〉 { + (〈1;y〉 & { + d: "b" + }) + }, + ] + res: [ + (〈1;a〉.b.c & { + d: "b" + }), + ] + a: { + b: { + [string]: { + d: string + s: ("a" + 〈0;d〉) + } + } + } + a: { + b: { + c: { + d: string + } + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/021_complex_groundness_2.txtar b/internal/core/compile/testdata/sync/fulleval/021_complex_groundness_2.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/021_complex_groundness_2.txtar @@ -0,0 +1,60 @@ +#name: complex groundness 2 +#evalFull +-- in.cue -- +r1: f1 & {y: "c"} @test(eq, { + y: "c" + res: {d: "c", s: "ac"} +}) + +f1: {y: string, res: a.b.c & {d: y}} @test(eq, { + y: string + res: { + d: string + s: _|_ @test(err, code=incomplete, + pos=[15:25, 6:34, 15:14, 20:23, 21:13]) + } +}) + +a: b: c: {d: string, s: "a" + d} @test(eq, { + d: string + s: _|_ @test(err, code=incomplete, + pos=[15:25, 15:14, 20:23, 21:13]) +}) +a: b: [C=string]: {d: string, s: "a" + d} +a: b: c: d: string +-- out/compile -- +--- in.cue +{ + r1: (〈0;f1〉 & { + y: "c" + }) + f1: { + y: string + res: (〈1;a〉.b.c & { + d: 〈1;y〉 + }) + } + a: { + b: { + c: { + d: string + s: ("a" + 〈0;d〉) + } + } + } + a: { + b: { + [string]: { + d: string + s: ("a" + 〈0;d〉) + } + } + } + a: { + b: { + c: { + d: string + } + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/022_references_from_template_to_concrete.txtar b/internal/core/compile/testdata/sync/fulleval/022_references_from_template_to_concrete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/022_references_from_template_to_concrete.txtar @@ -0,0 +1,32 @@ +-- in.cue -- +// res is a list containing t; res[0] shares t's vertex. +res: [t] @test(eq, [{x: {a: "XDDDD", b: str: "DDDD", c: "X"}}]) @test(shareID=T, at=0) +t: { + [X=string]: { + a: c + b.str + b: str: string + c: "X" + } + x: {b: str: "DDDD"} @test(eq, {a: "XDDDD", b: str: "DDDD", c: "X"}) +} @test(shareID=T) +-- out/compile -- +--- in.cue +{ + res: [ + 〈1;t〉, + ] + t: { + [string]: { + a: (〈0;c〉 + 〈0;b〉.str) + b: { + str: string + } + c: "X" + } + x: { + b: { + str: "DDDD" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/024_Issue_#23.txtar b/internal/core/compile/testdata/sync/fulleval/024_Issue_#23.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/024_Issue_#23.txtar @@ -0,0 +1,19 @@ +# Tests that unifying a struct with a disjunction where neither branch matches reports +# an empty disjunction error. Issue #23. +-- in.cue -- +x: {a: 1} | {a: 2} +y: x & {a: 3} @test(err, code=eval, + suberr=(code=eval, contains="conflicting values", args=[1, 3], pos=[in.cue:1:8, in.cue:2:4, in.cue:2:12]), + suberr=(code=eval, contains="conflicting values", args=[2, 3], pos=[in.cue:1:17, in.cue:2:4, in.cue:2:12])) +-- out/compile -- +--- in.cue +{ + x: ({ + a: 1 + }|{ + a: 2 + }) + y: (〈0;x〉 & { + a: 3 + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar b/internal/core/compile/testdata/sync/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar @@ -0,0 +1,46 @@ +#name: dont convert incomplete errors to non-incomplete +#evalFull +-- in.cue -- +import "strings" + +n1: {min: min} @test(eq, { + min: _|_ @test(err, code=cycle, contains="n1.max: cycle with field: min (and 1 more errors)", pos=[3:23]) + max: _|_ @test(err, code=cycle, contains="n1.max: cycle with field: min (and 1 more errors)", pos=[3:23]) +}) +n2: -num @test(err, code=incomplete, contains="operand num of '-' not concrete", pos=[0:6]) +n3: +num @test(err, code=incomplete, contains="operand num of '+' not concrete", pos=[0:6]) +n4: num + num @test(err, code=incomplete, contains="non-concrete value <4 in operand to +", pos=[0:5, 12:6]) +n5: num - num @test(err, code=incomplete, contains="non-concrete value <4 in operand to -", pos=[0:5, 11:6]) +n6: num * num @test(err, code=incomplete, contains="non-concrete value <4 in operand to *", pos=[0:5, 10:6]) +n7: num / num @test(err, code=incomplete, contains="non-concrete value <4 in operand to /", pos=[0:5, 9:6]) + +b1: !is @test(err, code=incomplete, contains="operand is of '!' not concrete", pos=[0:6]) + +s1: "\(str)" @test(err, code=incomplete, contains="non-concrete value string", pos=[0:5, 4:6]) +s2: strings.ContainsAny("dd") @test(kind=string) +s3: strings.ContainsAny(str, "dd") @test(err, code=incomplete, contains="non-concrete value string", pos=[0:5, 2:6]) + +str: string @test(eq, string) +num: <4 @test(eq, <4) +is: bool @test(eq, bool) +-- out/compile -- +--- in.cue +{ + n1: { + min: <〈0;max〉 + max: >〈0;min〉 + } + n2: -〈0;num〉 + n3: +〈0;num〉 + n4: (〈0;num〉 + 〈0;num〉) + n5: (〈0;num〉 - 〈0;num〉) + n6: (〈0;num〉 * 〈0;num〉) + n7: (〈0;num〉 / 〈0;num〉) + b1: !〈0;is〉 + s1: "\(〈0;str〉)" + s2: 〈import;strings〉.ContainsAny("dd") + s3: 〈import;strings〉.ContainsAny(〈0;str〉, "dd") + str: string + num: <4 + is: bool +} diff --git a/internal/core/compile/testdata/sync/fulleval/027_len_of_incomplete_types.txtar b/internal/core/compile/testdata/sync/fulleval/027_len_of_incomplete_types.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/027_len_of_incomplete_types.txtar @@ -0,0 +1,47 @@ +-- in.cue -- +args: *[] | [...string] +v1: len(args) @test(eq, 0) +v2: len([]) @test(eq, 0) +v3: len({}) @test(eq, 0) +v4: len({a: 3}) @test(eq, 1) +v5: len({a: 3} | {a: 4}) @test(err, code=incomplete, contains="unresolved disjunction", pos=[0:7]) +v6: len('sf' | 'dd') @test(err, code=incomplete, contains="unresolved disjunction", pos=[0:7]) +v7: len([2] | *[1, 2]) @test(eq, 2) +v8: len([2] | [1, 2]) @test(err, code=incomplete, contains="unresolved disjunction", pos=[0:7]) +v9: len("😂") @test(eq, 4, + hint="len of strings should be deprecated and this should be an error in the future") +v10: len("") @test(eq, 0, + hint="len of strings should be deprecated and this should be an error in the future") +-- out/compile -- +--- in.cue +{ + args: (*[]|[ + ...string, + ]) + v1: len(〈0;args〉) + v2: len([]) + v3: len({}) + v4: len({ + a: 3 + }) + v5: len(({ + a: 3 + }|{ + a: 4 + })) + v6: len(('sf'|'dd')) + v7: len(([ + 2, + ]|*[ + 1, + 2, + ])) + v8: len(([ + 2, + ]|[ + 1, + 2, + ])) + v9: len("😂") + v10: len("") +} diff --git a/internal/core/compile/testdata/sync/fulleval/028_slice_rewrite_bug.txtar b/internal/core/compile/testdata/sync/fulleval/028_slice_rewrite_bug.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/028_slice_rewrite_bug.txtar @@ -0,0 +1,37 @@ +-- in.cue -- +t1: { + fn: { + arg: [...int] & [1] + out: arg[1:] + } + fn1: fn & {arg: [1]} + @test(eq, { + fn: { + arg: [1] + out: [] + } + fn1: { + arg: [1] + out: [] + } + }) +} +-- out/compile -- +--- in.cue +{ + t1: { + fn: { + arg: ([ + ...int, + ] & [ + 1, + ]) + out: 〈0;arg〉[1:] + } + fn1: (〈0;fn〉 & { + arg: [ + 1, + ] + }) + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/029_Issue_#94.txtar b/internal/core/compile/testdata/sync/fulleval/029_Issue_#94.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/029_Issue_#94.txtar @@ -0,0 +1,57 @@ +# Tests field visibility and comprehension iteration: comprehensions only iterate +# regular (non-optional, non-hidden, non-definition) fields; select and index access +# have different rules for optional, hidden, and definition fields. Issue #94. +-- in.cue -- +foo: { + opt?: 1 + "txt": 2 + #def: 3 + regular: 4 + _hidden: 5 + @test(eq, {opt?: 1, txt: 2, #def: 3, regular: 4, _hidden: 5}) +} +comp: { for k, v in foo {"\(k)": v} } @test(eq, {txt: 2, regular: 4}) +select: { + opt: foo.opt @test(err, code=incomplete, contains="cannot reference optional field", pos=[0:15]) + "txt": foo.txt @test(eq, 2) + #def: foo.#def @test(eq, 3) + regular: foo.regular @test(eq, 4) + _hidden: foo._hidden @test(eq, 5) +} +index: { + opt: foo["opt"] @test(err, code=incomplete, contains="cannot reference optional field", pos=[0:15]) + "txt": foo["txt"] @test(eq, 2) + #def: foo["#def"] @test(err, code=incomplete, contains="undefined field", pos=[0:15]) + regular: foo["regular"] @test(eq, 4) + _hidden: foo["_hidden"] @test(err, code=incomplete, contains="undefined field", pos=[0:15]) +} +-- out/compile -- +--- in.cue +{ + foo: { + opt?: 1 + txt: 2 + #def: 3 + regular: 4 + _hidden: 5 + } + comp: { + for k, v in 〈1;foo〉 { + "\(〈1;k〉)": 〈1;v〉 + } + } + select: { + opt: 〈1;foo〉.opt + txt: 〈1;foo〉.txt + #def: 〈1;foo〉.#def + regular: 〈1;foo〉.regular + _hidden: 〈1;foo〉._hidden + } + index: { + opt: 〈1;foo〉["opt"] + txt: 〈1;foo〉["txt"] + #def: 〈1;foo〉["#def"] + regular: 〈1;foo〉["regular"] + _hidden: 〈1;foo〉["_hidden"] + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/030_retain_references_with_interleaved_embedding.txtar b/internal/core/compile/testdata/sync/fulleval/030_retain_references_with_interleaved_embedding.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/030_retain_references_with_interleaved_embedding.txtar @@ -0,0 +1,44 @@ +#name: retain references with interleaved embedding +#evalFull +-- in.cue -- +a: d: { + #base + #info: {...} + Y: #info.X +} @test(eq, { + #info: {X: "foo"} + Y: "foo" +}) @test(closed) + +#base: { + #info: {...} @test(closed) +} @test(eq, { #info: {} }) + +a: [Name=string]: {#info: { + X: "foo" +}} +-- out/compile -- +--- in.cue +{ + a: { + d: { + 〈2;#base〉 + #info: { + ... + } + Y: 〈0;#info〉.X + } + } + #base: { + #info: { + ... + } + } + a: { + [string]: { + #info: { + X: "foo" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/031_comparison_against_bottom.txtar b/internal/core/compile/testdata/sync/fulleval/031_comparison_against_bottom.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/031_comparison_against_bottom.txtar @@ -0,0 +1,43 @@ +-- in.cue -- +a: _|_ == _|_ @test(eq, true) +b: err == 1 & 2 @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[in.cue:12:6, in.cue:12:10]) // not a literal error, so not allowed +c: err == _|_ @test(eq, true) // allowed +d: err != _|_ @test(eq, false) // allowed +e: err != 1 & 3 @test(err, code=eval, contains="conflicting values", args=[2, 1], pos=[in.cue:12:6, in.cue:12:10]) +// z: err == err // TODO: should infer to be true? +f: ({a: 1} & {a: 2}) == _|_ @test(eq, true) +g: ({a: 1} & {b: 2}) == _|_ @test(eq, false) +h: _|_ == ({a: 1} & {a: 2}) @test(eq, true) +i: _|_ == ({a: 1} & {b: 2}) @test(eq, false) + +err: 1 & 2 @test(err, code=eval, contains="conflicting values 2 and 1", pos=[in.cue:12:6, in.cue:12:10]) +-- out/compile -- +--- in.cue +{ + a: (_|_(explicit error (_|_ literal) in source) == _|_(explicit error (_|_ literal) in source)) + b: ((〈0;err〉 == 1) & 2) + c: (〈0;err〉 == _|_(explicit error (_|_ literal) in source)) + d: (〈0;err〉 != _|_(explicit error (_|_ literal) in source)) + e: ((〈0;err〉 != 1) & 3) + f: (({ + a: 1 + } & { + a: 2 + }) == _|_(explicit error (_|_ literal) in source)) + g: (({ + a: 1 + } & { + b: 2 + }) == _|_(explicit error (_|_ literal) in source)) + h: (_|_(explicit error (_|_ literal) in source) == ({ + a: 1 + } & { + a: 2 + })) + i: (_|_(explicit error (_|_ literal) in source) == ({ + a: 1 + } & { + b: 2 + })) + err: (1 & 2) +} diff --git a/internal/core/compile/testdata/sync/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar b/internal/core/compile/testdata/sync/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/032_or_builtin_should_not_fail_on_non-concrete_empty_list.txtar @@ -0,0 +1,39 @@ +# Tests that the or() builtin does not panic when called with a non-concrete +# (empty) list, such as when no comprehension entries are produced. +# The #JobID field should be an incomplete error in the base definition, but +# successfully resolve to a concrete string once jobs has at least one entry. +#name: or builtin should not fail on non-concrete empty list +#evalFull +-- in.cue -- +#Workflow: { + jobs: { + [jobID=string]: { + } + } + #JobID: or([for k, _ in jobs {k}]) @test(err, code=incomplete, contains="empty list in call to or", pos=[0:10]) + // #JobID is incomplete when jobs has no entries — or([]) is not allowed. +} + +foo: #Workflow & { + jobs: foo: { + } +} @test(eq, {jobs: {foo: {}}, #JobID: "foo"}) +-- out/compile -- +--- in.cue +{ + #Workflow: { + jobs: { + [string]: {} + } + #JobID: or([ + for k, _ in 〈1;jobs〉 { + 〈1;k〉 + }, + ]) + } + foo: (〈0;#Workflow〉 & { + jobs: { + foo: {} + } + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/034_label_and_field_aliases.txtar b/internal/core/compile/testdata/sync/fulleval/034_label_and_field_aliases.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/034_label_and_field_aliases.txtar @@ -0,0 +1,48 @@ +#name: label and field aliases +#evalFull +-- in.cue -- +p: [ID=string]: {name: ID} +p: q: _ @test(eq, {name: "q"}) +A="foo=bar": "str" // TODO(inline): make this work @test(eq, at="foo=bar", "str") +a: A @test(eq, "str") +B=bb: 4 +@test(eq, at=bb, 4) +b1: B @test(eq, 4) +b1: bb +C="\(a)": 5 +c: C @test(eq, 5) + +@test(debugCheck, """ + (struct){ + p: (struct){ + q: (struct){ + name: (string){ "q" } + } + } + "foo=bar": (string){ "str" } + a: (string){ "str" } + bb: (int){ 4 } + b1: (int){ 4 } + c: (int){ 5 } + str: (int){ 5 } + } + """) +-- out/compile -- +--- in.cue +{ + p: { + [string]: { + name: 〈1;-〉 + } + } + p: { + q: _ + } + "foo=bar": "str" + a: 〈0;"foo=bar"〉 + bb: 4 + b1: 〈0;bb〉 + b1: 〈0;bb〉 + "\(〈0;a〉)": 5 + c: 〈0;("\(〈0;a〉)")〉 +} diff --git a/internal/core/compile/testdata/sync/fulleval/035_optionals_with_label_filters.txtar b/internal/core/compile/testdata/sync/fulleval/035_optionals_with_label_filters.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/035_optionals_with_label_filters.txtar @@ -0,0 +1,81 @@ +#name: optionals with label filters +#evalFull +# Tests that optional fields with label filters enforce their constraints: +# fields not matching the pattern or constraint fail with "field not allowed" +# or bound violations. jobs is the happy path; jobs1, jobs2, jobs3 are faulty. +-- in.cue -- +#JobID: =~"^[a-zA-Z]*$" +#Job: { + name: string + cmd: string +} +#Jobs: { + {[#JobID]: #Job} + + {[=~"Test$"]: name: =~"^test"}// Must work without ... +} + +jobs: foo: name: "allGood" +jobs: foo: name: "allGood" + +jobs1: #Jobs +jobs1: foo1: {} // faulty +@test(err, code=eval, at=jobs1.foo1, contains="field not allowed", pos=[-1:8]) + +jobs2: #Jobs +jobs2: fooTest: name: "badName" // faulty +@test(err, code=eval, at=jobs2.fooTest.name, contains="invalid value", pos=[-12:22, -18:8, -1:23]) + +jobs3: #Jobs +jobs3: [string]: #Job +jobs3: fooTest1: name: "badName" // faulty +@test(err, code=eval, at=jobs3.fooTest1, contains="field not allowed", pos=[-2:8, -1:8]) + +-- out/compile -- +--- in.cue +{ + #JobID: =~"^[a-zA-Z]*$" + #Job: { + name: string + cmd: string + } + #Jobs: { + { + [〈2;#JobID〉]: 〈2;#Job〉 + } + { + [=~"Test$"]: { + name: =~"^test" + } + } + } + jobs: { + foo: { + name: "allGood" + } + } + jobs: { + foo: { + name: "allGood" + } + } + jobs1: 〈0;#Jobs〉 + jobs1: { + foo1: {} + } + jobs2: 〈0;#Jobs〉 + jobs2: { + fooTest: { + name: "badName" + } + } + jobs3: 〈0;#Jobs〉 + jobs3: { + [string]: 〈1;#Job〉 + } + jobs3: { + fooTest1: { + name: "badName" + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/040.txtar b/internal/core/compile/testdata/sync/fulleval/040.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/040.txtar @@ -0,0 +1,43 @@ +# Tests that a disjunction inside a definition resolves correctly when a +# discriminant field is set. After unifying #Task with {op: "pull"}, the +# "pull" branch is selected and expressions using the defaulted tag +# field (tag: *"latest" | string) evaluate concretely. +#evalFull +-- in.cue -- +#Task: { + { + op: "pull" + tag: *"latest" | string + refToTag: tag + tagExpr: tag + "dd" + tagInString: "\(tag)" + } | { + op: "scratch" + } +} + +foo: #Task & {"op": "pull"} @test(eq, { + op: "pull" + tag: *"latest" | string + refToTag: *"latest" | string + tagExpr: "latestdd" + tagInString: "latest" +}) +-- out/compile -- +--- in.cue +{ + #Task: { + ({ + op: "pull" + tag: (*"latest"|string) + refToTag: 〈0;tag〉 + tagExpr: (〈0;tag〉 + "dd") + tagInString: "\(〈0;tag〉)" + }|{ + op: "scratch" + }) + } + foo: (〈0;#Task〉 & { + op: "pull" + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/041.txtar b/internal/core/compile/testdata/sync/fulleval/041.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/041.txtar @@ -0,0 +1,25 @@ +-- in.cue -- +t: { + #ok: *true | bool + if #ok { + x: int + } + @test(eq, { + #ok: *true | bool + x: int + }) +} +s: t & {#ok: false} @test(eq, {#ok: false}) +-- out/compile -- +--- in.cue +{ + t: { + #ok: (*true|bool) + if 〈0;#ok〉 { + x: int + } + } + s: (〈0;t〉 & { + #ok: false + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/042_cross-dependent_comprehension.txtar b/internal/core/compile/testdata/sync/fulleval/042_cross-dependent_comprehension.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/042_cross-dependent_comprehension.txtar @@ -0,0 +1,29 @@ +# Tests that comprehension conditions referencing fields resolve correctly when the +# condition is cross-dependent. x unifies #a with b:true and c:4, resolving the +# comprehension. y is an alias of x with the same value. +-- in.cue -- +#a: { + if b { + c: 4 + } + b: bool + @test(err, code=incomplete, args=[bool], pos=[in.cue:5:5]) +} +x: (#a & {b: true}) & {c: 4} @test(eq, {b: true, c: 4}) @test(shareID=xy) +y: x @test(eq, {b: true, c: 4}) @test(shareID=xy) +-- out/compile -- +--- in.cue +{ + #a: { + if 〈0;b〉 { + c: 4 + } + b: bool + } + x: ((〈0;#a〉 & { + b: true + }) & { + c: 4 + }) + y: 〈0;x〉 +} diff --git a/internal/core/compile/testdata/sync/fulleval/043_optional_expanded_before_lookup.txtar b/internal/core/compile/testdata/sync/fulleval/043_optional_expanded_before_lookup.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/043_optional_expanded_before_lookup.txtar @@ -0,0 +1,33 @@ +#name: optional expanded before lookup +#evalFull +-- in.cue -- +test: [ID=_]: { + name: ID +} + +test: A: { + field1: "1" + field2: "2" +} + +B: test.A & {} @test(eq, { + field1: "1" + field2: "2" + name: "A" +}) +-- out/compile -- +--- in.cue +{ + test: { + [_]: { + name: 〈1;-〉 + } + } + test: { + A: { + field1: "1" + field2: "2" + } + } + B: (〈0;test〉.A & {}) +} diff --git a/internal/core/compile/testdata/sync/fulleval/044_Issue_#178.txtar b/internal/core/compile/testdata/sync/fulleval/044_Issue_#178.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/044_Issue_#178.txtar @@ -0,0 +1,25 @@ +# Tests that encoding built-in functions called with non-concrete arguments +# correctly return an "incomplete" error rather than panicking. Issue: calling +# csv.Decode or hex.EncodedLen with abstract (non-concrete) values caused a +# nil pointer dereference panic instead of a proper incomplete error. +# https://cuelang.org/issue/178 +#name: Issue #178 +#evalFull +-- in.cue -- +import "encoding/csv" + +import "encoding/hex" + +foo: csv.Decode(data) @test(err, code=incomplete) +data: bytes @test(kind=bytes) + +len: int @test(kind=int) +bar: hex.EncodedLen(len) @test(err, code=incomplete) +-- out/compile -- +--- in.cue +{ + foo: 〈import;"encoding/csv"〉.Decode(〈0;data〉) + data: bytes + len: int + bar: 〈import;"encoding/hex"〉.EncodedLen(〈0;len〉) +} diff --git a/internal/core/compile/testdata/sync/fulleval/046_non-structural_direct_cycles.txtar b/internal/core/compile/testdata/sync/fulleval/046_non-structural_direct_cycles.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/046_non-structural_direct_cycles.txtar @@ -0,0 +1,21 @@ +# Tests non-structural direct cycles where a struct is unified with one of its own +# fields. c1 resolves successfully (bar.baz is merged), c2 conflicts because bar:1 +# (int) cannot unify with the struct c2.bar. +-- in.cue -- +c1: {bar: baz: 2} & c1.bar @test(eq, {bar: {baz: 2}, baz: 2}) +c2: {bar: 1} & c2.bar @test(err, code=eval, + contains="conflicting values", + args=[{bar:1}, 1, struct, int], + pos=[0:5, 0:16, 0:21]) +-- out/compile -- +--- in.cue +{ + c1: ({ + bar: { + baz: 2 + } + } & 〈0;c1〉.bar) + c2: ({ + bar: 1 + } & 〈0;c2〉.bar) +} diff --git a/internal/core/compile/testdata/sync/fulleval/047_dont_bind_to_string_labels.txtar b/internal/core/compile/testdata/sync/fulleval/047_dont_bind_to_string_labels.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/047_dont_bind_to_string_labels.txtar @@ -0,0 +1,16 @@ +-- in.cue -- + +x: 1 +y: { + "x": 2 + z: x @test(eq, 1) +} +-- out/compile -- +--- in.cue +{ + x: 1 + y: { + x: 2 + z: 〈1;x〉 + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar b/internal/core/compile/testdata/sync/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar @@ -0,0 +1,13 @@ +#name: dont pass incomplete values to builtins +#evalFull +-- in.cue -- +import "encoding/json" + +input: string @test(kind=string) +foo: json.Marshal(input) @test(err, code=incomplete) +-- out/compile -- +--- in.cue +{ + input: string + foo: 〈import;"encoding/json"〉.Marshal(〈0;input〉) +} diff --git a/internal/core/compile/testdata/sync/fulleval/049_alias_reuse_in_nested_scope.txtar b/internal/core/compile/testdata/sync/fulleval/049_alias_reuse_in_nested_scope.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/049_alias_reuse_in_nested_scope.txtar @@ -0,0 +1,58 @@ +# Tests that let bindings in nested scopes are correctly scoped and can be reused. +# #Foo uses a let alias pointing to an empty or disjunction (error); #A and #B use +# let aliases tied to foo, which become dynamic field keys. b instantiates #B. +-- in.cue -- +#Foo: { + let X = or([for k, _ in {} {k}]) + connection: [X]: X @test(err, code=incomplete, pos=[0:11], contains="in call", args=[or]) + @test(eq, { + connection: _|_ @test(err, code=incomplete, contains="#Foo.X: error in call to or: empty list in call to or", pos=[2:10]) + }) +} +#A: { + foo: "key" + let X = foo + a: foo: [X]: X + @test(eq, {foo: "key", a: {foo: {["key"]: "key"}}}) +} +#B: { + foo: string + let X = foo + a: foo: [X]: X +} +b: #B & {foo: "key"} @test(eq, {foo: "key", a: {foo: {}}}) +-- out/compile -- +--- in.cue +{ + #Foo: { + let X#1 = or([ + for k, _ in {} { + 〈1;k〉 + }, + ]) + connection: { + [〈1;let X#1〉]: 〈1;let X#1〉 + } + } + #A: { + foo: "key" + let X#2 = 〈0;foo〉 + a: { + foo: { + [〈2;let X#2〉]: 〈2;let X#2〉 + } + } + } + #B: { + foo: string + let X#3 = 〈0;foo〉 + a: { + foo: { + [〈2;let X#3〉]: 〈2;let X#3〉 + } + } + } + b: (〈0;#B〉 & { + foo: "key" + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/050_json_Marshaling_detects_incomplete.txtar b/internal/core/compile/testdata/sync/fulleval/050_json_Marshaling_detects_incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/050_json_Marshaling_detects_incomplete.txtar @@ -0,0 +1,24 @@ +#name: json Marshaling detects incomplete +#evalFull +-- in.cue -- +import "encoding/json" + +a: json.Marshal({a: string}) @test(err, code=incomplete) + +foo: { + a: 3 @test(eq, 3) + b: foo.c @test(err, code=incomplete) +} +b: json.Marshal(foo) @test(err, code=incomplete) +-- out/compile -- +--- in.cue +{ + a: 〈import;"encoding/json"〉.Marshal({ + a: string + }) + foo: { + a: 3 + b: 〈1;foo〉.c + } + b: 〈import;"encoding/json"〉.Marshal(〈0;foo〉) +} diff --git a/internal/core/compile/testdata/sync/fulleval/051_detectIncompleteYAML.txtar b/internal/core/compile/testdata/sync/fulleval/051_detectIncompleteYAML.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/051_detectIncompleteYAML.txtar @@ -0,0 +1,48 @@ +#name: detectIncompleteYAML +#evalFull +-- in.cue -- +package foobar + +import yaml "encoding/yaml" + +#Spec: { + _vars: {something: string} + data: { + #foo: { + use: _vars.something + } + baz: yaml.Marshal(_vars.something) @test(err, code=incomplete, pos=[0:11]) + foobar: yaml.Marshal(#foo) @test(err, code=incomplete, pos=[0:11, -6:21, -3:9]) + } +} +Val: #Spec & { + _vars: something: "var-string" +} @test(eq, { + _vars$foobar: something: "var-string" + data: { + #foo: use: "var-string" + baz: "var-string\n" + foobar: "use: var-string\n" + } +}) +-- out/compile -- +--- in.cue +{ + #Spec: { + _vars(:foobar): { + something: string + } + data: { + #foo: { + use: 〈2;_vars(:foobar)〉.something + } + baz: 〈import;"encoding/yaml"〉.Marshal(〈1;_vars(:foobar)〉.something) + foobar: 〈import;"encoding/yaml"〉.Marshal(〈0;#foo〉) + } + } + Val: (〈0;#Spec〉 & { + _vars(:foobar): { + something: "var-string" + } + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/052_detectIncompleteJSON.txtar b/internal/core/compile/testdata/sync/fulleval/052_detectIncompleteJSON.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/052_detectIncompleteJSON.txtar @@ -0,0 +1,48 @@ +#name: detectIncompleteJSON +#evalFull +-- in.cue -- +package foobar + +import "encoding/json" + +#Spec: { + _vars: {something: string} + data: { + #foo: { + use: _vars.something + } + baz: json.Marshal(_vars.something) @test(err, code=incomplete) + foobar: json.Marshal(#foo) @test(err, code=incomplete) + } +} +Val: #Spec & { + _vars: something: "var-string" +} @test(eq, { + _vars$foobar: something: "var-string" + data: { + #foo: use: "var-string" + baz: "\"var-string\"" + foobar: "{\"use\":\"var-string\"}" + } +}) +-- out/compile -- +--- in.cue +{ + #Spec: { + _vars(:foobar): { + something: string + } + data: { + #foo: { + use: 〈2;_vars(:foobar)〉.something + } + baz: 〈import;"encoding/json"〉.Marshal(〈1;_vars(:foobar)〉.something) + foobar: 〈import;"encoding/json"〉.Marshal(〈0;#foo〉) + } + } + Val: (〈0;#Spec〉 & { + _vars(:foobar): { + something: "var-string" + } + }) +} diff --git a/internal/core/compile/testdata/sync/fulleval/053_issue312.txtar b/internal/core/compile/testdata/sync/fulleval/053_issue312.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/053_issue312.txtar @@ -0,0 +1,24 @@ +# Tests a comprehension with a disjunction of close({}) and a pattern +# constraint. Issue: https://cuelang.org/issue/312 — the default selection +# and closing behavior of a disjunction inside a comprehension should work +# correctly. +#name: issue312 +#evalFull +-- in.cue -- + +for x in [1] { + *close({}) | {[_]: null} +} + +@test(eq, *{} | {}) +-- out/compile -- +--- in.cue +{ + for _, x in [ + 1, + ] { + (*close({})|{ + [_]: null + }) + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/054_issue312.txtar b/internal/core/compile/testdata/sync/fulleval/054_issue312.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/054_issue312.txtar @@ -0,0 +1,22 @@ +-- in.cue -- +x: { + y: *1 | {a: 2} + for x in [1] {y} +} @test(eq, { + a: 2 + y: *1 | { a: 2 } +}) +-- out/compile -- +--- in.cue +{ + x: { + y: (*1|{ + a: 2 + }) + for _, x in [ + 1, + ] { + 〈2;y〉 + } + } +} diff --git a/internal/core/compile/testdata/sync/fulleval/055_issue318.txtar b/internal/core/compile/testdata/sync/fulleval/055_issue318.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/fulleval/055_issue318.txtar @@ -0,0 +1,29 @@ +# Tests that string interpolation consistently detects references to +# non-existent fields. Issue: an interpolation with both a valid and an invalid +# field reference (e.g. "\(arg.x) \(arg.y)") silently swallowed the error for +# the invalid field, while a single invalid reference was correctly reported. +# https://cuelang.org/issue/318 +# +-- in.cue -- +#T: { + arg: x: string + out1: "\(arg.x) \(arg.y)" @test(err, code=eval) + // TODO: is this really an eval error if it is referred to within a + // definitions? + out2: "\(arg.y)" @test(err, code=eval) + vx: arg.x @test(kind=string) + vy: arg.y @test(err, code=eval) +} +-- out/compile -- +--- in.cue +{ + #T: { + arg: { + x: string + } + out1: "\(〈0;arg〉.x) \(〈0;arg〉.y)" + out2: "\(〈0;arg〉.y)" + vx: 〈0;arg〉.x + vy: 〈0;arg〉.y + } +} diff --git a/internal/core/compile/testdata/sync/inlinetest/closedness.txtar b/internal/core/compile/testdata/sync/inlinetest/closedness.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/closedness.txtar @@ -0,0 +1,73 @@ +-- in.cue -- +t1: close({b: {}}) +t1: _ @test(closed) +t1: b: _ @test(closed=false) +t1: _ @test(allows, "b") +t1: _ @test(allows=false, foo) + +#X: {[=~"^Q*$"]: int} + +#X: _ @test(closed) +#X: _ @test(allows, Q) +#X: _ @test(allows=false, X) +#X: _ @test(allows=false, string) + +t2: #X +t2: _ @test(closed) +t2: _ @test(allows, Q) +t2: _ @test(allows=false, X) +t2: _ @test(allows=false, string) + +#Y: {...} + +t3: #Y +t3: _ @test(closed) +t3: _ @test(allows, Q) +t3: _ @test(allows, X) +t3: _ @test(allows, string) + +// t4: "string" (quoted) targets the literal field named string; +// string (unquoted) targets the any-string pattern constraint. +t4: close({"string": 1}) +t4: _ @test(closed) +t4: _ @test(allows, "string") // quoted: literal field named string +t4: _ @test(allows=false, string) // unquoted: any-string pattern not present +-- out/compile -- +--- in.cue +{ + t1: close({ + b: {} + }) + t1: _ + t1: { + b: _ + } + t1: _ + t1: _ + #X: { + [=~"^Q*$"]: int + } + #X: _ + #X: _ + #X: _ + #X: _ + t2: 〈0;#X〉 + t2: _ + t2: _ + t2: _ + t2: _ + #Y: { + ... + } + t3: 〈0;#Y〉 + t3: _ + t3: _ + t3: _ + t3: _ + t4: close({ + string: 1 + }) + t4: _ + t4: _ + t4: _ +} diff --git a/internal/core/compile/testdata/sync/inlinetest/debug.txtar b/internal/core/compile/testdata/sync/inlinetest/debug.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/debug.txtar @@ -0,0 +1,66 @@ +-- in.cue -- +// debugCheck: compare debug-printer output via @test(debugCheck, ...) attributes. + +// ── scalar value ───────────────────────── + +debugCheckScalar: 42 @test(debugCheck, "(int){ 42 }") + +// ── struct value ───────────────────────── + +debugCheckStruct: { + @test(debugCheck, """ + (struct){ + a: (int){ 1 } + b: (int){ 2 } + } + """) + a: 1 + b: 2 +} + +// ── computed struct ─────────────────────── + +debugCheckComputed: { + @test(debugCheck, """ + (struct){ + x: (int){ 10 } + y: (int){ 20 } + } + """) + x: 10 + y: x * 2 +} + +// ── version override: v3 debugCheck takes precedence ── +// Both default and v3 have the same expected output here, +// verifying that versioned attrs are accepted and applied correctly. + +debugCheckVersioned: { + @test(debugCheck, """ + (struct){ + z: (int){ 99 } + } + """) + @test(debugCheck:v3, """ + (struct){ + z: (int){ 99 } + } + """) + z: 99 +} +-- out/compile -- +--- in.cue +{ + debugCheckScalar: 42 + debugCheckStruct: { + a: 1 + b: 2 + } + debugCheckComputed: { + x: 10 + y: (〈0;x〉 * 2) + } + debugCheckVersioned: { + z: 99 + } +} diff --git a/internal/core/compile/testdata/sync/inlinetest/decl_eq.txtar b/internal/core/compile/testdata/sync/inlinetest/decl_eq.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/decl_eq.txtar @@ -0,0 +1,29 @@ +-- in.cue -- +// File-level @test(eq, VALUE) as a decl attribute: checks the entire +// file's evaluated value against VALUE. All fields are covered +// implicitly — no per-field @test is required. + +a: 1 +b: a + 1 +c: { + x: "hello" + y: b +} +@test(eq, { + a: 1 + b: 2 + c: { + x: "hello" + y: 2 + } +}) +-- out/compile -- +--- in.cue +{ + a: 1 + b: (〈0;a〉 + 1) + c: { + x: "hello" + y: 〈1;b〉 + } +} diff --git a/internal/core/compile/testdata/sync/inlinetest/decl_eq_mixed.txtar b/internal/core/compile/testdata/sync/inlinetest/decl_eq_mixed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/decl_eq_mixed.txtar @@ -0,0 +1,14 @@ +-- in.cue -- +// File-level @test(eq, ...) coexists with field-level @test attributes. +// Both assertions run. The file-level @test covers all fields, so per-field +// coverage is not required, but individual fields may still carry @test. + +x: 1 @test(eq, 1) +y: x + 1 +@test(eq, {x: 1, y: 2}) +-- out/compile -- +--- in.cue +{ + x: 1 + y: (〈0;x〉 + 1) +} diff --git a/internal/core/compile/testdata/sync/inlinetest/decl_eq_pattern.txtar b/internal/core/compile/testdata/sync/inlinetest/decl_eq_pattern.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/decl_eq_pattern.txtar @@ -0,0 +1,17 @@ +-- in.cue -- +// File-level @test(eq, VALUE) where a pattern constraint contributes +// to the output — the eq check applies to the whole file. + +{[X=string]: baz: X} +bar: {} +@test(eq, {bar: baz: "bar"}) +-- out/compile -- +--- in.cue +{ + { + [string]: { + baz: 〈1;-〉 + } + } + bar: {} +} diff --git a/internal/core/compile/testdata/sync/inlinetest/hidden_fields.txtar b/internal/core/compile/testdata/sync/inlinetest/hidden_fields.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/hidden_fields.txtar @@ -0,0 +1,55 @@ +-- in.cue -- +// Tests that hidden fields in @test(eq, {...}) must be fully specified. +// A hidden field present in the value but absent from the expected struct +// causes a test failure. A hidden field in the expected struct that is absent +// from the value also causes a failure. + +package foo + +// -- hidden field present in both value and expected -- +// Field-attribute form: hidden field in both value and expected passes. +hiddenInBoth: { + _secret: 42 + a: _secret + 1 +} @test(eq, {_secret$foo: 42, a: 43}) + +// Decl-attribute form. +hiddenDeclForm: { + @test(eq, {_secret$foo: "x", b: "xx"}) + _secret: "x" + b: _secret + _secret +} + +// Hidden definition field in both value and expected. +hiddenDefInBoth: { + _#Meta: {info: "internal"} + a: 1 +} @test(eq, {_#Meta$foo: {info: "internal"}, a: 1}) + +// -- no hidden fields -- + +// No hidden fields on either side: passes trivially. +noHidden: {a: 1, b: 2} @test(eq, {a: 1, b: 2}) + +-- out/compile -- +--- in.cue +{ + hiddenInBoth: { + _secret(:foo): 42 + a: (〈0;_secret(:foo)〉 + 1) + } + hiddenDeclForm: { + _secret(:foo): "x" + b: (〈0;_secret(:foo)〉 + 〈0;_secret(:foo)〉) + } + hiddenDefInBoth: { + _#Meta(:foo): { + info: "internal" + } + a: 1 + } + noHidden: { + a: 1 + b: 2 + } +} diff --git a/internal/core/compile/testdata/sync/inlinetest/permute.txtar b/internal/core/compile/testdata/sync/inlinetest/permute.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/permute.txtar @@ -0,0 +1,101 @@ +-- in.cue -- +// Structural permute tests: @test(permute) placed on the struct whose fields +// should be permuted — either as a decl attr on the container, or as a decl +// attr directly on the 'in' struct. + +// ── Container-level @test(permute): permutes all fields of `in` ── + +threeFieldPermute: { + @test(permute, count=6) + a: b + c + b: 1 + c: 2 + @test(eq, { + a: 3 + b: 1 + c: 2 + }) +} + +twoFieldPermute: { + @test(permute, count=2) + x: y + 1 + y: 5 + @test(eq, { + x: 6 + y: 5 + }) +} + +// ── Decl attr on `in` directly: equivalent syntax ── + +inDeclPermute: { + @test(permute, count=6) + p: q + r + q: 3 + r: 7 + @test(eq, { + p: 10 + q: 3 + r: 7 + }) +} + +// ── Self-contained concrete struct: trivially order-invariant ── + +concretePermute: { + x: { + @test(permute, count=6) + alpha: 1 + beta: 2 + gamma: 3 + } + y: { + @test(permute, count=6) + alpha: 1 + beta: 2 + gamma: 3 + } + @test(eq, { + x: { + alpha: 1 + beta: 2 + gamma: 3 + } + y: { + alpha: 1 + beta: 2 + gamma: 3 + } + }) +} +-- out/compile -- +--- in.cue +{ + threeFieldPermute: { + a: (〈0;b〉 + 〈0;c〉) + b: 1 + c: 2 + } + twoFieldPermute: { + x: (〈0;y〉 + 1) + y: 5 + } + inDeclPermute: { + p: (〈0;q〉 + 〈0;r〉) + q: 3 + r: 7 + } + concretePermute: { + x: { + alpha: 1 + beta: 2 + gamma: 3 + } + y: { + alpha: 1 + beta: 2 + gamma: 3 + } + } +} diff --git a/internal/core/compile/testdata/sync/inlinetest/struct_eq.txtar b/internal/core/compile/testdata/sync/inlinetest/struct_eq.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/struct_eq.txtar @@ -0,0 +1,14 @@ +-- in.cue -- +myStruct: { + @test(eq, {a: 1, b: 2}) + a: 1 + b: a + 1 +} +-- out/compile -- +--- in.cue +{ + myStruct: { + a: 1 + b: (〈0;a〉 + 1) + } +} diff --git a/internal/core/compile/testdata/sync/inlinetest/structural.txtar b/internal/core/compile/testdata/sync/inlinetest/structural.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/structural.txtar @@ -0,0 +1,73 @@ +-- in.cue -- +// Tests converted from structural form to inline form. + +// ── error-only ───────────────────────── + +errOnly: 1 & 2 @test(err, code=eval, contains="conflicting values %s and %s", args=[2, 1], pos=[0:10, 0:14]) + +errWithCode: string & 1 @test(err, code=eval, + contains="conflicting values %s and %s (mismatched types %s and %s)", + args=[string, 1, string, int], pos=[0:14, 0:23]) + +// ── eq: computed struct ──────────────── + +eqBasic: {a: 1, b: 2} @test(eq, {a: 1, b: 2}) + +eqComputed: { + @test(eq, {x: 10, y: 20}) + x: 10 + y: x * 2 +} + +// ── skip ────────────────────────────── + +skippedTest: {a: 1} @test(skip, why="demonstrating skip") + +// ── desc ────────────────────────────── + +descTest: {v: "ok"} @test(desc="description") @test(eq, {v: "ok"}) + +// ── version-specific ────────────────── + +versionOverride: {x: 1} @test(eq, {x: 1}) @test(eq:unknown, {x: 3}) + +// ── plain fixture field + references ────────────────── + +// A plain field with no @test is accessible but not a sub-test. +plainFixture: { + x: 42 +} + +refsFixture: plainFixture.x @test(eq, 42) + +// ── mixed inline ────────────────────── + +mixedInline: 42 @test(eq, 42) +-- out/compile -- +--- in.cue +{ + errOnly: (1 & 2) + errWithCode: (string & 1) + eqBasic: { + a: 1 + b: 2 + } + eqComputed: { + x: 10 + y: (〈0;x〉 * 2) + } + skippedTest: { + a: 1 + } + descTest: { + v: "ok" + } + versionOverride: { + x: 1 + } + plainFixture: { + x: 42 + } + refsFixture: 〈0;plainFixture〉.x + mixedInline: 42 +} diff --git a/internal/core/compile/testdata/sync/inlinetest/validators.txtar b/internal/core/compile/testdata/sync/inlinetest/validators.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/inlinetest/validators.txtar @@ -0,0 +1,23 @@ +-- in.cue -- +import "struct" + +// Validator equality: a value produced by applying a builtin validator +// can be compared with @test(eq, ). + +// Standalone validator: BaseValue of the vertex is the BuiltinValidator +// itself, so equalTerminal is called directly with two BuiltinValidators. +rawMax: struct.MaxFields(2) @test(eq, struct.MaxFields(2)) +rawMin: struct.MinFields(3) @test(eq, struct.MinFields(3)) + +intMixDirect: int & <=1 @test(eq, <=1 & int) +intMixEmbed: {int & <=1} @test(eq, {<=1 & int}) +-- out/compile -- +--- in.cue +{ + rawMax: 〈import;struct〉.MaxFields(2) + rawMin: 〈import;struct〉.MinFields(3) + intMixDirect: (int & <=1) + intMixEmbed: { + (int & <=1) + } +} diff --git a/internal/core/compile/testdata/sync/interpolation/041_interpolation.txtar b/internal/core/compile/testdata/sync/interpolation/041_interpolation.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/interpolation/041_interpolation.txtar @@ -0,0 +1,19 @@ +-- in.cue -- +a: "\(4)" @test(eq, "4") +b: "one \(a) two \( a+c )" @test(eq, "one 4 two 4one") +c: "one" @test(eq, "one") +d: "\(r)" @test(err, code=incomplete, contains="invalid interpolation: non-concrete value _", pos=[0:4], hint="position of r itself would be nice") +u: "\(_)" @test(err, code=incomplete|eval, contains="invalid interpolation: non-concrete value _", pos=[0:4, 0:7]) @test(err:todo, code=eval) // literal _ can never resolve. +r: _ +e: "\([])" @test(err, code=eval, contains="invalid interpolation: cannot use [] (type list)", pos=[0:4, 0:7]) +-- out/compile -- +--- in.cue +{ + a: "\(4)" + b: "one \(〈0;a〉) two \((〈0;a〉 + 〈0;c〉))" + c: "one" + d: "\(〈0;r〉)" + u: "\(_)" + r: _ + e: "\([])" +} diff --git a/internal/core/compile/testdata/sync/interpolation/042_multiline_interpolation.txtar b/internal/core/compile/testdata/sync/interpolation/042_multiline_interpolation.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/interpolation/042_multiline_interpolation.txtar @@ -0,0 +1,74 @@ +-- in.cue -- +a1: """ + before + \(4) + after + """ @test(eq, "before\n4\nafter") +a2: """ + before + \(4) + + """ @test(eq, "before\n4\n") +a3: """ + + \(4) + after + """ @test(eq, "\n4\nafter") +a4: """ + + \(4) + + """ @test(eq, "\n4\n") +m1: """ + before + \( + 4) + after + """ @test(eq, "before\n4\nafter") +m2: """ + before + \( + 4) + + """ @test(eq, "before\n4\n") +m3: """ + + \( + + 4) + after + """ @test(eq, "\n4\nafter") +m4: """ + + \( + 4) + + """ @test(eq, "\n4\n") +-- out/compile -- +--- in.cue +{ + a1: "before + \(4) + after" + a2: "before + \(4) + " + a3: " + \(4) + after" + a4: " + \(4) + " + m1: "before + \(4) + after" + m2: "before + \(4) + " + m3: " + \(4) + after" + m4: " + \(4) + " +} diff --git a/internal/core/compile/testdata/sync/interpolation/incomplete.txtar b/internal/core/compile/testdata/sync/interpolation/incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/interpolation/incomplete.txtar @@ -0,0 +1,32 @@ +Issue #553 +-- in.cue -- +a: "foo" @test(eq, "foo") +b: "boo" @test(eq, "boo") +commands: { + #c: { + help: "help!" + } +} +out: """ + a is \(a) + b is \(b) + + c is \(commands.#c.help) + d is \(commands.#d.help) + """ @test(err, code=incomplete) +-- out/compile -- +--- in.cue +{ + a: "foo" + b: "boo" + commands: { + #c: { + help: "help!" + } + } + out: "a is \(〈0;a〉) + b is \(〈0;b〉) + + c is \(〈0;commands〉.#c.help) + d is \(〈0;commands〉.#d.help)" +} diff --git a/internal/core/compile/testdata/sync/interpolation/issue487.txtar b/internal/core/compile/testdata/sync/interpolation/issue487.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/interpolation/issue487.txtar @@ -0,0 +1,44 @@ +# Tests that string interpolation correctly reports "incomplete" errors when +# the interpolated field is abstract (non-concrete), while still allowing the +# parent struct to be unified with a concrete value. Issue: interpolation inside +# a definition produced an "incomplete" error on the definition field itself, +# but the unified concrete result (e.g. `a: #R & {pos: 67}`) should evaluate +# to a concrete string. +# https://cuelang.org/issue/487 +-- in.cue -- +t1: { + #R: { + pos: uint + name: "hello_\(pos)" @test(err, code=incomplete) + } + a: #R & {pos: 67} @test(eq, {pos: 67, name: "hello_67"}) @test(closed) +} +t2: { + #R: { + pos: string + name: "hello_\(pos)" @test(err, code=incomplete) + } + a: #R & {pos: "a"} @test(eq, {pos: "a", name: "hello_a"}) @test(closed) +} +-- out/compile -- +--- in.cue +{ + t1: { + #R: { + pos: &(int, >=0) + name: "hello_\(〈0;pos〉)" + } + a: (〈0;#R〉 & { + pos: 67 + }) + } + t2: { + #R: { + pos: string + name: "hello_\(〈0;pos〉)" + } + a: (〈0;#R〉 & { + pos: "a" + }) + } +} diff --git a/internal/core/compile/testdata/sync/interpolation/scalars.txtar b/internal/core/compile/testdata/sync/interpolation/scalars.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/interpolation/scalars.txtar @@ -0,0 +1,35 @@ +-- in.cue -- +bool1: "1+1=2: \(true)" @test(eq, "1+1=2: true") +bool1: "1+1=2: \(true)" +bool2: "1+1=1: \(false)" @test(eq, "1+1=1: false") + +// one replacement character +b1: 'a\xED\x95a' @test(eq, 'a\xed\x95a') +bytes1s: "\(b1)" @test(eq, "a\uFFFDa") +bytes1b: '\(b1)' @test(eq, 'a\xed\x95a') + +// two replacement characters +b2: 'a\x80\x95a' @test(eq, 'a\x80\x95a') +bytes2s: "\(b2)" @test(eq, "a�a") +bytes2b: '\(b2)' @test(eq, 'a\x80\x95a') + +// preserve precision +n1: "\(1) \(2.00)" @test(eq, "1 2.00") + +// but normalize representation +n2: "\(1e2)" @test(eq, "1E+2") +-- out/compile -- +--- in.cue +{ + bool1: "1+1=2: \(true)" + bool1: "1+1=2: \(true)" + bool2: "1+1=1: \(false)" + b1: 'a\xed\x95a' + bytes1s: "\(〈0;b1〉)" + bytes1b: '\(〈0;b1〉)' + b2: 'a\x80\x95a' + bytes2s: "\(〈0;b2〉)" + bytes2b: '\(〈0;b2〉)' + n1: "\(1) \(2.00)" + n2: "\(1E+2)" +} diff --git a/internal/core/compile/testdata/sync/lists/019_list_types.txtar b/internal/core/compile/testdata/sync/lists/019_list_types.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/lists/019_list_types.txtar @@ -0,0 +1,95 @@ +-- in.cue -- +import "list" + +l0: list.Repeat([int], 3) +l0: [1, 2, 3] @test(eq, [1, 2, 3]) +l2: [...{a: int}] +l2: [{a: 1}, {a: 2, b: 3}] @test(eq, [{a: 1}, {a: 2, b: 3}]) + +// TODO: work out a decent way to specify length ranges of lists. +// l3: <=10*[int] +// l3: [1, 2, 3, ...] + +s1: (list.Repeat([int], 6))[2:3] @test(eq, [int]) +s2: [0, 2, 3][1:2] @test(eq, [2]) + +i1: (list.Repeat([int], 6))[2] @test(eq, int) +i2: [0, 2, 3][2] @test(eq, 3) + +t0: [...{a: 8}] +t0: [{}] @test(eq, [{a: 8}]) +t1: [...] +t1: [...int] @test(eq, []) + +e0: list.Repeat([{}], 2) +e0: [{}] @test(err, code=eval, contains="incompatible list lengths", args=[1, 2], pos=[], hint="missing positions") +e1: [...int] +e1: [...float] @test(eq, []) +-- out/compile -- +--- in.cue +{ + l0: 〈import;list〉.Repeat([ + int, + ], 3) + l0: [ + 1, + 2, + 3, + ] + l2: [ + ...{ + a: int + }, + ] + l2: [ + { + a: 1 + }, + { + a: 2 + b: 3 + }, + ] + s1: 〈import;list〉.Repeat([ + int, + ], 6)[2:3] + s2: [ + 0, + 2, + 3, + ][1:2] + i1: 〈import;list〉.Repeat([ + int, + ], 6)[2] + i2: [ + 0, + 2, + 3, + ][2] + t0: [ + ...{ + a: 8 + }, + ] + t0: [ + {}, + ] + t1: [ + ..., + ] + t1: [ + ...int, + ] + e0: 〈import;list〉.Repeat([ + {}, + ], 2) + e0: [ + {}, + ] + e1: [ + ...int, + ] + e1: [ + ...float, + ] +} diff --git a/internal/core/compile/testdata/sync/lists/020_list_compilefail.txtar b/internal/core/compile/testdata/sync/lists/020_list_compilefail.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/lists/020_list_compilefail.txtar @@ -0,0 +1,61 @@ +#inlinetest:exclude CUE source contains compile-time errors (invalid operands to *) +# which prevent the inline runner from compiling the source. +#name: list arithmetic +#evalPartial +-- in.cue -- +l3: <=2 * [] +l4: <=2 * [int] +l5: <=2 * (int * [int]) +b: <=5 * [int] +b: [1, 2, ...] +c: (>=3 & <=5) * [int] +c: [1, 2, ...] +d: >=2 * [int] +d: [1, 2, ...] +-- out/compile -- +l3: invalid operand <=2 ('*' requires concrete value): + ./in.cue:1:5 +l4: invalid operand <=2 ('*' requires concrete value): + ./in.cue:2:5 +l5: invalid operand <=2 ('*' requires concrete value): + ./in.cue:3:5 +l5: invalid operand int ('*' requires concrete value): + ./in.cue:3:12 +b: invalid operand <=5 ('*' requires concrete value): + ./in.cue:4:5 +d: invalid operand >=2 ('*' requires concrete value): + ./in.cue:8:4 +--- in.cue +{ + l3: (<=2 * []) + l4: (<=2 * [ + int, + ]) + l5: (<=2 * (int * [ + int, + ])) + b: (<=5 * [ + int, + ]) + b: [ + 1, + 2, + ..., + ] + c: ((>=3 & <=5) * [ + int, + ]) + c: [ + 1, + 2, + ..., + ] + d: (>=2 * [ + int, + ]) + d: [ + 1, + 2, + ..., + ] +} diff --git a/internal/core/compile/testdata/sync/lists/021_list_equality.txtar b/internal/core/compile/testdata/sync/lists/021_list_equality.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/lists/021_list_equality.txtar @@ -0,0 +1,343 @@ +-- in.cue -- +eq0: [] == [] @test(eq, true) +eq1: [...] == [] @test(eq, true) +eq2: [] == [...] @test(eq, true) +eq3: [...] == [...] @test(eq, true) + +eq4: [1] == [1] @test(eq, true) +eq5: [1, ...] == [1] @test(eq, true) +eq6: [1] == [1, ...] @test(eq, true) +eq7: [1, ...] == [1, ...] @test(eq, true) + +eq8: [1, 2] == [1, 2] @test(eq, true) +eq9: [1, 2, ...] == [1, 2] @test(eq, true) +eq10: [1, 2] == [1, 2, ...] @test(eq, true) +eq11: [1, 2, ...] == [1, 2, ...] @test(eq, true) + +ne0: [] != [] @test(eq, false) +ne1: [...] != [] @test(eq, false) +ne2: [] != [...] @test(eq, false) +ne3: [...] != [...] @test(eq, false) + +ne4: [1] != [1] @test(eq, false) +ne5: [1, ...] != [1] @test(eq, false) +ne6: [1] != [1, ...] @test(eq, false) +ne7: [1, ...] != [1, ...] @test(eq, false) + +ne8: [1, 2] != [1, 2] @test(eq, false) +ne9: [1, 2, ...] != [1, 2] @test(eq, false) +ne10: [1, 2] != [1, 2, ...] @test(eq, false) +ne11: [1, 2, ...] != [1, 2, ...] @test(eq, false) + +feq0: [] == [1] @test(eq, false) +feq1: [...] == [1] @test(eq, false) +feq2: [] == [1, ...] @test(eq, false) +feq3: [...] == [1, ...] @test(eq, false) + +feq4: [1] == [] @test(eq, false) +feq5: [1, ...] == [] @test(eq, false) +feq6: [1] == [...] @test(eq, false) +feq7: [1, ...] == [...] @test(eq, false) + +feq8: [1, 2] == [1] @test(eq, false) +feq9: [1, ...] == [1, 2] @test(eq, false) +feq10: [1, 2] == [1, ...] @test(eq, false) +feq11: [1, ...] == [1, 2, ...] @test(eq, false) + +fne0: [] != [1] @test(eq, true) +fne1: [...] != [1] @test(eq, true) +fne2: [] != [1, ...] @test(eq, true) +fne3: [1, ...] != [1, ...] @test(eq, false) + +fne4: [1] != [] @test(eq, true) +fne5: [1, ...] != [] @test(eq, true) +fne6: [1] != [...] @test(eq, true) +fne7: [1, ...] != [...] @test(eq, true) + +fne8: [1, 2] != [1] @test(eq, true) +fne9: [1, ...] != [1, 2] @test(eq, true) +fne10: [1, 2] != [1, ...] @test(eq, true) +fne11: [1, ...] != [1, 2, ...] @test(eq, true) + +eqIncomplete1: [1] == [string] @test(err, code=incomplete, contains="invalid right-hand value to '=='", pos=[0:16]) + +neIncomplete1: [1] != [string] @test(err, code=incomplete, contains="invalid right-hand value to '!='", pos=[0:16]) +-- out/compile -- +--- in.cue +{ + eq0: ([] == []) + eq1: ([ + ..., + ] == []) + eq2: ([] == [ + ..., + ]) + eq3: ([ + ..., + ] == [ + ..., + ]) + eq4: ([ + 1, + ] == [ + 1, + ]) + eq5: ([ + 1, + ..., + ] == [ + 1, + ]) + eq6: ([ + 1, + ] == [ + 1, + ..., + ]) + eq7: ([ + 1, + ..., + ] == [ + 1, + ..., + ]) + eq8: ([ + 1, + 2, + ] == [ + 1, + 2, + ]) + eq9: ([ + 1, + 2, + ..., + ] == [ + 1, + 2, + ]) + eq10: ([ + 1, + 2, + ] == [ + 1, + 2, + ..., + ]) + eq11: ([ + 1, + 2, + ..., + ] == [ + 1, + 2, + ..., + ]) + ne0: ([] != []) + ne1: ([ + ..., + ] != []) + ne2: ([] != [ + ..., + ]) + ne3: ([ + ..., + ] != [ + ..., + ]) + ne4: ([ + 1, + ] != [ + 1, + ]) + ne5: ([ + 1, + ..., + ] != [ + 1, + ]) + ne6: ([ + 1, + ] != [ + 1, + ..., + ]) + ne7: ([ + 1, + ..., + ] != [ + 1, + ..., + ]) + ne8: ([ + 1, + 2, + ] != [ + 1, + 2, + ]) + ne9: ([ + 1, + 2, + ..., + ] != [ + 1, + 2, + ]) + ne10: ([ + 1, + 2, + ] != [ + 1, + 2, + ..., + ]) + ne11: ([ + 1, + 2, + ..., + ] != [ + 1, + 2, + ..., + ]) + feq0: ([] == [ + 1, + ]) + feq1: ([ + ..., + ] == [ + 1, + ]) + feq2: ([] == [ + 1, + ..., + ]) + feq3: ([ + ..., + ] == [ + 1, + ..., + ]) + feq4: ([ + 1, + ] == []) + feq5: ([ + 1, + ..., + ] == []) + feq6: ([ + 1, + ] == [ + ..., + ]) + feq7: ([ + 1, + ..., + ] == [ + ..., + ]) + feq8: ([ + 1, + 2, + ] == [ + 1, + ]) + feq9: ([ + 1, + ..., + ] == [ + 1, + 2, + ]) + feq10: ([ + 1, + 2, + ] == [ + 1, + ..., + ]) + feq11: ([ + 1, + ..., + ] == [ + 1, + 2, + ..., + ]) + fne0: ([] != [ + 1, + ]) + fne1: ([ + ..., + ] != [ + 1, + ]) + fne2: ([] != [ + 1, + ..., + ]) + fne3: ([ + 1, + ..., + ] != [ + 1, + ..., + ]) + fne4: ([ + 1, + ] != []) + fne5: ([ + 1, + ..., + ] != []) + fne6: ([ + 1, + ] != [ + ..., + ]) + fne7: ([ + 1, + ..., + ] != [ + ..., + ]) + fne8: ([ + 1, + 2, + ] != [ + 1, + ]) + fne9: ([ + 1, + ..., + ] != [ + 1, + 2, + ]) + fne10: ([ + 1, + 2, + ] != [ + 1, + ..., + ]) + fne11: ([ + 1, + ..., + ] != [ + 1, + 2, + ..., + ]) + eqIncomplete1: ([ + 1, + ] == [ + string, + ]) + neIncomplete1: ([ + 1, + ] != [ + string, + ]) +} diff --git a/internal/core/compile/testdata/sync/packages/builtin.txtar b/internal/core/compile/testdata/sync/packages/builtin.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/packages/builtin.txtar @@ -0,0 +1,15 @@ +#inlinetest:exclude imports an undefined package "x/y"; the inline runner cannot +# compile the source when package resolution fails. +-- x.cue -- +import "x/y" + +foo: [ + y, +] +-- out/compile -- +--- x.cue +{ + foo: [ + 〈import;"x/y"〉, + ] +} diff --git a/internal/core/compile/testdata/sync/packages/embed.txtar b/internal/core/compile/testdata/sync/packages/embed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/packages/embed.txtar @@ -0,0 +1,33 @@ +exec cue eval ./pkg:foo +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- in.cue -- +package foo + +import "mod.test/pkg:bar" + +bar +z: 3 + +@test(eq, {z: 3, foo: {y: 2, x: 1}, y: 2, x: 1}) +-- pkg/bar.cue -- +package bar + +import "mod.test/pkg:baz" + +foo: { + baz + y: 2 +} +foo +-- pkg/baz.cue -- +package baz + +x: 1 +-- out/compile -- +--- in.cue +{ + 〈import;"mod.test/pkg:bar"〉 + z: 3 +} diff --git a/internal/core/compile/testdata/sync/packages/issue398.txtar b/internal/core/compile/testdata/sync/packages/issue398.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/packages/issue398.txtar @@ -0,0 +1,32 @@ +# Tests that transitive package imports are correctly propagated. When foo imports +# bar which imports baz, evaluating foo should include values from all three +# packages rather than omitting the transitively imported baz contents. +# https://cuelang.org/issue/398 +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- foo.cue -- +package foo + +import "mod.test/pkg:bar" + +bar +zz: 3 +@test(eq, {zz: 3, yy: 2, xx: 1}) +-- pkg/bar.cue -- +package bar + +import "mod.test/pkg:baz" + +baz +yy: 2 +-- pkg/baz.cue -- +package baz + +xx: 1 +-- out/compile -- +--- foo.cue +{ + 〈import;"mod.test/pkg:bar"〉 + zz: 3 +} diff --git a/internal/core/compile/testdata/sync/packages/sub.txtar b/internal/core/compile/testdata/sync/packages/sub.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/packages/sub.txtar @@ -0,0 +1,24 @@ +exec cue eval ./pkg:foo +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- in.cue -- +package test + +import pkg2 "mod.test/foo/pkg1" + +#pkg1: pkg2.Object + +"Hello \(#pkg1)!" + +@test(eq, {"Hello World!", #pkg1: "World"}) +-- foo/pkg1/file.cue -- +package pkg1 + +Object: "World" +-- out/compile -- +--- in.cue +{ + #pkg1: 〈import;"mod.test/foo/pkg1"〉.Object + "Hello \(〈0;#pkg1〉)!" +} diff --git a/internal/core/compile/testdata/sync/references/alias.txtar b/internal/core/compile/testdata/sync/references/alias.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/alias.txtar @@ -0,0 +1,364 @@ +-- in.cue -- +@experiment(aliasv2) + +// Basic postfix alias - simple form +a1~X1: { + foo: 1 +} +b1: X1.foo + 2 @test(eq, 3) + +a1p~(X1p): { + foo: 1 +} +b1p: X1p.foo + 2 @test(eq, 3) + + +// Basic postfix alias - dual form +a2~(K2,V2): { + name: K2 + val: V2.foo +} +a2: {foo: 42} @test(eq, {name: "a2", val: 42, foo: 42}) + +// Postfix alias with _ for field +a3~(K3,_): { + foo: 1 +} +b3: K3 @test(eq, "a3") + +// Postfix alias with _ for label +a4~(_,V4): { + foo: 1 +} +b4: V4.foo + 2 @test(eq, 3) + +// Dynamic field with postfix alias +("dyn")~X5: { + foo: 1 +} +b5: X5.foo + 10 @test(eq, 11) + +// Dynamic field with dual form +("dyn2")~(K6,V6): { + name: K6 + val: V6.foo +} +dyn2: {foo: 100} @test(eq, {foo: 100, name: "dyn2", val: 100}) + +// Pattern constraint with postfix alias - scoped to value only +// The field alias should create a recursive reference +pattern: { + [string]~(LabelAlias,_): { + labelRef: LabelAlias + } + foo: {} + @test(eq, {foo: {labelRef: "foo"}}) +} + +// Pattern constraint with dual form +pattern2: { + [string]~(LabelName,FieldRef): { + labelVal: LabelName + fieldVal: FieldRef.data + } + foo: {data: 1} + bar: {data: 2} + @test(eq, { + foo: {data: 1, labelVal: "foo", fieldVal: 1} + bar: {data: 2, labelVal: "bar", fieldVal: 2} + }) +} + +// Pattern constraint - field alias creates recursive reference +// TODO: fix this. Note that this is also broken with old aliases. +// pattern3recursive: { +// [string]~(_, FieldAlias): { +// // FieldAlias refers to this field, creating recursion +// recursive: FieldAlias +// } +// foo: {} +// } + +// Nested structs with postfix aliases +nested~X7: { + inner~Y7: { + a: 1 + } + b: Y7.a + X7.inner.a +} +result1: nested.b @test(eq, 2) + +// Multiple fields with aliases referencing each other +multi: { + a~A8: 1 + b~B8: A8 + 2 + c: B8 + 3 + @test(eq, {a: 1, b: 3, c: 6}) +} + +// Postfix alias in comprehension +comp: { + items: [1, 2, 3] + for i, v in items { + "\(i)"~X9: { + index: i + value: v + double: X9.value * 2 + } + } + @test(eq, { + items: [1, 2, 3] + "0": {index: 0, value: 1, double: 2} + "1": {index: 1, value: 2, double: 4} + "2": {index: 2, value: 3, double: 6} + }) +} + +// Postfix alias with constraints +constrained~X10?: { + required: true +} +test1: X10.required @test(err, code=incomplete, contains="cannot reference optional field: constrained", pos=[0:8]) @test(err, code=incomplete, contains="cannot reference optional field: %s", args=[constrained], pos=[0:8]) + +// Interpolation with postfix alias +"\("inter")"~X11: { + foo: 1 +} +b6: X11.foo + 5 @test(eq, 6) + +// Postfix alias with optional and default +opt~X12?: { + a: 1 + b: X12 @test(err, code=incomplete, contains="field not found: opt", pos=[]) +} @test(err, code=incomplete, contains="field not found: %v", args=[opt], pos=[]) + +// TODO: seemingly wrong semantics, but matches old behavior. +def~Y13: { + b: 2 + c: Y13.b +} | {b: 3} @test(eq, {b: 2, c: 2} | {b: 3}) + +// Pattern with blank identifier - label only visible in value +pattern3: { + [string]~(LN14,_): { + labelName: LN14 + } + test: {} + + @test(eq, {test: {labelName: "test"}}) +} + +// Pattern with blank identifier - field only visible in value +pattern4: { + [string]~(_,FR15): { + fieldRef: FR15.x + } + test: {x: 99} + @test(eq, {test: {x: 99, fieldRef: 99}}) +} + +// Multiple aliases in same scope +same: { + a~A16: 1 + b~B16: 2 + c: A16 + B16 + + @test(eq, {a: 1, b: 2, c: 3}) +} + +// Alias referencing earlier alias +chain~X17: { + a: 1 +} @test(eq, {a: 1}) +chain2~Y18: { + ref: X17.a +} @test(eq, {ref: 1}) +result2: Y18.ref @test(eq, 1) + +// Postfix alias with list value +list~X19: [1, 2, 3] +b7: X19[0] + X19[1] @test(eq, 3) + +// Postfix alias with disjunction +disj~X20: 1 | 2 | 3 +b8: X20 @test(eq, 1 | 2 | 3) + +// Nested pattern constraints with aliases +deep: { + [string]~(OuterLabel,_): { + [string]~(InnerLabel, InnerField): { + outer: OuterLabel + inner: InnerLabel + value: InnerField.x + } + foo: {x: 1} + } + bar: {} + @test(eq, { + bar: { + foo: { + x: 1 + outer: "bar" + inner: "foo" + value: 1 + } + } + }) +} + +// Alias with definition +#Def~X21: { + field: 42 +} +usedef: X21.field @test(eq, 42) +-- out/compile -- +--- in.cue +{ + a1: { + foo: 1 + } + b1: (〈0;a1〉.foo + 2) + a1p: { + foo: 1 + } + b1p: (〈0;a1p〉.foo + 2) + a2: { + name: "a2" + val: 〈1;a2〉.foo + } + a2: { + foo: 42 + } + a3: { + foo: 1 + } + b3: "a3" + a4: { + foo: 1 + } + b4: (〈0;a4〉.foo + 2) + "dyn": { + foo: 1 + } + b5: (〈0;("dyn")〉.foo + 10) + "dyn2": { + name: 〈1;-〉 + val: 〈1;("dyn2")〉.foo + } + dyn2: { + foo: 100 + } + pattern: { + [string]: { + labelRef: 〈1;-〉 + } + foo: {} + } + pattern2: { + [string]: { + labelVal: 〈1;-〉 + fieldVal: 〈1;(〈0;-〉)〉.data + } + foo: { + data: 1 + } + bar: { + data: 2 + } + } + nested: { + inner: { + a: 1 + } + b: (〈0;inner〉.a + 〈1;nested〉.inner.a) + } + result1: 〈0;nested〉.b + multi: { + a: 1 + b: (〈0;a〉 + 2) + c: (〈0;b〉 + 3) + } + comp: { + items: [ + 1, + 2, + 3, + ] + for i, v in 〈0;items〉 { + "\(〈1;i〉)": { + index: 〈2;i〉 + value: 〈2;v〉 + double: (〈1;("\(〈1;i〉)")〉.value * 2) + } + } + } + constrained?: { + required: true + } + test1: 〈0;constrained〉.required + "\("inter")": { + foo: 1 + } + b6: (〈0;("\("inter")")〉.foo + 5) + opt?: { + a: 1 + b: 〈1;opt〉 + } + def: ({ + b: 2 + c: 〈1;def〉.b + }|{ + b: 3 + }) + pattern3: { + [string]: { + labelName: 〈1;-〉 + } + test: {} + } + pattern4: { + [string]: { + fieldRef: 〈1;(〈0;-〉)〉.x + } + test: { + x: 99 + } + } + same: { + a: 1 + b: 2 + c: (〈0;a〉 + 〈0;b〉) + } + chain: { + a: 1 + } + chain2: { + ref: 〈1;chain〉.a + } + result2: 〈0;chain2〉.ref + list: [ + 1, + 2, + 3, + ] + b7: (〈0;list〉[0] + 〈0;list〉[1]) + disj: (1|2|3) + b8: 〈0;disj〉 + deep: { + [string]: { + [string]: { + outer: 〈2;-〉 + inner: 〈1;-〉 + value: 〈1;(〈0;-〉)〉.x + } + foo: { + x: 1 + } + } + bar: {} + } + #Def: { + field: 42 + } + usedef: 〈0;#Def〉.field +} diff --git a/internal/core/compile/testdata/sync/references/alias_err.txtar b/internal/core/compile/testdata/sync/references/alias_err.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/alias_err.txtar @@ -0,0 +1,60 @@ +#inlinetest:exclude compile-time alias errors prevent CUE source compilation; @test(err) requires successful compile +-- old.cue -- +// issue2527: self-referential alias in key `x=(x):` caused an "unreachable" +// panic (https://cuelang.org/issue/2527). +issue2527: { + x=(x): 3 +} +// issue2094: alias Y referring to a dynamic-key field X declared afterward +// caused a panic due to ordering sensitivity (https://cuelang.org/issue/2094). +issue2094: { + Y=(X): string + X=("foo"): "bar" +} +-- new.cue -- +@experiment(aliasv2) + +// issue2527: self-referential alias in key `(x)~x:` caused an "unreachable" +// panic (https://cuelang.org/issue/2527). +issue2527: { + (x)~x: 3 +} +// issue2094: alias Y referring to a dynamic-key field X declared afterward +// caused a panic due to ordering sensitivity (https://cuelang.org/issue/2094). +issue2094: { + (X)~Y: string + ("foo")~X: "bar" +} +-- out/compile -- +issue2527: cyclic reference in field alias: + ./new.cue:6:3 +issue2094: cyclic reference in field alias: + ./new.cue:11:3 +issue2094: unreferenced alias or let clause Y: + ./new.cue:11:5 +issue2527: cyclic reference in field alias: + ./old.cue:4:5 +issue2094: unreferenced alias or let clause Y: + ./old.cue:9:2 +issue2094: cyclic reference in field alias: + ./old.cue:9:5 +--- new.cue +{ + issue2527: { + 〈0;(_|_(cyclic reference in field alias))〉: 3 + } + issue2094: { + 〈0;("foo")〉: string + "foo": "bar" + } +} +--- old.cue +{ + issue2527: { + 〈0;(_|_(cyclic reference in field alias))〉: 3 + } + issue2094: { + 〈0;("foo")〉: string + "foo": "bar" + } +} diff --git a/internal/core/compile/testdata/sync/references/embed_self.txtar b/internal/core/compile/testdata/sync/references/embed_self.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/embed_self.txtar @@ -0,0 +1,10 @@ +-- in.cue -- +Foo: {} @test(eq, {}) + +Foo +-- out/compile -- +--- in.cue +{ + Foo: {} + 〈0;Foo〉 +} diff --git a/internal/core/compile/testdata/sync/references/errors.txtar b/internal/core/compile/testdata/sync/references/errors.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/errors.txtar @@ -0,0 +1,57 @@ +-- references.cue -- +missingField: { + a: {} + r: a.b @test(err, code=incomplete, contains="undefined field: b", pos=[0:7]) +} + +missingFieldClosed: { + #a: {} + r: #a.b @test(err, code=eval, contains="undefined field: b", pos=[0:8]) +} + +missingFieldNested: { + a: {} + // Must refer to `b` in error + r: a.b.c @test(err, code=incomplete, contains="undefined field: b", pos=[0:7]) +} + +missingFieldNestedClosed: { + #a: {} + + // Must refer to `d` in error + r: #a.d.c @test(err, code=eval, contains="undefined field: d", pos=[0:8]) +} + +missingFieldNestedInInterpolation: { + a: {} + // Must refer to `b` in error + r1: "\(a.b.c)" @test(err, code=incomplete, contains="invalid interpolation: undefined field: b", pos=[0:6, 0:11]) + // Must refer to `d` in error: in case only one error is shown for a + // a location, ensure it doesn't alphabetically sort and pick `c` instead. + r2: "\(a.d.c)" @test(err, code=incomplete, contains="invalid interpolation: undefined field: d", pos=[0:6, 0:11]) +} +-- out/compile -- +--- references.cue +{ + missingField: { + a: {} + r: 〈0;a〉.b + } + missingFieldClosed: { + #a: {} + r: 〈0;#a〉.b + } + missingFieldNested: { + a: {} + r: 〈0;a〉.b.c + } + missingFieldNestedClosed: { + #a: {} + r: 〈0;#a〉.d.c + } + missingFieldNestedInInterpolation: { + a: {} + r1: "\(〈0;a〉.b.c)" + r2: "\(〈0;a〉.d.c)" + } +} diff --git a/internal/core/compile/testdata/sync/references/incomplete.txtar b/internal/core/compile/testdata/sync/references/incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/incomplete.txtar @@ -0,0 +1,64 @@ +-- in.cue -- +comprehensions: { + a: {} + b: { + if a.b { + } + } @test(err, code=incomplete, contains="undefined field: b", pos=[1:8]) + c: { + for x in a.b {x} + } @test(err, code=incomplete, contains="comprehensions.c: undefined field: b", pos=[1:14]) +} + +openStruct: { + a: {} + b: a.c @test(err, code=incomplete, contains="openStruct.b: undefined field: c", pos=[0:7]) +} + +selectFromTop: { + top: _ + a: top.foo @test(err, code=incomplete, contains="top.foo undefined as top is incomplete", pos=[0:7]) +} + +indexOnTop: { + top: _ + a: top[2] @test(err, code=incomplete, contains="top[2] undefined as top is incomplete", pos=[0:7]) +} + +incompleteIndex: { + top: _ + a: [1][top] @test(err, code=eval, contains="invalid index top (invalid type _)", pos=[0:7, 0:11]) +} +-- out/compile -- +--- in.cue +{ + comprehensions: { + a: {} + b: { + if 〈1;a〉.b {} + } + c: { + for _, x in 〈1;a〉.b { + 〈1;x〉 + } + } + } + openStruct: { + a: {} + b: 〈0;a〉.c + } + selectFromTop: { + top: _ + a: 〈0;top〉.foo + } + indexOnTop: { + top: _ + a: 〈0;top〉[2] + } + incompleteIndex: { + top: _ + a: [ + 1, + ][〈0;top〉] + } +} diff --git a/internal/core/compile/testdata/sync/references/index.txtar b/internal/core/compile/testdata/sync/references/index.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/index.txtar @@ -0,0 +1,88 @@ +-- in.cue -- +intIndex: [2][0] @test(eq, 2) +stringIndex: {foo: "bar"}["foo"] @test(eq, "bar") + +stringOfNumberIndex: {"3": 3}["3"] @test(eq, 3) + +indexToDefault: (*[0] | {})[0] @test(eq, 0) +outOfBoundsDisjunction: (*[] | {})[1] @test(err, code=eval, contains="index out of range [1] with length 0", pos=[0:36]) + +// Ensure these are errors. +indexDoesNotDistribute: (*[] | [1])[0] @test(err, code=eval, contains="index out of range [0] with length 0", pos=[0:37]) +doesNotDistributeType: { + l: [] + a: (*l | {"3": 3})["3"] @test(err, code=eval, contains="undefined field", pos=[0:21]) +} + +stringIndexToList: [2][""] @test(err, code=eval, contains="undefined field", pos=[0:24]) +indexOutOfBounds2: 2[2] @test(err, code=eval, contains="invalid operand 2 (found int, want list or struct)", pos=[0:20]) +booleanIndex: [][true] @test(err, code=eval, contains="invalid index true (invalid type bool)", pos=[0:20, 0:23]) +indexOutOfBounds3: [1, 2, 3][4] @test(err, code=eval, contains="index out of range [4] with length 3", pos=[0:30]) +negativeIndex: [1, 2, 3][-1] @test(err, code=eval, contains="invalid index -1 (index must be non-negative)", pos=[0:20, 0:30]) + +varIndexTooLarge: { + n: 3 + a: [1, 2, 3][n] @test(err, code=eval, contains="index out of range [3] with length 3", pos=[0:15]) +} + +varNegativeIndex: { + n: -1 + a: [1, 2, 3][n] @test(err, code=eval, contains="index n out of range [-1]", pos=[0:5, -1:5, 0:15]) +} +-- out/compile -- +--- in.cue +{ + intIndex: [ + 2, + ][0] + stringIndex: { + foo: "bar" + }["foo"] + stringOfNumberIndex: { + "3": 3 + }["3"] + indexToDefault: (*[ + 0, + ]|{})[0] + outOfBoundsDisjunction: (*[]|{})[1] + indexDoesNotDistribute: (*[]|[ + 1, + ])[0] + doesNotDistributeType: { + l: [] + a: (*〈0;l〉|{ + "3": 3 + })["3"] + } + stringIndexToList: [ + 2, + ][""] + indexOutOfBounds2: 2[2] + booleanIndex: [][true] + indexOutOfBounds3: [ + 1, + 2, + 3, + ][4] + negativeIndex: [ + 1, + 2, + 3, + ][-1] + varIndexTooLarge: { + n: 3 + a: [ + 1, + 2, + 3, + ][〈0;n〉] + } + varNegativeIndex: { + n: -1 + a: [ + 1, + 2, + 3, + ][〈0;n〉] + } +} diff --git a/internal/core/compile/testdata/sync/references/labels.txtar b/internal/core/compile/testdata/sync/references/labels.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/labels.txtar @@ -0,0 +1,273 @@ +-- in.cue -- +// Label aliases + +// direct +a: [X=string]: X +a: bar: _ +@test(eq, {bar: "bar"}, at=a) + +// in struct +b: [X=string]: {X} +b: bar: _ +@test(eq, {bar: "bar"}, at=b) + +// in structs +c: [X=string]: X +c: [Y=string]: {{{Y}}} +c: bar: _ +@test(eq, {bar: "bar"}, at=c) + +// in sub field +d: [X=string]: name: X +d: bar: {} +@test(eq, {bar: {name: "bar"}}, at=d) + +// nested +e: [X=string]: [Y=string]: X + Y +e: foo: bar: _ +@test(eq, {foo: {bar: "foobar"}}, at=e) + +patternField: t1: { + r=[string]: {b: r | null} + a: {r: 0} + @test(eq, {a: {r: 0, b: null}}) +} + +patternField: t2: { + a: {r: 0} + x=[string]: {z: 1, b: x.z} + @test(eq, {a: {r: 0, z: 1, b: 1}}) +} + +// Field aliases + +bar: 3 +f1: C="foo\(bar)": { + name: "xx" + foo: C.name +} +@test(eq, { + foo3: { + name: "xx" + foo: "xx" + foo3baz: {name: "xx", a: "xx", b: "xx"} + } +}, at=f1) + +// nested +f1: D="foo\(bar)": E="foo\(bar)baz": { + name: "xx" + a: D["foo\(bar)baz"].name + b: E.name +} + +// Combo + +c1: C="foo\(bar)": [D=string]: { + name: D + foo: C.x.name +} +c1: foo3: x: _ +@test(eq, {foo3: {x: {name: "x", foo: "x"}}}, at=c1) + + +emptyLabel: { + "": 1 + a: emptyLabel[""] + @test(eq, {"": 1, a: 1}) +} + +underscore: a: { + // Issue #1454 + foo: #Foo + foo: "_": "bar" + #Foo: [=~""]: string + @test(eq, {foo: {"_": "bar"}, #Foo: {}}) +} + +underscore: c: { + foo: "_": "any" + foo: [=~""]: string + @test(eq, {foo: {"_": "any"}}) +} + +underscore: d: { + bar: "_": "any" + #bar: [string]: string + bar: #bar + @test(eq, {bar: {"_": "any"}, #bar: {}}) +} + +underscore: e: { + baz: "_h": "any" + #baz: [=~"_"]: string + baz: #baz + @test(eq, {baz: {"_h": "any"}, #baz: {}}) +} + +// TODO: support. Also not yet supported in old implementation. +// c10: { +// C=[string]: { +// name: "x" +// foo: C.name +// } +// } +// c2: c1 & { x: _ } + +invalidPattern: { + [=~"BAD)" & =~"x"]: string + y: 123 + @test(err, code=eval, contains="invalid regexp", pos=[1:22]) +} +-- out/compile -- +--- in.cue +{ + a: { + [string]: 〈0;-〉 + } + a: { + bar: _ + } + b: { + [string]: { + 〈1;-〉 + } + } + b: { + bar: _ + } + c: { + [string]: 〈0;-〉 + } + c: { + [string]: { + { + { + 〈3;-〉 + } + } + } + } + c: { + bar: _ + } + d: { + [string]: { + name: 〈1;-〉 + } + } + d: { + bar: {} + } + e: { + [string]: { + [string]: (〈1;-〉 + 〈0;-〉) + } + } + e: { + foo: { + bar: _ + } + } + patternField: { + t1: { + [string]: { + b: (〈1;(〈0;-〉)〉|null) + } + a: { + r: 0 + } + } + } + patternField: { + t2: { + a: { + r: 0 + } + [string]: { + z: 1 + b: 〈1;(〈0;-〉)〉.z + } + } + } + bar: 3 + f1: { + "foo\(〈1;bar〉)": { + name: "xx" + foo: 〈1;("foo\(〈1;bar〉)")〉.name + } + } + f1: { + "foo\(〈1;bar〉)": { + "foo\(〈2;bar〉)baz": { + name: "xx" + a: 〈2;("foo\(〈1;bar〉)")〉["foo\(〈3;bar〉)baz"].name + b: 〈1;("foo\(〈2;bar〉)baz")〉.name + } + } + } + c1: { + "foo\(〈1;bar〉)": { + [string]: { + name: 〈1;-〉 + foo: 〈2;("foo\(〈1;bar〉)")〉.x.name + } + } + } + c1: { + foo3: { + x: _ + } + } + emptyLabel: { + "": 1 + a: 〈1;emptyLabel〉[""] + } + underscore: { + a: { + foo: 〈0;#Foo〉 + foo: { + "_": "bar" + } + #Foo: { + [=~""]: string + } + } + } + underscore: { + c: { + foo: { + "_": "any" + } + foo: { + [=~""]: string + } + } + } + underscore: { + d: { + bar: { + "_": "any" + } + #bar: { + [string]: string + } + bar: 〈0;#bar〉 + } + } + underscore: { + e: { + baz: { + "_h": "any" + } + #baz: { + [=~"_"]: string + } + baz: 〈0;#baz〉 + } + } + invalidPattern: { + [(=~"BAD)" & =~"x")]: string + y: 123 + } +} diff --git a/internal/core/compile/testdata/sync/references/labelstop.txtar b/internal/core/compile/testdata/sync/references/labelstop.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/labelstop.txtar @@ -0,0 +1,16 @@ +TODO: add matching when bulk optional fields are allowed +alongside other fields. +-- in.cue -- +{[X=string]: baz: X} +bar: {} +@test(eq, {bar: baz: "bar"}) +-- out/compile -- +--- in.cue +{ + { + [string]: { + baz: 〈1;-〉 + } + } + bar: {} +} diff --git a/internal/core/compile/testdata/sync/references/let.txtar b/internal/core/compile/testdata/sync/references/let.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/let.txtar @@ -0,0 +1,304 @@ +-- in.cue -- +import "list" + +a1list: [{1}] +let A1 = a1list +a1: 100*A1[0] + A1[0] @test(eq, 101) + +a2list: [{2}] +let A2 = a2list +a2: b: 100*A2[0] + A2[0] @test(eq, 202) + +a3list: [{3}] +let A3 = a3list +a3: b: c: 100*A3[0] + A3[0] @test(eq, 303) + +a4list: [{4}] +let A4 = a4list +a4: [for x in A4 {v: 404}] @test(eq, [{v: 404}]) + +a5list: [{5}] +let A5 = a5list +a5: b: [for x in A5 {v: 505}] @test(eq, [{v: 505}]) + +a6list: [{6}] +let A6 = a6list +a6: b: c: [for x in A6 {v: 606}] @test(eq, [{v: 606}]) + +a7list: [{7}] +let A7 = a7list +a7: {for x in A7 {v: 707}} @test(eq, {v: 707}) + +a8list: [{8}] +let A8 = a8list +a8: b: {for x in A8 {v: 808}} @test(eq, {v: 808}) + +a9list: [{9}] +let A9 = a9list +a9: b: c: {for x in A9 {v: 909}} @test(eq, {v: 909}) + +// Issue #609: +// When a let value resolved to an incomplete value, it should pass this +// incomplete status to the expression in which it used. But 609 reported +// a gobbling of this incomplete status. The problem seemed to be not +// exclusive to the use of let, though. +incompleteLet: { + input: [1, 2, 3, 4, 5] + + last: { + min: list.Min(input) + max: list.Max(input) + } + + bar: { + let mn = last.min + let mx = list.max + + min: mn + max: mx @test(err, code=incomplete, contains="undefined field: max", pos=[-3:17]) + } + + x: { + if list.max < 0 { + } + } + @test(eq, { + input: [1, 2, 3, 4, 5] + last: {min: 1, max: 5} + bar: { + min: 1 + max: _|_ @test(err, code=incomplete, contains="incompleteLet.bar.max: undefined field: max", pos=[54:17]) + } + x: _|_ @test(err, code=incomplete, contains="incompleteLet.x: undefined field: max", pos=[61:11]) + }) +} + +// Let references should also work inside embedded scalars. +// Issue #1955 +scalarReference: { + inScalar: p0: { + 5 + let x = 6 + #b: x + @test(eq, {5, #b: 6}) + } + inScalar: p1: { + #b: x + let x = 6 + 5 + @test(eq, {5, #b: 6}) + } + inList: p0: { + let x = { a: 1 } + [ x ] + @test(eq, [{a: 1}]) + } + inList: p1: { + [ x ] + let x = { a: 1 } + @test(eq, [{a: 1}]) + } +} + +// Strange let declaration behavior: accessing the last element of a list via +// a let-bound variable failed when the let appeared before the list definition. +// https://cuelang.org/issue/1116 +issue1116: { + a: { + #a: ["a", "b"] + let List = #a + List[len(List)-1] + @test(eq, {"b", #a: ["a", "b"]}) + } + b: { + let List = #a + List[len(List)-1] + #a: ["a", "b"] + @test(eq, {"b", #a: ["a", "b"]}) + } +} +-- out/compile -- +--- in.cue +{ + a1list: [ + { + 1 + }, + ] + let A1#1 = 〈0;a1list〉 + a1: ((100 * 〈0;let A1#1〉[0]) + 〈0;let A1#1〉[0]) + a2list: [ + { + 2 + }, + ] + let A2#2 = 〈0;a2list〉 + a2: { + b: ((100 * 〈1;let A2#2〉[0]) + 〈1;let A2#2〉[0]) + } + a3list: [ + { + 3 + }, + ] + let A3#3 = 〈0;a3list〉 + a3: { + b: { + c: ((100 * 〈2;let A3#3〉[0]) + 〈2;let A3#3〉[0]) + } + } + a4list: [ + { + 4 + }, + ] + let A4#4 = 〈0;a4list〉 + a4: [ + for _, x in 〈1;let A4#4〉 { + v: 404 + }, + ] + a5list: [ + { + 5 + }, + ] + let A5#5 = 〈0;a5list〉 + a5: { + b: [ + for _, x in 〈2;let A5#5〉 { + v: 505 + }, + ] + } + a6list: [ + { + 6 + }, + ] + let A6#6 = 〈0;a6list〉 + a6: { + b: { + c: [ + for _, x in 〈3;let A6#6〉 { + v: 606 + }, + ] + } + } + a7list: [ + { + 7 + }, + ] + let A7#7 = 〈0;a7list〉 + a7: { + for _, x in 〈1;let A7#7〉 { + v: 707 + } + } + a8list: [ + { + 8 + }, + ] + let A8#8 = 〈0;a8list〉 + a8: { + b: { + for _, x in 〈2;let A8#8〉 { + v: 808 + } + } + } + a9list: [ + { + 9 + }, + ] + let A9#9 = 〈0;a9list〉 + a9: { + b: { + c: { + for _, x in 〈3;let A9#9〉 { + v: 909 + } + } + } + } + incompleteLet: { + input: [ + 1, + 2, + 3, + 4, + 5, + ] + last: { + min: 〈import;list〉.Min(〈1;input〉) + max: 〈import;list〉.Max(〈1;input〉) + } + bar: { + let mn#A = 〈1;last〉.min + let mx#B = 〈import;list〉.max + min: 〈0;let mn#A〉 + max: 〈0;let mx#B〉 + } + x: { + if (〈import;list〉.max < 0) {} + } + } + scalarReference: { + inScalar: { + p0: { + 5 + let x#C = 6 + #b: 〈0;let x#C〉 + } + } + inScalar: { + p1: { + #b: 〈0;let x#D〉 + let x#D = 6 + 5 + } + } + inList: { + p0: { + let x#E = { + a: 1 + } + [ + 〈1;let x#E〉, + ] + } + } + inList: { + p1: { + [ + 〈1;let x#F〉, + ] + let x#F = { + a: 1 + } + } + } + } + issue1116: { + a: { + #a: [ + "a", + "b", + ] + let List#10 = 〈0;#a〉 + 〈0;let List#10〉[(len(〈0;let List#10〉) - 1)] + } + b: { + let List#11 = 〈0;#a〉 + 〈0;let List#11〉[(len(〈0;let List#11〉) - 1)] + #a: [ + "a", + "b", + ] + } + } +} diff --git a/internal/core/compile/testdata/sync/references/letcycle.txtar b/internal/core/compile/testdata/sync/references/letcycle.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/letcycle.txtar @@ -0,0 +1,161 @@ +#inlinetest:exclude mutually recursive let bindings produce compile-time cycle errors +# which prevent the inline runner from compiling the source. Issue #1042. +#expandLetExpr: true +-- in.cue -- +import "list" + +cycles: { + a: { + let A = {c: B} + let B = A + out: A + } + + b: { + let A = {c: B} + let B = {A.c} + out: A + } + + issue1042: { + #FullAdder: { + // IN + a: bool + b: bool + c: bool + // OUT + sum: bool + carry: bool + } + + #Add16: { + a: [bool] * 16 + b: [bool] * 16 + out: [bool] * 16 + + let fulladders = [ + for i in list.Range(0, 4, 1) { + #FullAdder & {"a": a[i], "b": b[i], c: carries[i]} + }, + ] + let carries = [ + false, + for i in list.Range(0, 4, 1) {fulladders[i].carry}, + ] + out: [ + for i in list.Range(0, 4, 1) {fulladders[i].sum}, + ] + } + } +} +-- out/compile -- +cycles.a.let[].c: cyclic references in let clause or alias: + ./in.cue:5:15 +cycles.b.let[].c: cyclic references in let clause or alias: + ./in.cue:11:15 +cycles.issue1042.#Add16.let[].for[].c: cyclic references in let clause or alias: + ./in.cue:34:45 +--- in.cue +{ + cycles: { + a: { + let A#1 = { + c: 〈1;let B#2〉=>〈0;let A#1〉=>{ + c: 〈1;let B#2〉=>_|_(cyclic references in let clause or alias) + } + } + let B#2 = 〈0;let A#1〉=>{ + c: 〈1;let B#2〉=>_|_(cyclic references in let clause or alias) + } + out: 〈0;let A#1〉=>{ + c: 〈1;let B#2〉=>_|_(cyclic references in let clause or alias) + } + } + b: { + let A#3 = { + c: 〈1;let B#4〉=>{ + 〈1;let A#3〉=>{ + c: 〈1;let B#4〉=>_|_(cyclic references in let clause or alias) + }.c + } + } + let B#4 = { + 〈1;let A#3〉=>{ + c: 〈1;let B#4〉=>_|_(cyclic references in let clause or alias) + }.c + } + out: 〈0;let A#3〉=>{ + c: 〈1;let B#4〉=>_|_(cyclic references in let clause or alias) + } + } + issue1042: { + #FullAdder: { + a: bool + b: bool + c: bool + sum: bool + carry: bool + } + #Add16: { + a: ([ + bool, + ] * 16) + b: ([ + bool, + ] * 16) + out: ([ + bool, + ] * 16) + let fulladders#5 = [ + for _, i in 〈import;list〉.Range(0, 4, 1) { + (〈4;#FullAdder〉 & { + a: 〈4;a〉[〈2;i〉] + b: 〈4;b〉[〈2;i〉] + c: 〈4;let carries#6〉=>[ + false, + for _, i in 〈import;list〉.Range(0, 4, 1) { + 〈3;let fulladders#5〉=>[ + for _, i in 〈import;list〉.Range(0, 4, 1) { + (〈4;#FullAdder〉 & { + a: 〈4;a〉[〈2;i〉] + b: 〈4;b〉[〈2;i〉] + c: 〈4;let carries#6〉=>_|_(cyclic references in let clause or alias)[〈2;i〉] + }) + }, + ][〈1;i〉].carry + }, + ][〈2;i〉] + }) + }, + ] + let carries#6 = [ + false, + for _, i in 〈import;list〉.Range(0, 4, 1) { + 〈3;let fulladders#5〉=>[ + for _, i in 〈import;list〉.Range(0, 4, 1) { + (〈4;#FullAdder〉 & { + a: 〈4;a〉[〈2;i〉] + b: 〈4;b〉[〈2;i〉] + c: 〈4;let carries#6〉=>_|_(cyclic references in let clause or alias)[〈2;i〉] + }) + }, + ][〈1;i〉].carry + }, + ] + out: [ + for _, i in 〈import;list〉.Range(0, 4, 1) { + 〈3;let fulladders#5〉=>[ + for _, i in 〈import;list〉.Range(0, 4, 1) { + (〈4;#FullAdder〉 & { + a: 〈4;a〉[〈2;i〉] + b: 〈4;b〉[〈2;i〉] + c: 〈4;let carries#6〉=>_|_(cyclic references in let clause or alias)[〈2;i〉] + }) + }, + ][〈1;i〉].sum + }, + ] + } + } + } +} diff --git a/internal/core/compile/testdata/sync/references/optional.txtar b/internal/core/compile/testdata/sync/references/optional.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/optional.txtar @@ -0,0 +1,27 @@ +-- in.cue -- +t1: a: { + foo?: int + + b: foo @test(err, code=incomplete) +} +t2: a: { + b: foo @test(err, code=incomplete) + + foo?: int +} +-- out/compile -- +--- in.cue +{ + t1: { + a: { + foo?: int + b: 〈0;foo〉 + } + } + t2: { + a: { + b: 〈0;foo〉 + foo?: int + } + } +} diff --git a/internal/core/compile/testdata/sync/references/package.txtar b/internal/core/compile/testdata/sync/references/package.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/package.txtar @@ -0,0 +1,32 @@ +-- cue.mod/module.cue -- +module: "mod.test" +language: version: "v0.9.0" +-- in.cue -- +package exitcode + +import ( + pkg "foo.com/example" +) + +a: 1 + +incomplete: pkg.Settings +@test(eq, { + a: 1 + incomplete: {} +}) +-- cue.mod/pkg/foo.com/example/example.cue -- +package example + +// An incomplete error in a package is not transferred to a +// package that is using it. +// +// Issue #550 +blah: Settings.anyKey +Settings: {} +-- out/compile -- +--- in.cue +{ + a: 1 + incomplete: 〈import;"foo.com/example"〉.Settings +} diff --git a/internal/core/compile/testdata/sync/references/self.txtar b/internal/core/compile/testdata/sync/references/self.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/self.txtar @@ -0,0 +1,208 @@ +Test various self reference cases. +-- in.cue -- +@experiment(aliasv2) + +// Basic self usage - top level +a: self.b @test(eq, "hello") +b: "hello" + +// Nested self usage - should refer to x struct +x: { + y: self.z + z: "world" +} @test(eq, {y: "world", z: "world"}) + +// Shorthand notation - self should refer to foo struct +foo: bar: self.baz @test(eq, "greeting") +foo: baz: "greeting" @test(eq, "greeting") // TODO(inline): reference marking does not work with "self" + +// Multiple levels of nesting +nested: { + level1: { + field: self.value + value: "level1 value" + } +} @test(eq, { + level1: { + field: "level1 value" + value: "level1 value" + } +}) + +// Self in list context +listTest: { + items: [1, 2, self[0], self[1]] + first: 1 + second: 2 +} @test(eq, { + items: [1, 2, 1, 2] + first: 1 + second: 2 +}) + +// Self with computed selectors +computed: { + key: "test" + value: self["key"] +} @test(eq, {key: "test", value: "test"}) + +// Cyclic reference detection +cycle: self.cycle @test(eq, _) + +-- list.cue -- +@experiment(aliasv2) +import "list" + +#IntStrings: {list.Repeat([int, string], div(len(self), 2))} +listCheck: ok1: #IntStrings +listCheck: ok1: [1, "foo", 2, "bar"] @test(eq, [1, "foo", 2, "bar"]) + +listCheck: err: #IntStrings +listCheck: err: [1, "foo", "bar", 2] @test(err, code=eval, path=2, contains="conflicting values %s and %s (mismatched types %s and %s)", args=["bar", int, string, int], pos=[-5:14, -5:15, -5:28, -1:17, 0:28]) + +-- withlet.cue -- +@experiment(aliasv2) + +withLet: { + let X = self + foo: 1 + + bar: { + baz: X.foo + } +} @test(eq, {foo: 1, bar: {baz: 1}}) +-- validator.cue -- +@experiment(structcmp) +@experiment(aliasv2) + +validator: { + err1: {{{{== (self + 1)}}}} @test(err, code=eval, + contains="invalid value %v (out of bound %s)", args=[2, ==3], + pos=[0:12, 0:8, 4:8] + ) + err1: 2 + + err2: {== (self + 1)} @test(err, code=eval, + contains="invalid value %v (out of bound %s)", args=[2, ==3], + pos=[0:9, 0:8, 4:8] + ) + err2: 2 +} + +cyclicErr: { + err3: == (self + 1) @test(err, code=eval, + contains="invalid operands %s and %s to '%s' (type %s and %s)", + pos=[0:12, -1:12, 0:19] + ) + err3: 4 +} + +-- experiment_test.cue -- +// Test self usage without experiment enabled (should fail) + +a: { + b: self.c + c: 3 +} + +-- out/compile -- +--- in.cue +{ + a: 〈1〉.b + b: "hello" + x: { + y: 〈1〉.z + z: "world" + } + foo: { + bar: 〈1〉.baz + } + foo: { + baz: "greeting" + } + nested: { + level1: { + field: 〈1〉.value + value: "level1 value" + } + } + listTest: { + items: [ + 1, + 2, + 〈1〉[0], + 〈1〉[1], + ] + first: 1 + second: 2 + } + computed: { + key: "test" + value: 〈1〉["key"] + } + cycle: 〈1〉.cycle +} +--- list.cue +{ + #IntStrings: { + 〈import;list〉.Repeat([ + int, + string, + ], div(len(〈1〉), 2)) + } + listCheck: { + ok1: 〈1;#IntStrings〉 + } + listCheck: { + ok1: [ + 1, + "foo", + 2, + "bar", + ] + } + listCheck: { + err: 〈1;#IntStrings〉 + } + listCheck: { + err: [ + 1, + "foo", + "bar", + 2, + ] + } +} +--- validator.cue +{ + validator: { + err1: { + { + { + { + ==(〈1〉 + 1) + } + } + } + } + err1: 2 + err2: { + ==(〈1〉 + 1) + } + err2: 2 + } + cyclicErr: { + err3: ==(〈1〉 + 1) + err3: 4 + } +} +--- withlet.cue +{ + withLet: { + let X#1 = 〈1〉 + foo: 1 + bar: { + baz: 〈1;let X#1〉.foo + } + } +} diff --git a/internal/core/compile/testdata/sync/references/value.txtar b/internal/core/compile/testdata/sync/references/value.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/references/value.txtar @@ -0,0 +1,50 @@ +-- in.cue -- +structShorthand: X={b: 3, c: X.b} @test(eq, {b: 3, c: 3}) + +// Note that X and Y are subtly different, as they have different bindings: +// one binds to the field, the other to the value. In this case, that does not +// make a difference. +fieldAndValue: X=foo: Y={3, #sum: X + Y} @test(eq, {3, #sum: 6}) + +valueCycle: b: X=3 + X @test(err, code=cycle, contains="cycle with field", pos=[0:22]) + +// Issue #1003 +listValueAlias: X = [1, 2, X[0]] @test(eq, [1, 2, 1]) + +-- err.cue -- +@experiment(structcmp) + +cycleErr: X={ + err3: == (X + 1) + err3: 4 + @test(err, code=eval, contains="invalid operands", pos=[1:12, 0:13, 1:16]) +} +-- out/compile -- +--- err.cue +{ + cycleErr: { + err3: ==(〈1〉 + 1) + err3: 4 + } +} +--- in.cue +{ + structShorthand: { + b: 3 + c: 〈1〉.b + } + fieldAndValue: { + foo: { + 3 + #sum: (〈1;foo〉 + 〈1〉) + } + } + valueCycle: { + b: (3 + 〈0〉) + } + listValueAlias: [ + 1, + 2, + 〈1〉[0], + ] +} diff --git a/internal/core/compile/testdata/sync/resolve/000_convert___to_top.txtar b/internal/core/compile/testdata/sync/resolve/000_convert___to_top.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/000_convert___to_top.txtar @@ -0,0 +1,11 @@ +# Tests that a pattern constraint [_]: _ over an open struct results in +# an open struct without any concrete fields. +-- in.cue -- +a: {[_]: _} @test(eq, {}) +-- out/compile -- +--- in.cue +{ + a: { + [_]: _ + } +} diff --git a/internal/core/compile/testdata/sync/resolve/001.txtar b/internal/core/compile/testdata/sync/resolve/001.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/001.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +a: b.c.d @test(eq, 3) +b: {c: {d: 3}} +c: {c: d.d} @test(eq, {c: 2}) +d: {d: 2} +-- out/compile -- +--- in.cue +{ + a: 〈0;b〉.c.d + b: { + c: { + d: 3 + } + } + c: { + c: 〈1;d〉.d + } + d: { + d: 2 + } +} diff --git a/internal/core/compile/testdata/sync/resolve/004.txtar b/internal/core/compile/testdata/sync/resolve/004.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/004.txtar @@ -0,0 +1,16 @@ +-- in.cue -- +a: _ +b: a @test(eq, {d: 1}) @test(shareID=ba) +a: {d: 1, d: _} @test(eq, {d: 1}) @test(shareID=ba) +b: _ +-- out/compile -- +--- in.cue +{ + a: _ + b: 〈0;a〉 + a: { + d: 1 + d: _ + } + b: _ +} diff --git a/internal/core/compile/testdata/sync/resolve/005_JSON.txtar b/internal/core/compile/testdata/sync/resolve/005_JSON.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/005_JSON.txtar @@ -0,0 +1,16 @@ +-- in.cue -- +a="a": 3 +@test(eq, at=a, 3) +b: a @test(eq, 3) +o: {"a\nb": 2} @test(eq, {"a\nb": 2}) +c: o["a\nb"] @test(eq, 2) +-- out/compile -- +--- in.cue +{ + a: 3 + b: 〈0;a〉 + o: { + "a\nb": 2 + } + c: 〈0;o〉["a\nb"] +} diff --git a/internal/core/compile/testdata/sync/resolve/006_arithmetic.txtar b/internal/core/compile/testdata/sync/resolve/006_arithmetic.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/006_arithmetic.txtar @@ -0,0 +1,19 @@ +# Tests arithmetic operations including division producing floats and +# conflicting types (int & float). +-- in.cue -- +v1: 1.0T / 2.0 @test(eq, 5.0e+11) +v2: 2.0 == 2 @test(eq, true) +n1: 1 @test(eq, 1) @test(kind=int) +v5: 2.0 / n1 @test(eq, 2.0) +v6: 1.0 / 1.0 @test(eq, 1.0) @test(kind:todo=int, hint="may consider this") +e2: int & 4.0/2.0 @test(err, code=eval, contains="conflicting values int and 2.0", pos=[0:5, 0:11]) +-- out/compile -- +--- in.cue +{ + v1: (1000000000000 / 2.0) + v2: (2.0 == 2) + n1: 1 + v5: (2.0 / 〈0;n1〉) + v6: (1.0 / 1.0) + e2: (int & (4.0 / 2.0)) +} diff --git a/internal/core/compile/testdata/sync/resolve/007_inequality.txtar b/internal/core/compile/testdata/sync/resolve/007_inequality.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/007_inequality.txtar @@ -0,0 +1,17 @@ +-- in.cue -- +a: 1 != 2 @test(eq, true) +b: 1 != null @test(eq, true) +c: true == null @test(eq, false) +d: null != {} @test(eq, true) +e: null == [] @test(eq, false) +f: 0 == 0.0 @test(eq, true) // types are unified first TODO: make this consistent +-- out/compile -- +--- in.cue +{ + a: (1 != 2) + b: (1 != null) + c: (true == null) + d: (null != {}) + e: (null == []) + f: (0 == 0.0) +} diff --git a/internal/core/compile/testdata/sync/resolve/008_attributes.txtar b/internal/core/compile/testdata/sync/resolve/008_attributes.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/008_attributes.txtar @@ -0,0 +1,20 @@ +-- in.cue -- +a: {foo: 1 @foo() @baz(1)} @test(eq, {foo: 1 @foo() @baz(1)}) +b: {foo: 1 @bar() @foo()} @test(eq, {foo: 1 @foo() @bar()}) +c: a & b @test(eq, {foo: 1 @foo() @baz(1) @bar()}) + +e: a & {foo: 1 @foo(other)} @test(eq, {foo: 1 @foo(other) @foo() @baz(1)}) +-- out/compile -- +--- in.cue +{ + a: { + foo: 1 + } + b: { + foo: 1 + } + c: (〈0;a〉 & 〈0;b〉) + e: (〈0;a〉 & { + foo: 1 + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/009_optional_field_unification.txtar b/internal/core/compile/testdata/sync/resolve/009_optional_field_unification.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/009_optional_field_unification.txtar @@ -0,0 +1,31 @@ +-- in.cue -- +a: {foo?: string} @test(eq, {foo?: string}) +b: {foo: "foo"} @test(eq, {foo: "foo"}) +c: a & b @test(eq, {foo: "foo"}) +d: a & {"foo"?: "bar"} @test(eq, {foo?: "bar"}) + +e: { + g1: 1 + "g\(1)"?: 1 + "g\(2)"?: 2 + @test(eq, {g1: 1, g2?: 2}) +} +-- out/compile -- +--- in.cue +{ + a: { + foo?: string + } + b: { + foo: "foo" + } + c: (〈0;a〉 & 〈0;b〉) + d: (〈0;a〉 & { + foo?: "bar" + }) + e: { + g1: 1 + "g\(1)"?: 1 + "g\(2)"?: 2 + } +} diff --git a/internal/core/compile/testdata/sync/resolve/010_optional_field_resolves_to_incomplete.txtar b/internal/core/compile/testdata/sync/resolve/010_optional_field_resolves_to_incomplete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/010_optional_field_resolves_to_incomplete.txtar @@ -0,0 +1,15 @@ +-- in.cue -- +r: { + a?: 3 + b: a @test(err, code=incomplete, contains="cannot reference optional field: a", pos=[0:6]) + c: r["a"] @test(err, code=incomplete, contains="cannot reference optional field: a", pos=[0:8]) +} +-- out/compile -- +--- in.cue +{ + r: { + a?: 3 + b: 〈0;a〉 + c: 〈1;r〉["a"] + } +} diff --git a/internal/core/compile/testdata/sync/resolve/011_bounds.txtar b/internal/core/compile/testdata/sync/resolve/011_bounds.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/011_bounds.txtar @@ -0,0 +1,120 @@ +-- in.cue -- +i1: >1 & 5 @test(eq, 5) +i2: (>=0 & <=10) & 5 @test(eq, 5) +i3: !=null & [] @test(eq, []) +i4: !=2 & !=4 @test(eq, !=2 & !=4) + +s1: >=0 & <=10 & !=1 @test(eq, >=0 & <=10 & !=1) // no simplification +s2: >=0 & <=10 & !=11 @test(eq, >=0 & <=10) +s3: >5 & !=5 @test(eq, >5) +s4: <10 & !=10 @test(eq, <10) +s5: !=2 & !=2 @test(eq, !=2) + +// TODO: could change inequality +s6: !=2 & >=2 @test(eq, >=2 & !=2) @test(eq:todo, >2) +s7: >=2 & !=2 @test(eq, >=2 & !=2) @test(eq:todo, >2) + +s8: !=5 & >5 @test(eq, >5) + +s10: >=0 & <=10 & <12 & >1 @test(eq, >1 & <=10) // >1 & <=10 +s11: >0 & >=0 & <=12 & <12 @test(eq, >0 & <12) // >0 & <12 + +s20: >=10 & <=10 @test(eq, >=10 & <=10) @test(eq:todo, ==10) + +s22: >5 & <=6 @test(eq, >5 & <=6) // no simplification +s22a: >5 & (<=6 & int) @test(eq, >5 & <=6 & int) @test(eq:todo, ==6) +s22b: (int & >5) & <=6 @test(eq, >5 & <=6 & int) @test(eq:todo, ==6) +s22c: >=5 & (<6 & int) @test(eq, >=5 & <6 & int) @test(eq:todo, ==5) +s22d: (int & >=5) & <6 @test(eq, >=5 & <6 & int) @test(eq:todo, ==5) +s22e: (>=5 & <6) & int @test(eq, >=5 & <6 & int) @test(eq:todo, ==5) +s22f: int & (>=5 & <6) @test(eq, >=5 & <6 & int) @test(eq:todo, ==5) + +s23: >0 & <2 @test(eq, >0 & <2) // no simplification +s23a: (>0 & <2) & int @test(eq, >0 & <2 & int) @test(eq:todo, ==1) +s23b: int & (>0 & <2) @test(eq, >0 & <2 & int) @test(eq:todo, ==1) +s23c: (int & >0) & <2 @test(eq, >0 & <2 & int) @test(eq:todo, ==1) +s23d: >0 & (int & <2) @test(eq, >0 & <2 & int) @test(eq:todo, ==1) +s23e: >0.0 & <2.0 @test(eq, >0.0 & <2.0) // no simplification + +s30: >0 & int @test(eq, >0 & int) + +floats: { + [string]: float + f1: <10.0 & <=5.0 @test(eq, <=5.0 & float) + f2: <=10.0 & <5.0 @test(eq, <5.0 & float) + f3: <1.1 & <=1.1 @test(eq, <1.1 & float) + f4: <=1.1 & <=1.1 @test(eq, <=1.1 & float) + f5: >1.1 & >=1.1 @test(eq, >1.1 & float) + f6: >=1.1 & >1.1 @test(eq, >1.1 & float) + f7: >=1.1 & <=1.1 @test(eq, >=1.1 & <=1.1 & float) + + issue1310: >=2.1 & <=1.0 @test(err, code=eval, contains="incompatible number bounds", pos=[0:21, 0:13]) + fe2: >2.1 & <=2.1 @test(err, code=eval, contains="incompatible number bounds", pos=[0:20, 0:13]) + + fe3: float & >2 & <=3 @test(eq, >2 & <=3 & float) +} + +e1: null & !=null @test(err, code=eval, contains="conflicting values null and !=null", pos=[0:5, 0:12]) +e2: !=null & null @test(err, code=eval, contains="conflicting values null and !=null", pos=[0:5, 0:14]) +e3: >1 & 1 @test(err, code=eval, contains="invalid value 1", pos=[0:5, 0:10]) +e4: <0 & 0 @test(err, code=eval, contains="invalid value 0", pos=[0:5, 0:10]) +e5: >1 & <0 @test(err, code=eval, contains="incompatible number bounds", pos=[0:10, 0:5]) +e6: >11 & <11 @test(err, code=eval, contains="incompatible number bounds", pos=[0:11, 0:5]) +e7: >=11 & <11 @test(err, code=eval, contains="incompatible number bounds", pos=[0:12, 0:5]) +e8: >11 & <=11 @test(err, code=eval, contains="incompatible number bounds", pos=[0:11, 0:5]) +e9: >"a" & <1 @test(err, code=eval, contains="conflicting values", pos=[0:5, 0:12]) +-- out/compile -- +--- in.cue +{ + i1: (>1 & 5) + i2: ((>=0 & <=10) & 5) + i3: (!=null & []) + i4: (!=2 & !=4) + s1: ((>=0 & <=10) & !=1) + s2: ((>=0 & <=10) & !=11) + s3: (>5 & !=5) + s4: (<10 & !=10) + s5: (!=2 & !=2) + s6: (!=2 & >=2) + s7: (>=2 & !=2) + s8: (!=5 & >5) + s10: (((>=0 & <=10) & <12) & >1) + s11: (((>0 & >=0) & <=12) & <12) + s20: (>=10 & <=10) + s22: (>5 & <=6) + s22a: (>5 & (<=6 & int)) + s22b: ((int & >5) & <=6) + s22c: (>=5 & (<6 & int)) + s22d: ((int & >=5) & <6) + s22e: ((>=5 & <6) & int) + s22f: (int & (>=5 & <6)) + s23: (>0 & <2) + s23a: ((>0 & <2) & int) + s23b: (int & (>0 & <2)) + s23c: ((int & >0) & <2) + s23d: (>0 & (int & <2)) + s23e: (>0.0 & <2.0) + s30: (>0 & int) + floats: { + [string]: float + f1: (<10.0 & <=5.0) + f2: (<=10.0 & <5.0) + f3: (<1.1 & <=1.1) + f4: (<=1.1 & <=1.1) + f5: (>1.1 & >=1.1) + f6: (>=1.1 & >1.1) + f7: (>=1.1 & <=1.1) + issue1310: (>=2.1 & <=1.0) + fe2: (>2.1 & <=2.1) + fe3: ((float & >2) & <=3) + } + e1: (null & !=null) + e2: (!=null & null) + e3: (>1 & 1) + e4: (<0 & 0) + e5: (>1 & <0) + e6: (>11 & <11) + e7: (>=11 & <11) + e8: (>11 & <=11) + e9: (>"a" & <1) +} diff --git a/internal/core/compile/testdata/sync/resolve/012_bound_conversions.txtar b/internal/core/compile/testdata/sync/resolve/012_bound_conversions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/012_bound_conversions.txtar @@ -0,0 +1,30 @@ +-- in.cue -- +r0: int & >0.1 & <=1.9 @test(eq, >0.1 & <=1.9 & int) +r1: int & >0.1 & <1.9 @test(eq, >0.1 & <1.9 & int) +r2: int & >=0.1 & <1.9 @test(eq, >=0.1 & <1.9 & int) +r3: int & >=-1.9 & <=-0.1 @test(eq, >=-1.9 & <=-0.1 & int) +r4: int & >-1.9 & <=-0.1 @test(eq, >-1.9 & <=-0.1 & int) + +r5: >=1.1 & <=1.1 @test(eq, >=1.1 & <=1.1) @test(eq:todo, ==1.1) +r6: r5 & 1.1 @test(eq, 1.1) + +c1: (1.2 & >1.3) & <2 @test(err, code=eval, contains="invalid value 1.2", pos=[0:12, 0:6]) +c2: 1.2 & (>1.3 & <2) @test(err, code=eval, contains="invalid value 1.2", pos=[0:12, 0:5]) + +c3: 1.2 & (>=1 & <2) @test(eq, 1.2) +c4: 1.2 & (>=1 & <2 & int) @test(err, code=eval, contains="conflicting values 1.2 and int", pos=[0:5, 0:23]) +-- out/compile -- +--- in.cue +{ + r0: ((int & >0.1) & <=1.9) + r1: ((int & >0.1) & <1.9) + r2: ((int & >=0.1) & <1.9) + r3: ((int & >=-1.9) & <=-0.1) + r4: ((int & >-1.9) & <=-0.1) + r5: (>=1.1 & <=1.1) + r6: (〈0;r5〉 & 1.1) + c1: ((1.2 & >1.3) & <2) + c2: (1.2 & (>1.3 & <2)) + c3: (1.2 & (>=1 & <2)) + c4: (1.2 & ((>=1 & <2) & int)) +} diff --git a/internal/core/compile/testdata/sync/resolve/013_custom_validators.txtar b/internal/core/compile/testdata/sync/resolve/013_custom_validators.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/013_custom_validators.txtar @@ -0,0 +1,21 @@ +-- in.cue -- +import "strings" + +a: strings.ContainsAny("ab") +a: "after" @test(eq, "after") + +b: strings.ContainsAny("c") +b: "dog" @test(err, code=eval, contains="invalid value \"dog\"", pos=[-1:4, -1:24, 0:4]) + +c: strings.ContainsAny("d") & strings.ContainsAny("g") +c: "dog" @test(eq, "dog") +-- out/compile -- +--- in.cue +{ + a: 〈import;strings〉.ContainsAny("ab") + a: "after" + b: 〈import;strings〉.ContainsAny("c") + b: "dog" + c: (〈import;strings〉.ContainsAny("d") & 〈import;strings〉.ContainsAny("g")) + c: "dog" +} diff --git a/internal/core/compile/testdata/sync/resolve/014_null_coalescing.txtar b/internal/core/compile/testdata/sync/resolve/014_null_coalescing.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/014_null_coalescing.txtar @@ -0,0 +1,11 @@ +-- in.cue -- +a: null @test(eq, null) +b: a.x | "b" @test(eq, "b") +c: a["x"] | "c" @test(eq, "c") +-- out/compile -- +--- in.cue +{ + a: null + b: (〈0;a〉.x|"b") + c: (〈0;a〉["x"]|"c") +} diff --git a/internal/core/compile/testdata/sync/resolve/016_index.txtar b/internal/core/compile/testdata/sync/resolve/016_index.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/016_index.txtar @@ -0,0 +1,71 @@ +-- in.cue -- +a: [2][0] @test(eq, 2) +b: {foo: "bar"}["foo"] @test(eq, "bar") +c: (*l | {"3": 3})["3"] @test(err, code=eval, contains="undefined field", pos=[0:20]) +d: (*[] | [1])[0] @test(err, code=eval, contains="index out of range [0]", pos=[0:16]) +l: [] @test(eq, []) + +e1: [2][""] @test(err, code=eval, contains="undefined field", pos=[0:9]) +e2: 2[2] @test(err, code=eval, contains="invalid operand 2", pos=[0:5]) +e3: [][true] @test(err, code=eval, contains="invalid index true", pos=[0:5, 0:8]) +e4: [1, 2, 3][3] @test(err, code=eval, contains="index out of range [3]", pos=[0:15]) +e5: [1, 2, 3][-1] @test(err, code=eval, contains="invalid index -1", pos=[0:5, 0:15]) +e6: (*[] | {})[1] @test(err, code=eval, contains="index out of range [1]", pos=[0:16]) +e7: [1, 2, 3][3] @test(err, code=eval, contains="index out of range [3]", pos=[0:15]) +e8: [1, 2, 3][-1] @test(err, code=eval, contains="invalid index -1", pos=[0:5, 0:15]) +e9: (*[] | {})[1] @test(err, code=eval, contains="index out of range [1]", pos=[0:16]) + +def: { + a: 1 + #b: 3 +} @test(eq, {a: 1, #b: 3}) +e10: def["b"] @test(err, code=incomplete, contains="undefined field: b", pos=[0:10]) +-- out/compile -- +--- in.cue +{ + a: [ + 2, + ][0] + b: { + foo: "bar" + }["foo"] + c: (*〈0;l〉|{ + "3": 3 + })["3"] + d: (*[]|[ + 1, + ])[0] + l: [] + e1: [ + 2, + ][""] + e2: 2[2] + e3: [][true] + e4: [ + 1, + 2, + 3, + ][3] + e5: [ + 1, + 2, + 3, + ][-1] + e6: (*[]|{})[1] + e7: [ + 1, + 2, + 3, + ][3] + e8: [ + 1, + 2, + 3, + ][-1] + e9: (*[]|{})[1] + def: { + a: 1 + #b: 3 + } + e10: 〈0;def〉["b"] +} diff --git a/internal/core/compile/testdata/sync/resolve/017_disjunctions_of_lists.txtar b/internal/core/compile/testdata/sync/resolve/017_disjunctions_of_lists.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/017_disjunctions_of_lists.txtar @@ -0,0 +1,24 @@ +-- in.cue -- +l: [ int, int] | [ string, string] @test(eq, [int, int] | [string, string]) + +l1: ["a", "b"] @test(eq, ["a", "b"]) +l2: l & ["c", "d"] @test(eq, ["c", "d"]) +-- out/compile -- +--- in.cue +{ + l: ([ + int, + int, + ]|[ + string, + string, + ]) + l1: [ + "a", + "b", + ] + l2: (〈0;l〉 & [ + "c", + "d", + ]) +} diff --git a/internal/core/compile/testdata/sync/resolve/018_slice.txtar b/internal/core/compile/testdata/sync/resolve/018_slice.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/018_slice.txtar @@ -0,0 +1,37 @@ +-- in.cue -- +a: [2][0:0] @test(eq, []) +b: [0][1:1] @test(eq, []) +e1: [][1:1] @test(err, code=eval, contains="index 1 out of range", pos=[0:5]) +e2: [0][-1:0] @test(err, code=eval, contains="cannot convert negative number", pos=[0:5]) +e3: [0][1:0] @test(err, code=eval, contains="invalid slice index", pos=[0:5]) +e4: [0][1:2] @test(err, code=eval, contains="index 2 out of range", pos=[0:5]) +e5: 4[1:2] @test(err, code=eval, contains="cannot slice 4", pos=[0:5]) +e6: [2]["":] @test(err, code=eval, contains="cannot use \"\"", pos=[0:5, 0:9]) +e7: [2][:"9"] @test(err, code=eval, contains="cannot use \"9\"", pos=[0:5, 0:10]) +-- out/compile -- +--- in.cue +{ + a: [ + 2, + ][0:0] + b: [ + 0, + ][1:1] + e1: [][1:1] + e2: [ + 0, + ][-1:0] + e3: [ + 0, + ][1:0] + e4: [ + 0, + ][1:2] + e5: 4[1:2] + e6: [ + 2, + ]["":] + e7: [ + 2, + ][:"9"] +} diff --git a/internal/core/compile/testdata/sync/resolve/022_list_unification.txtar b/internal/core/compile/testdata/sync/resolve/022_list_unification.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/022_list_unification.txtar @@ -0,0 +1,20 @@ +-- in.cue -- +a: {l: ["foo", v], v: l[1]} @test(eq, {l: ["foo", _], v: _}) +b: a & {l: [_, "bar"]} @test(eq, {l: ["foo", "bar"], v: "bar"}) +-- out/compile -- +--- in.cue +{ + a: { + l: [ + "foo", + 〈1;v〉, + ] + v: 〈0;l〉[1] + } + b: (〈0;a〉 & { + l: [ + _, + "bar", + ] + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/023_correct_error_messages.txtar b/internal/core/compile/testdata/sync/resolve/023_correct_error_messages.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/023_correct_error_messages.txtar @@ -0,0 +1,8 @@ +-- in.cue -- +a: "a" & 1 @test(err, code=eval, contains="conflicting values", + args=["a", 1], pos=[0:4, 0:10]) +-- out/compile -- +--- in.cue +{ + a: ("a" & 1) +} diff --git a/internal/core/compile/testdata/sync/resolve/024_structs.txtar b/internal/core/compile/testdata/sync/resolve/024_structs.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/024_structs.txtar @@ -0,0 +1,28 @@ +-- in.cue -- +a: t & {c: 5} @test(eq, {c: 5, d: 15}) // {c:5,d:15} +b: ti & {c: 7} @test(eq, {c: 7, d: 21}) // {c:7,d:21} +t: { + c: number + d: c * 3 @test(err, code=incomplete, contains="non-concrete value number in operand to *", pos=[0:5, -1:5]) +} +ti: t & {c: int} @test(eq, { + c: int + d: _|_ @test(err, code=incomplete, contains="non-concrete value number in operand to *", pos=[5:5 4:5 7:13]) +}) +-- out/compile -- +--- in.cue +{ + a: (〈0;t〉 & { + c: 5 + }) + b: (〈0;ti〉 & { + c: 7 + }) + t: { + c: number + d: (〈0;c〉 * 3) + } + ti: (〈0;t〉 & { + c: int + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/025_definitions.txtar b/internal/core/compile/testdata/sync/resolve/025_definitions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/025_definitions.txtar @@ -0,0 +1,86 @@ +-- in.cue -- +#Foo: { + field: int + recursive: { + field: string + } + + @test(eq, {field: int, recursive: {field: string}}) + @test(closed) +} + +// Allowed +#Foo1: {field: int} +#Foo1: {field2: string} @test(eq, {field: int, field2: string}) @test(closed) + +foo: #Foo +foo: {feild: 2} @test(err, code=eval, contains="field not allowed", pos=[0:7]) + +foo1: #Foo +foo1: { + field: 2 @test(eq, 2) + recursive: { + feild: 2 @test(err, code=eval, contains="field not allowed", pos=[0:3]) + } +} + +#Bar: { + field: int + {[A=_]: int} + + @test(eq, {field: int, [_]: int}) + @test(closed) +} +bar: #Bar +bar: {feild: 2} @test(eq, {feild: 2, field: int}) + +#Mixed: string +Mixed: string + +mixedRec: {#Mixed: string} +mixedRec: {Mixed: string} @test(eq, {#Mixed: string, Mixed: string}) +-- out/compile -- +--- in.cue +{ + #Foo: { + field: int + recursive: { + field: string + } + } + #Foo1: { + field: int + } + #Foo1: { + field2: string + } + foo: 〈0;#Foo〉 + foo: { + feild: 2 + } + foo1: 〈0;#Foo〉 + foo1: { + field: 2 + recursive: { + feild: 2 + } + } + #Bar: { + field: int + { + [_]: int + } + } + bar: 〈0;#Bar〉 + bar: { + feild: 2 + } + #Mixed: string + Mixed: string + mixedRec: { + #Mixed: string + } + mixedRec: { + Mixed: string + } +} diff --git a/internal/core/compile/testdata/sync/resolve/027_new-style_definitions.txtar b/internal/core/compile/testdata/sync/resolve/027_new-style_definitions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/027_new-style_definitions.txtar @@ -0,0 +1,30 @@ +-- in.cue -- +#Foo: { + a: 1 + b: int +} @test(eq, {a: 1, b: int}) @test(closed) +"#Foo": #Foo & {b: 1} @test(eq, {b: 1, a: 1}) @test(closed) + +bulk: {[string]: string} & { + #def: 4 // Different namespace, so bulk option does not apply. + _hid: 3 + a: "foo" +} @test(eq, {#def: 4, _hid: 3, a: "foo"}) +-- out/compile -- +--- in.cue +{ + #Foo: { + a: 1 + b: int + } + "#Foo": (〈0;#Foo〉 & { + b: 1 + }) + bulk: ({ + [string]: string + } & { + #def: 4 + _hid: 3 + a: "foo" + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar b/internal/core/compile/testdata/sync/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/029_non-closed_definition_carries_over_closedness_to_enclosed_template.txtar @@ -0,0 +1,68 @@ +-- in.cue -- +#S: { + [string]: {a: int} +} @test(eq, {}) @test(closed) +a: #S & { + v: {b: int} +} @test(err, code=eval, at=v.b, contains="field not allowed", pos=[1:6]) +#Q: { + [string]: {a: int} | {b: int} +} @test(eq, {}) @test(closed) +b: #Q & { + w: {c: int} +} @test(err, code=eval, at=w, contains="field not allowed", pos=[1:6]) +// NOTE: the above test is marked at w, not w.c, because it fails both +// disjunctions. We probably want to record it at c, or at least give a better +// error message. +@test(err:todo, code=eval, at=b.w.c, contains="field not allowed") + +#R: { + [string]: [{a: int}, {b: int}] +} @test(eq, {}) @test(closed) +c: #R & { + w: [{d: int}, ...] +} @test(err, code=eval, at=w.0.d, contains="field not allowed", pos=[1:7]) +-- out/compile -- +--- in.cue +{ + #S: { + [string]: { + a: int + } + } + a: (〈0;#S〉 & { + v: { + b: int + } + }) + #Q: { + [string]: ({ + a: int + }|{ + b: int + }) + } + b: (〈0;#Q〉 & { + w: { + c: int + } + }) + #R: { + [string]: [ + { + a: int + }, + { + b: int + }, + ] + } + c: (〈0;#R〉 & { + w: [ + { + d: int + }, + ..., + ] + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/030_definitions_with_disjunctions.txtar b/internal/core/compile/testdata/sync/resolve/030_definitions_with_disjunctions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/030_definitions_with_disjunctions.txtar @@ -0,0 +1,40 @@ +-- in.cue -- +#Foo: { + field: int + + {a: 1} | + {b: 2} +} @test(eq, {field: int, a: 1} | {field: int, b: 2}) + +foo: #Foo +foo: {a: 1} @test(eq, {a: 1, field: int}) + +bar: #Foo +bar: {c: 2} @test(err, code=eval, contains="field not allowed", pos=[0:7]) + +baz: #Foo +baz: {b: 2} @test(eq, {b: 2, field: int}) +-- out/compile -- +--- in.cue +{ + #Foo: { + field: int + ({ + a: 1 + }|{ + b: 2 + }) + } + foo: 〈0;#Foo〉 + foo: { + a: 1 + } + bar: 〈0;#Foo〉 + bar: { + c: 2 + } + baz: 〈0;#Foo〉 + baz: { + b: 2 + } +} diff --git a/internal/core/compile/testdata/sync/resolve/031_definitions_with_disjunctions_recurisive.txtar b/internal/core/compile/testdata/sync/resolve/031_definitions_with_disjunctions_recurisive.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/031_definitions_with_disjunctions_recurisive.txtar @@ -0,0 +1,29 @@ +-- in.cue -- +#Foo: { + x: { + field: int + + {a: 1} | + {b: 2} + } + x: c: 3 +} @test(eq, { + x: {field: int, c: 3, a: 1} | {field: int, c: 3, b: 2} +}) +-- out/compile -- +--- in.cue +{ + #Foo: { + x: { + field: int + ({ + a: 1 + }|{ + b: 2 + }) + } + x: { + c: 3 + } + } +} diff --git a/internal/core/compile/testdata/sync/resolve/033_top-level_definition_with_struct_and_disjunction.txtar b/internal/core/compile/testdata/sync/resolve/033_top-level_definition_with_struct_and_disjunction.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/033_top-level_definition_with_struct_and_disjunction.txtar @@ -0,0 +1,30 @@ +-- in.cue -- +#def: { + Type: string + Text: string + Size: int +} + +#def: { + Type: "B" + Size: 0 +} | { + Type: "A" + Size: 1 +} @test(eq, {Type: "B", Text: string, Size: 0} | {Type: "A", Text: string, Size: 1}) +-- out/compile -- +--- in.cue +{ + #def: { + Type: string + Text: string + Size: int + } + #def: ({ + Type: "B" + Size: 0 + }|{ + Type: "A" + Size: 1 + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/034_closing_structs.txtar b/internal/core/compile/testdata/sync/resolve/034_closing_structs.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/034_closing_structs.txtar @@ -0,0 +1,50 @@ +-- in.cue -- +op: {x: int} @test(eq, {x: int}) // {x: int} +ot: {x: int, ...} @test(eq, {x: int}) // {x: int, ...} +cp: close({x: int}) @test(eq, {x: int}) @test(closed) // closed({x: int}) +ct: close({x: int, ...}) @test(eq, {x: int}) @test(closed) @test(shareID=ctct) @test(allows, string) + +opot: op & ot @test(eq, {x: int}) // {x: int, ...} +otop: ot & op @test(eq, {x: int}) // {x: int, ...} +opcp: op & cp @test(eq, {x: int}) @test(closed) @test(allows=false, string) +cpop: cp & op @test(eq, {x: int}) @test(closed) @test(allows=false, string) +opct: op & ct @test(eq, {x: int}) @test(closed) @test(allows, string) +ctop: ct & op @test(eq, {x: int}) @test(closed) @test(allows, string) +otcp: ot & cp @test(eq, {x: int}) @test(closed) @test(allows, string) @test(allows:todo=false, string) +cpot: cp & ot @test(eq, {x: int}) @test(closed) @test(allows, string) @test(allows:todo=false, string) +otct: ot & ct @test(eq, {x: int}) @test(closed) @test(allows, string) +ctot: ct & ot @test(eq, {x: int}) @test(closed) @test(allows, string) +cpct: cp & ct @test(eq, {x: int}) @test(closed) @test(allows, string) @test(allows:todo=false, string) +ctcp: ct & cp @test(eq, {x: int}) @test(closed) @test(allows, string) @test(allows:todo=false, string) +ctct: ct & ct @test(eq, {x: int}) @test(closed) @test(shareID=ctct) @test(allows, string) +-- out/compile -- +--- in.cue +{ + op: { + x: int + } + ot: { + x: int + ... + } + cp: close({ + x: int + }) + ct: close({ + x: int + ... + }) + opot: (〈0;op〉 & 〈0;ot〉) + otop: (〈0;ot〉 & 〈0;op〉) + opcp: (〈0;op〉 & 〈0;cp〉) + cpop: (〈0;cp〉 & 〈0;op〉) + opct: (〈0;op〉 & 〈0;ct〉) + ctop: (〈0;ct〉 & 〈0;op〉) + otcp: (〈0;ot〉 & 〈0;cp〉) + cpot: (〈0;cp〉 & 〈0;ot〉) + otct: (〈0;ot〉 & 〈0;ct〉) + ctot: (〈0;ct〉 & 〈0;ot〉) + cpct: (〈0;cp〉 & 〈0;ct〉) + ctcp: (〈0;ct〉 & 〈0;cp〉) + ctct: (〈0;ct〉 & 〈0;ct〉) +} diff --git a/internal/core/compile/testdata/sync/resolve/035_excluded_embedding_from_closing.txtar b/internal/core/compile/testdata/sync/resolve/035_excluded_embedding_from_closing.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/035_excluded_embedding_from_closing.txtar @@ -0,0 +1,45 @@ +-- in.cue -- +#S: { + a: {c: int} + { + c: {d: int} + } + let B = {open: int} + b: B +} @test(eq, { + a: {c: int} + c: {d: int} + b: {open: int} +}) +V: #S & { + c: e: int + b: extra: int +} +@test(err, code=eval, at=V.b.extra, contains="field not allowed", pos=[-2:5]) +@test(err, code=eval, at=V.c.e, contains="field not allowed", pos=[-4:5]) +-- out/compile -- +--- in.cue +{ + #S: { + a: { + c: int + } + { + c: { + d: int + } + } + let B#1 = { + open: int + } + b: 〈0;let B#1〉 + } + V: (〈0;#S〉 & { + c: { + e: int + } + b: { + extra: int + } + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/038_incomplete_comprehensions.txtar b/internal/core/compile/testdata/sync/resolve/038_incomplete_comprehensions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/038_incomplete_comprehensions.txtar @@ -0,0 +1,38 @@ +-- in.cue -- +A: { + for v in src { + "\(v)": v + } + src: _ + if true { + baz: "baz" + } + @test(err, code=incomplete, contains="cannot range over src", pos=[1:11]) +} +B: A & { + src: ["foo", "bar"] +} @test(eq, { + src: ["foo", "bar"] + baz: "baz" + foo: "foo" + bar: "bar" +}) +-- out/compile -- +--- in.cue +{ + A: { + for _, v in 〈0;src〉 { + "\(〈1;v〉)": 〈1;v〉 + } + src: _ + if true { + baz: "baz" + } + } + B: (〈0;A〉 & { + src: [ + "foo", + "bar", + ] + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/039_reference_to_root.txtar b/internal/core/compile/testdata/sync/resolve/039_reference_to_root.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/039_reference_to_root.txtar @@ -0,0 +1,48 @@ +-- in.cue -- +a: {b: int} @test(eq, {b: int}) +c: a & { + b: 100 + d: a.b + 3 // do not resolve as c != a. +} @test(eq, {b: 100, d: _|_ @test(err, + code=incomplete, contains="non-concrete value int in operand to +", pos=[4:5, 1:8])}) +x: { + b: int + c: b + 5 @test(err, code=incomplete, contains="non-concrete value int in operand to +", pos=[0:5, -1:5]) + @test(eq, {b: int, c: _|_}) +} +y: x & {b: 100} @test(eq, {b: 100, c: 105}) // c should resolve to 105 +v: { + b: int + c: v.b + 5 @test(err, code=incomplete, contains="non-concrete value int in operand to +", pos=[0:5, -1:5]) // reference starting from copied node. + @test(eq, {b: int, c: _|_}) +} +w: v & {b: 100} @test(eq, {b: 100, c: _|_}) +wp: v & {b: 100} @test(eq, {b: 100, c: _|_}) +-- out/compile -- +--- in.cue +{ + a: { + b: int + } + c: (〈0;a〉 & { + b: 100 + d: (〈1;a〉.b + 3) + }) + x: { + b: int + c: (〈0;b〉 + 5) + } + y: (〈0;x〉 & { + b: 100 + }) + v: { + b: int + c: (〈1;v〉.b + 5) + } + w: (〈0;v〉 & { + b: 100 + }) + wp: (〈0;v〉 & { + b: 100 + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/040_references_from_template_to_concrete.txtar b/internal/core/compile/testdata/sync/resolve/040_references_from_template_to_concrete.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/040_references_from_template_to_concrete.txtar @@ -0,0 +1,40 @@ +-- in.cue -- +res: [t] @test(eq, [{ + x: { + a: "XDDDD" + b: str: "DDDD" + c: "X" + } +}]) +@test(shareID=T, at=res[0]) +@test(shareID=T, at=t) +t: [X=string]: { + a: c + b.str + b: str: string + c: "X" +} +t: x: {b: str: "DDDD"} @test(eq, {b: {str: "DDDD"}, a: "XDDDD", c: "X"}) + +-- out/compile -- +--- in.cue +{ + res: [ + 〈1;t〉, + ] + t: { + [string]: { + a: (〈0;c〉 + 〈0;b〉.str) + b: { + str: string + } + c: "X" + } + } + t: { + x: { + b: { + str: "DDDD" + } + } + } +} diff --git a/internal/core/compile/testdata/sync/resolve/043_diamond-shaped_constraints.txtar b/internal/core/compile/testdata/sync/resolve/043_diamond-shaped_constraints.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/043_diamond-shaped_constraints.txtar @@ -0,0 +1,38 @@ +-- in.cue -- +S: { + A: { + a: 1 + } + B: A & { + b: 2 + } + @test(eq, {A: {a: 1}, B: {b: 2, a: 1}}) +} +T: S & {// S == { A: { a:1 }, B: { a:1, b:2 } } + A: { + c: 3 + } + B: { + d: 4 // Combines constraints S.A, S.B, T.A, and T.B // S.B & A + } +} @test(eq, {A: {c: 3, a: 1}, B: {d: 4, b: 2, c: 3, a: 1}}) +-- out/compile -- +--- in.cue +{ + S: { + A: { + a: 1 + } + B: (〈0;A〉 & { + b: 2 + }) + } + T: (〈0;S〉 & { + A: { + c: 3 + } + B: { + d: 4 + } + }) +} diff --git a/internal/core/compile/testdata/sync/resolve/044_field_templates.txtar b/internal/core/compile/testdata/sync/resolve/044_field_templates.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/044_field_templates.txtar @@ -0,0 +1,57 @@ +-- in.cue -- +a: { + {[name=_]: int} + k: 1 +} @test(eq, {k: 1}) +b: { + {[X=_]: {x: 0, y: *1 | int}} + v: {} + w: {x: 0} +} +b: {[y=_]: {}} @test(eq, { + v: {x: 0, y: *1 | int} + w: {x: 0, y: *1 | int} +}) +c: { + {[Name=_]: {name: Name, y: 1}} + foo: {} + bar: _ +} @test(eq, { + foo: {name: "foo", y: 1} + bar: {name: "bar", y: 1} +}) +-- out/compile -- +--- in.cue +{ + a: { + { + [_]: int + } + k: 1 + } + b: { + { + [_]: { + x: 0 + y: (*1|int) + } + } + v: {} + w: { + x: 0 + } + } + b: { + [_]: {} + } + c: { + { + [_]: { + name: 〈1;-〉 + y: 1 + } + } + foo: {} + bar: _ + } +} diff --git a/internal/core/compile/testdata/sync/resolve/045_range_unification.txtar b/internal/core/compile/testdata/sync/resolve/045_range_unification.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/045_range_unification.txtar @@ -0,0 +1,85 @@ +-- in.cue -- +// with concrete values +a1: >=1 & <=5 & 3 @test(eq, 3) +a2: >=1 & <=5 & 1 @test(eq, 1) +a3: >=1 & <=5 & 5 @test(eq, 5) +a4: >=1 & <=5 & 6 @test(err, code=eval, contains="invalid value", args=[6], pos=[0:11, 0:17]) +a5: >=1 & <=5 & 0 @test(err, code=eval, contains="invalid value", args=[0], pos=[0:5, 0:17]) + +a6: 3 & >=1 & <=5 @test(eq, 3) +a7: 1 & >=1 & <=5 @test(eq, 1) +a8: 5 & >=1 & <=5 @test(eq, 5) +a9: 6 & >=1 & <=5 @test(err, code=eval, contains="invalid value", args=[6], pos=[0:16, 0:6]) +a10: 0 & >=1 & <=5 @test(err, code=eval, contains="invalid value", args=[0], pos=[0:10, 0:6]) + +// with ranges +b1: >=1 & <=5 & >=1 & <=5 @test(eq, >=1 & <=5) +b2: >=1 & <=5 & >=1 & <=1 @test(eq, >=1 & <=1) +b3: >=1 & <=5 & >=5 & <=5 @test(eq, >=5 & <=5) +b4: >=1 & <=5 & >=2 & <=3 @test(eq, >=2 & <=3) +b5: >=1 & <=5 & >=3 & <=9 @test(eq, >=3 & <=5) +b6: >=1 & <=5 & >=5 & <=9 @test(eq, >=5 & <=5) +b7: >=1 & <=5 & >=6 & <=9 @test(err, code=eval, contains="incompatible number bounds", pos=[0:17, 0:11]) + +b8: >=1 & <=5 & >=1 & <=5 @test(eq, >=1 & <=5) +b9: >=1 & <=1 & >=1 & <=5 @test(eq, >=1 & <=1) +b10: >=5 & <=5 & >=1 & <=5 @test(eq, >=5 & <=5) +b11: >=2 & <=3 & >=1 & <=5 @test(eq, >=2 & <=3) +b12: >=3 & <=9 & >=1 & <=5 @test(eq, >=3 & <=5) +b13: >=5 & <=9 & >=1 & <=5 @test(eq, >=5 & <=5) +b14: >=6 & <=9 & >=1 & <=5 @test(err, code=eval, contains="incompatible number bounds", pos=[0:24, 0:6]) + +// ranges with more general types +c1: int & >=1 & <=5 @test(eq, >=1 & <=5 & int) +c2: >=1 & <=5 & int @test(eq, >=1 & <=5 & int) +c3: string & >=1 & <=5 @test(err, code=eval, contains="conflicting values", args=[string, >=1], pos=[0:5, 0:14]) +c4: >=1 & <=5 & string @test(err, code=eval, contains="conflicting values", args=[string, >=1], pos=[0:5, 0:17]) + +// other types +s1: >="d" & <="z" & "e" @test(eq, "e") +s2: >="d" & <="z" & "ee" @test(eq, "ee") + +n1: number & >=1 & <=2 @test(eq, >=1 & <=2) +n2: int & >=1.1 & <=1.3 @test(err, code=eval, contains="incompatible integer bounds", pos=[0:19, 0:11]) +n3: >=1.0 & <=3.0 & 2 @test(eq, 2) +n4: >=0.0 & <=0.1 & 0.09999 @test(eq, 0.09999) +n5: >=1 & <=5 & 2.5 @test(eq, 2.5) +-- out/compile -- +--- in.cue +{ + a1: ((>=1 & <=5) & 3) + a2: ((>=1 & <=5) & 1) + a3: ((>=1 & <=5) & 5) + a4: ((>=1 & <=5) & 6) + a5: ((>=1 & <=5) & 0) + a6: ((3 & >=1) & <=5) + a7: ((1 & >=1) & <=5) + a8: ((5 & >=1) & <=5) + a9: ((6 & >=1) & <=5) + a10: ((0 & >=1) & <=5) + b1: (((>=1 & <=5) & >=1) & <=5) + b2: (((>=1 & <=5) & >=1) & <=1) + b3: (((>=1 & <=5) & >=5) & <=5) + b4: (((>=1 & <=5) & >=2) & <=3) + b5: (((>=1 & <=5) & >=3) & <=9) + b6: (((>=1 & <=5) & >=5) & <=9) + b7: (((>=1 & <=5) & >=6) & <=9) + b8: (((>=1 & <=5) & >=1) & <=5) + b9: (((>=1 & <=1) & >=1) & <=5) + b10: (((>=5 & <=5) & >=1) & <=5) + b11: (((>=2 & <=3) & >=1) & <=5) + b12: (((>=3 & <=9) & >=1) & <=5) + b13: (((>=5 & <=9) & >=1) & <=5) + b14: (((>=6 & <=9) & >=1) & <=5) + c1: ((int & >=1) & <=5) + c2: ((>=1 & <=5) & int) + c3: ((string & >=1) & <=5) + c4: ((>=1 & <=5) & string) + s1: ((>="d" & <="z") & "e") + s2: ((>="d" & <="z") & "ee") + n1: ((number & >=1) & <=2) + n2: ((int & >=1.1) & <=1.3) + n3: ((>=1.0 & <=3.0) & 2) + n4: ((>=0.0 & <=0.1) & 0.09999) + n5: ((>=1 & <=5) & 2.5) +} diff --git a/internal/core/compile/testdata/sync/resolve/046_predefined_ranges.txtar b/internal/core/compile/testdata/sync/resolve/046_predefined_ranges.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/046_predefined_ranges.txtar @@ -0,0 +1,24 @@ +#inlinetest:exclude skip — tests the debug printer, not evaluator semantics +-- in.cue -- +k1: int8 +k1: 44 + +k2: int64 +k2: -8_000_000_000 + +s1: int8 +s2: uint16 +s3: float32 +s4: uint +-- out/compile -- +--- in.cue +{ + k1: &(int, >=-128, <=127) + k1: 44 + k2: &(int, >=-9223372036854775808, <=9223372036854775807) + k2: -8000000000 + s1: &(int, >=-128, <=127) + s2: &(int, >=0, <=65535) + s3: &(>=-340282346638528859811704183484516925440, <=340282346638528859811704183484516925440) + s4: &(int, >=0) +} diff --git a/internal/core/compile/testdata/sync/resolve/046_predefined_ranges_error.txtar b/internal/core/compile/testdata/sync/resolve/046_predefined_ranges_error.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/046_predefined_ranges_error.txtar @@ -0,0 +1,9 @@ +-- in.cue -- +e1: int16 +e1: 100_000 @test(err, code=eval, contains="invalid value 100000", pos=[0:5]) +-- out/compile -- +--- in.cue +{ + e1: &(int, >=-32768, <=32767) + e1: 100000 +} diff --git a/internal/core/compile/testdata/sync/resolve/047_struct_comprehensions.txtar b/internal/core/compile/testdata/sync/resolve/047_struct_comprehensions.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/047_struct_comprehensions.txtar @@ -0,0 +1,49 @@ +#name: struct comprehensions +#evalPartial +-- in.cue -- +obj: foo: a: "bar" +obj: [Name=string]: { + a: *"dummy" | string + if true { + sub: as: a + } +} + +for k, v in {#def: 1, opt?: 2, _hid: 3, reg: 4} { + "\(k)": v +} +@test(eq, { + obj: foo: { + a: "bar" + sub: as: "bar" + }, + reg: 4 +}) + +-- out/compile -- +--- in.cue +{ + obj: { + foo: { + a: "bar" + } + } + obj: { + [string]: { + a: (*"dummy"|string) + if true { + sub: { + as: 〈2;a〉 + } + } + } + } + for k, v in { + #def: 1 + opt?: 2 + _hid: 3 + reg: 4 + } { + "\(〈1;k〉)": 〈1;v〉 + } +} diff --git a/internal/core/compile/testdata/sync/resolve/048_builtins.txtar b/internal/core/compile/testdata/sync/resolve/048_builtins.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/resolve/048_builtins.txtar @@ -0,0 +1,202 @@ +-- in.cue -- +import ( + "list" + "strings" +) + +a1: { + a: and([b, c]) + b: =~"oo" + c: =~"fo" +} @test(eq, { + a: =~"oo" & =~"fo" + b: =~"oo" + c: =~"fo" +}) +a2: a1 & {a: "foo"} @test(eq, {a: "foo", b: =~"oo", c: =~"fo"}) +a3: a1 & {a: "bar"} @test(err, code=eval, + suberr=(code=eval, contains="invalid value", args=["bar", =~"oo"], pos=[-8:5, -9:5, 0:14]), + suberr=(code=eval, contains="invalid value", args=["bar", =~"fo"], pos=[-7:5, -9:5, 0:14])) + +o1: { + a: or([b, c]) + b: string + c: "bar" +} @test(eq, {a: string | "bar", b: string, c: "bar"}) +o2: o1 & {a: "foo"} @test(eq, {a: "foo", b: string, c: "bar"}) +o3: o1 & {a: "foo", b: "baz"} @test(err, code=eval, + suberr=(code=eval, contains="conflicting values", args=["bar", "foo"], pos=[-5:12, -3:5, 0:5, 0:14]), + suberr=(code=eval, contains="conflicting values", args=["baz", "foo"], pos=[-5:9, 0:5, 0:14, 0:24])) + +// Issue #585 +stringListErrors: { + a: { + x: [string, ...string] + result: strings.Join(x, " ") @test(err, code=incomplete, + contains="non-concrete value string for element", pos=[0:11, -1:7]) + } + + b: { + x: [int, ...string] + result: strings.Join(x, " ") @test(err, code=eval, + contains="cannot use value int (int) as string", pos=[0:11, -1:7]) + } + + c: { + x: [] + result: strings.Join(x, int) @test(err, code=eval, + contains="cannot use int (type int) as string in argument 2 to strings.Join", + pos=[0:27]) + } +} + +decimalListErrors: { + a: { + x: [string] + result: list.Avg(x) @test(err, code=eval, + contains="invalid list element", pos=[0:11, -1:7]) + // TODO: allow checking wrapped errors: args=[string, number], + } + + b: { + x: [int, ...string] + result: list.Avg(x) @test(err, code=incomplete, + contains="non-concrete value int for element 0 of number list argument 0", pos=[0:11, -1:7]) + } +} +-- issue3648.cue -- +// Fully finalize values before passing them to builtins. + +// "not properly initialized" error regression in evalv3 involving builtins: +// list.Concat received an unfinalized value when called from a pattern constraint. +// https://cuelang.org/issue/3648 +import "list" + +issue3648: reduced: { + [string]: { + a: list.Concat([b]) + b: [{}] + } + foo: {} + + @test(eq, {foo: {a: [{}], b: [{}]}}) +} +issue3648: full: { + #Redirect: path?: string + + [string]: { + // Note that this bug disappears if the order of the fields below is swapped. + allRedirects: list.Concat([redirects]) + redirects: [...#Redirect] + } + foo: {} + + @test(eq, { + #Redirect: {path?: string} + [string]: { + allRedirects: list.Concat([[]]) + redirects: [] + } + foo: {allRedirects: [], redirects: []} + }) +} +-- out/compile -- +--- in.cue +{ + a1: { + a: and([ + 〈1;b〉, + 〈1;c〉, + ]) + b: =~"oo" + c: =~"fo" + } + a2: (〈0;a1〉 & { + a: "foo" + }) + a3: (〈0;a1〉 & { + a: "bar" + }) + o1: { + a: or([ + 〈1;b〉, + 〈1;c〉, + ]) + b: string + c: "bar" + } + o2: (〈0;o1〉 & { + a: "foo" + }) + o3: (〈0;o1〉 & { + a: "foo" + b: "baz" + }) + stringListErrors: { + a: { + x: [ + string, + ...string, + ] + result: 〈import;strings〉.Join(〈0;x〉, " ") + } + b: { + x: [ + int, + ...string, + ] + result: 〈import;strings〉.Join(〈0;x〉, " ") + } + c: { + x: [] + result: 〈import;strings〉.Join(〈0;x〉, int) + } + } + decimalListErrors: { + a: { + x: [ + string, + ] + result: 〈import;list〉.Avg(〈0;x〉) + } + b: { + x: [ + int, + ...string, + ] + result: 〈import;list〉.Avg(〈0;x〉) + } + } +} +--- issue3648.cue +{ + issue3648: { + reduced: { + [string]: { + a: 〈import;list〉.Concat([ + 〈1;b〉, + ]) + b: [ + {}, + ] + } + foo: {} + } + } + issue3648: { + full: { + #Redirect: { + path?: string + } + [string]: { + allRedirects: 〈import;list〉.Concat([ + 〈1;redirects〉, + ]) + redirects: [ + ...〈2;#Redirect〉, + ] + } + foo: {} + } + } +} diff --git a/internal/core/compile/testdata/sync/scalars/embed.txtar b/internal/core/compile/testdata/sync/scalars/embed.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/scalars/embed.txtar @@ -0,0 +1,349 @@ +-- in.cue -- +// Issue #739: Tests that scalar values (integers, lists, strings) embedded in +// structs participate correctly in arithmetic, indexing, and built-in function +// calls (list.Concat, strings.Join). Also covers definitions and optional fields +// used alongside embedded scalars, and comprehensions gated on optional presence. +// +// Issue #794: Tests that a hidden field used as a list element inside an embedded +// struct resolves to its concrete value (hidden.issue794: _foo embedded as [_foo]). +import "strings" +import "list" + +intEmbed: { + a1: { + 2 + @test(eq, 2) + } + a2: { + v: { + 3 + #foo: a2.v + 1 + } + w: v + x: v.#foo + @test(eq, { + v: {3, #foo: 4} @test(shareID=a2vw) + w: {3, #foo: 4} @test(shareID=a2vw) + x: 4 + }) + } + a3: a1 + a2.v @test(eq, 5) +} + +listEmbed: { + a1: { + 2 + @test(eq, 2) + } + b3: { + [1, 2] + #foo: 1 + @test(eq, {[1, 2], #foo: 1}) + } + b4: list.Concat([b3, b3]) @test(eq, [1, 2, 1, 2]) + b5: b3[1] @test(eq, 2) + b6: b3[5] @test(err, code=eval, contains="index out of range [5] with length 2", pos=[0:9]) + b7: b4[a1] @test(eq, 1) +} + +stringEmbed: { + s1: { + "foo" + #bar: "bar" + @test(eq, {"foo", #bar: "bar"}) + } + s2: [ s1, {s1.#bar, #baz: 4}] @test(eq, [ + {"foo", #bar: "bar"}, + {"bar", #baz: 4}, + ]) + s3: strings.Join(s2, "--") @test(eq, "foo--bar") +} + +outPattern: { + sum: { + out: #a + #b + #a: int + #b: int + } + used: { + sum & {#a: 1, #b: 3} + @test(eq, { + out: 4 + #a: 1 + #b: 3 + }) + } +} + +arithmetic: { + sum: { + #a + #b + #a: int + #b: int + } + a1: (sum & {_, #a: 1, #b: 3}) + 2 @test(eq, 6) + a2: 2 + (sum & {_, #a: 1, #b: 3}) @test(eq, 6) + a3: 2 + (2 + (sum & {_, #a: 1, #b: 3})) @test(eq, 8) +} + +defCheck: { + a: { + #def: 1 + @test(eq, {#def: 1}) + } + b: a.#def @test(eq, 1) +} + +optionalExists: { + string | { + value?: string + + if value != _|_ { + other: int + } + } + @test(eq, { string } | {value?: string}) +} + +optionalCheck: { + thing: string | { + value?: string + + if value != _|_ { + other: int + } + } + + thing: { + value: "some string" + other: 3 + } @test(eq, { + value: "some string" + other: 3 + }) +} + +hidden: { + issue794: { + _foo: "foo" + [_foo] + @test(eq, { + _foo: "foo" + ["foo"] + }) + } +} + +-- issue2113.cue -- +// Issue #2113: Tests that embedded scalars inside a definition function (#fn with +// an embedded bare value) resolve correctly when the definition is specialized, +// regardless of which field is declared first. The @test(permute) exercises all +// declaration orders to confirm order-independence. +merged: t1: { + @test(permute, count=6) + + #fn: { #in2: _, _ } + #fn: { #in2: c1: string, #in2.c1 } + x: #fn & {#in2: {c1: "V 1"}, _} + @test(eq, { + #fn: { string, #in2: c1: string } + x: { + "V 1" + #in2: {c1: "V 1"} + } + }) +} + +-- issue2163.cue -- +// Issue #2163: Tests that a self-referencing embedded expression — a definition +// that embeds (#Func & {_foo: #in, "buzz"}) + "fiz", where the embedded result +// depends on an inner field — does not panic or produce a spurious error. +selfRefInEmbed: t1: { + #Func: { + #in: _ + _ + } + #fn: #Func + #fn: { + #in: _ + + (#Func & { + _foo: #in + "buzz" + }) + "fiz" + } + + @test(eq, { + #Func: { + _ + #in: _ + } + #fn: { + "buzzfiz" + #in: _ + } + }) +} + +-- out/compile -- +--- in.cue +{ + intEmbed: { + a1: { + 2 + } + a2: { + v: { + 3 + #foo: (〈2;a2〉.v + 1) + } + w: 〈0;v〉 + x: 〈0;v〉.#foo + } + a3: (〈0;a1〉 + 〈0;a2〉.v) + } + listEmbed: { + a1: { + 2 + } + b3: { + [ + 1, + 2, + ] + #foo: 1 + } + b4: 〈import;list〉.Concat([ + 〈1;b3〉, + 〈1;b3〉, + ]) + b5: 〈0;b3〉[1] + b6: 〈0;b3〉[5] + b7: 〈0;b4〉[〈0;a1〉] + } + stringEmbed: { + s1: { + "foo" + #bar: "bar" + } + s2: [ + 〈1;s1〉, + { + 〈2;s1〉.#bar + #baz: 4 + }, + ] + s3: 〈import;strings〉.Join(〈0;s2〉, "--") + } + outPattern: { + sum: { + out: (〈0;#a〉 + 〈0;#b〉) + #a: int + #b: int + } + used: { + (〈1;sum〉 & { + #a: 1 + #b: 3 + }) + } + } + arithmetic: { + sum: { + (〈0;#a〉 + 〈0;#b〉) + #a: int + #b: int + } + a1: ((〈0;sum〉 & { + _ + #a: 1 + #b: 3 + }) + 2) + a2: (2 + (〈0;sum〉 & { + _ + #a: 1 + #b: 3 + })) + a3: (2 + (2 + (〈0;sum〉 & { + _ + #a: 1 + #b: 3 + }))) + } + defCheck: { + a: { + #def: 1 + } + b: 〈0;a〉.#def + } + optionalExists: { + (string|{ + value?: string + if (〈0;value〉 != _|_(explicit error (_|_ literal) in source)) { + other: int + } + }) + } + optionalCheck: { + thing: (string|{ + value?: string + if (〈0;value〉 != _|_(explicit error (_|_ literal) in source)) { + other: int + } + }) + thing: { + value: "some string" + other: 3 + } + } + hidden: { + issue794: { + _foo: "foo" + [ + 〈1;_foo〉, + ] + } + } +} +--- issue2113.cue +{ + merged: { + t1: { + #fn: { + #in2: _ + _ + } + #fn: { + #in2: { + c1: string + } + 〈0;#in2〉.c1 + } + x: (〈0;#fn〉 & { + #in2: { + c1: "V 1" + } + _ + }) + } + } +} +--- issue2163.cue +{ + selfRefInEmbed: { + t1: { + #Func: { + #in: _ + _ + } + #fn: 〈0;#Func〉 + #fn: { + #in: _ + ((〈1;#Func〉 & { + _foo: 〈1;#in〉 + "buzz" + }) + "fiz") + } + } + } +} diff --git a/internal/core/compile/testdata/sync/scalars/embed_bound.txtar b/internal/core/compile/testdata/sync/scalars/embed_bound.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/scalars/embed_bound.txtar @@ -0,0 +1,28 @@ +-- in.cue -- +// Embedding !=null at file scope should preserve the constraint, +// not collapse to (struct){}. + +a: { + !=null +} @test(eq, !=null) + +// As a field value, !=null is preserved. Verify parity. +b: !=null @test(eq, !=null) + +// !=null as embedding combined with a regular field. +c: { + !=null + x: 1 +} @test(eq, {x: 1}) +-- out/compile -- +--- in.cue +{ + a: { + !=null + } + b: !=null + c: { + !=null + x: 1 + } +} diff --git a/internal/core/compile/testdata/sync/scalars/emptystruct.txtar b/internal/core/compile/testdata/sync/scalars/emptystruct.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/scalars/emptystruct.txtar @@ -0,0 +1,195 @@ +// Tests that unifying a struct with an embedded scalar and definition fields +// against a definition (or disjunction of definitions) works correctly. +// The `ellipsis`, `bulk`, and `optional` groups cover open definitions with +// `...`, bulk constraints, and optional fields respectively. The `issue783` +// group covers the original bug: unifying such a struct against a disjunction +// of definitions (`{...} | {string, ...}`) was incorrectly failing or dropping +// disjunction branches. +// https://cuelang.org/issue/783 +-- in.cue -- +elipsis: { + test1: { + string + #foo: "bar" + } + + #Def: { + ... + #foo: string + _ + } + check: test1 & #Def + + @test(eq, { + test1: { + string + #foo: "bar" + } + #Def: { + #foo: string + _ + } + check: { + string + #foo: "bar" + } + }) +} + +bulk: { + test1: { + string + #foo: "bar" + } + + #Def: { + [string]: int + #foo: string + _ + } + check: test1 & #Def @test(eq, { + [string]: int + #foo: "bar" + string + }) @test(closed, hint="could be either") +} + +optional: { + test1: { + string + #foo: "bar" + } + + #Def: { + bar?: int + #foo: string + _ + } + check: test1 & #Def @test(eq, { + string + bar?: int + #foo: "bar" + }) +} + +// Tests that unifying a struct with an embedded scalar and definition fields +// against a definition (or disjunction of definitions) works correctly. +// The `ellipsis`, `bulk`, and `optional` groups cover open definitions with +// `...`, bulk constraints, and optional fields respectively. The `issue783` +// group covers the original bug: unifying such a struct against a disjunction +// of definitions (`{...} | {string, ...}`) was incorrectly failing or dropping +// disjunction branches. +// https://cuelang.org/issue/783 +issue783: { + test1: { + string + #foo: "bar" + } + + test2: { + hello: "world" + #foo: "bar" + } + + #Def1: { + ... + #foo: string + } | { + string + #foo: string + } @test(eq, { + #foo: string + } | { + string + #foo: string + }) + + check1a: test1 & #Def1 @test(eq, { + string + #foo: "bar" + }) + check1b: test2 & #Def1 @test(eq, { + hello: "world" + #foo: "bar" + }) + + #Def2: { + ... + #foo: string + _ + } + check2a: test1 & #Def2 @test(eq, { + string + #foo: "bar" + }) + check2b: test2 & #Def2 @test(eq, { + hello: "world" + #foo: "bar" + }) +} +-- out/compile -- +--- in.cue +{ + elipsis: { + test1: { + string + #foo: "bar" + } + #Def: { + ... + #foo: string + _ + } + check: (〈0;test1〉 & 〈0;#Def〉) + } + bulk: { + test1: { + string + #foo: "bar" + } + #Def: { + [string]: int + #foo: string + _ + } + check: (〈0;test1〉 & 〈0;#Def〉) + } + optional: { + test1: { + string + #foo: "bar" + } + #Def: { + bar?: int + #foo: string + _ + } + check: (〈0;test1〉 & 〈0;#Def〉) + } + issue783: { + test1: { + string + #foo: "bar" + } + test2: { + hello: "world" + #foo: "bar" + } + #Def1: ({ + ... + #foo: string + }|{ + string + #foo: string + }) + check1a: (〈0;test1〉 & 〈0;#Def1〉) + check1b: (〈0;test2〉 & 〈0;#Def1〉) + #Def2: { + ... + #foo: string + _ + } + check2a: (〈0;test1〉 & 〈0;#Def2〉) + check2b: (〈0;test2〉 & 〈0;#Def2〉) + } +} diff --git a/internal/core/compile/testdata/sync/scalars/yield.txtar b/internal/core/compile/testdata/sync/scalars/yield.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/scalars/yield.txtar @@ -0,0 +1,55 @@ +// Issue #729 +-- in.cue -- +ifScalar: { + _#cond: true + + if _#cond {5} + @test(eq, { + 5 + _#cond: true + }) +} + +ifScalarConflict: { + _#cond: true + + if _#cond {5} + + "soo" + @test(err, code=eval, contains="conflicting values", args=["soo", 5, string, int], pos=[0:19, 3:2, 3:13, 5:2]) +} + +ifScalarNested: { + _#cond: true + + if _#cond {{{5}}} + + @test(eq, {5, _#cond: true}) +} +-- out/compile -- +--- in.cue +{ + ifScalar: { + _#cond: true + if 〈0;_#cond〉 { + 5 + } + } + ifScalarConflict: { + _#cond: true + if 〈0;_#cond〉 { + 5 + } + "soo" + } + ifScalarNested: { + _#cond: true + if 〈0;_#cond〉 { + { + { + 5 + } + } + } + } +} diff --git a/internal/core/compile/testdata/sync/basicrewrite/aliases/aliases.txtar b/internal/core/compile/testdata/sync/basicrewrite/aliases/aliases.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/basicrewrite/aliases/aliases.txtar @@ -0,0 +1,34 @@ +-- in.cue -- +t0: { + a=_a: _ + let _b = a + _out: _b + @test(eq, { + _a: _ + let _b = _ + _out: _ + }) +} +t1: { + _a: b + let b = c + c=d: 3 +} @test(eq, { + _a: 3 + let b = 3 + d: 3 +}) +-- out/compile -- +--- in.cue +{ + t0: { + _a: _ + let _b#1 = 〈0;_a〉 + _out: 〈0;let _b#1〉 + } + t1: { + _a: 〈0;let b#2〉 + let b#2 = 〈0;d〉 + d: 3 + } +} diff --git a/internal/core/compile/testdata/sync/builtins/list/issue332.txtar b/internal/core/compile/testdata/sync/builtins/list/issue332.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/list/issue332.txtar @@ -0,0 +1,37 @@ +# Tests that list.FlattenN does not spuriously report an "incomplete value" +# error when its input list is derived from a definition field passed through +# a conjunction. Previously FlattenN failed when the list element was abstract. +# https://cuelang.org/issue/332 +-- in.cue -- +import "list" + +#d: { + #x: string + result: [#x] +} +#foo: { + X=#x: _ + y: list.FlattenN((#d & {#x: X}).result, 1) +} +r: #foo & { + #x: "hello" +} @test(eq, {#x: "hello", y: ["hello"]}) +-- out/compile -- +--- in.cue +{ + #d: { + #x: string + result: [ + 〈1;#x〉, + ] + } + #foo: { + #x: _ + y: 〈import;list〉.FlattenN((〈1;#d〉 & { + #x: 〈1;#x〉 + }).result, 1) + } + r: (〈0;#foo〉 & { + #x: "hello" + }) +} diff --git a/internal/core/compile/testdata/sync/builtins/list/sort.txtar b/internal/core/compile/testdata/sync/builtins/list/sort.txtar new file mode 100644 --- /dev/null +++ b/internal/core/compile/testdata/sync/builtins/list/sort.txtar @@ -0,0 +1,18 @@ +-- in.cue -- +import "list" + +a: list.Sort([2, 3, 1, 4], {x: _, y: _, less: x < y}) @test(eq, [1, 2, 3, 4]) +-- out/compile -- +--- in.cue +{ + a: 〈import;list〉.Sort([ + 2, + 3, + 1, + 4, + ], { + x: _ + y: _ + less: (〈0;x〉 < 〈0;y〉) + }) +}