cue: prepare to hoist index type

Change-Id: If27ae95cff0e43de01d1fc03938e487d57fc67eb
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6507
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast.go b/cue/ast.go
index 1f322c7..09d9d36 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -150,7 +150,7 @@
 func (v *astVisitor) resolve(n *ast.Ident) value {
 	ctx := v.ctx()
 	name := v.ident(n)
-	label := v.label(name, true)
+	label := v.Label(name, true)
 	if r := v.resolveRoot; r != nil {
 		for _, a := range r.arcs {
 			if a.feature == label {
@@ -254,7 +254,7 @@
 				if i != len(n.Elts)-1 {
 					return v1.walk(x.Type) // Generate an error
 				}
-				f := v.ctx().label("_", true)
+				f := v.ctx().Label("_", true)
 				sig := &params{}
 				sig.add(f, &basicType{newNode(x), stringKind})
 				template := &lambdaExpr{newNode(x), sig, &top{newNode(x)}}
@@ -429,9 +429,9 @@
 			a, ok := expr.(*ast.Alias)
 			if ok {
 				expr = a.Expr
-				f = v.label(v.ident(a.Ident), true)
+				f = v.Label(v.ident(a.Ident), true)
 			} else {
-				f = v.label("_", true)
+				f = v.Label("_", true)
 			}
 
 			// Parse the key filter or a bulk-optional field. The special value
@@ -456,7 +456,7 @@
 				v.errf(x, "map element type cannot be a definition")
 			}
 			v.sel = "*"
-			f := v.label(v.ident(x.Ident), true)
+			f := v.Label(v.ident(x.Ident), true)
 
 			sig := &params{}
 			sig.add(f, &basicType{newNode(lab), stringKind})
@@ -474,7 +474,7 @@
 					v.sel = "*"
 				}
 			}
-			f, ok := v.nodeLabel(x)
+			f, ok := v.NodeLabel(x)
 			if !ok {
 				return v.errf(lab, "invalid field name: %v", lab)
 			}
@@ -587,7 +587,7 @@
 			break
 		}
 
-		f := v.label(name, true)
+		f := v.Label(name, true)
 		if _, ok := n.Node.(*ast.ImportSpec); ok {
 			n2 := v.mapScope(n.Node)
 			ref := &nodeRef{baseValue: newExpr(n), node: n2, label: f}
@@ -631,7 +631,7 @@
 				ret = v.errf(n, "invalid label: %v", err)
 
 			case name != "":
-				f = v.label(name, true)
+				f = v.Label(name, true)
 				ret = &selectorExpr{newExpr(n), ret, f}
 
 			default:
@@ -704,7 +704,7 @@
 		ret = &selectorExpr{
 			newExpr(n),
 			v.walk(n.X),
-			v.label(v.ident(n.Sel), true),
+			v.Label(v.ident(n.Sel), true),
 		}
 		v.inSelector--
 
@@ -822,10 +822,10 @@
 			if n.Key != nil {
 				key = v.ident(n.Key)
 			}
-			f := v.label(key, true)
+			f := v.Label(key, true)
 			fn.add(f, &basicType{newExpr(n.Key), stringKind | intKind})
 
-			f = v.label(v.ident(n.Value), true)
+			f = v.Label(v.ident(n.Value), true)
 			fn.add(f, &top{})
 
 			y = &feed{newExpr(n.Source), v.walk(n.Source), fn}
diff --git a/cue/binop.go b/cue/binop.go
index b7ec258..01d0037 100644
--- a/cue/binop.go
+++ b/cue/binop.go
@@ -570,7 +570,7 @@
 		return ctx.mkErr(x, "invalid custom validator")
 	} else if !b.b {
 		var buf bytes.Buffer
-		fmt.Fprintf(&buf, "%s.%s", ctx.labelStr(x.call.pkg), x.call.Name)
+		fmt.Fprintf(&buf, "%s.%s", ctx.LabelStr(x.call.pkg), x.call.Name)
 		buf.WriteString("(")
 		for _, a := range x.args {
 			buf.WriteString(ctx.str(a))
@@ -672,7 +672,7 @@
 			// TODO: pass position of key, not value. Currently does not have
 			// a position.
 			return ctx.mkErr(a.v, a.v, "field %q not allowed in closed struct",
-				ctx.labelStr(a.feature))
+				ctx.LabelStr(a.feature))
 		}
 		cp := ctx.copy(a.v)
 		obj.arcs = append(obj.arcs,
@@ -688,7 +688,7 @@
 				if a.definition != b.definition {
 					src := binSrc(x.Pos(), op, a.v, b.v)
 					return ctx.mkErr(src, "field %q declared as definition and regular field",
-						ctx.labelStr(a.feature))
+						ctx.LabelStr(a.feature))
 				}
 				w := b.v
 				if x.closeStatus.shouldFinalize() {
@@ -717,7 +717,7 @@
 			// TODO: pass position of key, not value. Currently does not have a
 			// position.
 			return ctx.mkErr(a.v, x, "field %q not allowed in closed struct",
-				ctx.labelStr(a.feature))
+				ctx.LabelStr(a.feature))
 		}
 		a.setValue(v)
 		obj.arcs = append(obj.arcs, a)
diff --git a/cue/build.go b/cue/build.go
index 33c24c5..634cdb1 100644
--- a/cue/build.go
+++ b/cue/build.go
@@ -20,6 +20,7 @@
 	"sync"
 
 	"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"
@@ -121,20 +122,11 @@
 // may import builtin packages. Use Build to allow importing non-builtin
 // packages.
 func (r *Runtime) CompileExpr(expr ast.Expr) (*Instance, error) {
-	ctx := r.buildContext()
-	p := ctx.NewInstance("", dummyLoad)
-	switch x := expr.(type) {
-	case *ast.StructLit:
-		_ = p.AddSyntax(&ast.File{Decls: x.Elts})
-	default:
-		_ = p.AddSyntax(&ast.File{
-			Decls: []ast.Decl{&ast.EmbedDecl{Expr: expr}},
-		})
+	f, err := astutil.ToFile(expr)
+	if err != nil {
+		return nil, err
 	}
-	if p.Err != nil {
-		return nil, p.Err
-	}
-	return r.complete(p)
+	return r.CompileFile(f)
 }
 
 // Parse parses a CUE source value into a CUE Instance. The source code may
@@ -192,14 +184,9 @@
 //
 // Deprecated: use CompileExpr
 func (r *Runtime) FromExpr(expr ast.Expr) (*Instance, error) {
-	i := r.index().newInstance(nil)
-	err := i.insertFile(&ast.File{
+	return r.CompileFile(&ast.File{
 		Decls: []ast.Decl{&ast.EmbedDecl{Expr: expr}},
 	})
-	if err != nil {
-		return nil, err
-	}
-	return i, nil
 }
 
 // index maps conversions from label names to internal codes.
@@ -239,7 +226,6 @@
 	// FileSet idea from the API. Just take the hit of the extra pointers for
 	// positions in the ast, and then optimize the storage in an abstract
 	// machine implementation for storing graphs.
-	token.NewFile("dummy", sharedOffset, 0)
 	i := &index{
 		labelMap:      map[string]label{"": 0},
 		labels:        []string{""},
@@ -262,22 +248,32 @@
 	return i
 }
 
-func (idx *index) strLabel(str string) label {
-	return idx.label(str, false)
+func (idx *index) StrLabel(str string) label {
+	return idx.Label(str, false)
 }
 
-func (idx *index) nodeLabel(n ast.Node) (f label, ok bool) {
+func (idx *index) NodeLabel(n ast.Node) (f label, ok bool) {
 	switch x := n.(type) {
 	case *ast.BasicLit:
 		name, _, err := ast.LabelName(x)
-		return idx.label(name, false), err == nil
+		return idx.Label(name, false), err == nil
 	case *ast.Ident:
 		name, err := ast.ParseIdent(x)
-		return idx.label(name, true), err == nil
+		return idx.Label(name, true), err == nil
 	}
 	return 0, false
 }
 
+func (idx *index) HasLabel(s string) (ok bool) {
+	for x := idx; x != nil; x = x.parent {
+		_, ok = x.labelMap[s]
+		if ok {
+			break
+		}
+	}
+	return ok
+}
+
 func (idx *index) findLabel(s string) (f label, ok bool) {
 	for x := idx; x != nil; x = x.parent {
 		f, ok = x.labelMap[s]
@@ -288,7 +284,7 @@
 	return f, ok
 }
 
-func (idx *index) label(s string, isIdent bool) label {
+func (idx *index) Label(s string, isIdent bool) label {
 	f, ok := idx.findLabel(s)
 	if !ok {
 		f = label(len(idx.labelMap)) + idx.offset
@@ -307,13 +303,18 @@
 	return f
 }
 
-func (idx *index) labelStr(l label) string {
+func (idx *index) LabelStr(l label) string {
 	l >>= labelShift
 	for ; l < idx.offset; idx = idx.parent {
 	}
 	return idx.labels[l-idx.offset]
 }
 
+func isBuiltin(s string) bool {
+	_, ok := builtins[s]
+	return ok
+}
+
 func (idx *index) loadInstance(p *build.Instance) *Instance {
 	if inst := idx.loaded[p]; inst != nil {
 		if !inst.complete {
@@ -324,11 +325,13 @@
 		return inst
 	}
 	files := p.Files
-	inst := idx.newInstance(p)
+	inst := newInstance(idx, p)
+	idx.loaded[p] = inst
+
 	if inst.Err == nil {
 		// inst.instance.index.state = s
 		// inst.instance.inst = p
-		inst.Err = resolveFiles(idx, p)
+		inst.Err = resolveFiles(idx, p, isBuiltin)
 		for _, f := range files {
 			err := inst.insertFile(f)
 			inst.Err = errors.Append(inst.Err, err)
@@ -344,7 +347,11 @@
 	return n.Pos().String()
 }
 
-func resolveFiles(idx *index, p *build.Instance) errors.Error {
+func resolveFiles(
+	idx *index,
+	p *build.Instance,
+	isBuiltin func(s string) bool,
+) errors.Error {
 	// Link top-level declarations. As top-level entries get unified, an entry
 	// may be linked to any top-level entry of any of the files.
 	allFields := map[string]ast.Node{}
@@ -358,14 +365,20 @@
 		}
 	}
 	for _, f := range p.Files {
-		if err := resolveFile(idx, f, p, allFields); err != nil {
+		if err := resolveFile(idx, f, p, allFields, isBuiltin); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
-func resolveFile(idx *index, f *ast.File, p *build.Instance, allFields map[string]ast.Node) errors.Error {
+func resolveFile(
+	idx *index,
+	f *ast.File,
+	p *build.Instance,
+	allFields map[string]ast.Node,
+	isBuiltin func(s string) bool,
+) errors.Error {
 	unresolved := map[string][]*ast.Ident{}
 	for _, u := range f.Unresolved {
 		unresolved[u.Name] = append(unresolved[u.Name], u)
@@ -390,7 +403,7 @@
 		name := path.Base(id)
 		if imp := p.LookupImport(id); imp != nil {
 			name = imp.PkgName
-		} else if _, ok := builtins[id]; !ok {
+		} else if !isBuiltin(id) {
 			errs = errors.Append(errs,
 				nodeErrorf(spec, "package %q not found", id))
 			continue
diff --git a/cue/build_test.go b/cue/build_test.go
index 97bf20b..51309a5 100644
--- a/cue/build_test.go
+++ b/cue/build_test.go
@@ -85,7 +85,7 @@
 			ImportPath: importPath,
 			PkgName:    "foo",
 		}},
-	}, map[string]ast.Node{})
+	}, map[string]ast.Node{}, isBuiltin)
 
 	if err != nil {
 		t.Errorf("exected no error, found %v", err)
diff --git a/cue/builtin.go b/cue/builtin.go
index a13d384..616cf4b 100644
--- a/cue/builtin.go
+++ b/cue/builtin.go
@@ -71,11 +71,11 @@
 
 func mustCompileBuiltins(ctx *context, p *builtinPkg, pkgName string) *structLit {
 	obj := &structLit{}
-	pkgLabel := ctx.label(pkgName, false)
+	pkgLabel := ctx.Label(pkgName, false)
 	for _, b := range p.native {
 		b.pkg = pkgLabel
 
-		f := ctx.label(b.Name, false) // never starts with _
+		f := ctx.Label(b.Name, false) // never starts with _
 		// n := &node{baseValue: newBase(imp.Path)}
 		var v evaluated = b
 		if b.Const != "" {
@@ -243,7 +243,7 @@
 	if x.pkg == 0 {
 		return x.Name
 	}
-	return fmt.Sprintf("%s.%s", ctx.labelStr(x.pkg), x.Name)
+	return fmt.Sprintf("%s.%s", ctx.LabelStr(x.pkg), x.Name)
 }
 
 func (x *builtin) isValidator() bool {
@@ -288,29 +288,7 @@
 		if err := recover(); err != nil {
 			errVal = err
 		}
-		const msg = "error in call to %s: %v"
-		switch err := errVal.(type) {
-		case nil:
-		case *callError:
-			ret = err.b
-		case *json.MarshalerError:
-			if err, ok := err.Err.(*marshalError); ok && err.b != nil {
-				ret = err.b
-			}
-		case *marshalError:
-			ret = err.b
-			ret = ctx.mkErr(src, x, ret, msg, x.name(ctx), err)
-		case *valueError:
-			ret = err.err
-			ret = ctx.mkErr(src, x, ret, msg, x.name(ctx), err)
-		default:
-			if call.err == internal.ErrIncomplete {
-				ret = ctx.mkErr(src, codeIncomplete, "incomplete value")
-			} else {
-				// TODO: store the underlying error explicitly
-				ret = ctx.mkErr(src, x, msg, x.name(ctx), err)
-			}
-		}
+		ret = processErr(&call, errVal, ret)
 	}()
 	x.Func(&call)
 	switch v := call.ret.(type) {
@@ -322,6 +300,36 @@
 	return convert(ctx, x, true, call.ret)
 }
 
+func processErr(call *callCtxt, errVal interface{}, ret value) value {
+	ctx := call.ctx
+	x := call.builtin
+	src := call.src
+	const msg = "error in call to %s: %v"
+	switch err := errVal.(type) {
+	case nil:
+	case *callError:
+		ret = err.b
+	case *json.MarshalerError:
+		if err, ok := err.Err.(*marshalError); ok && err.b != nil {
+			ret = err.b
+		}
+	case *marshalError:
+		ret = err.b
+		ret = ctx.mkErr(src, x, ret, msg, x.name(ctx), err)
+	case *valueError:
+		ret = err.err
+		ret = ctx.mkErr(src, x, ret, msg, x.name(ctx), err)
+	default:
+		if call.err == internal.ErrIncomplete {
+			ret = ctx.mkErr(src, codeIncomplete, "incomplete value")
+		} else {
+			// TODO: store the underlying error explicitly
+			ret = ctx.mkErr(src, x, msg, x.name(ctx), err)
+		}
+	}
+	return ret
+}
+
 // callCtxt is passed to builtin implementations.
 type callCtxt struct {
 	src     source
@@ -384,7 +392,7 @@
 		if s == nil {
 			return v
 		}
-		a := s.lookup(ctx, ctx.label(name, false))
+		a := s.lookup(ctx, ctx.Label(name, false))
 		if a.v == nil {
 			return v
 		}
diff --git a/cue/debug.go b/cue/debug.go
index 630b4be..3de2dcf 100644
--- a/cue/debug.go
+++ b/cue/debug.go
@@ -142,7 +142,7 @@
 		return strconv.Itoa(int(f))
 	}
 
-	str := p.ctx.labelStr(f)
+	str := p.ctx.LabelStr(f)
 	if strings.HasPrefix(str, "#") && f&definition == 0 ||
 		strings.HasPrefix(str, "_") && f&hidden == 0 ||
 		!ast.IsValidIdent(str) {
diff --git a/cue/eval.go b/cue/eval.go
index e5794c5..9965410 100644
--- a/cue/eval.go
+++ b/cue/eval.go
@@ -126,11 +126,11 @@
 		}
 		n := sc.lookup(ctx, x.feature)
 		if n.optional {
-			field := ctx.labelStr(x.feature)
+			field := ctx.LabelStr(x.feature)
 			return ctx.mkErr(x, codeIncomplete, "field %q is optional", field)
 		}
 		if n.val() == nil {
-			field := ctx.labelStr(x.feature)
+			field := ctx.LabelStr(x.feature)
 			if st, ok := sc.(*structLit); ok && !st.isClosed() {
 				return ctx.mkErr(x, codeIncomplete, "undefined field %q", field)
 			}
@@ -161,11 +161,11 @@
 		}
 		n := sc.lookup(ctx, x.feature)
 		if n.optional {
-			field := ctx.labelStr(x.feature)
+			field := ctx.LabelStr(x.feature)
 			return ctx.mkErr(x, codeIncomplete, "field %q is optional", field)
 		}
 		if n.val() == nil {
-			field := ctx.labelStr(x.feature)
+			field := ctx.LabelStr(x.feature)
 			if st, ok := sc.(*structLit); ok && !st.isClosed() {
 				return ctx.mkErr(x, codeIncomplete, "undefined field %q", field)
 			}
@@ -198,7 +198,7 @@
 		if e.is(index, stringKind, msgIndexType, k) {
 			s := index.strValue()
 			// TODO: must lookup
-			n := v.lookup(ctx, ctx.strLabel(s))
+			n := v.lookup(ctx, ctx.StrLabel(s))
 			if n.definition {
 				return ctx.mkErr(x, index,
 					"field %q is a definition", s)
@@ -247,7 +247,7 @@
 		if e.is(index, stringKind, msgIndexType, k) {
 			s := index.strValue()
 			// TODO: must lookup
-			n := v.lookup(ctx, ctx.strLabel(s))
+			n := v.lookup(ctx, ctx.StrLabel(s))
 			if n.definition {
 				return ctx.mkErr(x, index,
 					"field %q is a definition", s)
@@ -474,7 +474,7 @@
 	if !k.kind().isAnyOf(stringKind) {
 		return ctx.mkErr(k, "key must be of type string")
 	}
-	f := ctx.label(k.strValue(), true)
+	f := ctx.Label(k.strValue(), true)
 	st := &structLit{baseValue: x.baseValue}
 	st.insertValue(ctx, f, x.opt, x.def, v, x.attrs, x.doc)
 	return st
diff --git a/cue/export.go b/cue/export.go
index af4e116..ea5e9d0 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -135,8 +135,8 @@
 	s = strings.ToUpper(s)
 	lab := s
 	for {
-		if _, ok := p.ctx.findLabel(lab); !ok {
-			p.ctx.label(lab, true)
+		if !p.ctx.HasLabel(lab) {
+			p.ctx.Label(lab, true)
 			break
 		}
 		lab = s + fmt.Sprintf("%0.6x", rand.Intn(1<<24))
@@ -145,7 +145,7 @@
 }
 
 func (p *exporter) label(f label) ast.Label {
-	str := p.ctx.labelStr(f)
+	str := p.ctx.LabelStr(f)
 	if strings.HasPrefix(str, "#") && f&definition == 0 ||
 		strings.HasPrefix(str, "_") && f&hidden == 0 ||
 		!ast.IsValidIdent(str) {
@@ -155,7 +155,7 @@
 }
 
 func (p *exporter) identifier(f label) *ast.Ident {
-	str := p.ctx.labelStr(f)
+	str := p.ctx.LabelStr(f)
 	return &ast.Ident{Name: str}
 }
 
@@ -171,7 +171,7 @@
 			Source: p.expr(x.source),
 		}
 		key := x.fn.params.arcs[0]
-		if p.ctx.labelStr(key.feature) != "_" {
+		if p.ctx.LabelStr(key.feature) != "_" {
 			feed.Key = p.identifier(key.feature)
 		}
 		return feed, x.fn.value.(yielder)
@@ -187,22 +187,22 @@
 	short := info.short
 	if !ok {
 		short = inst.PkgName
-		if _, ok := p.top[p.ctx.label(short, true)]; ok && preferred != "" {
+		if _, ok := p.top[p.ctx.Label(short, true)]; ok && preferred != "" {
 			short = preferred
 			info.name = short
 		}
 		for {
-			if _, ok := p.top[p.ctx.label(short, true)]; !ok {
+			if _, ok := p.top[p.ctx.Label(short, true)]; !ok {
 				break
 			}
 			short += "x"
 			info.name = short
 		}
 		info.short = short
-		p.top[p.ctx.label(short, true)] = true
+		p.top[p.ctx.Label(short, true)] = true
 		p.imports[pkg] = info
 	}
-	f := p.ctx.label(short, true)
+	f := p.ctx.Label(short, true)
 	for _, e := range p.stack {
 		if e.from == f {
 			if info.alias == "" {
@@ -435,7 +435,7 @@
 		if x.pkg == 0 {
 			return ast.NewIdent(x.Name)
 		}
-		pkg := p.ctx.labelStr(x.pkg)
+		pkg := p.ctx.LabelStr(x.pkg)
 		inst := builtins[pkg]
 		short := p.shortName(inst, "", pkg)
 		return ast.NewSel(ast.NewIdent(short), x.Name)
@@ -445,7 +445,7 @@
 			// NOTE: this nodeRef is used within a selector.
 			return nil
 		}
-		short := p.ctx.labelStr(x.label)
+		short := p.ctx.LabelStr(x.label)
 
 		if inst := p.ctx.getImportFromNode(x.node); inst != nil {
 			return ast.NewIdent(p.shortName(inst, short, inst.ImportPath))
@@ -457,7 +457,7 @@
 	case *selectorExpr:
 		n := p.expr(x.x)
 		if n != nil {
-			return ast.NewSel(n, p.ctx.labelStr(x.feature))
+			return ast.NewSel(n, p.ctx.LabelStr(x.feature))
 		}
 		f := x.feature
 		ident := p.identifier(f)
@@ -486,7 +486,7 @@
 			if conflict {
 				ident = e.to
 				if e.to == nil {
-					name := p.unique(p.ctx.labelStr(f))
+					name := p.unique(p.ctx.LabelStr(f))
 					e.syn.Elts = append(e.syn.Elts, &ast.Alias{
 						Ident: p.ident(name),
 						Expr:  p.identifier(f),
diff --git a/cue/go.go b/cue/go.go
index 24843ea..20dee9a 100644
--- a/cue/go.go
+++ b/cue/go.go
@@ -70,7 +70,7 @@
 	}
 	expr, err := parser.ParseExpr("<field:>", tag)
 	if err != nil {
-		field := ctx.labelStr(field)
+		field := ctx.LabelStr(field)
 		return ctx.mkErr(baseValue{}, "invalid tag %q for field %q: %v", tag, field, err)
 	}
 	v := newVisitor(ctx.index, nil, nil, obj, true)
@@ -389,7 +389,7 @@
 				if name == "-" {
 					continue
 				}
-				f := ctx.strLabel(name)
+				f := ctx.StrLabel(name)
 				obj.arcs = append(obj.arcs, arc{feature: f, v: sub})
 			}
 			sort.Sort(obj)
@@ -438,12 +438,12 @@
 			// Assign label in normalized order.
 			sort.Strings(sorted)
 			for _, k := range sorted {
-				ctx.strLabel(k)
+				ctx.StrLabel(k)
 			}
 
 			// Now assign the labels to the arcs.
 			for i, k := range keys {
-				obj.arcs[i].feature = ctx.strLabel(k)
+				obj.arcs[i].feature = ctx.StrLabel(k)
 			}
 			sort.Sort(obj)
 			return obj
@@ -597,7 +597,7 @@
 			if name == "-" {
 				continue
 			}
-			l := ctx.strLabel(name)
+			l := ctx.StrLabel(name)
 			obj.arcs = append(obj.arcs, arc{
 				feature: l,
 				// The GO JSON decoder always allows a value to be undefined.
@@ -658,7 +658,7 @@
 
 		obj := newStruct(baseValue{})
 		sig := &params{}
-		sig.add(ctx.label("_", true), &basicType{k: stringKind})
+		sig.add(ctx.Label("_", true), &basicType{k: stringKind})
 		v := goTypeToValueRec(ctx, allowNullDefault, t.Elem())
 		if v == nil {
 			return ctx.mkErr(baseValue{}, "unsupported Go type (%v)", t.Elem())
diff --git a/cue/instance.go b/cue/instance.go
index b16be57..0ec3dee 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -83,7 +83,7 @@
 }
 
 // newInstance creates a new instance. Use Insert to populate the instance.
-func (x *index) newInstance(p *build.Instance) *Instance {
+func newInstance(x *index, p *build.Instance) *Instance {
 	// TODO: associate root source with structLit.
 	st := &structLit{baseValue: baseValue{nil}}
 	i := &Instance{
@@ -237,7 +237,7 @@
 
 	idx := inst.index
 
-	i := idx.newInstance(p)
+	i := newInstance(idx, p)
 	if i.Err != nil {
 		return i
 	}
@@ -251,7 +251,7 @@
 	}
 	i.scope = v.obj
 
-	if err := resolveFiles(idx, p); err != nil {
+	if err := resolveFiles(idx, p, isBuiltin); err != nil {
 		i.setError(err)
 		return i
 	}
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index 5a394be..e7480da 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -39,10 +39,10 @@
 
 func compileInstance(t *testing.T, body string) (*context, *Instance, error) {
 	var r Runtime
-	inst, err := r.Parse("test", body)
+	inst, err := r.Compile("test", body)
 
 	if err != nil {
-		x := newIndex(sharedIndex).newInstance(nil)
+		x := newInstance(newIndex(sharedIndex), nil)
 		ctx := x.newContext()
 		return ctx, x, err
 	}
diff --git a/cue/subsume.go b/cue/subsume.go
index 05881cb..e1e58d9 100644
--- a/cue/subsume.go
+++ b/cue/subsume.go
@@ -36,7 +36,7 @@
 			src := binSrc(token.NoPos, opUnify, s.gt, s.lt)
 			var ok bool
 			if s.missing != 0 {
-				b = ctx.mkErr(src, "missing field %q", ctx.labelStr(s.missing))
+				b = ctx.mkErr(src, "missing field %q", ctx.LabelStr(s.missing))
 			} else if b, ok = binOp(ctx, src, opUnify, s.gt, s.lt).(*bottom); !ok {
 				b = ctx.mkErr(src, "value not an instance")
 			}
@@ -180,7 +180,7 @@
 				if b.optional || b.definition {
 					continue
 				}
-				name := ctx.labelStr(b.feature)
+				name := ctx.LabelStr(b.feature)
 				arg := &stringLit{x.baseValue, name, nil}
 				u, _ := x.optionals.constraint(ctx, arg)
 				if u != nil && !s.subsumes(u, b.v) {
@@ -248,7 +248,7 @@
 				}
 				a := x.lookup(ctx, b.feature)
 				if a.val() == nil {
-					name := ctx.labelStr(b.feature)
+					name := ctx.LabelStr(b.feature)
 					arg := &stringLit{x.baseValue, name, nil}
 					u, _ := x.optionals.constraint(ctx, arg)
 					if u == nil { // subsumption already checked
diff --git a/cue/subsume_test.go b/cue/subsume_test.go
index 8925bd5..d41ada7 100644
--- a/cue/subsume_test.go
+++ b/cue/subsume_test.go
@@ -454,9 +454,9 @@
 			var a, b value
 			for _, arc := range root.arcs {
 				switch arc.feature {
-				case ctx.strLabel("a"):
+				case ctx.StrLabel("a"):
 					a = arc.v
-				case ctx.strLabel("b"):
+				case ctx.StrLabel("b"):
 					b = arc.v
 				}
 			}
diff --git a/cue/types.go b/cue/types.go
index 5c68c88..e1f2ce2 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -152,13 +152,13 @@
 func (o *structValue) At(i int) (key string, v Value) {
 	a := o.arcs[i]
 	v = newChildValue(o, i)
-	return o.ctx.labelStr(a.feature), v
+	return o.ctx.LabelStr(a.feature), v
 }
 
 // Lookup reports the field for the given key. The returned Value is invalid
 // if it does not exist.
 func (o *structValue) Lookup(key string) Value {
-	f := o.ctx.strLabel(key)
+	f := o.ctx.StrLabel(key)
 	i := 0
 	len := o.Len()
 	for ; i < len; i++ {
@@ -281,7 +281,7 @@
 	if i.f == 0 {
 		return ""
 	}
-	return i.ctx.labelStr(i.f)
+	return i.ctx.LabelStr(i.f)
 }
 
 // IsHidden reports if a field is hidden from the data model.
@@ -563,7 +563,7 @@
 	case listKind:
 		a = append(a, strconv.FormatInt(int64(v.index), 10))
 	case structKind:
-		f := idx.labelStr(v.arc.feature)
+		f := idx.LabelStr(v.arc.feature)
 		if v.arc.feature&(hidden|definition) == 0 {
 			if !isIdent(f) && !isNumber(f) {
 				f = quote(f, '"')
@@ -634,7 +634,7 @@
 			x := obj.obj
 			ctx := obj.ctx
 			if x.optionals != nil {
-				name := ctx.labelStr(x.arcs[i].feature)
+				name := ctx.LabelStr(x.arcs[i].feature)
 				arg := &stringLit{x.baseValue, name, nil}
 
 				val, _ := x.optionals.constraint(ctx, arg)
@@ -720,7 +720,7 @@
 			return nil, nil
 		}
 
-		a = append(a, ctx.label(s.str, false))
+		a = append(a, ctx.Label(s.str, false))
 
 	case *nodeRef:
 		n = x
@@ -821,7 +821,7 @@
 	if v.path.feature == 0 {
 		return "", false
 	}
-	return v.idx.labelStr(v.path.feature), true
+	return v.idx.LabelStr(v.path.feature), true
 }
 
 // Kind returns the kind of value. It returns BottomKind for atomic values that
@@ -1430,7 +1430,7 @@
 	// rewritten.
 	x := s.s
 	if x.optionals != nil {
-		name := ctx.labelStr(x.arcs[i].feature)
+		name := ctx.LabelStr(x.arcs[i].feature)
 		arg := &stringLit{x.baseValue, name, nil}
 
 		val, _ := x.optionals.constraint(ctx, arg)
@@ -1440,7 +1440,7 @@
 	}
 
 	v := Value{ctx.index, &valueData{s.v.path, uint32(i), a}}
-	str := ctx.labelStr(a.feature)
+	str := ctx.LabelStr(a.feature)
 	return FieldInfo{str, i, v, a.definition, a.optional, a.feature&hidden != 0}
 }
 
@@ -1448,7 +1448,7 @@
 // look up a definition or hidden field (starting with `_` or `_#`). Otherwise
 // it interprets name as an arbitrary string for a regular field.
 func (s *Struct) FieldByName(name string, isIdent bool) (FieldInfo, error) {
-	f := s.v.ctx().label(name, isIdent)
+	f := s.v.ctx().Label(name, isIdent)
 	for i, a := range s.s.arcs {
 		if a.feature == f {
 			return s.Field(i), nil
@@ -1515,7 +1515,7 @@
 		return newErrValue(v, err)
 	}
 
-	f := v.ctx().label(name, true)
+	f := v.ctx().Label(name, true)
 	for i, a := range o.arcs {
 		if a.feature == f {
 			if f&hidden != 0 || !a.definition || a.optional {
@@ -1751,7 +1751,7 @@
 	switch sel := v.path.v.(type) {
 	case *selectorExpr:
 		x = sel.x
-		feature = ctx.labelStr(sel.feature)
+		feature = ctx.LabelStr(sel.feature)
 
 	case *indexExpr:
 		e := sel.index.evalPartial(ctx)
@@ -1772,7 +1772,7 @@
 func mkPath(c *context, up *valueData, x value, feature string, d int) (imp *Instance, a []string) {
 	switch x := x.(type) {
 	case *selectorExpr:
-		imp, a = mkPath(c, up, x.x, c.labelStr(x.feature), d+1)
+		imp, a = mkPath(c, up, x.x, c.LabelStr(x.feature), d+1)
 		if imp == nil {
 			return nil, nil
 		}
@@ -1818,7 +1818,7 @@
 	}
 	root, a = mkFromRoot(c, up.parent, d+1)
 	if up.parent != nil {
-		a = append(a, c.labelStr(up.feature))
+		a = append(a, c.LabelStr(up.feature))
 	} else {
 		root = up.v
 	}
@@ -1867,7 +1867,7 @@
 		}
 		path := make([]string, len(p.stack))
 		for i, v := range p.stack {
-			path[len(path)-1-i] = ctx.labelStr(v)
+			path[len(path)-1-i] = ctx.LabelStr(v)
 		}
 		p.paths = append(p.paths, path)
 		p.stack = p.stack[:i]
@@ -2291,7 +2291,7 @@
 		a = append(a, remakeValue(v, x.x))
 		a = append(a, remakeValue(v, &stringLit{
 			x.baseValue,
-			v.ctx().labelStr(x.feature),
+			v.ctx().LabelStr(x.feature),
 			nil,
 		}))
 		op = SelectorOp
diff --git a/cue/types_test.go b/cue/types_test.go
index b615158..0421920 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -770,7 +770,7 @@
 	}
 }
 
-func compile(t *testing.T, r *Runtime, s string) *Instance {
+func compileT(t *testing.T, r *Runtime, s string) *Instance {
 	t.Helper()
 	inst, err := r.Compile("", s)
 	if err != nil {
@@ -838,8 +838,8 @@
 			path = strings.Split(tc.path, ",")
 		}
 
-		v := compile(t, r, tc.in).Value().Fill(tc.x, path...)
-		w := compile(t, r, tc.out).Value()
+		v := compileT(t, r, tc.in).Value().Fill(tc.x, path...)
+		w := compileT(t, r, tc.out).Value()
 
 		if !reflect.DeepEqual(goValue(v), goValue(w)) {
 			t.Errorf("\ngot:  %s\nwant: %s", v, w)
@@ -899,7 +899,7 @@
 
 	for _, tc := range testCases {
 		t.Run(tc.def, func(t *testing.T) {
-			v := compile(t, r, tc.in).Value()
+			v := compileT(t, r, tc.in).Value()
 			v = v.LookupDef(tc.def)
 			got := fmt.Sprint(v)
 
diff --git a/cue/value.go b/cue/value.go
index 00a958f..fd5ada1 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -26,6 +26,7 @@
 	"cuelang.org/go/cue/ast"
 	"cuelang.org/go/cue/literal"
 	"cuelang.org/go/cue/token"
+	"cuelang.org/go/internal/core/adt"
 )
 
 type value interface {
@@ -805,7 +806,7 @@
 		return false
 	}
 
-	str := ctx.labelStr(f)
+	str := ctx.LabelStr(f)
 	arg := &stringLit{str: str}
 
 	found, ok := o.match(ctx, arg)
@@ -1015,7 +1016,7 @@
 			// TODO: adding more technical debt here. The evaluator should be
 			// rewritten.
 			if x.optionals != nil {
-				name := ctx.labelStr(x.arcs[i].feature)
+				name := ctx.LabelStr(x.arcs[i].feature)
 				arg := &stringLit{x.baseValue, name, nil}
 
 				val, _ := x.optionals.constraint(ctx, arg)
@@ -1206,7 +1207,7 @@
 	}
 
 	if x.arcs[i].feature&(hidden|definition) == 0 {
-		name := ctx.labelStr(x.arcs[i].feature)
+		name := ctx.LabelStr(x.arcs[i].feature)
 		arg := &stringLit{x.baseValue, name, nil}
 
 		var val value
@@ -1223,7 +1224,7 @@
 }
 
 // A label is a canonicalized feature name.
-type label uint32
+type label = adt.Feature
 
 const (
 	hidden     label = 0x01 // only set iff identifier starting with _ or #_
@@ -1361,7 +1362,7 @@
 			src := binSrc(token.NoPos, opUnify, p.v, value)
 			x.arcs[i].v = ctx.mkErr(src,
 				"field %q declared as definition and regular field",
-				ctx.labelStr(f))
+				ctx.LabelStr(f))
 			isDef = false
 		}
 		x.arcs[i].definition = isDef
@@ -1913,7 +1914,7 @@
 		for i, a := range src.arcs {
 			key := &stringLit{
 				x.baseValue,
-				ctx.labelStr(a.feature),
+				ctx.LabelStr(a.feature),
 				nil,
 			}
 			if a.definition || a.optional || a.feature&hidden != 0 {