internal/core/adt: fix disjunct dedupping regression
Equal was called on unfinalized values, which could lead
to premuture elimination of values.
Fixes #641
Change-Id: I56343ecee2c8bb6332903b5deed7906fd00925b3
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8224
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/testdata/eval/disjunctions.txtar b/cue/testdata/eval/disjunctions.txtar
index 31eba44..5027d2b 100644
--- a/cue/testdata/eval/disjunctions.txtar
+++ b/cue/testdata/eval/disjunctions.txtar
@@ -108,6 +108,31 @@
j: i.bar
}
+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"
+ }
+ }
+}
-- out/eval --
Errors:
f: 2 errors in empty disjunction:
@@ -251,6 +276,33 @@
// ./in.cue:107:6
}
}
+ issue641: (struct){
+ #A: (#struct){
+ type: (string){ "a" }
+ x: (string){ "" }
+ }
+ #B: (#struct){
+ type: (string){ "b" }
+ x: (string){ string }
+ }
+ #C: (#struct){
+ b: (struct){ |((#struct){
+ type: (string){ "a" }
+ x: (string){ "" }
+ }, (#struct){
+ type: (string){ "b" }
+ x: (string){ string }
+ }) }
+ }
+ e: (struct){
+ foobar: (#struct){
+ b: (#struct){
+ type: (string){ "b" }
+ x: (string){ "foobar" }
+ }
+ }
+ }
+ }
}
-- out/compile --
--- in.cue
@@ -411,4 +463,29 @@
})
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"
+ })
+ })
+ }
+ }
}
diff --git a/internal/core/adt/disjunct.go b/internal/core/adt/disjunct.go
index a24de24..d7b8f2f 100644
--- a/internal/core/adt/disjunct.go
+++ b/internal/core/adt/disjunct.go
@@ -165,22 +165,16 @@
}
return
}
- if n.node.BaseValue == nil {
- n.node.BaseValue = n.getValidators()
- }
-
- // TODO: clean up this mess:
- result := *n.node // XXX: n.result = snapshotVertex(n.node)?
-
- if recursive && state < Finalized {
- *n = m
- }
- n.result = result
- n.node = &n.result
if recursive {
+ *n = m
+ n.result = *n.node // XXX: n.result = snapshotVertex(n.node)?
+ n.node = &n.result
n.disjuncts = append(n.disjuncts, n)
}
+ if n.node.BaseValue == nil {
+ n.node.BaseValue = n.getValidators()
+ }
case len(n.disjunctions) > 0:
// Process full disjuncts to ensure that erroneous disjuncts are
@@ -201,6 +195,8 @@
// not be done unless there is complete information.
state = Partial
}
+ // TODO(perf): ideally always finalize. See comment below
+ // state = Finalized
for _, dn := range a {
switch {
@@ -272,6 +268,12 @@
outer:
for _, d := range n.disjuncts {
for _, v := range p.disjuncts {
+ // TODO(perf): not checking equality here may lead to polynomial
+ // blowup. Doesn't seem to affect large configurations, though,
+ // where this could matter at the moment.
+ if state != Finalized {
+ break
+ }
if Equal(n.ctx, &v.result, &d.result) {
if d.defaultMode == isDefault {
v.defaultMode = isDefault