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
 			}