cue: avoid early evaluation in several cases
Change-Id: Id7aa7d83b44732530805ed00bd44ece8412c6dc1
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/1786
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/ast.go b/cue/ast.go
index 4c5ece5..c4a2366 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -112,9 +112,11 @@
ctx := v.ctx()
label := v.label(n.Name, true)
if r := v.resolveRoot; r != nil {
- if a := r.lookup(v.ctx(), label); a.val() != nil {
- return &selectorExpr{newExpr(n),
- &nodeRef{baseValue: newExpr(n), node: r}, label}
+ for _, a := range r.arcs {
+ if a.feature == label {
+ return &selectorExpr{newExpr(n),
+ &nodeRef{baseValue: newExpr(n), node: r}, label}
+ }
}
if v.inSelector > 0 {
if p := getBuiltinShorthandPkg(ctx, n.Name); p != nil {
@@ -131,6 +133,8 @@
if err != nil {
return ctx.mkErr(newNode(imp), "illformed import spec")
}
+ // TODO: allow builtin *and* imported package. The result is a unified
+ // struct.
if p := getBuiltinPkg(ctx, path); p != nil {
return p
}
diff --git a/cue/context.go b/cue/context.go
index 7bfaae5..c115c7f 100644
--- a/cue/context.go
+++ b/cue/context.go
@@ -34,6 +34,8 @@
inSum int
cycleErr bool
+ noManifest bool
+
// for debug strings
nodeRefs map[scope]string
diff --git a/cue/evaluator.go b/cue/evaluator.go
index ad8c835..37b306c 100644
--- a/cue/evaluator.go
+++ b/cue/evaluator.go
@@ -16,6 +16,9 @@
func (c *context) manifest(v value) evaluated {
evaluated := v.evalPartial(c)
+ if c.noManifest {
+ return evaluated
+ }
for {
x, ok := evaluated.(*disjunction)
if !ok {
diff --git a/cue/types.go b/cue/types.go
index df76119..35a9576 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -920,9 +920,10 @@
if w.path == nil {
return v
}
- a := v.eval(ctx)
- b := w.eval(ctx)
- val := ctx.manifest(mkBin(ctx, token.NoPos, opUnify, a, b))
+ a := v.path.cache.evalPartial(ctx)
+ b := w.path.cache.evalPartial(ctx)
+ src := binSrc(token.NoPos, opUnify, a, b)
+ val := binOp(ctx, src, opUnify, a, b)
if err := validate(ctx, val); err != nil {
val = err
}
diff --git a/cue/value.go b/cue/value.go
index 976cd40..d1d8cf6 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -395,10 +395,17 @@
func mkIntRange(a, b string) evaluated {
from := &bound{op: opGeq, value: parseInt(intKind, a)}
to := &bound{op: opLeq, value: parseInt(intKind, b)}
- return &unification{
+ e := &unification{
binSrc(token.NoPos, opUnify, from, to),
[]evaluated{from, to},
}
+ // TODO: make this an integer
+ // int := &basicType{k: intKind}
+ // e = &unification{
+ // binSrc(token.NoPos, opUnify, int, e),
+ // []evaluated{int, e},
+ // }
+ return e
}
var predefinedRanges = map[string]evaluated{
@@ -1029,6 +1036,12 @@
return (!lt.marked || gt.marked) && subsumes(ctx, gt.val, lt.val, 0)
}
k := 0
+
+ // manifesting values should be disabled for recursive evaluation as
+ // these values may still be bound to another value later on, for instance
+ // when the result of this value is unified with another value.
+ noManifest := ctx.noManifest
+ ctx.noManifest = true
outer:
for i, v := range x.values {
// TODO: this is pre-evaluation is quite aggressive. Verify whether
@@ -1059,6 +1072,7 @@
x.values[k] = v
k++
}
+ ctx.noManifest = noManifest
switch k {
case 0: