internal: replace untyped functions with typed ones

- UnifyBuiltin
- FromGoValue / FromGoType
- EvalExpr

Change-Id: I361630412b48ca2c0c5fbc31f627e53a8921ecb0
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9425
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 123c390..ac06401 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -31,7 +31,6 @@
 	"cuelang.org/go/cue/load"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/cue/token"
-	"cuelang.org/go/internal"
 	"cuelang.org/go/internal/encoding"
 	"cuelang.org/go/internal/filetypes"
 	"cuelang.org/go/internal/value"
@@ -350,7 +349,8 @@
 	if len(i.expr) == 0 {
 		return i.iter.value()
 	}
-	return internal.EvalExpr(i.iter.value(), i.expr[i.i]).(cue.Value)
+	// TODO: replace with FillPath.
+	return value.EvalExpr(i.iter.value(), i.expr[i.i])
 }
 
 type config struct {
diff --git a/cmd/cue/cmd/custom.go b/cmd/cue/cmd/custom.go
index ead236c..a19cce0 100644
--- a/cmd/cue/cmd/custom.go
+++ b/cmd/cue/cmd/custom.go
@@ -29,7 +29,6 @@
 
 	"cuelang.org/go/cue"
 	"cuelang.org/go/cue/errors"
-	"cuelang.org/go/internal"
 	itask "cuelang.org/go/internal/task"
 	"cuelang.org/go/internal/value"
 	_ "cuelang.org/go/pkg/tool/cli" // Register tasks
@@ -201,7 +200,7 @@
 		}
 
 		// Verify entry against template.
-		v = internal.UnifyBuiltin(v, kind).(cue.Value)
+		v = value.UnifyBuiltin(v, kind)
 		if err := v.Err(); err != nil {
 			return nil, errors.Promote(err, "newTask")
 		}
diff --git a/cue/builtin.go b/cue/builtin.go
index ee88ab1..74aa56b 100644
--- a/cue/builtin.go
+++ b/cue/builtin.go
@@ -15,12 +15,8 @@
 package cue
 
 import (
-	"strings"
-
 	"cuelang.org/go/cue/token"
-	"cuelang.org/go/internal"
 	"cuelang.org/go/internal/core/adt"
-	"cuelang.org/go/internal/core/runtime"
 )
 
 func pos(n adt.Node) (p token.Pos) {
@@ -33,23 +29,3 @@
 	}
 	return src.Pos()
 }
-
-func init() {
-	// TODO: unroll this function. Should no longer be necessary to be internal.
-	internal.UnifyBuiltin = func(val interface{}, kind string) interface{} {
-		v := val.(Value)
-
-		p := strings.Split(kind, ".")
-		pkg, name := p[0], p[1]
-		s, _ := runtime.SharedRuntime.LoadImport(pkg)
-		if s == nil {
-			return v
-		}
-		a := s.Lookup(v.idx.Label(name, false))
-		if a == nil {
-			return v
-		}
-
-		return v.Unify(makeValue(v.idx, a))
-	}
-}
diff --git a/cue/go.go b/cue/go.go
deleted file mode 100644
index bd77055..0000000
--- a/cue/go.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2020 CUE Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cue
-
-import (
-	"cuelang.org/go/internal"
-	"cuelang.org/go/internal/core/adt"
-	"cuelang.org/go/internal/core/convert"
-	"cuelang.org/go/internal/core/eval"
-)
-
-func init() {
-	internal.FromGoValue = func(runtime, x interface{}, nilIsTop bool) interface{} {
-		r := runtime.(*Runtime)
-		ctx := eval.NewContext(r.index(), nil)
-		v := convert.GoValueToValue(ctx, x, nilIsTop)
-		n := adt.ToVertex(v)
-		return Value{r.index(), n}
-	}
-
-	internal.FromGoType = func(runtime, x interface{}) interface{} {
-		r := runtime.(*Runtime)
-		ctx := eval.NewContext(r.index(), nil)
-		expr, err := convert.GoTypeToExpr(ctx, x)
-		if err != nil {
-			expr = &adt.Bottom{Err: err}
-		}
-		n := &adt.Vertex{}
-		n.AddConjunct(adt.MakeRootConjunct(nil, expr))
-		return Value{r.index(), n}
-
-		// return convertType(runtime.(*Runtime), x)
-	}
-}
diff --git a/cue/instance.go b/cue/instance.go
index cae1f9a..c0b47f6 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -173,15 +173,6 @@
 	return v
 }
 
-func init() {
-	internal.EvalExpr = func(value, expr interface{}) interface{} {
-		v := value.(Value)
-		e := expr.(ast.Expr)
-		ctx := newContext(v.idx)
-		return newValueRoot(v.idx, ctx, evalExpr(ctx, v.v, e))
-	}
-}
-
 // pkgID reports a package path that can never resolve to a valid package.
 func pkgID() string {
 	return "_"
diff --git a/cuego/cuego.go b/cuego/cuego.go
index f2460a3..9b71a96 100644
--- a/cuego/cuego.go
+++ b/cuego/cuego.go
@@ -20,8 +20,9 @@
 	"sync"
 
 	"cuelang.org/go/cue"
+	"cuelang.org/go/cue/cuecontext"
 	"cuelang.org/go/cue/parser"
-	"cuelang.org/go/internal"
+	"cuelang.org/go/internal/value"
 )
 
 // DefaultContext is the shared context used with top-level functions.
@@ -159,12 +160,12 @@
 var (
 	mutex    sync.Mutex
 	instance *cue.Instance
-	runtime  = &cue.Runtime{}
+	runtime  = cuecontext.New()
 )
 
 func init() {
 	var err error
-	instance, err = runtime.Compile("<cuego>", "{}")
+	instance, err = value.ConvertToRuntime(runtime).Compile("<cuego>", "{}")
 	if err != nil {
 		panic(err)
 	}
@@ -176,7 +177,7 @@
 	// Instance) here as any previously unrecognized field can never match an
 	// existing one and can only be merged.
 	mutex.Lock()
-	v = internal.FromGoValue(runtime, x, nilIsNull).(cue.Value)
+	v = value.FromGoValue(runtime, x, nilIsNull)
 	mutex.Unlock()
 	if err := v.Err(); err != nil {
 		return v, err
@@ -204,7 +205,7 @@
 	// Instance) here as any previously unrecognized field can never match an
 	// existing one and can only be merged.
 	mutex.Lock()
-	v := internal.FromGoType(runtime, x).(cue.Value)
+	v := value.FromGoType(runtime, x)
 	mutex.Unlock()
 	return v
 }
diff --git a/encoding/gocode/gocodec/codec.go b/encoding/gocode/gocodec/codec.go
index 0951959..3d0035d 100644
--- a/encoding/gocode/gocodec/codec.go
+++ b/encoding/gocode/gocodec/codec.go
@@ -25,7 +25,6 @@
 
 	"cuelang.org/go/cue"
 	"cuelang.org/go/cue/cuecontext"
-	"cuelang.org/go/internal"
 	"cuelang.org/go/internal/value"
 )
 
@@ -36,7 +35,7 @@
 // A Codec decodes and encodes CUE from and to Go values and validates and
 // completes Go values based on CUE templates.
 type Codec struct {
-	runtime *cue.Runtime
+	runtime *cue.Context
 	mutex   sync.RWMutex
 }
 
@@ -46,7 +45,7 @@
 // Runtime is not used elsewhere while using Codec. However, only the concurrent
 // use of Decode, Validate, and Complete is efficient.
 func New(r *cue.Runtime, c *Config) *Codec {
-	return &Codec{runtime: r}
+	return &Codec{runtime: value.ConvertToContext(r)}
 }
 
 // ExtractType extracts a CUE value from a Go type.
@@ -162,24 +161,24 @@
 	return w.Unify(v).Decode(x)
 }
 
-func fromGoValue(r *cue.Runtime, x interface{}, allowDefault bool) (cue.Value, error) {
-	v := internal.FromGoValue(r, x, allowDefault).(cue.Value)
+func fromGoValue(r *cue.Context, x interface{}, allowDefault bool) (cue.Value, error) {
+	v := value.FromGoValue(r, x, allowDefault)
 	if err := v.Err(); err != nil {
 		return v, err
 	}
 	return v, nil
 }
 
-func fromGoType(r *cue.Runtime, x interface{}) (cue.Value, error) {
-	v := internal.FromGoType(r, x).(cue.Value)
+func fromGoType(r *cue.Context, x interface{}) (cue.Value, error) {
+	v := value.FromGoType(r, x)
 	if err := v.Err(); err != nil {
 		return v, err
 	}
 	return v, nil
 }
 
-func checkAndForkContext(r *cue.Runtime, v cue.Value) *cue.Runtime {
-	rr := value.ConvertToRuntime(v.Context())
+func checkAndForkContext(r *cue.Context, v cue.Value) *cue.Context {
+	rr := v.Context()
 	if r != rr {
 		panic("value not from same runtime")
 	}
diff --git a/internal/internal.go b/internal/internal.go
index 9cd1500..1dfc178 100644
--- a/internal/internal.go
+++ b/internal/internal.go
@@ -43,30 +43,6 @@
 // incomplete.
 var ErrIncomplete = errors.New("incomplete value")
 
-// EvalExpr evaluates an expression within an existing struct value.
-// Identifiers only resolve to values defined within the struct.
-//
-// Expressions may refer to builtin packages if they can be uniquely identified
-//
-// Both value and result are of type cue.Value, but are an interface to prevent
-// cyclic dependencies.
-//
-// TODO: extract interface
-var EvalExpr func(value, expr interface{}) (result interface{})
-
-// FromGoValue converts an arbitrary Go value to the corresponding CUE value.
-// instance must be of type *cue.Instance.
-// The returned value is a cue.Value, which the caller must cast to.
-var FromGoValue func(instance, x interface{}, allowDefault bool) interface{}
-
-// FromGoType converts an arbitrary Go type to the corresponding CUE value.
-// instance must be of type *cue.Instance.
-// The returned value is a cue.Value, which the caller must cast to.
-var FromGoType func(instance, x interface{}) interface{}
-
-// UnifyBuiltin returns the given Value unified with the given builtin template.
-var UnifyBuiltin func(v interface{}, kind string) interface{}
-
 // MakeInstance makes a new instance from a value.
 var MakeInstance func(value interface{}) (instance interface{})
 
diff --git a/internal/value/value.go b/internal/value/value.go
index a91343b..35e208c 100644
--- a/internal/value/value.go
+++ b/internal/value/value.go
@@ -17,8 +17,15 @@
 package value
 
 import (
+	"strings"
+
 	"cuelang.org/go/cue"
+	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/internal/core/adt"
+	"cuelang.org/go/internal/core/compile"
+	"cuelang.org/go/internal/core/convert"
+	"cuelang.org/go/internal/core/eval"
 	"cuelang.org/go/internal/core/runtime"
 	"cuelang.org/go/internal/types"
 )
@@ -38,17 +45,91 @@
 	return t.R, t.V
 }
 
-// TODO:
 // Make wraps cue.MakeValue.
 func Make(ctx *adt.OpContext, v adt.Value) cue.Value {
 	return (*cue.Context)(ctx.Impl().(*runtime.Runtime)).Encode(v)
 }
 
-//
-// func Make(r *runtime.Runtime, v *adt.Vertex) cue.Value {
-// 	return cue.Value{}
-// }
+func MakeError(r *runtime.Runtime, err errors.Error) cue.Value {
+	b := &adt.Bottom{Err: err}
+	node := &adt.Vertex{BaseValue: b}
+	node.UpdateStatus(adt.Finalized)
+	node.AddConjunct(adt.MakeRootConjunct(nil, b))
+	return (*cue.Context)(r).Encode(node)
+}
 
-// func MakeError(r *runtime.Runtime, err error) cue.Value {
-// 	return cue.Value{}
-// }
+// UnifyBuiltin returns the given Value unified with the given builtin template.
+func UnifyBuiltin(v cue.Value, kind string) cue.Value {
+	p := strings.Split(kind, ".")
+	pkg, name := p[0], p[1]
+	s, _ := runtime.SharedRuntime.LoadImport(pkg)
+	if s == nil {
+		return v
+	}
+
+	ctx := v.Context()
+	a := s.Lookup((*runtime.Runtime)(ctx).Label(name, false))
+	if a == nil {
+		return v
+	}
+
+	return v.Unify(ctx.Encode(a))
+}
+
+func FromGoValue(r *cue.Context, x interface{}, nilIsTop bool) cue.Value {
+	rt := (*runtime.Runtime)(r)
+	rt.Init()
+	ctx := eval.NewContext(rt, nil)
+	v := convert.GoValueToValue(ctx, x, nilIsTop)
+	n := adt.ToVertex(v)
+	return r.Encode(n)
+}
+
+func FromGoType(r *cue.Context, x interface{}) cue.Value {
+	rt := (*runtime.Runtime)(r)
+	rt.Init()
+	ctx := eval.NewContext(rt, nil)
+	expr, err := convert.GoTypeToExpr(ctx, x)
+	if err != nil {
+		expr = &adt.Bottom{Err: err}
+	}
+	n := &adt.Vertex{}
+	n.AddConjunct(adt.MakeRootConjunct(nil, expr))
+	return r.Encode(n)
+}
+
+// EvalExpr evaluates an expression within an existing struct value.
+// Identifiers only resolve to values defined within the struct.
+//
+// Expressions may refer to builtin packages if they can be uniquely identified
+func EvalExpr(value cue.Value, expr ast.Expr) cue.Value {
+	r, scope := ToInternal(value)
+	ctx := eval.NewContext(r, nil)
+
+	cfg := &compile.Config{
+		Scope: scope,
+		Imports: func(x *ast.Ident) (pkgPath string) {
+			if !isBuiltin(x.Name) {
+				return ""
+			}
+			return x.Name
+		},
+	}
+
+	c, err := compile.Expr(cfg, ctx, pkgID(), expr)
+	if err != nil {
+		return MakeError(r, err)
+	}
+	v := adt.Resolve(ctx, c)
+
+	return (*cue.Context)(r).Encode(v)
+}
+
+func isBuiltin(s string) bool {
+	return runtime.SharedRuntime.IsBuiltinPackage(s)
+}
+
+// pkgID reports a package path that can never resolve to a valid package.
+func pkgID() string {
+	return "_"
+}
diff --git a/pkg/tool/file/file_test.go b/pkg/tool/file/file_test.go
index c9bc38f..983be53 100644
--- a/pkg/tool/file/file_test.go
+++ b/pkg/tool/file/file_test.go
@@ -24,8 +24,8 @@
 
 	"cuelang.org/go/cue"
 	"cuelang.org/go/cue/parser"
-	"cuelang.org/go/internal"
 	"cuelang.org/go/internal/task"
+	"cuelang.org/go/internal/value"
 )
 
 func parse(t *testing.T, kind, expr string) cue.Value {
@@ -40,7 +40,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	return internal.UnifyBuiltin(i.Value(), kind).(cue.Value)
+	return value.UnifyBuiltin(i.Value(), kind)
 }
 func TestRead(t *testing.T) {
 	v := parse(t, "tool/file.Read", `{filename: "testdata/input.foo"}`)
diff --git a/pkg/tool/os/env_test.go b/pkg/tool/os/env_test.go
index 8a6d9fb..1680a87 100644
--- a/pkg/tool/os/env_test.go
+++ b/pkg/tool/os/env_test.go
@@ -26,8 +26,8 @@
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/cue/token"
-	"cuelang.org/go/internal"
 	"cuelang.org/go/internal/task"
+	"cuelang.org/go/internal/value"
 )
 
 func TestGetenv(t *testing.T) {
@@ -140,5 +140,5 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	return internal.UnifyBuiltin(i.Value(), kind).(cue.Value)
+	return value.UnifyBuiltin(i.Value(), kind)
 }