internal/core/cue: fix hang on cycles in embeddings in comprehensions

Fixes a failure to pass down cycle information down environments
for comprehensions.

Also preserves the Vertex pointer by introducing an indirection
and resolving this again in resolution. Pointer identity is used
in cycle detection, so this approach caused this to break.

Fixes #587

Change-Id: I0febf03f3c96fdfcccf427ccb45534e2242c3aae
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7621
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/testdata/cycle/structural.txtar b/cue/testdata/cycle/structural.txtar
index ddbba75..ddc4ad5 100644
--- a/cue/testdata/cycle/structural.txtar
+++ b/cue/testdata/cycle/structural.txtar
@@ -125,6 +125,26 @@
     }
 }
 
+// Issue #587
+b13: root: a: [ for x in root {x} ]
+
+// Issue #587
+b14: {
+  root: {
+    a: [...int]
+
+    for x in a {
+      "\(x)": {}
+    }
+
+    b: [ for x in root {x}]
+  }
+}
+
+// This is okay
+// Issue #587
+b15: root: a: { for x in root {x} }
+
 // Issue #502 -- unused bulk constraints are not cyclic
 p1: {
   #T: {
@@ -363,6 +383,8 @@
 Errors:
 a1.f.0: structural cycle
 a3.f.g: structural cycle
+b13.root.a.0.0: structural cycle
+b14.root.b.1.1: structural cycle
 b4.x.y.0: structural cycle
 b6.b.a.0: conflicting values 1 and [1] (mismatched types int and list):
     ./in.cue:51:16
@@ -379,33 +401,33 @@
 e2.a.c: structural cycle
 e2.b.c: structural cycle
 e3.a: conflicting values [a] and {c:a} (mismatched types list and struct):
-    ./in.cue:257:8
-    ./in.cue:258:8
+    ./in.cue:277:8
+    ./in.cue:278:8
 e3.a.0: conflicting values [a] and {c:a} (mismatched types list and struct):
-    ./in.cue:257:8
-    ./in.cue:258:8
+    ./in.cue:277:8
+    ./in.cue:278:8
 e3.a.0: structural cycle
 e3.a.c: conflicting values [a] and {c:a} (mismatched types list and struct):
-    ./in.cue:257:8
-    ./in.cue:258:8
+    ./in.cue:277:8
+    ./in.cue:278:8
 e3.a.c: structural cycle
 e3.b: conflicting values [b] and {c:b} (mismatched types list and struct):
-    ./in.cue:260:8
-    ./in.cue:261:8
+    ./in.cue:280:8
+    ./in.cue:281:8
 e3.b.0: conflicting values [b] and {c:b} (mismatched types list and struct):
-    ./in.cue:260:8
-    ./in.cue:261:8
+    ./in.cue:280:8
+    ./in.cue:281:8
 e3.b.0: structural cycle
 e3.b.c: conflicting values [b] and {c:b} (mismatched types list and struct):
-    ./in.cue:260:8
-    ./in.cue:261:8
+    ./in.cue:280:8
+    ./in.cue:281:8
 e3.b.c: structural cycle
 e4.a.0: conflicting values [{c:1}] and {} (mismatched types list and struct):
-    ./in.cue:265:13
-    ./in.cue:266:9
+    ./in.cue:285:13
+    ./in.cue:286:9
 e4.b.0: conflicting values [{c:1}] and {} (mismatched types list and struct):
-    ./in.cue:268:9
-    ./in.cue:269:13
+    ./in.cue:288:9
+    ./in.cue:289:13
 p2.#T.a.b.link: structural cycle
 p3.#U.#T.a.b.link: structural cycle
 p5.#T.a.0.link: structural cycle
@@ -414,11 +436,11 @@
 b4.x.y.0: structural cycle:
     ./in.cue:41:8
 d2.a.b.c.d.t: structural cycle:
-    ./in.cue:222:8
+    ./in.cue:242:8
 d2.r: structural cycle:
-    ./in.cue:222:8
+    ./in.cue:242:8
 0: structural cycle:
-    ./in.cue:232:19
+    ./in.cue:252:19
 
 Result:
 (_|_){
@@ -652,6 +674,60 @@
       sum: (int){ 10 }
     }
   }
+  b13: (_|_){
+    // [structural cycle]
+    root: (_|_){
+      // [structural cycle]
+      a: (_|_){
+        // [structural cycle]
+        0: (_|_){
+          // [structural cycle]
+          0: (_|_){
+            // [structural cycle] b13.root.a.0.0: structural cycle
+            0: (_|_){// {
+              //   〈1;x〉
+              // }
+            }
+          }
+        }
+      }
+    }
+  }
+  b14: (_|_){
+    // [structural cycle]
+    root: (_|_){
+      // [structural cycle]
+      a: (list){
+      }
+      b: (_|_){
+        // [structural cycle]
+        0: (list){
+        }
+        1: (_|_){
+          // [structural cycle]
+          0: (list){
+          }
+          1: (_|_){
+            // [structural cycle] b14.root.b.1.1: structural cycle
+            0: (_|_){// {
+              //   〈1;x〉
+              // }
+            }
+            1: (_|_){// {
+              //   〈1;x〉
+              // }
+            }
+          }
+        }
+      }
+    }
+  }
+  b15: (struct){
+    root: (struct){
+      a: (struct){
+      }
+    }
+  }
   p1: (struct){
     #T: (#struct){
       a: (#struct){
@@ -921,11 +997,11 @@
     // [structural cycle]
     x: (_|_){
       // [structural cycle] d2.a.b.c.d.t: structural cycle:
-      //     ./in.cue:222:8
+      //     ./in.cue:242:8
     }
     r: (_|_){
       // [structural cycle] d2.r: structural cycle:
-      //     ./in.cue:222:8
+      //     ./in.cue:242:8
       c: (_|_){// {
         //   d: {
         //     h: int
@@ -968,19 +1044,19 @@
           // [structural cycle]
           c: (_|_){
             // [structural cycle] 0: structural cycle:
-            //     ./in.cue:232:19
+            //     ./in.cue:252:19
           }
         }
       }
       indirect: (_|_){
         // [structural cycle] 0: structural cycle:
-        //     ./in.cue:232:19
+        //     ./in.cue:252:19
       }
       i: (int){ 1 }
     }
     x: (_|_){
       // [structural cycle] 0: structural cycle:
-      //     ./in.cue:232:19
+      //     ./in.cue:252:19
       i: (int){ 0 }
     }
   }
@@ -1026,12 +1102,12 @@
     // [eval]
     a: (_|_){
       // [eval] e3.a: conflicting values [a] and {c:a} (mismatched types list and struct):
-      //     ./in.cue:257:8
-      //     ./in.cue:258:8
+      //     ./in.cue:277:8
+      //     ./in.cue:278:8
       c: (_|_){
         // [eval] e3.a.c: conflicting values [a] and {c:a} (mismatched types list and struct):
-        //     ./in.cue:257:8
-        //     ./in.cue:258:8
+        //     ./in.cue:277:8
+        //     ./in.cue:278:8
         // e3.a.c: structural cycle
         c: (_|_){// 〈1;a〉
         }
@@ -1040,8 +1116,8 @@
       }
       0: (_|_){
         // [eval] e3.a.0: conflicting values [a] and {c:a} (mismatched types list and struct):
-        //     ./in.cue:257:8
-        //     ./in.cue:258:8
+        //     ./in.cue:277:8
+        //     ./in.cue:278:8
         // e3.a.0: structural cycle
         c: (_|_){// 〈1;a〉
         }
@@ -1051,12 +1127,12 @@
     }
     b: (_|_){
       // [eval] e3.b: conflicting values [b] and {c:b} (mismatched types list and struct):
-      //     ./in.cue:260:8
-      //     ./in.cue:261:8
+      //     ./in.cue:280:8
+      //     ./in.cue:281:8
       c: (_|_){
         // [eval] e3.b.c: conflicting values [b] and {c:b} (mismatched types list and struct):
-        //     ./in.cue:260:8
-        //     ./in.cue:261:8
+        //     ./in.cue:280:8
+        //     ./in.cue:281:8
         // e3.b.c: structural cycle
         c: (_|_){// 〈1;b〉
         }
@@ -1065,8 +1141,8 @@
       }
       0: (_|_){
         // [eval] e3.b.0: conflicting values [b] and {c:b} (mismatched types list and struct):
-        //     ./in.cue:260:8
-        //     ./in.cue:261:8
+        //     ./in.cue:280:8
+        //     ./in.cue:281:8
         // e3.b.0: structural cycle
         c: (_|_){// 〈1;b〉
         }
@@ -1081,8 +1157,8 @@
       // [eval]
       0: (_|_){
         // [eval] e4.a.0: conflicting values [{c:1}] and {} (mismatched types list and struct):
-        //     ./in.cue:265:13
-        //     ./in.cue:266:9
+        //     ./in.cue:285:13
+        //     ./in.cue:286:9
         0: (struct){
           c: (int){ 1 }
         }
@@ -1092,8 +1168,8 @@
       // [eval]
       0: (_|_){
         // [eval] e4.b.0: conflicting values [{c:1}] and {} (mismatched types list and struct):
-        //     ./in.cue:268:9
-        //     ./in.cue:269:13
+        //     ./in.cue:288:9
+        //     ./in.cue:289:13
         0: (struct){
           c: (int){ 1 }
         }
@@ -1415,6 +1491,39 @@
       }
     }
   }
+  b13: {
+    root: {
+      a: [
+        for _, x in 〈1;root〉 {
+          〈1;x〉
+        },
+      ]
+    }
+  }
+  b14: {
+    root: {
+      a: [
+        ...int,
+      ]
+      for _, x in 〈0;a〉 {
+        "\(〈1;x〉)": {}
+      }
+      b: [
+        for _, x in 〈1;root〉 {
+          〈1;x〉
+        },
+      ]
+    }
+  }
+  b15: {
+    root: {
+      a: {
+        for _, x in 〈2;root〉 {
+          〈1;x〉
+        }
+      }
+    }
+  }
   p1: {
     #T: {
       a: {
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index f0fd940..411a7ad 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -159,7 +159,15 @@
 func (c *OpContext) spawn(node *Vertex) *OpContext {
 	sub := *c
 	node.Parent = c.e.Vertex
-	sub.e = &Environment{Up: c.e, Vertex: node}
+	sub.e = &Environment{
+		Up:     c.e,
+		Vertex: node,
+
+		// Copy cycle data.
+		Cyclic: c.e.Cyclic,
+		Deref:  c.e.Deref,
+		Cycles: c.e.Cycles,
+	}
 	return &sub
 }
 
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index ef88abf..d8c4876 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -1185,9 +1185,12 @@
 		n := &Vertex{status: Finalized}
 
 		// TODO: only needed if value label != _
-		b := *a
-		b.Label = x.Value
-		n.Arcs = append(n.Arcs, &b)
+
+		b := &Vertex{
+			Label: x.Value,
+			Value: a,
+		}
+		n.Arcs = append(n.Arcs, b)
 
 		if x.Key != 0 {
 			v := &Vertex{Label: x.Key}
diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go
index 39d8597..006ee26 100644
--- a/internal/core/eval/eval.go
+++ b/internal/core/eval/eval.go
@@ -1140,6 +1140,13 @@
 			n.exprs = append(n.exprs, v)
 			break
 		}
+		for {
+			x, ok := arc.Value.(*adt.Vertex)
+			if !ok {
+				break
+			}
+			arc = x
+		}
 
 		// We need to ensure that each arc is only unified once (or at least) a
 		// bounded time, witch each conjunct. Comprehensions, for instance, may
@@ -1888,7 +1895,8 @@
 					label, err := adt.MakeLabel(x.Source(), index, adt.IntLabel)
 					n.addErr(err)
 					index++
-					n.insertField(label, adt.MakeConjunct(e, st, l.id))
+					c := adt.MakeConjunct(e, st, l.id)
+					n.insertField(label, c)
 				})
 				hasComprehension = true
 				if err != nil && !err.IsIncomplete() {