cue: fix marshaling bug

Closes #326

Change-Id: I9568c60e953f645af5080446f354217a8dd3f234
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5420
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/testdata/script/issue315.txt b/cmd/cue/cmd/testdata/script/issue315.txt
index 8d3cd83..2937c20 100644
--- a/cmd/cue/cmd/testdata/script/issue315.txt
+++ b/cmd/cue/cmd/testdata/script/issue315.txt
@@ -3,7 +3,7 @@
 cmp stderr expect-stderr
 
 -- expect-stderr --
-incomplete value X.y in interpolation:
+incomplete value 'X.y' in interpolation:
     ./file.cue:16:3
     ./file.cue:3:5
 -- file.cue --
diff --git a/cue/eval.go b/cue/eval.go
index 000ebea..e5794c5 100644
--- a/cue/eval.go
+++ b/cue/eval.go
@@ -399,7 +399,7 @@
 	}
 	if incomplete != nil {
 		return ctx.mkErr(incomplete, codeIncomplete,
-			"incomplete value %s in interpolation", ctx.str(incomplete))
+			"incomplete value '%s' in interpolation", ctx.str(incomplete))
 	}
 	return &stringLit{x.baseValue, buf.String(), nil}
 }
diff --git a/cue/types.go b/cue/types.go
index 6ef9b5c..06e8c35 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -855,7 +855,18 @@
 		i := Iterator{ctx: ctx, val: v, iter: l, len: len(l.elem.arcs)}
 		return marshalList(&i)
 	case structKind:
-		obj, _ := v.structValData(ctx)
+		obj, err := v.structValData(ctx)
+		st := obj.obj
+		if len(st.comprehensions) > 0 {
+			// This should always evaluate to incomplete. However, fall back
+			// to a bad error message, rather than crashing, in case it doesn't.
+			err, _ := st.comprehensions[0].comp.evalPartial(ctx).(*bottom)
+			return nil, toMarshalErr(v, err)
+		}
+
+		if err != nil {
+			return nil, toMarshalErr(v, err)
+		}
 		return obj.marshalJSON()
 	case bottomKind:
 		return nil, toMarshalErr(v, x.(*bottom))
diff --git a/cue/types_test.go b/cue/types_test.go
index aa4da04..bb173e4 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -2023,6 +2023,36 @@
 		foo: Task & {"op": "pull"}
 		`,
 		json: `{"foo":{"op":"pull","tag":"latest","tagInString":"latestdd"}}`,
+	}, {
+		// Issue #326
+		value: `x: "\(string)": "v"`,
+		err:   `x: incomplete value 'string' in interpolation`,
+	}, {
+		// Issue #326
+		value: `x: "\(bool)": "v"`,
+		err:   `x: expression in interpolation must evaluate to a number kind or string (found bool)`,
+	}, {
+		// Issue #326
+		value: `
+		x: {
+			for k, v in y {
+				"\(k)": v
+			}
+		}
+		y: {}
+		`,
+		json: `{"x":{},"y":{}}`,
+	}, {
+		// Issue #326
+		value: `
+		x: {
+			for k, v in y {
+				"\(k)": v
+			}
+		}
+		y: _
+		`,
+		err: `x: incomplete feed source`,
 	}}
 	for i, tc := range testCases {
 		t.Run(fmt.Sprintf("%d/%v", i, tc.value), func(t *testing.T) {