cue: add InferBuiltins EncodeOption

This functionality is currently partially internal or deprecated.
This adds this functionality to the new API.

This also removes a cyclic dependency in package dependencies
that needs to be removed for the implementation of structure
sharing.

This moves resolveExpr to below BuildExpr, as their bodies are
almost the same (functionally the same at the moment).
This also removes dead code.

Expresses the old CompileExpr in terms of the new BuildExpr.
This is mostly done as a  verification and to allow automatic
rewrites in the future.

Change-Id: I7d63aa097dd8f652b9b0b0181a2b148c8bb1f2d4
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9571
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 1840f97..eddf609 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -350,8 +350,11 @@
 	if len(i.expr) == 0 {
 		return i.iter.value()
 	}
-	// TODO: replace with FillPath.
-	return value.EvalExpr(i.iter.value(), i.expr[i.i])
+	v := i.iter.value()
+	return v.Context().BuildExpr(i.expr[i.i],
+		cue.Scope(v),
+		cue.InferBuiltins(true),
+	)
 }
 
 type config struct {
diff --git a/cue/build.go b/cue/build.go
index 9c603af..f4cd6b2 100644
--- a/cue/build.go
+++ b/cue/build.go
@@ -16,6 +16,7 @@
 
 import (
 	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/ast/astutil"
 	"cuelang.org/go/cue/build"
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/internal/core/adt"
@@ -78,11 +79,22 @@
 //
 // Deprecated: use BuildExpr. The use of Instance is being phased out.
 func (r *hiddenRuntime) CompileExpr(expr ast.Expr) (*Instance, error) {
-	v, p, err := r.runtime().CompileExpr(nil, expr)
+	f, err := astutil.ToFile(expr)
 	if err != nil {
 		return nil, err
 	}
-	return r.complete(p, v)
+	v := (*Context)(r).BuildExpr(expr)
+	err = v.Err()
+	inst := &Instance{
+		index: r.runtime(),
+		root:  v.v,
+		inst: &build.Instance{
+			Files: []*ast.File{f},
+		},
+		Err:        errors.Promote(err, ""),
+		Incomplete: err != nil,
+	}
+	return inst, err
 }
 
 // Parse parses a CUE source value into a CUE Instance. The source code may be
@@ -149,7 +161,3 @@
 		Decls: []ast.Decl{&ast.EmbedDecl{Expr: expr}},
 	})
 }
-
-func isBuiltin(s string) bool {
-	return runtime.SharedRuntime.IsBuiltinPackage(s)
-}
diff --git a/cue/context.go b/cue/context.go
index e84f4fb..5360563 100644
--- a/cue/context.go
+++ b/cue/context.go
@@ -16,9 +16,12 @@
 
 import (
 	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/ast/astutil"
 	"cuelang.org/go/cue/build"
 	"cuelang.org/go/cue/errors"
+	"cuelang.org/go/cue/token"
 	"cuelang.org/go/internal/core/adt"
+	"cuelang.org/go/internal/core/compile"
 	"cuelang.org/go/internal/core/convert"
 	"cuelang.org/go/internal/core/debug"
 	"cuelang.org/go/internal/core/eval"
@@ -78,6 +81,23 @@
 	return func(o *runtime.Config) { o.Filename = filename }
 }
 
+// InferBuiltins allows unresolved references to bind to builtin packages with a
+// unique package name.
+//
+// This option is intended for evaluating expressions in a context where import
+// statements cannot be used. It is not recommended to use this for evaluating
+// CUE files.
+func InferBuiltins(elide bool) BuildOption {
+	return func(o *runtime.Config) {
+		o.Imports = func(x *ast.Ident) (pkgPath string) {
+			if !o.Runtime.IsBuiltinPackage(x.Name) {
+				return ""
+			}
+			return x.Name
+		}
+	}
+}
+
 func (c *Context) parseOptions(options []BuildOption) (cfg runtime.Config) {
 	cfg.Runtime = (*runtime.Runtime)(c)
 	for _, f := range options {
@@ -143,14 +163,39 @@
 // The returned Value will represent an error, accessible through Err, if any
 // error occurred.
 func (c *Context) BuildExpr(x ast.Expr, options ...BuildOption) Value {
+	r := c.runtime()
 	cfg := c.parseOptions(options)
-	v, p, err := c.runtime().CompileExpr(&cfg, x)
+
+	ctx := c.ctx()
+
+	astutil.ResolveExpr(x, errFn)
+	conjunct, err := compile.Expr(&cfg.Config, r, anonymousPkg, x)
 	if err != nil {
-		return c.makeError(p.Err)
+		return c.makeError(err)
 	}
+	v := adt.Resolve(ctx, conjunct)
+
 	return c.make(v)
 }
 
+func errFn(pos token.Pos, msg string, args ...interface{}) {}
+
+// resolveExpr binds unresolved expressions to values in the expression or v.
+func resolveExpr(ctx *adt.OpContext, v *adt.Vertex, x ast.Expr) adt.Value {
+	cfg := &compile.Config{Scope: v}
+
+	astutil.ResolveExpr(x, errFn)
+
+	c, err := compile.Expr(cfg, ctx, anonymousPkg, x)
+	if err != nil {
+		return &adt.Bottom{Err: err}
+	}
+	return adt.Resolve(ctx, c)
+}
+
+// anonymousPkg reports a package path that can never resolve to a valid package.
+const anonymousPkg = "_"
+
 // CompileString parses and build a Value from the given source string.
 //
 // The returned Value will represent an error, accessible through Err, if any
diff --git a/cue/instance.go b/cue/instance.go
index df01f0a..9340844 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -190,66 +190,6 @@
 	return v
 }
 
-// pkgID reports a package path that can never resolve to a valid package.
-func pkgID() string {
-	return "_"
-}
-
-// evalExpr evaluates expr within scope.
-func evalExpr(ctx *adt.OpContext, scope *adt.Vertex, expr ast.Expr) adt.Value {
-	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 &adt.Bottom{Err: err}
-	}
-	return adt.Resolve(ctx, c)
-
-	// scope.Finalize(ctx) // TODO: not appropriate here.
-	// switch s := scope.Value.(type) {
-	// case *bottom:
-	// 	return s
-	// case *adt.StructMarker:
-	// default:
-	// 	return ctx.mkErr(scope, "instance is not a struct, found %s", scope.Kind())
-	// }
-
-	// c := ctx
-
-	// x, err := compile.Expr(&compile.Config{Scope: scope}, c.Runtime, expr)
-	// if err != nil {
-	// 	return c.NewErrf("could not evaluate %s: %v", c.Str(x), err)
-	// }
-
-	// env := &adt.Environment{Vertex: scope}
-
-	// switch v := x.(type) {
-	// case adt.Value:
-	// 	return v
-	// case adt.Resolver:
-	// 	r, err := c.Resolve(env, v)
-	// 	if err != nil {
-	// 		return err
-	// 	}
-	// 	return r
-
-	// case adt.Evaluator:
-	// 	e, _ := c.Evaluate(env, x)
-	// 	return e
-
-	// }
-
-	// return c.NewErrf("could not evaluate %s", c.Str(x))
-}
-
 // ID returns the package identifier that uniquely qualifies module and
 // package name.
 func (inst *Instance) ID() string {
@@ -278,12 +218,12 @@
 // Eval evaluates an expression within an existing instance.
 //
 // Expressions may refer to builtin packages if they can be uniquely identified.
+//
+// Deprecated: use
+// inst.Value().Context().BuildExpr(expr, Scope(inst.Value), InferBuiltins(true))
 func (inst *hiddenInstance) Eval(expr ast.Expr) Value {
-	ctx := newContext(inst.index)
-	v := inst.root
-	v.Finalize(ctx)
-	result := evalExpr(ctx, v, expr)
-	return newValueRoot(inst.index, ctx, result)
+	v := inst.Value()
+	return v.Context().BuildExpr(expr, Scope(v), InferBuiltins(true))
 }
 
 // DO NOT USE.
diff --git a/cue/query.go b/cue/query.go
index a4cec1f..4428527 100644
--- a/cue/query.go
+++ b/cue/query.go
@@ -15,11 +15,7 @@
 package cue
 
 import (
-	"cuelang.org/go/cue/ast"
-	"cuelang.org/go/cue/ast/astutil"
-	"cuelang.org/go/cue/token"
 	"cuelang.org/go/internal/core/adt"
-	"cuelang.org/go/internal/core/compile"
 )
 
 // This file contains query-related code.
@@ -38,21 +34,6 @@
 	return v.v
 }
 
-func errFn(pos token.Pos, msg string, args ...interface{}) {}
-
-// resolveExpr binds unresolved expressions to values in the expression or v.
-func resolveExpr(ctx *adt.OpContext, v *adt.Vertex, x ast.Expr) adt.Value {
-	cfg := &compile.Config{Scope: v}
-
-	astutil.ResolveExpr(x, errFn)
-
-	c, err := compile.Expr(cfg, ctx, pkgID(), x)
-	if err != nil {
-		return &adt.Bottom{Err: err}
-	}
-	return adt.Resolve(ctx, c)
-}
-
 // LookupPath reports the value for path p relative to v.
 func (v Value) LookupPath(p Path) Value {
 	if v.v == nil {
diff --git a/internal/core/runtime/build.go b/internal/core/runtime/build.go
index e38101c..1dcb820 100644
--- a/internal/core/runtime/build.go
+++ b/internal/core/runtime/build.go
@@ -114,15 +114,6 @@
 	return v, p
 }
 
-func (r *Runtime) CompileExpr(cfg *Config, expr ast.Expr) (*adt.Vertex, *build.Instance, error) {
-	f, err := astutil.ToFile(expr)
-	if err != nil {
-		return nil, nil, err
-	}
-	v, p := r.CompileFile(cfg, f)
-	return v, p, p.Err
-}
-
 func (x *Runtime) buildSpec(cfg *Config, b *build.Instance, spec *ast.ImportSpec) (errs errors.Error) {
 	info, err := astutil.ParseImportSpec(spec)
 	if err != nil {
diff --git a/internal/value/value.go b/internal/value/value.go
index 35e208c..5e05864 100644
--- a/internal/value/value.go
+++ b/internal/value/value.go
@@ -20,10 +20,8 @@
 	"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"
@@ -97,39 +95,3 @@
 	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/encoding/yaml/manual.go b/pkg/encoding/yaml/manual.go
index f1fde15..c018763 100644
--- a/pkg/encoding/yaml/manual.go
+++ b/pkg/encoding/yaml/manual.go
@@ -23,7 +23,6 @@
 	"cuelang.org/go/internal"
 	cueyaml "cuelang.org/go/internal/encoding/yaml"
 	"cuelang.org/go/internal/third_party/yaml"
-	"cuelang.org/go/internal/value"
 )
 
 // Marshal returns the YAML encoding of v.
@@ -84,7 +83,7 @@
 	if err != nil {
 		return false, err
 	}
-	r := value.ConvertToRuntime(v.Context())
+	r := v.Context()
 	for {
 		expr, err := d.Decode()
 		if err != nil {
@@ -94,8 +93,8 @@
 			return false, err
 		}
 
-		inst, err := r.CompileExpr(expr)
-		if err != nil {
+		x := r.BuildExpr(expr)
+		if err := x.Err(); err != nil {
 			return false, err
 		}
 
@@ -108,7 +107,7 @@
 		// if err := v.Subsume(inst.Value(), cue.Final()); err != nil {
 		// 	return false, err
 		// }
-		x := v.Unify(inst.Value())
+		x = v.Unify(x)
 		if err := x.Err(); err != nil {
 			return false, err
 		}
@@ -128,7 +127,7 @@
 	if err != nil {
 		return false, err
 	}
-	r := value.ConvertToRuntime(v.Context())
+	r := v.Context()
 	for {
 		expr, err := d.Decode()
 		if err != nil {
@@ -138,12 +137,12 @@
 			return false, err
 		}
 
-		inst, err := r.CompileExpr(expr)
-		if err != nil {
+		x := r.BuildExpr(expr)
+		if err := x.Err(); err != nil {
 			return false, err
 		}
 
-		if x := v.Unify(inst.Value()); x.Err() != nil {
+		if x := v.Unify(x); x.Err() != nil {
 			return false, x.Err()
 		}
 	}