internal/core/adt: introduce HasDefaults for Disjunction
Unlike DisjunctionExpr, there is additional information
needed for Disjunction that cannot be derived from its
context:
If a Disjunction had failing defaults, all remaining terms
should be interpreted as not default in marked disjunction,
instead of terms in an unmarked disjunction. This is
indistinguishable from just NumDefaults and Errors.
Change-Id: I053d825da795c5487b5966df7378fd3cc37bd9a5
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8108
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/internal/core/adt/default.go b/internal/core/adt/default.go
index ad3382c..3140845 100644
--- a/internal/core/adt/default.go
+++ b/internal/core/adt/default.go
@@ -29,6 +29,10 @@
func (d *Disjunction) Default() Value {
switch d.NumDefaults {
case 0:
+ if d.HasDefaults {
+ // empty disjunction
+ return &Bottom{}
+ }
return d
case 1:
return d.Values[0]
@@ -54,6 +58,13 @@
switch d.NumDefaults {
case 0:
+ if d.HasDefaults {
+ v = &Vertex{
+ Parent: v.Parent,
+ status: Finalized,
+ BaseValue: &Bottom{},
+ }
+ }
return v
case 1:
w = d.Values[0]
diff --git a/internal/core/adt/disjunct.go b/internal/core/adt/disjunct.go
index b47c32c..aae182e 100644
--- a/internal/core/adt/disjunct.go
+++ b/internal/core/adt/disjunct.go
@@ -88,10 +88,12 @@
env *Environment
values []disjunct
numDefaults int
+ hasDefaults bool
cloneID CloseInfo
}
type disjunct struct {
+ v *Vertex
expr Expr
isDefault bool
}
@@ -105,7 +107,7 @@
if isDef {
numDefaults++
}
- a = append(a, disjunct{v.Val, isDef})
+ a = append(a, disjunct{nil, v.Val, isDef})
}
sort.SliceStable(a, func(i, j int) bool {
@@ -113,18 +115,20 @@
})
n.disjunctions = append(n.disjunctions,
- envDisjunct{env, a, numDefaults, cloneID})
+ envDisjunct{env, a, numDefaults, numDefaults > 0, cloneID})
+
}
func (n *nodeContext) addDisjunctionValue(env *Environment, x *Disjunction, cloneID CloseInfo) {
a := make([]disjunct, 0, len(x.Values))
for i, v := range x.Values {
- a = append(a, disjunct{v, i < x.NumDefaults})
+ a = append(a, disjunct{v, nil, i < x.NumDefaults})
}
n.disjunctions = append(n.disjunctions,
- envDisjunct{env, a, x.NumDefaults, cloneID})
+ envDisjunct{env, a, x.NumDefaults, x.HasDefaults, cloneID})
+
}
func (n *nodeContext) expandDisjuncts(
@@ -216,8 +220,12 @@
cn := dn.clone()
*cn.node = snapshotVertex(dn.snapshot)
- c := MakeConjunct(d.env, v.expr, d.cloneID)
- cn.addExprConjunct(c)
+ if v.v != nil {
+ cn.addValueConjunct(d.env, v.v, d.cloneID)
+ } else {
+ c := MakeConjunct(d.env, v.expr, d.cloneID)
+ cn.addExprConjunct(c)
+ }
newMode := mode(d, v)
@@ -302,7 +310,7 @@
func mode(d envDisjunct, v disjunct) defaultMode {
var mode defaultMode
switch {
- case d.numDefaults == 0:
+ case !d.hasDefaults:
mode = maybeDefault
case v.isDefault:
mode = isDefault
diff --git a/internal/core/adt/eval.go b/internal/core/adt/eval.go
index fc62de6..0365249 100644
--- a/internal/core/adt/eval.go
+++ b/internal/core/adt/eval.go
@@ -569,20 +569,28 @@
func (n *nodeContext) createDisjunct() *Disjunction {
a := make([]*Vertex, len(n.disjuncts))
p := 0
+ hasDefaults := false
for i, x := range n.disjuncts {
v := new(Vertex)
*v = x.result
- if x.defaultMode == isDefault {
+ switch x.defaultMode {
+ case isDefault:
a[i] = a[p]
a[p] = v
p++
- } else {
+ hasDefaults = true
+
+ case notDefault:
+ hasDefaults = true
+ fallthrough
+ case maybeDefault:
a[i] = v
}
}
return &Disjunction{
Values: a,
NumDefaults: p,
+ HasDefaults: hasDefaults,
}
}
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index 4563e88..d8f5118 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -1323,6 +1323,7 @@
// NumDefaults indicates the number of default values.
NumDefaults int
+ HasDefaults bool
}
func (x *Disjunction) Source() ast.Node { return x.Src }