// This files tests that values are properly "frozen" in case of mutual
// references. Non-structural cyclic references are okay, as long a property
// that is dependended upon in the cycle is not changed after the fact,
// that is, a value may not become more specific after it is used.
-- in.cue --
freezing: t1: ok: {
	#a: x: "a"
	len(#a) // 1
}

-- comprehension.cue --
// This should be an incomplete error, as z is inserted in x, over which the
// comprehension loops. Adding a field z to x would fix this.
// This test would fail in the old evaluator, depending on ordering.
comprehension: t1: _
comprehension: t1: ok: p0: {
	x: y: {}
	// order of comprehensions matter in old evaluator.
	for _ in x {
		if true { x: z: a: {} }
	}
	if true {
		if true { x: z: a: {} }
	}
}

comprehension: t1: ok: p1: {
	for _ in x {
		if true { x: z: a: {} }
	}
	x: y: {}
	if true {
		if true { x: z: a: {} }
	}
}

comprehension: t1: ok: p2: {
	for _ in x {
		if true { x: z: a: {} }
	}
	if true {
		if true { x: z: a: {} }
	}
	x: y: {}
}

comprehension: t1: ok: p3: {
	x: y: {}
	if true {
		if true { x: z: a: {} }
	}
	for _ in x {
		if true { x: z: a: {} }
	}
}

comprehension: t1: ok: p4: {
	if true {
		if true { x: z: a: {} }
	}
	x: y: {}
	for _ in x {
		if true { x: z: a: {} }
	}
}

comprehension: t1: ok: p5: {
	if true {
		if true { x: z: a: {} }
	}
	for _ in x {
		if true { x: z: a: {} }
	}
	x: y: {}
}


comprehension: t2: err: {
	a: {
		x: 1
		for k, v in a {
			(k+"q"): v // This increases the set of fields in a.
		}
	}
}

comprehension: t3: err: {
	// mutual dependencies not okay in this case, as the set of fields grows.
	a: x: 1
	b: y: 1
	a: {
		for k, v in b {
			(k+"q"): v
		}
	}
	b: {
		for k, v in a {
			(k): v
		}
	}
}

comprehension: t4: ok: {
	// It is okay to make x more specific as long as no fields are added.
	x: y: {}
	for _ in x {
		if true { x: y: a: {} }
	}
}

comprehension: moreSpecific: ok: {
	a: {
		x: int
		for k, v in a {
			(k): 1
		}
	}
}

comprehension: moreSpecific: err: {
	a: {
		x: {y: 1}
		// len(v) should free the size of x.
		for k, v in a if len(v) > 0 {
			(k): {z: 1}
		}
	}
}
-- issue3178.cue --
issue3178: {
	// This should pass. Reasoning:
	// - second comprehension runs
	// - in order to satisfy, first comprehension must run
	// - first comprehension runs and completes
	input: [ "Value" ]
	output: {...}
	for name in input {
			output: "\(name)": true
	}
	for name, v in output {
	}
}
-- out/eval/stats --
Leaks:  14
Freed:  58
Reused: 51
Allocs: 21
Retain: 15

Unifications: 72
Conjuncts:    127
Disjuncts:    83
-- out/evalalpha --
Errors:
comprehension.t2.err.a: adding field xq not allowed as field set was already referenced:
    ./comprehension.cue:71:13
comprehension.t3.err.a: adding field xq not allowed as field set was already referenced:
    ./comprehension.cue:82:13
comprehension.moreSpecific.err.a.x: adding field z not allowed as field set was already referenced:
    ./comprehension.cue:114:9

Result:
(_|_){
  // [eval]
  comprehension: (_|_){
    // [eval]
    t1: (struct){
      ok: (struct){
        p0: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p1: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p2: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p3: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p4: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p5: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
      }
    }
    t2: (_|_){
      // [eval]
      err: (_|_){
        // [eval]
        a: (_|_){
          // [eval] comprehension.t2.err.a: adding field xq not allowed as field set was already referenced:
          //     ./comprehension.cue:71:13
          x: (int){ 1 }
        }
      }
    }
    t3: (_|_){
      // [eval]
      err: (_|_){
        // [eval]
        a: (_|_){
          // [eval] comprehension.t3.err.a: adding field xq not allowed as field set was already referenced:
          //     ./comprehension.cue:82:13
          x: (int){ 1 }
        }
        b: (struct){
          y: (int){ 1 }
          x: (int){ 1 }
        }
      }
    }
    t4: (struct){
      ok: (struct){
        x: (struct){
          y: (struct){
            a: (struct){
            }
          }
        }
      }
    }
    moreSpecific: (_|_){
      // [eval]
      ok: (struct){
        a: (struct){
          x: (int){ 1 }
        }
      }
      err: (_|_){
        // [eval]
        a: (_|_){
          // [eval] comprehension.moreSpecific.err.a.x: adding field z not allowed as field set was already referenced:
          //     ./comprehension.cue:114:9
          x: (struct){
            y: (int){ 1 }
          }
        }
      }
    }
  }
  freezing: (struct){
    t1: (struct){
      ok: (int){
        1
        #a: (#struct){
          x: (string){ "a" }
        }
      }
    }
  }
  issue3178: (struct){
    input: (#list){
      0: (string){ "Value" }
    }
    output: (struct){
      Value: (bool){ true }
    }
  }
}
-- diff/-out/evalalpha<==>+out/eval --
diff old new
--- old
+++ new
@@ -1,11 +1,10 @@
 Errors:
-comprehension.moreSpecific.err.a: field z not allowed by earlier comprehension or reference cycle
-comprehension.t1.ok.p0.x: field z not allowed by earlier comprehension or reference cycle
-comprehension.t1.ok.p1.x: field z not allowed by earlier comprehension or reference cycle
-comprehension.t1.ok.p2.x: field z not allowed by earlier comprehension or reference cycle
-comprehension.t2.err.a: field xq not allowed by earlier comprehension or reference cycle
-comprehension.t3.err.b: field x not allowed by earlier comprehension or reference cycle
-comprehension.t3.err.b: field yq not allowed by earlier comprehension or reference cycle
+comprehension.t2.err.a: adding field xq not allowed as field set was already referenced:
+    ./comprehension.cue:71:13
+comprehension.t3.err.a: adding field xq not allowed as field set was already referenced:
+    ./comprehension.cue:82:13
+comprehension.moreSpecific.err.a.x: adding field z not allowed as field set was already referenced:
+    ./comprehension.cue:114:9
 
 Result:
 (_|_){
@@ -12,38 +11,30 @@
   // [eval]
   comprehension: (_|_){
     // [eval]
-    t1: (_|_){
-      // [eval]
-      ok: (_|_){
-        // [eval]
-        p0: (_|_){
-          // [eval]
-          x: (_|_){
-            // [eval] comprehension.t1.ok.p0.x: field z not allowed by earlier comprehension or reference cycle
-            y: (struct){
-            }
-            z: (struct){
-              a: (struct){
-              }
-            }
-          }
-        }
-        p1: (_|_){
-          // [eval]
-          x: (_|_){
-            // [eval] comprehension.t1.ok.p1.x: field z not allowed by earlier comprehension or reference cycle
-            y: (struct){
-            }
-            z: (struct){
-              a: (struct){
-              }
-            }
-          }
-        }
-        p2: (_|_){
-          // [eval]
-          x: (_|_){
-            // [eval] comprehension.t1.ok.p2.x: field z not allowed by earlier comprehension or reference cycle
+    t1: (struct){
+      ok: (struct){
+        p0: (struct){
+          x: (struct){
+            y: (struct){
+            }
+            z: (struct){
+              a: (struct){
+              }
+            }
+          }
+        }
+        p1: (struct){
+          x: (struct){
+            y: (struct){
+            }
+            z: (struct){
+              a: (struct){
+              }
+            }
+          }
+        }
+        p2: (struct){
+          x: (struct){
             y: (struct){
             }
             z: (struct){
@@ -89,9 +80,9 @@
       err: (_|_){
         // [eval]
         a: (_|_){
-          // [eval] comprehension.t2.err.a: field xq not allowed by earlier comprehension or reference cycle
-          x: (int){ 1 }
-          xq: (int){ 1 }
+          // [eval] comprehension.t2.err.a: adding field xq not allowed as field set was already referenced:
+          //     ./comprehension.cue:71:13
+          x: (int){ 1 }
         }
       }
     }
@@ -99,16 +90,14 @@
       // [eval]
       err: (_|_){
         // [eval]
-        a: (struct){
-          x: (int){ 1 }
-          yq: (int){ 1 }
-        }
-        b: (_|_){
-          // [eval] comprehension.t3.err.b: field x not allowed by earlier comprehension or reference cycle
-          // comprehension.t3.err.b: field yq not allowed by earlier comprehension or reference cycle
+        a: (_|_){
+          // [eval] comprehension.t3.err.a: adding field xq not allowed as field set was already referenced:
+          //     ./comprehension.cue:82:13
+          x: (int){ 1 }
+        }
+        b: (struct){
           y: (int){ 1 }
           x: (int){ 1 }
-          yq: (int){ 1 }
         }
       }
     }
@@ -132,10 +121,10 @@
       err: (_|_){
         // [eval]
         a: (_|_){
-          // [eval] comprehension.moreSpecific.err.a: field z not allowed by earlier comprehension or reference cycle
+          // [eval] comprehension.moreSpecific.err.a.x: adding field z not allowed as field set was already referenced:
+          //     ./comprehension.cue:114:9
           x: (struct){
             y: (int){ 1 }
-            z: (int){ 1 }
           }
         }
       }
-- diff/explanation --
v0.7 fixes bugs in v0.6:
- comprehension.t1 should be at most an incomplete error, as it is fixable.
  Arguably they should pass, though, as there is a predictable path to its
  resolution.
-- out/eval --
Errors:
comprehension.moreSpecific.err.a: field z not allowed by earlier comprehension or reference cycle
comprehension.t1.ok.p0.x: field z not allowed by earlier comprehension or reference cycle
comprehension.t1.ok.p1.x: field z not allowed by earlier comprehension or reference cycle
comprehension.t1.ok.p2.x: field z not allowed by earlier comprehension or reference cycle
comprehension.t2.err.a: field xq not allowed by earlier comprehension or reference cycle
comprehension.t3.err.b: field x not allowed by earlier comprehension or reference cycle
comprehension.t3.err.b: field yq not allowed by earlier comprehension or reference cycle

Result:
(_|_){
  // [eval]
  comprehension: (_|_){
    // [eval]
    t1: (_|_){
      // [eval]
      ok: (_|_){
        // [eval]
        p0: (_|_){
          // [eval]
          x: (_|_){
            // [eval] comprehension.t1.ok.p0.x: field z not allowed by earlier comprehension or reference cycle
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p1: (_|_){
          // [eval]
          x: (_|_){
            // [eval] comprehension.t1.ok.p1.x: field z not allowed by earlier comprehension or reference cycle
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p2: (_|_){
          // [eval]
          x: (_|_){
            // [eval] comprehension.t1.ok.p2.x: field z not allowed by earlier comprehension or reference cycle
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p3: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p4: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
        p5: (struct){
          x: (struct){
            y: (struct){
            }
            z: (struct){
              a: (struct){
              }
            }
          }
        }
      }
    }
    t2: (_|_){
      // [eval]
      err: (_|_){
        // [eval]
        a: (_|_){
          // [eval] comprehension.t2.err.a: field xq not allowed by earlier comprehension or reference cycle
          x: (int){ 1 }
          xq: (int){ 1 }
        }
      }
    }
    t3: (_|_){
      // [eval]
      err: (_|_){
        // [eval]
        a: (struct){
          x: (int){ 1 }
          yq: (int){ 1 }
        }
        b: (_|_){
          // [eval] comprehension.t3.err.b: field x not allowed by earlier comprehension or reference cycle
          // comprehension.t3.err.b: field yq not allowed by earlier comprehension or reference cycle
          y: (int){ 1 }
          x: (int){ 1 }
          yq: (int){ 1 }
        }
      }
    }
    t4: (struct){
      ok: (struct){
        x: (struct){
          y: (struct){
            a: (struct){
            }
          }
        }
      }
    }
    moreSpecific: (_|_){
      // [eval]
      ok: (struct){
        a: (struct){
          x: (int){ 1 }
        }
      }
      err: (_|_){
        // [eval]
        a: (_|_){
          // [eval] comprehension.moreSpecific.err.a: field z not allowed by earlier comprehension or reference cycle
          x: (struct){
            y: (int){ 1 }
            z: (int){ 1 }
          }
        }
      }
    }
  }
  freezing: (struct){
    t1: (struct){
      ok: (int){
        1
        #a: (#struct){
          x: (string){ "a" }
        }
      }
    }
  }
  issue3178: (struct){
    input: (#list){
      0: (string){ "Value" }
    }
    output: (struct){
      Value: (bool){ true }
    }
  }
}
-- out/compile --
--- comprehension.cue
{
  comprehension: {
    t1: _
  }
  comprehension: {
    t1: {
      ok: {
        p0: {
          x: {
            y: {}
          }
          for _, _ in 〈0;x〉 {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          if true {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
        }
      }
    }
  }
  comprehension: {
    t1: {
      ok: {
        p1: {
          for _, _ in 〈0;x〉 {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          x: {
            y: {}
          }
          if true {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
        }
      }
    }
  }
  comprehension: {
    t1: {
      ok: {
        p2: {
          for _, _ in 〈0;x〉 {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          if true {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          x: {
            y: {}
          }
        }
      }
    }
  }
  comprehension: {
    t1: {
      ok: {
        p3: {
          x: {
            y: {}
          }
          if true {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          for _, _ in 〈0;x〉 {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
        }
      }
    }
  }
  comprehension: {
    t1: {
      ok: {
        p4: {
          if true {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          x: {
            y: {}
          }
          for _, _ in 〈0;x〉 {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
        }
      }
    }
  }
  comprehension: {
    t1: {
      ok: {
        p5: {
          if true {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          for _, _ in 〈0;x〉 {
            if true {
              x: {
                z: {
                  a: {}
                }
              }
            }
          }
          x: {
            y: {}
          }
        }
      }
    }
  }
  comprehension: {
    t2: {
      err: {
        a: {
          x: 1
          for k, v in 〈1;a〉 {
            (〈1;k〉 + "q"): 〈1;v〉
          }
        }
      }
    }
  }
  comprehension: {
    t3: {
      err: {
        a: {
          x: 1
        }
        b: {
          y: 1
        }
        a: {
          for k, v in 〈1;b〉 {
            (〈1;k〉 + "q"): 〈1;v〉
          }
        }
        b: {
          for k, v in 〈1;a〉 {
            〈1;k〉: 〈1;v〉
          }
        }
      }
    }
  }
  comprehension: {
    t4: {
      ok: {
        x: {
          y: {}
        }
        for _, _ in 〈0;x〉 {
          if true {
            x: {
              y: {
                a: {}
              }
            }
          }
        }
      }
    }
  }
  comprehension: {
    moreSpecific: {
      ok: {
        a: {
          x: int
          for k, v in 〈1;a〉 {
            〈1;k〉: 1
          }
        }
      }
    }
  }
  comprehension: {
    moreSpecific: {
      err: {
        a: {
          x: {
            y: 1
          }
          for k, v in 〈1;a〉 if (len(〈0;v〉) > 0) {
            〈1;k〉: {
              z: 1
            }
          }
        }
      }
    }
  }
}
--- in.cue
{
  freezing: {
    t1: {
      ok: {
        #a: {
          x: "a"
        }
        len(〈0;#a〉)
      }
    }
  }
}
--- issue3178.cue
{
  issue3178: {
    input: [
      "Value",
    ]
    output: {
      ...
    }
    for _, name in 〈0;input〉 {
      output: {
        "\(〈2;name〉)": true
      }
    }
    for name, v in 〈0;output〉 {}
  }
}
