cue: return arc type, instead of individual parameters

Change-Id: I97c7a8d761e5a51fdfe0a5e22db34b41b5969da1
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/1681
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/instance.go b/cue/instance.go
index 87481bf..b2c17f2 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -217,7 +217,7 @@
 		obj, err := v.structVal(ctx)
 		if err != nil {
 			v := err.(*bottom)
-			return Value{idx, &valueData{v: v, raw: v}}
+			return Value{idx, &valueData{arc: arc{cache: v, v: v}}}
 		}
 		v = obj.Lookup(k)
 	}
diff --git a/cue/types.go b/cue/types.go
index 1f0a368..949df68 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -148,9 +148,9 @@
 		i.cur = Value{}
 		return false
 	}
-	eval, orig, f, attrs := i.iter.iterAt(i.ctx, i.p)
-	i.cur = i.val.makeChild(i.ctx, uint32(i.p), f, eval, orig, attrs)
-	i.f = f
+	arc := i.iter.iterAt(i.ctx, i.p)
+	i.cur = i.val.makeChild(i.ctx, uint32(i.p), arc)
+	i.f = arc.feature
 	i.p++
 	return true
 }
@@ -201,7 +201,7 @@
 	if err := v.checkKind(v.ctx(), k); err != nil {
 		return nil, err
 	}
-	n, _ := v.path.v.(*numLit)
+	n, _ := v.path.cache.(*numLit)
 	return n, nil
 }
 
@@ -288,7 +288,7 @@
 	if !v.IsInt() {
 		return false
 	}
-	n, _ := v.path.v.(*numLit)
+	n, _ := v.path.cache.(*numLit)
 	return n.v.Sign() >= 0
 }
 
@@ -439,12 +439,9 @@
 }
 
 type valueData struct {
-	parent  *valueData
-	feature label
-	index   uint32
-	v       evaluated
-	raw     value
-	attrs   *attributes
+	parent *valueData
+	index  uint32
+	arc
 }
 
 // Value holds any value, which may be a Boolean, Error, List, Null, Number,
@@ -456,29 +453,30 @@
 
 func newValueRoot(ctx *context, x value) Value {
 	v := x.evalPartial(ctx)
-	return Value{ctx.index, &valueData{nil, 0, 0, v, x, nil}}
+	return Value{ctx.index, &valueData{nil, 0, arc{cache: v, v: x}}}
 }
 
 func newChildValue(obj *structValue, i int) Value {
-	eval := obj.ctx.manifest(obj.n.at(obj.ctx, i))
 	a := obj.n.arcs[i]
-	return Value{obj.ctx.index, &valueData{obj.path, a.feature, uint32(i), eval, a.v, a.attrs}}
+	a.cache = obj.ctx.manifest(obj.n.at(obj.ctx, i))
+
+	return Value{obj.ctx.index, &valueData{obj.path, uint32(i), a}}
 }
 
 func (v Value) ctx() *context {
 	return v.idx.newContext()
 }
 
-func (v Value) makeChild(ctx *context, i uint32, f label, eval evaluated, raw value, attrs *attributes) Value {
-	eval = ctx.manifest(eval)
-	return Value{v.idx, &valueData{v.path, f, i, eval, raw, attrs}}
+func (v Value) makeChild(ctx *context, i uint32, a arc) Value {
+	a.cache = ctx.manifest(a.cache)
+	return Value{v.idx, &valueData{v.path, i, a}}
 }
 
 func (v Value) eval(ctx *context) value {
-	if v.path == nil || v.path.v == nil {
+	if v.path == nil || v.path.cache == nil {
 		panic("undefined value")
 	}
-	return ctx.manifest(v.path.v)
+	return ctx.manifest(v.path.cache)
 }
 
 // Label reports he label used to obtain this value from the enclosing struct.
@@ -586,7 +584,7 @@
 // Syntax converts the possibly partially evaluated value into syntax. This
 // can use used to print the value with package format.
 func (v Value) Syntax() ast.Expr {
-	if v.path == nil || v.path.v == nil {
+	if v.path == nil || v.path.cache == nil {
 		return nil
 	}
 	ctx := v.ctx()
@@ -618,10 +616,10 @@
 	}
 	ctx := v.ctx()
 	a := []Value{}
-	for _, x := range separate(v.path.raw) {
+	for _, x := range separate(v.path.v) {
 		path := *v.path
-		path.v = x.evalPartial(ctx)
-		path.raw = x
+		path.cache = x.evalPartial(ctx)
+		path.v = x
 		a = append(a, Value{v.idx, &path})
 	}
 	return a
@@ -649,7 +647,7 @@
 	if v.path == nil {
 		return nil
 	}
-	return v.path.raw.syntax()
+	return v.path.v.syntax()
 }
 
 // Err returns the error represented by v or nil v is not an error.
@@ -682,7 +680,7 @@
 // IsValid reports whether this value is defined and evaluates to something
 // other than an error.
 func (v Value) IsValid() bool {
-	if v.path == nil || v.path.v == nil {
+	if v.path == nil || v.path.cache == nil {
 		return false
 	}
 	k := v.eval(v.ctx()).kind()
@@ -882,7 +880,7 @@
 // given its name.
 func (v Value) Template() func(label string) Value {
 	ctx := v.ctx()
-	x, ok := v.path.v.(*structLit)
+	x, ok := v.path.cache.(*structLit)
 	if !ok || x.template == nil {
 		return nil
 	}
@@ -934,7 +932,7 @@
 		fmt.Fprint(state, "<nil>")
 		return
 	}
-	io.WriteString(state, debugStr(ctx, v.path.v))
+	io.WriteString(state, debugStr(ctx, v.path.cache))
 }
 
 // References reports all references used to evaluate this value. It does not
@@ -942,7 +940,7 @@
 func (v Value) References() [][]string {
 	ctx := v.ctx()
 	pf := pathFinder{up: v.path}
-	raw := v.path.raw
+	raw := v.path.v
 	if raw == nil {
 		return nil
 	}
@@ -967,7 +965,7 @@
 	case *nodeRef:
 		i := len(p.stack)
 		up := p.up
-		for ; up != nil && up.v != x.node.(value); up = up.parent {
+		for ; up != nil && up.cache != x.node.(value); up = up.parent {
 		}
 		for ; up != nil && up.feature > 0; up = up.parent {
 			p.stack = append(p.stack, ctx.labelStr(up.feature))
diff --git a/cue/value.go b/cue/value.go
index f615bc3..5c432b1 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -60,11 +60,9 @@
 }
 
 type iterAtter interface {
-	// TODO: make iterAt return a struct type instead, possibly an arc!
-
 	// at returns the evaluated and its original value at the given position.
 	// If the original could not be found, it returns an error and nil.
-	iterAt(*context, int) (evaluated, value, label, *attributes)
+	iterAt(*context, int) arc
 }
 
 // caller must be implemented by any concrete lambdaKind
@@ -206,12 +204,12 @@
 func (x *bytesLit) kind() kind       { return bytesKind }
 func (x *bytesLit) strValue() string { return string(x.b) }
 
-func (x *bytesLit) iterAt(ctx *context, i int) (evaluated, value, label, *attributes) {
+func (x *bytesLit) iterAt(ctx *context, i int) arc {
 	if i >= len(x.b) {
-		return nil, nil, 0, nil
+		return arc{}
 	}
 	v := x.at(ctx, i)
-	return v, v, 0, nil
+	return arc{v: v, cache: v}
 }
 
 func (x *bytesLit) at(ctx *context, i int) evaluated {
@@ -260,13 +258,13 @@
 func (x *stringLit) kind() kind       { return stringKind }
 func (x *stringLit) strValue() string { return x.str }
 
-func (x *stringLit) iterAt(ctx *context, i int) (evaluated, value, label, *attributes) {
+func (x *stringLit) iterAt(ctx *context, i int) arc {
 	runes := []rune(x.str)
 	if i >= len(runes) {
-		return nil, nil, 0, nil
+		return arc{}
 	}
 	v := x.at(ctx, i)
-	return v, v, 0, nil
+	return arc{v: v, cache: v}
 }
 
 func (x *stringLit) at(ctx *context, i int) evaluated {
@@ -489,34 +487,36 @@
 // already have been evaluated. It returns an error and nil if there was an
 // issue evaluating the list itself.
 func (x *list) at(ctx *context, i int) evaluated {
-	e, _, _, _ := x.iterAt(ctx, i)
-	if e == nil {
+	arc := x.iterAt(ctx, i)
+	if arc.cache == nil {
 		return ctx.mkErr(x, "index %d out of bounds", i)
 	}
-	return e
+	return arc.cache
 }
 
 // iterAt returns the evaluated and original value of position i. List x must
 // already have been evaluated. It returns an error and nil if there was an
 // issue evaluating the list itself.
-func (x *list) iterAt(ctx *context, i int) (evaluated, value, label, *attributes) {
+func (x *list) iterAt(ctx *context, i int) arc {
 	if i < 0 {
-		return ctx.mkErr(x, "index %d out of bounds", i), nil, 0, nil
+		v := ctx.mkErr(x, "index %d out of bounds", i)
+		return arc{cache: v}
 	}
 	if i < len(x.a) {
-		return x.a[i].evalPartial(ctx), x.a[i], 0, nil
+		return arc{cache: x.a[i].evalPartial(ctx), v: x.a[i]}
 	}
 	max := maxNum(x.len.(evaluated))
 	if max.kind().isGround() {
 		if max.kind()&intKind == bottomKind {
-			return ctx.mkErr(max, "length indicator of list not of type int"), nil, 0, nil
+			v := ctx.mkErr(max, "length indicator of list not of type int")
+			return arc{cache: v}
 		}
 		n := max.(*numLit).intValue(ctx)
 		if i >= n {
-			return nil, nil, 0, nil
+			return arc{}
 		}
 	}
-	return x.typ.(evaluated), x.typ, 0, nil
+	return arc{cache: x.typ.(evaluated), v: x.typ}
 }
 
 func (x *list) isOpen() bool {
@@ -605,13 +605,14 @@
 	return nil, nil
 }
 
-func (x *structLit) iterAt(ctx *context, i int) (evaluated, value, label, *attributes) {
+func (x *structLit) iterAt(ctx *context, i int) arc {
 	x = x.expandFields(ctx)
 	if i >= len(x.arcs) {
-		return nil, nil, 0, nil
+		return arc{}
 	}
-	v := x.at(ctx, i)
-	return v, x.arcs[i].v, x.arcs[i].feature, x.arcs[i].attrs // TODO: return template & v for original?
+	a := x.arcs[i]
+	a.cache = x.at(ctx, i) // TODO: return template & v for original?
+	return a
 }
 
 func (x *structLit) at(ctx *context, i int) evaluated {