Skip to content

Commit db98b5f

Browse files
committed
internal/core/adt: fix default handling
Evalv3 omitted the implementation of the following rule: if all the marked disjuncts of a marked disjunction are eliminated, then the remaining unmarked disjuncts are considered as if they originated from an unmarked disjunction. This change implements this. We used gemini 2.5 to derive a proof of the correctness of this algorithm. In the general case, it is commutative, but not associative. However, this proof was derived for any possible lattice. Making it more specific for the CUE lattice, no counter example could be found. To be sure, we took the counter examples of the general case, or more specifically the recipe on how to construct it, and created some CUE code that conforms to this pattern. The resulting tests all showed that CUE was associative. Although not a full proof, it will have to suffice for now. Note that with the foreseen changes to default handling, this would not longer be an issue. Fixes #3908 Issue #1304 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: Ifde75945952f00e1c4c7b07dca833e59144b919c Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1214564 TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Matthew Sackman <[email protected]>
1 parent 45bcd34 commit db98b5f

File tree

5 files changed

+250
-243
lines changed

5 files changed

+250
-243
lines changed

cue/testdata/choosedefault/002_associativity_of_defaults.txtar

Lines changed: 195 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,60 @@ s2: *1 | ((*2 | 3) & (*2 | 3))
1212
s3: *1 | ((*2 | 3) & 3)
1313
s4: *1 | ((*2 | 3) & 2)
1414
s5: *1 | *(*2 | 3)
15+
16+
e1: *(1&2) | (*"x" | string)
17+
e2: (*"x" | string) | *(1&2)
18+
19+
-- complex.cue --
20+
// add some test cases suggested by an automated prover based on this pattern:
21+
// 1. ValK = (ValA & ValB_ND) & ValC_D \neq _|_ (the element we track must exist).
22+
// 2. ValC_D & (ValA & ValB_D) = _|_ (for Path 1 Cond(ValC_D, Disj_AB) to be true).
23+
// 3. ValC_D & ValB_D \neq _|_ (for Path 2 Cond(ValC_D, Disj_B) to be false).
24+
25+
// Let's define these CUE values. The trick is that ValA must introduce a
26+
// component that causes ValC_D to conflict with (ValA & ValB_D),
27+
// but ValC_D must *not* conflict with ValB_D on its own.
28+
t1: {
29+
va: {a: 1, b: 2}
30+
vb1: {c: 3}
31+
vb2: {c: 4}
32+
vc : {c: 4}
33+
vd: string
34+
35+
A: va | vd
36+
B: *vb1 | vb2 | vd
37+
C: *vc | vd
38+
39+
p1: (A & B) & C
40+
p2: A & (B & C)
41+
}
42+
t2: {
43+
va: 0 | 1 | 2
44+
vb1: 2 | 3
45+
vb2: 0 | 1 | 4
46+
vc: 0 | 3 | 4
47+
vd: string
48+
49+
A: va | vd
50+
B: *vb1 | vb2 | vd
51+
C: *vc | vd
52+
53+
p1: (A & B) & C
54+
p2: A & (B & C)
55+
}
56+
-- issue3908.cue --
57+
issue3908: reduced: p1: {
58+
string | *null
59+
string | *"str"
60+
}
61+
issue3908: reduced: p2: {
62+
string | *"str"
63+
string | *null
64+
}
65+
issue3908: full: {
66+
out: #Schema & { field: string | *"dataDefault" }
67+
#Schema: field: string | *null
68+
}
1569
-- out/def --
1670
x: a & b
1771
y: b & c
@@ -21,6 +75,42 @@ c: *"a" | *"b" | "c"
2175
-- out/legacy-debug --
2276
<0>{x: "a", y: (*"a" | *"b"), a: "a", b: "a", c: (*"a" | *"b")}
2377
-- out/compile --
78+
--- complex.cue
79+
{
80+
t1: {
81+
va: {
82+
a: 1
83+
b: 2
84+
}
85+
vb1: {
86+
c: 3
87+
}
88+
vb2: {
89+
c: 4
90+
}
91+
vc: {
92+
c: 4
93+
}
94+
vd: string
95+
A: (〈0;va〉|〈0;vd〉)
96+
B: (*〈0;vb1〉|〈0;vb2〉|〈0;vd〉)
97+
C: (*〈0;vc〉|〈0;vd〉)
98+
p1: ((〈0;A〉 & 〈0;B〉) & 〈0;C〉)
99+
p2: (〈0;A〉 & (〈0;B〉 & 〈0;C〉))
100+
}
101+
t2: {
102+
va: (0|1|2)
103+
vb1: (2|3)
104+
vb2: (0|1|4)
105+
vc: (0|3|4)
106+
vd: string
107+
A: (〈0;va〉|〈0;vd〉)
108+
B: (*〈0;vb1〉|〈0;vb2〉|〈0;vd〉)
109+
C: (*〈0;vc〉|〈0;vd〉)
110+
p1: ((〈0;A〉 & 〈0;B〉) & 〈0;C〉)
111+
p2: (〈0;A〉 & (〈0;B〉 & 〈0;C〉))
112+
}
113+
}
24114
--- in.cue
25115
{
26116
a: (*"a"|("b"|"c"))
@@ -33,19 +123,100 @@ c: *"a" | *"b" | "c"
33123
s3: (*1|((*2|3) & 3))
34124
s4: (*1|((*2|3) & 2))
35125
s5: (*1|*(*2|3))
126+
e1: (*(1 & 2)|(*"x"|string))
127+
e2: ((*"x"|string)|*(1 & 2))
128+
}
129+
--- issue3908.cue
130+
{
131+
issue3908: {
132+
reduced: {
133+
p1: {
134+
(string|*null)
135+
(string|*"str")
136+
}
137+
}
138+
}
139+
issue3908: {
140+
reduced: {
141+
p2: {
142+
(string|*"str")
143+
(string|*null)
144+
}
145+
}
146+
}
147+
issue3908: {
148+
full: {
149+
out: (〈0;#Schema〉 & {
150+
field: (string|*"dataDefault")
151+
})
152+
#Schema: {
153+
field: (string|*null)
154+
}
155+
}
156+
}
36157
}
37158
-- out/eval/stats --
38159
Leaks: 0
39-
Freed: 83
40-
Reused: 74
41-
Allocs: 9
42-
Retain: 0
43-
44-
Unifications: 11
45-
Conjuncts: 93
46-
Disjuncts: 83
160+
Freed: 382
161+
Reused: 370
162+
Allocs: 12
163+
Retain: 1
164+
165+
Unifications: 104
166+
Conjuncts: 516
167+
Disjuncts: 383
47168
-- out/eval --
48169
(struct){
170+
t1: (struct){
171+
va: (struct){
172+
a: (int){ 1 }
173+
b: (int){ 2 }
174+
}
175+
vb1: (struct){
176+
c: (int){ 3 }
177+
}
178+
vb2: (struct){
179+
c: (int){ 4 }
180+
}
181+
vc: (struct){
182+
c: (int){ 4 }
183+
}
184+
vd: (string){ string }
185+
A: ((string|struct)){ |((struct){
186+
a: (int){ 1 }
187+
b: (int){ 2 }
188+
}, (string){ string }) }
189+
B: ((string|struct)){ |(*(struct){
190+
c: (int){ 3 }
191+
}, (struct){
192+
c: (int){ 4 }
193+
}, (string){ string }) }
194+
C: ((string|struct)){ |(*(struct){
195+
c: (int){ 4 }
196+
}, (string){ string }) }
197+
p1: ((string|struct)){ |(*(struct){
198+
a: (int){ 1 }
199+
b: (int){ 2 }
200+
c: (int){ 4 }
201+
}, (string){ string }) }
202+
p2: ((string|struct)){ |(*(struct){
203+
a: (int){ 1 }
204+
b: (int){ 2 }
205+
c: (int){ 4 }
206+
}, (string){ string }) }
207+
}
208+
t2: (struct){
209+
va: (int){ |((int){ 0 }, (int){ 1 }, (int){ 2 }) }
210+
vb1: (int){ |((int){ 2 }, (int){ 3 }) }
211+
vb2: (int){ |((int){ 0 }, (int){ 1 }, (int){ 4 }) }
212+
vc: (int){ |((int){ 0 }, (int){ 3 }, (int){ 4 }) }
213+
vd: (string){ string }
214+
A: ((int|string)){ |((int){ 0 }, (int){ 1 }, (int){ 2 }, (string){ string }) }
215+
B: ((int|string)){ |(*(int){ 2 }, *(int){ 3 }, (int){ 0 }, (int){ 1 }, (int){ 4 }, (string){ string }) }
216+
C: ((int|string)){ |(*(int){ 0 }, *(int){ 3 }, *(int){ 4 }, (string){ string }) }
217+
p1: ((int|string)){ |(*(int){ 0 }, (string){ string }) }
218+
p2: ((int|string)){ |(*(int){ 0 }, (string){ string }) }
219+
}
49220
a: (string){ |(*(string){ "a" }, (string){ "b" }, (string){ "c" }) }
50221
b: (string){ |(*(string){ "a" }, (string){ "b" }, (string){ "c" }) }
51222
c: (string){ |(*(string){ "a" }, (string){ "b" }, (string){ "c" }) }
@@ -56,4 +227,20 @@ Disjuncts: 83
56227
s3: (int){ |(*(int){ 1 }, (int){ 3 }) }
57228
s4: (int){ |(*(int){ 1 }, (int){ 2 }) }
58229
s5: (int){ |(*(int){ 1 }, *(int){ 2 }, (int){ 3 }) }
230+
e1: (string){ |((string){ "x" }, (string){ string }) }
231+
e2: (string){ |((string){ "x" }, (string){ string }) }
232+
issue3908: (struct){
233+
reduced: (struct){
234+
p1: (string){ |(*(string){ "str" }, (string){ string }) }
235+
p2: (string){ |(*(string){ "str" }, (string){ string }) }
236+
}
237+
full: (struct){
238+
out: (#struct){
239+
field: (string){ |(*(string){ "dataDefault" }, (string){ string }) }
240+
}
241+
#Schema: (#struct){
242+
field: ((null|string)){ |(*(null){ null }, (string){ string }) }
243+
}
244+
}
245+
}
59246
}

0 commit comments

Comments
 (0)