cue: fix lookup

optionals were not always inserted at evaluation time

This was a regression introduced in v0.0.14, where
references were partially evaluated in certain cases,
causing a non-expanded value to be used for lookup.

Fixes #202

Change-Id: Ie541f5be315eeb0fa929a52477020ba464b57623
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4207
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index da385ee..e161ab8 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -2763,6 +2763,7 @@
 		}`,
 		out: `<0>{t: <1>{ok :: true, x: int}, s: <2>{ok :: false}}`,
 	}, {
+		desc: "cross-dependent comprehension",
 		// TODO(eval): fix: c should ultimately be allowed the struct. Current
 		// semantics require, however, that generated fields are not available
 		// for evaluation. This, however, does not have to hold, for closedness
@@ -2781,6 +2782,21 @@
 		// c should not be allowed, as it would break commutativiy.
 		// See comments above.
 		out: `<0>{a :: <1>C{b: bool if <2>.b yield <3>C{c: 4}}, x: _|_(4:field "c" not allowed in closed struct), y: _|_(4:field "c" not allowed in closed struct)}`,
+	}, {
+		desc: "optional expanded before lookup",
+		in: `
+		test: [ID=_]: {
+			name: ID
+		}
+
+		test: A: {
+			field1: "1"
+			field2: "2"
+		}
+
+		B: test.A & {}
+		`,
+		out: `<0>{test: <1>{[]: <2>(ID: string)-><3>{name: <2>.ID}, A: <4>{name: "A", field1: "1", field2: "2"}}, B: <5>{name: "A", field1: "1", field2: "2"}}`,
 	}}
 	rewriteHelper(t, testCases, evalFull)
 }
diff --git a/cue/value.go b/cue/value.go
index 858fa44..2ed0746 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -984,7 +984,18 @@
 	// noderef will have ensured that the ancestors were evaluated.
 	for i, a := range x.arcs {
 		if a.feature == f {
-			a.cache = x.at(ctx, i)
+			a := x.iterAt(ctx, i)
+			// TODO: adding more technical debt here. The evaluator should be
+			// rewritten.
+			if x.optionals != nil {
+				name := ctx.labelStr(x.arcs[i].feature)
+				arg := &stringLit{x.baseValue, name, nil}
+
+				val, _ := x.optionals.constraint(ctx, arg)
+				if val != nil {
+					a.v = mkBin(ctx, x.Pos(), opUnify, a.v, val)
+				}
+			}
 			return a
 		}
 	}
@@ -1014,13 +1025,8 @@
 	//
 	// Allow import of CUE files. These cannot have a package clause.
 
-	x, err := x.expandFields(ctx)
-	if err != nil {
-		return err
-	}
-	// if x.emit != nil && isBottom(x.emit) {
-	// 	return x.emit.(evaluated)
-	// }
+	var err *bottom
+
 	// Lookup is done by selector or index references. Either this is done on
 	// literal nodes or nodes obtained from references. In the later case,
 	// noderef will have ensured that the ancestors were evaluated.