internal/core/adt: fix special cycle condition

Where node could be used with a 0 status.
This will be fixed when cycle detection is fixed, which
can be done if structure sharing is implemented.

Change-Id: I001a4e4c2b880c2011f36ee34af4966114f1bca9
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8561
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar b/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar
index e2685bc..7fa3fa7 100644
--- a/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar
+++ b/cue/testdata/cycle/051_resolved_self-reference_cycles_with_disjunction.txtar
@@ -1,7 +1,20 @@
-# DO NOT EDIT; generated by go run testdata/gen.go
-#
 #name: resolved self-reference cycles with disjunction
 #evalPartial
+
+// TODO(cycle)
+//
+// Some of these examples used to work, but the changes corresponding to this
+// addition, it ceased to do so. Fixing these cycle issues seemed more
+// important than keeping this esoteric case working, which was already broken
+// in the last release anyway.
+//
+// Reproducer of underlying problem. Still works, but triggers unexpected
+// condition.
+//
+// xb1: xb2
+// xb2: xb3
+// xb3: xb2 + 0
+
 -- in.cue --
 // The second disjunct in xa1 is not resolvable and can be
 // eliminated:
@@ -174,10 +187,16 @@
   xa2: (int){ 8 }
   xa3: (int){ 6 }
   xa4: (int){ 10 }
-  xb1: (int){ 8 }
-  xb2: (int){ 8 }
-  xb3: (int){ 6 }
-  xb4: (int){ 10 }
+  xb1: (int){ 9 }
+  xb2: (_|_){
+    // [incomplete] xb2: unresolved disjunction 6 | 9 (type int):
+    //     ./in.cue:18:6
+  }
+  xb3: (int){ |((int){ 6 }, (int){ 9 }) }
+  xb4: (_|_){
+    // [incomplete] xb2: unresolved disjunction 6 | 9 (type int):
+    //     ./in.cue:18:6
+  }
   xc1: (int){ |((int){ 8 }, (int){ 9 }) }
   xc2: (int){ 8 }
   xc3: (_|_){
@@ -220,10 +239,16 @@
     //     ./in.cue:45:6
     //     ./in.cue:45:10
   }
-  xf1: (int){ 8 }
-  xf2: (int){ 8 }
-  xf3: (int){ 6 }
-  xf4: (int){ 10 }
+  xf1: (int){ 9 }
+  xf2: (_|_){
+    // [incomplete] xf2: unresolved disjunction 6 | 9 (type int):
+    //     ./in.cue:52:6
+  }
+  xf3: (int){ |((int){ 6 }, (int){ 9 }) }
+  xf4: (_|_){
+    // [incomplete] xf2: unresolved disjunction 6 | 9 (type int):
+    //     ./in.cue:52:6
+  }
   z1: (int){ |((int){ 11 }, (int){ 13 }) }
   z2: (int){ 10 }
   z3: (_|_){
diff --git a/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar b/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar
index 60e48f6..c37f9fa 100644
--- a/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar
+++ b/cue/testdata/cycle/052_resolved_self-reference_cycles_with_disjunction_with_defaults.txtar
@@ -143,7 +143,7 @@
   xa4: (int){ 10 }
   xb1: (int){ 8 }
   xb2: (int){ 8 }
-  xb3: (int){ 6 }
+  xb3: (int){ |(*(int){ 6 }, (int){ 9 }) }
   xb4: (int){ 10 }
   xc1: (int){ |(*(int){ 8 }, (int){ 9 }) }
   xc2: (int){ 8 }
diff --git a/internal/core/adt/eval.go b/internal/core/adt/eval.go
index 3e03ae0..38c0c94 100644
--- a/internal/core/adt/eval.go
+++ b/internal/core/adt/eval.go
@@ -184,6 +184,7 @@
 		return
 
 	case EvaluatingArcs:
+		Assertf(v.status > 0, "unexpected status %d", v.status)
 		return
 
 	case 0:
@@ -1321,6 +1322,16 @@
 
 	closeInfo = closeInfo.SpawnRef(arc, IsDef(x), x)
 
+	if arc.status == 0 && !inline {
+		// This is a rare condition, but can happen in certain
+		// evaluation orders. Unfortunately, adding this breaks
+		// resolution of cyclic mutually referring disjunctions. But it
+		// is necessary to prevent lookups in unevaluated structs.
+		// TODO(cycles): this can probably most easily be fixed with a
+		// having a more recursive implementation.
+		n.ctx.Unify(arc, AllArcs)
+	}
+
 	for _, c := range arc.Conjuncts {
 		var a []*Vertex
 		if env != nil {