internal/core/adt: introduce base value type
New type hierarchy:
Expr BaseValue
\. /
Value
Struct- and ListMarker are now only a
BaseValue and thus cannot be passed
as either a Value or Expr.
This makes the compiler enforce that List and
StructMarkers are not passed around as values.
The next step is to do some renaming.
Fixes #598
Change-Id: I205aec724fd8fc0eddc11fdbe27babe5c47fb622
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7765
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/cue/errors.go b/cue/errors.go
index b7d6fff..3ce30f0 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -101,13 +101,6 @@
Err: errors.Newf(token.NoPos, "undefined value"),
}
-func exists(v adt.Expr) bool {
- if err, ok := v.(*adt.Bottom); ok {
- return err.Code != codeNotExist
- }
- return true
-}
-
func (idx *index) mkErr(src adt.Node, args ...interface{}) *adt.Bottom {
var e *adt.Bottom
var code errCode = -1
diff --git a/cue/testdata/builtins/incomplete.txtar b/cue/testdata/builtins/incomplete.txtar
new file mode 100644
index 0000000..76954a4
--- /dev/null
+++ b/cue/testdata/builtins/incomplete.txtar
@@ -0,0 +1,151 @@
+-- in.cue --
+import "list"
+
+
+list1: {
+ // Note that Top is not incomplete, only its first element is.
+ // We allow FlattenN to proceed and pass on the incomplete values.
+ Out1: list.FlattenN(Top , 1)
+ Out2: [...] & list.FlattenN(Top , 1)
+ Out3: list.FlattenN(Top , 1) & [...]
+
+ // This evaluates to a list with an incomplete element.
+ Top: [
+ [ for _, F in _Sub { F } ],
+ ]
+
+ _Sub: a.b
+ a: {} // b does not
+}
+
+list2: {
+ Out1: list.FlattenN(_Top , 1)
+ Out2: [...] & list.FlattenN(_Top , 1)
+ Out3: list.FlattenN(_Top , 1) & [...]
+
+ // This evaluates to a list with an incomplete element.
+ _Top: [
+ for _, F in #Sub { F }
+ ]
+
+ #Sub: a.b
+ a: {} // b does not
+}
+
+value1: {
+ a: len('sf' | 'dd')
+}
+
+value2: {
+ len('sf' | 'dd')
+}
+
+-- out/eval --
+(struct){
+ list1: (struct){
+ Out1: (#list){
+ 0: (_|_){
+ // [incomplete] list1._Sub: undefined field b:
+ // ./in.cue:16:13
+ }
+ }
+ Out2: (#list){
+ 0: (_|_){
+ // [incomplete] list1._Sub: undefined field b:
+ // ./in.cue:16:13
+ }
+ }
+ Out3: (#list){
+ 0: (_|_){
+ // [incomplete] list1._Sub: undefined field b:
+ // ./in.cue:16:13
+ }
+ }
+ Top: (#list){
+ 0: (_|_){
+ // [incomplete] list1._Sub: undefined field b:
+ // ./in.cue:16:13
+ }
+ }
+ _Sub: (_|_){
+ // [incomplete] list1._Sub: undefined field b:
+ // ./in.cue:16:13
+ }
+ a: (struct){
+ }
+ }
+ list2: (struct){
+ Out1: (_|_){
+ // [incomplete] list2.#Sub: undefined field b:
+ // ./in.cue:30:13
+ }
+ Out2: (list){
+ }
+ Out3: (list){
+ }
+ _Top: (_|_){
+ // [incomplete] list2.#Sub: undefined field b:
+ // ./in.cue:30:13
+ }
+ #Sub: (_|_){
+ // [incomplete] list2.#Sub: undefined field b:
+ // ./in.cue:30:13
+ }
+ a: (struct){
+ }
+ }
+ value1: (struct){
+ a: (_|_){
+ // [incomplete] value1.a: unresolved disjunction 'sf' | 'dd' (type bytes):
+ // ./in.cue:35:8
+ }
+ }
+ value2: (_|_){
+ // [incomplete] value2: unresolved disjunction 'sf' | 'dd' (type bytes):
+ // ./in.cue:39:5
+ }
+}
+-- out/compile --
+--- in.cue
+{
+ list1: {
+ Out1: 〈import;list〉.FlattenN(〈0;Top〉, 1)
+ Out2: ([
+ ...,
+ ] & 〈import;list〉.FlattenN(〈0;Top〉, 1))
+ Out3: (〈import;list〉.FlattenN(〈0;Top〉, 1) & [
+ ...,
+ ])
+ Top: [
+ [
+ for _, F in 〈0;_Sub〉 {
+ 〈1;F〉
+ },
+ ],
+ ]
+ _Sub: 〈0;a〉.b
+ a: {}
+ }
+ list2: {
+ Out1: 〈import;list〉.FlattenN(〈0;_Top〉, 1)
+ Out2: ([
+ ...,
+ ] & 〈import;list〉.FlattenN(〈0;_Top〉, 1))
+ Out3: (〈import;list〉.FlattenN(〈0;_Top〉, 1) & [
+ ...,
+ ])
+ _Top: [
+ for _, F in 〈0;#Sub〉 {
+ 〈1;F〉
+ },
+ ]
+ #Sub: 〈0;a〉.b
+ a: {}
+ }
+ value1: {
+ a: len(('sf'|'dd'))
+ }
+ value2: {
+ len(('sf'|'dd'))
+ }
+}
diff --git a/cue/types.go b/cue/types.go
index e4d7cef..824594a 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1061,7 +1061,7 @@
if len(v.v.Conjuncts) == 1 {
return v.v.Conjuncts[0].Source()
}
- return v.v.Value.Source()
+ return v.v.ActualValue().Source()
}
// Err returns the error represented by v or nil v is not an error.
@@ -1125,7 +1125,10 @@
if v.v == nil {
return false
}
- return exists(v.v.Value)
+ if err, ok := v.v.Value.(*adt.Bottom); ok {
+ return err.Code != codeNotExist
+ }
+ return true
}
func (v Value) checkKind(ctx *context, want adt.Kind) *adt.Bottom {
diff --git a/internal/core/adt/adt.go b/internal/core/adt/adt.go
index a43792a..8336b8c 100644
--- a/internal/core/adt/adt.go
+++ b/internal/core/adt/adt.go
@@ -87,6 +87,11 @@
expr()
}
+// A BaseValue is any Value or a *Marker. It indicates the type of a Vertex.
+type BaseValue interface {
+ Kind() Kind
+}
+
// A Value represents a node in the evaluated data graph.
//
// All Values values can also be used as a Expr.
@@ -99,6 +104,9 @@
// An Evaluator provides a method to convert to a value.
type Evaluator interface {
Node
+
+ // evaluate evaluates the underlying expression. If the expression
+ // is incomplete, it may record the error in ctx and return nil.
evaluate(ctx *OpContext) Value
}
@@ -148,9 +156,7 @@
}
}
-func (x *NodeLink) Concreteness() Concreteness { return Concrete }
-func (x *ListMarker) Concreteness() Concreteness { return Concrete }
-func (x *StructMarker) Concreteness() Concreteness { return Concrete }
+func (x *NodeLink) Concreteness() Concreteness { return Concrete }
func (*Conjunction) Concreteness() Concreteness { return Constraint }
func (*Disjunction) Concreteness() Concreteness { return Constraint }
diff --git a/internal/core/adt/composite.go b/internal/core/adt/composite.go
index a6b56fe..cb73e84 100644
--- a/internal/core/adt/composite.go
+++ b/internal/core/adt/composite.go
@@ -180,7 +180,7 @@
// Value is the value associated with this vertex. For lists and structs
// this is a sentinel value indicating its kind.
- Value Value
+ Value BaseValue
// ChildErrors is the collection of all errors of children.
ChildErrors *Bottom
@@ -260,13 +260,14 @@
func (v *Vertex) ActualValue() Value {
// TODO: rename to Value.
switch x := v.Value.(type) {
- // XXX: remove
+ case nil:
+ return nil
case *StructMarker, *ListMarker:
return v
case Value:
return x
default:
- return v
+ panic(fmt.Sprintf("unexpected type %T", v.Value))
}
}
@@ -309,14 +310,14 @@
for i, c := range w.Conjuncts {
w.Conjuncts[i].CloseID = 0
if v, _ := c.x.(Value); v != nil {
- w.Conjuncts[i].x = toDataAll(v)
+ w.Conjuncts[i].x = toDataAll(v).(Value)
}
}
w.Closed = nil
return &w
}
-func toDataAll(v Value) Value {
+func toDataAll(v BaseValue) BaseValue {
switch x := v.(type) {
default:
return x
@@ -338,7 +339,8 @@
c := *x
c.Values = make([]Value, len(x.Values))
for i, v := range x.Values {
- c.Values[i] = toDataAll(v)
+ // This case is okay because the source is of type Value.
+ c.Values[i] = toDataAll(v).(Value)
}
return &c
}
@@ -372,11 +374,11 @@
}
func (v *Vertex) AddErr(ctx *OpContext, b *Bottom) {
- v.Value = CombineErrors(nil, v.Value, b)
+ v.Value = CombineErrors(nil, v.ActualValue(), b)
v.UpdateStatus(Finalized)
}
-func (v *Vertex) SetValue(ctx *OpContext, state VertexStatus, value Value) *Bottom {
+func (v *Vertex) SetValue(ctx *OpContext, state VertexStatus, value BaseValue) *Bottom {
v.Value = value
v.UpdateStatus(state)
return nil
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index 6c049a2..a68efa7 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -437,6 +437,10 @@
return v, true
}
+// getDefault resolves a disjunction to a single value. If there is no default
+// value, or if there is more than one default value, it reports an "incomplete"
+// error and return false. In all other cases it will return true, even if
+// v is already an error. v may be nil, in which case it will also return nil.
func (c *OpContext) getDefault(v Value, scalar bool) (result Value, ok bool) {
var d *Disjunction
switch x := v.(type) {
@@ -515,7 +519,6 @@
func (c *OpContext) eval(x Expr) (result Value) {
v := c.evalState(x, Partial)
return v
-
}
func (c *OpContext) evalState(v Expr, state VertexStatus) (result Value) {
@@ -557,10 +560,9 @@
return v
default:
- // return nil
- c.AddErrf("unexpected Expr type %T", v)
+ // This can only happen, really, if v == nil, which is not allowed.
+ panic(fmt.Sprintf("unexpected Expr type %T", v))
}
- return nil
}
func (c *OpContext) lookup(x *Vertex, pos token.Pos, l Feature) *Vertex {
@@ -674,7 +676,7 @@
node, ok := v.(*Vertex)
if ok {
- v = node.Value
+ v = node.ActualValue()
}
switch nv := v.(type) {
case nil:
@@ -682,13 +684,15 @@
return emptyNode
case *Bottom:
+ // TODO: this is a bit messy. In some cases errors are already added
+ // and in some cases not. Not a huge deal, as errors will be uniqued
+ // down the line, but could be better.
c.AddBottom(nv)
return emptyNode
- case *StructMarker, *ListMarker:
+ case *Vertex:
if node == nil {
- Assert("unexpected markers with nil node", false)
- return emptyNode
+ panic("unexpected markers with nil node")
}
default:
diff --git a/internal/core/adt/errors.go b/internal/core/adt/errors.go
index f29fe53..42f5906 100644
--- a/internal/core/adt/errors.go
+++ b/internal/core/adt/errors.go
@@ -153,7 +153,7 @@
if err == nil {
v.Value = &Bottom{
Code: recursive.Code,
- Value: x,
+ Value: v,
HasRecursive: true,
ChildError: true,
Err: recursive.Err,
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index bd4a02c..d617af7 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -899,9 +899,16 @@
func (x *CallExpr) evaluate(c *OpContext) Value {
fun := c.value(x.Fun)
args := []Value{}
- for _, a := range x.Args {
+ for i, a := range x.Args {
expr := c.value(a)
- if v, ok := expr.(*Vertex); ok {
+ switch v := expr.(type) {
+ case nil:
+ // There SHOULD be an error in the context. If not, we generate
+ // one.
+ c.Assertf(pos(x.Fun), c.HasErr(),
+ "argument %d to function %s is incomplete", i, c.Str(x.Fun))
+
+ case *Vertex:
// Remove the path of the origin for arguments. This results in
// more sensible error messages: an error should refer to the call
// site, not the original location of the argument.
@@ -910,7 +917,8 @@
w := *v
w.Parent = nil
args = append(args, &w)
- } else {
+
+ default:
args = append(args, expr)
}
}
@@ -969,7 +977,7 @@
func bottom(v Value) *Bottom {
if x, ok := v.(*Vertex); ok {
- v = x.Value
+ v = x.ActualValue()
}
b, _ := v.(*Bottom)
return b
diff --git a/internal/core/adt/kind.go b/internal/core/adt/kind.go
index ddc3cbb..5715693 100644
--- a/internal/core/adt/kind.go
+++ b/internal/core/adt/kind.go
@@ -45,7 +45,7 @@
// IsConcrete returns whether a value is concrete.
func IsConcrete(v Value) bool {
if x, ok := v.(*Vertex); ok {
- v = x.Value
+ return x.IsConcrete()
}
if v == nil {
return false
diff --git a/internal/core/compile/builtin.go b/internal/core/compile/builtin.go
index 75972dc..b1e3e5a 100644
--- a/internal/core/compile/builtin.go
+++ b/internal/core/compile/builtin.go
@@ -48,7 +48,7 @@
return c.NewInt64(int64(n), v)
default:
- v = x.Value
+ v = x.ActualValue()
}
}
@@ -98,7 +98,7 @@
}
a := []adt.Value{}
for _, c := range list {
- a = append(a, c.Value)
+ a = append(a, c.ActualValue())
}
return &adt.Conjunction{Values: a}
},
diff --git a/internal/core/debug/compact.go b/internal/core/debug/compact.go
index 16bb3bf..88b9965 100644
--- a/internal/core/debug/compact.go
+++ b/internal/core/debug/compact.go
@@ -44,7 +44,7 @@
return
}
- switch x.Value.(type) {
+ switch v := x.Value.(type) {
case *adt.StructMarker:
w.string("{")
for i, a := range x.Arcs {
@@ -67,8 +67,8 @@
}
w.string("]")
- default:
- w.node(x.Value)
+ case adt.Value:
+ w.node(v)
}
case *adt.StructMarker:
diff --git a/internal/core/debug/debug.go b/internal/core/debug/debug.go
index b847406..cb55cbe 100644
--- a/internal/core/debug/debug.go
+++ b/internal/core/debug/debug.go
@@ -193,15 +193,15 @@
// // return
// }
- default:
+ case adt.Value:
if len(x.Arcs) == 0 {
w.string(" ")
- w.node(x.Value)
+ w.node(v)
w.string(" }")
return
}
w.string("\n")
- w.node(x.Value)
+ w.node(v)
}
for _, a := range x.Arcs {
diff --git a/internal/core/eval/disjunct.go b/internal/core/eval/disjunct.go
index 57a2f7e..bef789b 100644
--- a/internal/core/eval/disjunct.go
+++ b/internal/core/eval/disjunct.go
@@ -137,14 +137,13 @@
if !ok {
err = n.getErr()
}
- _ = ok
if err == nil {
+ // TODO(disjuncts): Is this always correct? Especially for partial
+ // evaluation it is okay for child errors to have incomplete errors.
+ // Perhaps introduce an Err() method.
err = x.ChildErrors
}
if err != nil {
- if Debug {
- // fmt.Println(err)
- }
n.disjunctErrs = append(n.disjunctErrs, err)
}
return n.isFinal
diff --git a/internal/core/eval/equality.go b/internal/core/eval/equality.go
index cb9f9da..f98d74b 100644
--- a/internal/core/eval/equality.go
+++ b/internal/core/eval/equality.go
@@ -34,11 +34,15 @@
if x == y {
return true
}
- if len(x.Arcs) != len(y.Arcs) {
+ xk := x.Kind()
+ yk := y.Kind()
+
+ if xk != yk {
return false
}
- if len(x.Arcs) == 0 && len(y.Arcs) == 0 {
- return equalTerminal(ctx, x.Value, y.Value)
+
+ if len(x.Arcs) != len(y.Arcs) {
+ return false
}
loop1:
@@ -65,13 +69,20 @@
// return false
// }
- return equalTerminal(ctx, x.Value, y.Value)
+ v, ok1 := x.Value.(adt.Value)
+ w, ok2 := y.Value.(adt.Value)
+ if !ok1 && !ok2 {
+ return true // both are struct or list.
+ }
+
+ return equalTerminal(ctx, v, w)
}
func equalTerminal(ctx *adt.OpContext, v, w adt.Value) bool {
if v == w {
return true
}
+
switch x := v.(type) {
case *adt.Num, *adt.String, *adt.Bool, *adt.Bytes:
if b, ok := adt.BinOp(ctx, adt.EqualOp, v, w).(*adt.Bool); ok {
@@ -119,14 +130,6 @@
}
return true
- case *adt.ListMarker:
- _, ok := w.(*adt.ListMarker)
- return ok
-
- case *adt.StructMarker:
- _, ok := w.(*adt.StructMarker)
- return ok
-
case *adt.BuiltinValidator:
}
diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go
index 30499e1..7602714 100644
--- a/internal/core/eval/eval.go
+++ b/internal/core/eval/eval.go
@@ -147,7 +147,7 @@
//
// TODO: return *adt.Vertex
func (e *Evaluator) Evaluate(c *adt.OpContext, v *adt.Vertex) adt.Value {
- var resultValue adt.Value
+ var result adt.Vertex
if b, _ := v.Value.(*adt.Bottom); b != nil {
return b
@@ -159,10 +159,14 @@
s := e.evalVertex(c, v, adt.Partial, nil)
defer e.freeSharedNode(s)
- resultValue = v.Value
- if s.result_.Value != nil {
+ result = *v
+
+ if s.result_.Value != nil { // There is a complete result.
*v = s.result_
- resultValue = v.Value
+ result = *v
+ } else if b, ok := v.Value.(*adt.Bottom); ok {
+ *v = save
+ return b
} else {
*v = save
}
@@ -218,7 +222,7 @@
return d
}
- err, _ := resultValue.(*adt.Bottom)
+ err, _ := result.Value.(*adt.Bottom)
// BEFORE RESTORING, copy the value to return one
// with the temporary arcs.
if !s.done() && (err == nil || err.IsIncomplete()) {
@@ -241,7 +245,7 @@
// gets the concrete value.
//
if v.Value == nil {
- return resultValue
+ return &result
}
return v
}
@@ -515,7 +519,6 @@
n.node.UpdateStatus(adt.Partial)
// Either set to Conjunction or error.
- var v adt.Value = n.node.Value
// TODO: verify and simplify the below code to determine whether
// something is a struct.
markStruct := false
@@ -524,11 +527,15 @@
} else if len(n.node.Structs) > 0 {
markStruct = n.kind&adt.StructKind != 0 && !n.hasTop
}
- if v == nil && markStruct {
+ v := n.node.ActualValue()
+ if n.node.Value == nil && markStruct {
n.node.Value = &adt.StructMarker{}
v = n.node
}
if v != nil && adt.IsConcrete(v) {
+ // Also check when we already have errors as we may find more
+ // serious errors and would like to know about all errors anyway.
+
if n.lowerBound != nil {
if b := ctx.Validate(n.lowerBound, v); b != nil {
// TODO(errors): make Validate return boolean and generate
@@ -603,12 +610,14 @@
ctx := n.ctx
if cyclic := n.hasCycle && !n.hasNonCycle; cyclic {
- n.node.Value = adt.CombineErrors(nil, n.node.Value, &adt.Bottom{
- Code: adt.StructuralCycleError,
- Err: ctx.Newf("structural cycle"),
- Value: n.node.Value,
- // TODO: probably, this should have the referenced arc.
- })
+ n.node.Value = adt.CombineErrors(nil,
+ n.node.ActualValue(),
+ &adt.Bottom{
+ Code: adt.StructuralCycleError,
+ Err: ctx.Newf("structural cycle"),
+ Value: n.node.ActualValue(),
+ // TODO: probably, this should have the referenced arc.
+ })
} else {
// Visit arcs recursively to validate and compute error.
for _, a := range n.node.Arcs {
@@ -978,7 +987,7 @@
}
// getValidators sets the vertex' Value in case there was no concrete value.
-func (n *nodeContext) getValidators() adt.Value {
+func (n *nodeContext) getValidators() adt.BaseValue {
ctx := n.ctx
a := []adt.Value{}
@@ -1013,7 +1022,7 @@
a = append(a, &adt.BasicType{K: n.kind})
}
- var v adt.Value
+ var v adt.BaseValue
switch len(a) {
case 0:
// Src is the combined input.
@@ -1123,7 +1132,8 @@
}
}
-// evalExpr is only called by addExprConjunct.
+// evalExpr is only called by addExprConjunct. If an error occurs, it records
+// the error in n and returns nil.
func (n *nodeContext) evalExpr(v adt.Conjunct) {
// Require an Environment.
ctx := n.ctx
@@ -1409,6 +1419,9 @@
// TODO: evaluate value?
switch v := x.Value.(type) {
+ default:
+ panic("invalid value")
+
case *adt.ListMarker:
n.vLists = append(n.vLists, x)
return
@@ -1429,7 +1442,7 @@
closedInfo(n.node).insertFieldSet(id, &opt)
- default:
+ case adt.Value:
n.addValueConjunct(env, v, id)
// TODO: this would not be necessary if acceptor.isClose were
@@ -1922,7 +1935,8 @@
for _, a := range elems {
if a.Conjuncts == nil {
- n.insertField(a.Label, adt.MakeConjunct(nil, a.Value, 0))
+ x := a.Value.(adt.Value)
+ n.insertField(a.Label, adt.MakeConjunct(nil, x, 0))
continue
}
for _, c := range a.Conjuncts {
@@ -1933,9 +1947,6 @@
outer:
for i, l := range n.lists {
- oneOfTheLists = l.list
- anID = l.id
-
n.updateCyclicStatus(l.env)
index := int64(0)
@@ -1953,6 +1964,7 @@
hasComprehension = true
if err != nil {
n.addBottom(err)
+ continue outer
}
case *adt.Ellipsis:
@@ -1976,6 +1988,9 @@
}
}
+ oneOfTheLists = l.list
+ anID = l.id
+
switch closed := n.lists[i].elipsis == nil; {
case int(index) < max:
if closed {
diff --git a/internal/core/export/expr.go b/internal/core/export/expr.go
index a89beac..99cf2cf 100644
--- a/internal/core/export/expr.go
+++ b/internal/core/export/expr.go
@@ -271,8 +271,17 @@
e.top().upCount--
case adt.Value: // other values.
- if v, ok := x.(*adt.Vertex); ok {
- if v.IsList() {
+ switch v := x.(type) {
+ case nil:
+ case *adt.Top:
+ default:
+ e.values.AddConjunct(adt.MakeRootConjunct(env, x)) // GOBBLE TOP
+
+ case *adt.Vertex:
+ e.structs = append(e.structs, v.Structs...)
+
+ switch y := v.Value.(type) {
+ case *adt.ListMarker:
a := []ast.Expr{}
for _, x := range v.Elems() {
a = append(a, e.expr(x))
@@ -284,9 +293,13 @@
}
e.exprs = append(e.exprs, ast.NewList(a...))
return
- }
- e.structs = append(e.structs, v.Structs...)
+ case *adt.StructMarker:
+ x = nil
+
+ case adt.Value:
+ e.values.AddConjunct(adt.MakeRootConjunct(env, y)) // GOBBLE TOP
+ }
// generated, only consider arcs.
for _, a := range v.Arcs {
@@ -294,15 +307,7 @@
e.addConjunct(a.Label, env, a)
}
- x = v.Value
// e.exprs = append(e.exprs, e.value(v, v.Conjuncts...))
- // return
- }
-
- switch x.(type) {
- case *adt.StructMarker, *adt.Top:
- default:
- e.values.AddConjunct(adt.MakeRootConjunct(env, x)) // GOBBLE TOP
}
case *adt.BinaryExpr:
diff --git a/internal/core/export/value.go b/internal/core/export/value.go
index 7b5e99f..8583fd7 100644
--- a/internal/core/export/value.go
+++ b/internal/core/export/value.go
@@ -67,12 +67,15 @@
}
result = ast.NewBinExpr(token.AND, a...)
- default:
+ case adt.Value:
if e.showArcs(n) {
result = e.structComposite(n)
} else {
- result = e.value(n.Value, n.Conjuncts...)
+ result = e.value(x, n.Conjuncts...)
}
+
+ default:
+ panic("unknow value")
}
return result
}
@@ -336,7 +339,7 @@
case *adt.ListMarker:
// As lists may be long, put them at the end.
defer e.addEmbed(e.listComposite(v))
- default:
+ case adt.Value:
e.addEmbed(e.value(x))
}
diff --git a/internal/core/subsume/value.go b/internal/core/subsume/value.go
index 1adb068..f050b81 100644
--- a/internal/core/subsume/value.go
+++ b/internal/core/subsume/value.go
@@ -47,8 +47,11 @@
if a, ok := a.(*adt.Vertex); ok {
return s.vertices(a, b)
}
- // Safe to ignore arcs of w.
- return s.values(a, b.Value)
+ if v, ok := b.Value.(adt.Value); ok {
+ // Safe to ignore arcs of w.
+ return s.values(a, v)
+ }
+ // Check based on first value.
case *adt.Conjunction:
if _, ok := a.(*adt.Conjunction); ok {
@@ -126,14 +129,15 @@
case *adt.Vertex:
y, ok := b.(*adt.Vertex)
- if !ok {
- // // Under what conditions can we cast to the value?
- if len(x.Arcs) == 0 && x.Value != nil {
- return s.values(x.Value, b)
- }
- return false
+ if ok {
+ return s.vertices(x, y)
}
- return s.vertices(x, y)
+
+ // TODO: Under what conditions can we cast to the value?
+ if v, _ := x.Value.(adt.Value); v != nil {
+ return s.values(v, b)
+ }
+ return false
case *adt.Conjunction:
if y, ok := b.(*adt.Conjunction); ok {
diff --git a/internal/core/subsume/vertex.go b/internal/core/subsume/vertex.go
index 189b1d9..8041bc6 100644
--- a/internal/core/subsume/vertex.go
+++ b/internal/core/subsume/vertex.go
@@ -15,6 +15,8 @@
package subsume
import (
+ "fmt"
+
"cuelang.org/go/internal/core/adt"
"cuelang.org/go/internal/core/export"
)
@@ -65,8 +67,8 @@
return false
}
- default:
- if !s.values(v, y.Value) {
+ case adt.Value:
+ if !s.values(v, y.ActualValue()) {
return false
}
@@ -74,6 +76,9 @@
if final {
return true
}
+
+ default:
+ panic(fmt.Sprintf("unexpected type %T", v))
}
xClosed := x.IsClosed(ctx) && !s.IgnoreClosedness
diff --git a/internal/core/validate/validate.go b/internal/core/validate/validate.go
index f1da4e8..fe549ae 100644
--- a/internal/core/validate/validate.go
+++ b/internal/core/validate/validate.go
@@ -89,9 +89,10 @@
} else if v.checkConcrete() {
x := x.Default()
if !adt.IsConcrete(x) {
+ x := x.ActualValue()
v.add(&adt.Bottom{
Code: adt.IncompleteError,
- Err: v.ctx.Newf("incomplete value %v", v.ctx.Str(x.Value)),
+ Err: v.ctx.Newf("incomplete value %v", v.ctx.Str(x)),
})
}
}
diff --git a/tools/flow/tasks.go b/tools/flow/tasks.go
index 6ef1d6f..b301c9b 100644
--- a/tools/flow/tasks.go
+++ b/tools/flow/tasks.go
@@ -161,7 +161,7 @@
n := d.Node
for ; n != nil; n = n.Parent {
- if c.cfg.IgnoreConcrete && n.Value.Concreteness() <= adt.Concrete {
+ if c.cfg.IgnoreConcrete && n.IsConcrete() {
if k := n.Value.Kind(); k != adt.StructKind && k != adt.ListKind {
return nil
}