cue: allow a Value to be passed to Fill

Change-Id: I31c71e5a033339596b7827d0f4468b0ad82f9c54
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5186
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/go.go b/cue/go.go
index ae21031..f47eee8 100644
--- a/cue/go.go
+++ b/cue/go.go
@@ -214,6 +214,10 @@
 		}
 		return &nullLit{src.base()}
 
+	case *ast.File:
+		x := newVisitorCtx(ctx, nil, nil, nil, false)
+		return ctx.manifest(x.walk(v))
+
 	case ast.Expr:
 		x := newVisitorCtx(ctx, nil, nil, nil, false)
 		return ctx.manifest(x.walk(v))
diff --git a/cue/instance.go b/cue/instance.go
index 337acb0..92b72fe 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -334,29 +334,48 @@
 
 // Fill creates a new instance with the values of the old instance unified with
 // the given value. It is not possible to update the emit value.
+//
+// Values may be any Go value that can be converted to CUE, an ast.Expr or
+// a Value. In the latter case, it will panic if the Value is not from the same
+// Runtime.
 func (inst *Instance) Fill(x interface{}, path ...string) (*Instance, error) {
 	ctx := inst.newContext()
 	root := ctx.manifest(inst.rootValue)
 	for i := len(path) - 1; i >= 0; i-- {
 		x = map[string]interface{}{path[i]: x}
 	}
-	value := convert(ctx, root, true, x)
+	var value evaluated
+	if v, ok := x.(Value); ok {
+		if inst.index != v.ctx().index {
+			panic("value of type Value is not created with same Runtime as Instance")
+		}
+		value = v.eval(ctx)
+	} else {
+		value = convert(ctx, root, true, x)
+	}
 	eval := binOp(ctx, baseValue{}, opUnify, root, value)
 	// TODO: validate recursively?
 	err := inst.Err
 	var st *structLit
+	var stVal evaluated
 	switch x := eval.(type) {
 	case *structLit:
 		st = x
+		stVal = x
 	default:
 		// This should not happen.
-		err = errors.Newf(x.Pos(), "error filling struct")
+		b := ctx.mkErr(eval, "error filling struct")
+		err = inst.Value().toErr(b)
+		st = &structLit{emit: b}
+		stVal = b
 	case *bottom:
 		err = inst.Value().toErr(x)
+		st = &structLit{emit: x}
+		stVal = x
 	}
 	inst = inst.index.addInst(&Instance{
 		rootStruct: st,
-		rootValue:  st,
+		rootValue:  stVal,
 		inst:       nil,
 
 		// Omit ImportPath to indicate this is not an importable package.
diff --git a/cue/types.go b/cue/types.go
index a013eb0..0f8da53 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1361,6 +1361,10 @@
 
 // Fill creates a new value by unifying v with the value of x at the given path.
 //
+// Values may be any Go value that can be converted to CUE, an ast.Expr or
+// a Value. In the latter case, it will panic if the Value is not from the same
+// Runtime.
+//
 // 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.
 func (v Value) Fill(x interface{}, path ...string) Value {
@@ -1372,7 +1376,15 @@
 	for i := len(path) - 1; i >= 0; i-- {
 		x = map[string]interface{}{path[i]: x}
 	}
-	value := convert(ctx, root, true, x)
+	var value evaluated
+	if v, ok := x.(Value); ok {
+		if ctx.index != v.ctx().index {
+			panic("value of type Value is not created with same Runtime as Instance")
+		}
+		value = v.eval(ctx)
+	} else {
+		value = convert(ctx, root, true, x)
+	}
 	a := v.path.arc
 	a.v = mkBin(ctx, v.Pos(), opUnify, root, value)
 	a.cache = a.v.evalPartial(ctx)
diff --git a/cue/types_test.go b/cue/types_test.go
index 3d2ae62..aa90cd5 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -17,7 +17,6 @@
 import (
 	"bytes"
 	"fmt"
-	"go/parser"
 	"io/ioutil"
 	"math"
 	"math/big"
@@ -691,7 +690,6 @@
 }
 
 func TestLookup(t *testing.T) {
-	_ = parser.ParseFile
 	var runtime = new(Runtime)
 	inst, err := runtime.Compile("x.cue", `
 V :: {
@@ -774,6 +772,13 @@
 }
 
 func TestFill(t *testing.T) {
+	r := &Runtime{}
+
+	inst, err := r.CompileExpr(ast.NewStruct("bar", ast.NewString("baz")))
+	if err != nil {
+		t.Fatal(err)
+	}
+
 	testCases := []struct {
 		in   string
 		x    interface{}
@@ -799,6 +804,15 @@
 		out: `
 		"foo"
 		`,
+	}, {
+		in: `
+		foo: _
+		`,
+		x:    inst.Value(),
+		path: "foo",
+		out: `
+		{foo: {bar: "baz"}}
+		`,
 	}}
 
 	for _, tc := range testCases {
@@ -807,7 +821,6 @@
 			path = strings.Split(tc.path, ",")
 		}
 
-		r := &Runtime{}
 		v := compile(t, r, tc.in).Value().Fill(tc.x, path...)
 		w := compile(t, r, tc.out).Value()