internal/core/eval: simplify validators upon evaluator
Fixes #545
Change-Id: Ie4a7ca80b6be7a13c3547a31c3f85447fb174d55
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7222
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/internal/core/adt/simplify.go b/internal/core/adt/simplify.go
index cc35653..2c2e52b 100644
--- a/internal/core/adt/simplify.go
+++ b/internal/core/adt/simplify.go
@@ -33,11 +33,14 @@
switch {
case xCat == yCat:
- if x.Op == NotEqualOp || x.Op == MatchOp || x.Op == NotMatchOp {
+ switch x.Op {
+ // NOTE: EqualOp should not happen, but include it defensively.
+ // Maybe an API would use it, for instance.
+ case EqualOp, NotEqualOp, MatchOp, NotMatchOp:
if test(ctx, EqualOp, xv, yv) {
return x
}
- break // unify the two bounds
+ return nil // keep both bounds
}
// xCat == yCat && x.Op != NotEqualOp
@@ -193,3 +196,46 @@
}
return false
}
+
+// SimplifyValidator simplifies non-bound validators.
+//
+// Currently this only checks for pure equality. In the future this can be used
+// to simplify certain builtin validators analogously to how we simplify bounds
+// now.
+func SimplifyValidator(ctx *OpContext, v, w Validator) Validator {
+ switch x := v.(type) {
+ case *Builtin:
+ switch y := w.(type) {
+ case *Builtin:
+ if x == y {
+ return x
+ }
+
+ case *BuiltinValidator:
+ if y.Builtin == x && len(y.Args) == 0 {
+ return x
+ }
+ }
+
+ case *BuiltinValidator:
+ switch y := w.(type) {
+ case *Builtin:
+ return SimplifyValidator(ctx, y, x)
+
+ case *BuiltinValidator:
+ if x == y {
+ return x
+ }
+ if x.Builtin != y.Builtin || len(x.Args) != len(y.Args) {
+ return nil
+ }
+ for i, a := range x.Args {
+ if !test(ctx, EqualOp, a, y.Args[i]) {
+ return nil
+ }
+ }
+ return x
+ }
+ }
+ return nil
+}
diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go
index 5ab7c60..556d1a3 100644
--- a/internal/core/eval/eval.go
+++ b/internal/core/eval/eval.go
@@ -1294,11 +1294,36 @@
n.lowerBound = x
case adt.EqualOp, adt.NotEqualOp, adt.MatchOp, adt.NotMatchOp:
- n.checks = append(n.checks, x)
+ // This check serves as simplifier, but also to remove duplicates.
+ k := 0
+ match := false
+ for _, c := range n.checks {
+ if y, ok := c.(*adt.BoundValue); ok {
+ switch z := adt.SimplifyBounds(ctx, n.kind, x, y); {
+ case z == y:
+ match = true
+ case z == x:
+ continue
+ }
+ }
+ n.checks[k] = c
+ k++
+ }
+ n.checks = n.checks[:k]
+ if !match {
+ n.checks = append(n.checks, x)
+ }
return
}
case adt.Validator:
+ // This check serves as simplifier, but also to remove duplicates.
+ for i, y := range n.checks {
+ if b := adt.SimplifyValidator(ctx, x, y); b != nil {
+ n.checks[i] = b
+ return
+ }
+ }
n.checks = append(n.checks, x)
case *adt.Vertex: