cue: make defaults associative
Change-Id: Iad95267e29f08d595b4acbf151fbbe5ccbfb0233
diff --git a/cue/eval.go b/cue/eval.go
index e3ca92d..fa204a8 100644
--- a/cue/eval.go
+++ b/cue/eval.go
@@ -313,7 +313,16 @@
for _, v := range x.values {
n := v.val.evalPartial(ctx)
changed = changed || n != v.val
- dn.add(ctx, n, v.marked)
+ // Including elements of disjunctions recursively makes default handling
+ // associative (*a | (*b|c)) == ((*a|*b) | c).
+ if d, ok := n.(*disjunction); ok {
+ changed = true
+ for _, dv := range d.values {
+ dn.add(ctx, dv.val, dv.marked)
+ }
+ } else {
+ dn.add(ctx, n, v.marked)
+ }
}
// TODO: move to evaluator
if !changed {
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index 6c9032c..47cd3fc 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -400,13 +400,15 @@
`,
out: `<0>{a: "a", b: "b", c: _|_((*"a" | *"b"):more than one default remaining ("a" and "b"))}`,
}, {
- desc: "disambiguation non-conflict",
+ desc: "associativity of defaults",
in: `
a: *"a" | ("b" | "c")
b: (*"a" | "b") | "c"
- c: a & b
+ c: *"a" | (*"b" | "c")
+ x: a & b
+ y: b & c
`,
- out: `<0>{a: "a", b: _|_(((*"a" | "b") | "c"):more than one element remaining ((*"a" | "b") and "c")), c: "a"}`,
+ out: `<0>{a: "a", b: "a", c: _|_((*"a" | *"b" | "c"):more than one default remaining ("a" and "b")), x: "a", y: _|_((*"a" | *"b" | "c"):more than one default remaining ("a" and "b"))}`,
}}
rewriteHelper(t, testCases, evalFull)
}
diff --git a/doc/ref/spec.md b/doc/ref/spec.md
index 7e0691c..deabfbc 100644
--- a/doc/ref/spec.md
+++ b/doc/ref/spec.md
@@ -602,10 +602,6 @@
A _disjunction_ of two values `a` and `b`, denoted as `a | b` in CUE,
defines the smallest value `d` such that `a ⊑ d` and `b ⊑ d`.
This style of disjunctions is sometimes also referred to as sum types.
-Disjunctions can have any number of elements.
-<!--
-Important now we have marks, as *a | *b | c differs from *a | (*b | c).
--->
These all follow from the definition of disjunction:
- The disjunction of `a` with itself is always `a`.