cue: support optional fields for FillPath

Change-Id: I44addd5905d193e80c4c0924a1c300dac51c1a58
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9527
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cue/types.go b/cue/types.go
index 641bd9c..9e7aa70 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1590,7 +1590,6 @@
 // Any reference in v referring to the value at the given path will resolve to x
 // in the newly created value. The resulting value is not validated.
 //
-// List paths are not supported at this time.
 func (v Value) FillPath(p Path, x interface{}) Value {
 	if v.v == nil {
 		// TODO: panic here?
@@ -1616,9 +1615,26 @@
 		expr = convert.GoValueToValue(ctx, x, true)
 	}
 	for i := len(p.path) - 1; i >= 0; i-- {
-		switch sel := p.path[i]; {
-		case sel.sel.kind() == adt.IntLabel:
-			i := sel.sel.feature(ctx.Runtime).Index()
+		switch sel := p.path[i].sel; {
+		case sel == AnyString.sel:
+			expr = &adt.StructLit{Decls: []adt.Decl{
+				&adt.BulkOptionalField{
+					Filter: &adt.BasicType{K: adt.StringKind},
+					Value:  expr,
+				},
+			}}
+
+		case sel == anyIndex.sel:
+			expr = &adt.ListLit{Elems: []adt.Elem{
+				&adt.Ellipsis{Value: expr},
+			}}
+
+		case sel == anyDefinition.sel:
+			expr = &adt.Bottom{Err: errors.Newf(token.NoPos,
+				"AnyDefinition not supported")}
+
+		case sel.kind() == adt.IntLabel:
+			i := sel.feature(ctx.Runtime).Index()
 			list := &adt.ListLit{}
 			any := &adt.Top{}
 			// TODO(perf): make this a constant thing. This will be possible with the query extension.
@@ -1629,12 +1645,19 @@
 			expr = list
 
 		default:
-			expr = &adt.StructLit{Decls: []adt.Decl{
-				&adt.Field{
-					Label: p.path[i].sel.feature(v.idx),
+			var d adt.Decl
+			if sel.optional() {
+				d = &adt.OptionalField{
+					Label: sel.feature(v.idx),
 					Value: expr,
-				},
-			}}
+				}
+			} else {
+				d = &adt.Field{
+					Label: sel.feature(v.idx),
+					Value: expr,
+				}
+			}
+			expr = &adt.StructLit{Decls: []adt.Decl{d}}
 		}
 	}
 	n := &adt.Vertex{}
diff --git a/cue/types_test.go b/cue/types_test.go
index 27c2339..1751b94 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -1139,6 +1139,44 @@
 		x:    1,
 		path: ParsePath("0"),
 		out:  `[1]`,
+	}, {
+		in:   `[1, ...int]`,
+		x:    1,
+		path: ParsePath("1"),
+		out:  `[1, 1]`,
+	}, {
+		in:   `a: {b: v: int, c: v: int}`,
+		x:    1,
+		path: MakePath(Str("a"), AnyString, Str("v")),
+		out: `{
+	a: {
+		b: {
+			v: 1
+		}
+		c: {
+			v: 1
+		}
+	}
+}`,
+	}, {
+		in:   `a: [_]`,
+		x:    1,
+		path: MakePath(Str("a"), AnyIndex, Str("b")),
+		out: `{
+	a: [{
+		b: 1
+	}]
+}`,
+	}, {
+		in:   `a: 1`,
+		x:    1,
+		path: MakePath(Str("b").Optional()),
+		out:  `{a: 1}`,
+	}, {
+		in:   `b: int`,
+		x:    1,
+		path: MakePath(Str("b").Optional()),
+		out:  `{b: 1}`,
 	}}
 
 	for _, tc := range testCases {