internal/core/export: fix optional output bug

Fixes #662

Change-Id: Iac1198c0eabd9fcdbfa89db5c20d2c03d931afc5
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8325
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/internal/core/export/testdata/adt.txtar b/internal/core/export/testdata/adt.txtar
index a13f3b7..8668310 100644
--- a/internal/core/export/testdata/adt.txtar
+++ b/internal/core/export/testdata/adt.txtar
@@ -319,3 +319,5 @@
 		[1, _|_]
 	}
 }
+== Eval
+_|_ // e3: index out of range [2] with length 2
diff --git a/internal/core/export/testdata/alias.txtar b/internal/core/export/testdata/alias.txtar
index ce85066..5ce1676 100644
--- a/internal/core/export/testdata/alias.txtar
+++ b/internal/core/export/testdata/alias.txtar
@@ -83,3 +83,12 @@
 	Y="a-c": 5
 	"d-2": {}
 }
+== Eval
+{
+	"a-b":   4
+	foo:     4
+	bar?:    Y
+	baz:     3
+	Y="a-c": 5
+	"d-2": {}
+}
diff --git a/internal/core/export/testdata/def.txtar b/internal/core/export/testdata/def.txtar
index 381535c..155129b 100644
--- a/internal/core/export/testdata/def.txtar
+++ b/internal/core/export/testdata/def.txtar
@@ -1,24 +1,43 @@
 -- in.cue --
-a: int | *2
+a:  int | *2
+b?: 4 | 5
+c:  [string]: int
 -- out/definition --
-a: int | *2
+a:  int | *2
+b?: 4 | 5
+c: {
+	[string]: int
+}
 -- out/doc --
 []
 [a]
+[c]
 -- out/value --
 == Simplified
 {
 	a: *2 | int
+	c: {}
 }
 == Raw
 {
-	a: *2 | int
+	a:  *2 | int
+	b?: 4 | 5
+	c: {}
 }
 == Final
 {
 	a: 2
+	c: {}
 }
 == All
 {
-	a: *2 | int
+	a:  *2 | int
+	b?: 4 | 5
+	c: {}
+}
+== Eval
+{
+	a:  2
+	b?: 4 | 5
+	c: {}
 }
diff --git a/internal/core/export/testdata/docs.txtar b/internal/core/export/testdata/docs.txtar
index 89ff118..c8ad5bb 100644
--- a/internal/core/export/testdata/docs.txtar
+++ b/internal/core/export/testdata/docs.txtar
@@ -286,3 +286,26 @@
 		field2: int
 	}
 }
+== Eval
+{
+	Foo: {
+		field1: int
+		field2: int
+		dup3:   int
+	}
+	foos: {
+		MyFoo: {
+			field1: 0
+			field2: 1
+			dup3:   int
+		}
+	}
+	bar: {
+		field1: int
+		field2: int
+	}
+	baz: {
+		field1: int
+		field2: int
+	}
+}
diff --git a/internal/core/export/testdata/embedscalar.txtar b/internal/core/export/testdata/embedscalar.txtar
index 4302de6..33fd3c0 100644
--- a/internal/core/export/testdata/embedscalar.txtar
+++ b/internal/core/export/testdata/embedscalar.txtar
@@ -85,3 +85,19 @@
 		}
 	}
 }
+== Eval
+{
+	#top: 4
+	sub: {
+		#sub: 5
+		a: {
+			3
+			#foo: 4
+		}
+		b: {
+			#bar: 5
+			#baz: "foo"
+			[1, 2]
+		}
+	}
+}
diff --git a/internal/core/export/testdata/hidden.txtar b/internal/core/export/testdata/hidden.txtar
index 334b20e..644139c 100644
--- a/internal/core/export/testdata/hidden.txtar
+++ b/internal/core/export/testdata/hidden.txtar
@@ -55,3 +55,7 @@
 		_#val: 6
 	}
 }
+== Eval
+{
+	a: {}
+}
diff --git a/internal/core/export/testdata/issue662.txtar b/internal/core/export/testdata/issue662.txtar
new file mode 100644
index 0000000..ff9a2be
--- /dev/null
+++ b/internal/core/export/testdata/issue662.txtar
@@ -0,0 +1,53 @@
+
+-- uplot.cue --
+#LineConfig: {
+  lineColor?: string
+}
+
+#GraphFieldConfig: #LineConfig & {
+  drawStyle?: int
+}
+-- out/definition --
+#LineConfig: {
+	lineColor?: string
+}
+#GraphFieldConfig: {
+	#LineConfig
+	drawStyle?: int
+}
+-- out/doc --
+[]
+[#LineConfig]
+[#GraphFieldConfig]
+-- out/value --
+== Simplified
+{}
+== Raw
+{
+	#LineConfig: {
+		lineColor?: string
+	}
+	#GraphFieldConfig: {
+		lineColor?: string
+	}
+}
+== Final
+{}
+== All
+{
+	#LineConfig: {
+		lineColor?: string
+	}
+	#GraphFieldConfig: {
+		lineColor?: string
+	}
+}
+== Eval
+{
+	#LineConfig: {
+		lineColor?: string
+	}
+	#GraphFieldConfig: {
+		lineColor?: string
+	}
+}
diff --git a/internal/core/export/testdata/let.txtar b/internal/core/export/testdata/let.txtar
index 641b124..8044df2 100644
--- a/internal/core/export/testdata/let.txtar
+++ b/internal/core/export/testdata/let.txtar
@@ -166,3 +166,28 @@
 	}
 	y: "foo"
 }
+== Eval
+{
+	#Foo: 2
+	x:    "foo"
+	cfgs: [{
+		metadata: {
+			name: "one"
+		}
+	}, {
+		metadata: {
+			name: "two"
+		}
+	}]
+	let filepath = "kind-\(cfg.name)"
+	files: {
+		"\(filepath)": {
+			patches: cfg
+		}
+	} & {
+		"\(filepath)": {
+			patches: cfg
+		}
+	}
+	y: "foo"
+}
diff --git a/internal/core/export/testdata/simplify.txtar b/internal/core/export/testdata/simplify.txtar
index f754b70..7dbcb5c 100644
--- a/internal/core/export/testdata/simplify.txtar
+++ b/internal/core/export/testdata/simplify.txtar
@@ -50,3 +50,10 @@
 	}
 	s: strings.MinRunes(4) & strings.MaxRunes(7)
 }
+== Eval
+{
+	x: {
+		y: >=-9223372036854775808 & <=9223372036854775807 & int
+	}
+	s: strings.MinRunes(4) & strings.MaxRunes(7)
+}
diff --git a/internal/core/export/testdata/strings.txtar b/internal/core/export/testdata/strings.txtar
index 01c3fe4..6ac15c1 100644
--- a/internal/core/export/testdata/strings.txtar
+++ b/internal/core/export/testdata/strings.txtar
@@ -142,3 +142,29 @@
 		line!
 		'''
 }
+== Eval
+{
+	a: """
+		multi
+		line
+		"""
+	b: """
+		message: multi
+		line!
+		"""
+	c: {
+		d: """
+			multi
+			line
+			"""
+	}
+	bin1: '''
+		multi
+		line
+		'''
+	bin2: '''
+		multi
+		message: multi
+		line!
+		'''
+}
diff --git a/internal/core/export/testdata/topo.txtar b/internal/core/export/testdata/topo.txtar
index a39c486..47bc2da 100644
--- a/internal/core/export/testdata/topo.txtar
+++ b/internal/core/export/testdata/topo.txtar
@@ -65,3 +65,12 @@
 	f: 4
 	g: 4
 }
+== Eval
+{
+	a: 1
+	b: 1
+	c: 2
+	e: 3
+	f: 4
+	g: 4
+}
diff --git a/internal/core/export/value.go b/internal/core/export/value.go
index 612374d..fd5ff07 100644
--- a/internal/core/export/value.go
+++ b/internal/core/export/value.go
@@ -66,14 +66,6 @@
 
 		case !x.IsIncomplete() || len(n.Conjuncts) == 0:
 			result = e.bottom(x)
-
-		default:
-			// fall back to expression mode
-			a := []ast.Expr{}
-			for _, c := range n.Conjuncts {
-				a = append(a, e.expr(c.Expr()))
-			}
-			result = ast.NewBinExpr(token.AND, a...)
 		}
 
 	case adt.Value:
@@ -84,7 +76,15 @@
 		}
 
 	default:
-		panic("unknow value")
+		panic("unknown value")
+	}
+	if result == nil {
+		// fall back to expression mode
+		a := []ast.Expr{}
+		for _, c := range n.Conjuncts {
+			a = append(a, e.expr(c.Expr()))
+		}
+		result = ast.NewBinExpr(token.AND, a...)
 	}
 	return result
 }
@@ -405,7 +405,7 @@
 
 			arc = &adt.Vertex{Label: label}
 			v.MatchAndInsert(e.ctx, arc)
-			if len(v.Conjuncts) == 0 {
+			if len(arc.Conjuncts) == 0 {
 				continue
 			}
 
diff --git a/internal/core/export/value_test.go b/internal/core/export/value_test.go
index 22a53a4..df46544 100644
--- a/internal/core/export/value_test.go
+++ b/internal/core/export/value_test.go
@@ -60,6 +60,13 @@
 		all := export.All
 		all.ShowErrors = true
 
+		evalWithOptions := export.Profile{
+			TakeDefaults:    true,
+			ShowOptional:    true,
+			ShowDefinitions: true,
+			ShowAttributes:  true,
+		}
+
 		for _, tc := range []struct {
 			name string
 			fn   func(r adt.Runtime, id string, v adt.Value) (ast.Expr, errors.Error)
@@ -68,6 +75,7 @@
 			{"Raw", export.Raw.Value},
 			{"Final", export.Final.Value},
 			{"All", all.Value},
+			{"Eval", evalWithOptions.Value},
 		} {
 			fmt.Fprintln(t, "==", tc.name)
 			x, errs := tc.fn(r, pkgID, v)
@@ -105,6 +113,13 @@
 	p := export.All
 	p.ShowErrors = true
 
+	p = &export.Profile{
+		TakeDefaults:    true,
+		ShowOptional:    true,
+		ShowDefinitions: true,
+		ShowAttributes:  true,
+	}
+
 	x, errs := p.Value(r, "main", v)
 	if errs != nil {
 		t.Fatal(errs)