// Tests various evaluator stability fixes: panic in recursive disjunctions with
// list.FlattenN (issue3750), negative reference counter panic with pattern
// constraints and comprehensions (issue3780), fields dropped by for loop in let
// binding with disjunction (issue3770), and unexpected uninitialized node panic
// with if comprehensions and list comprehensions (issue3824).
-- issue3750.cue --
package p

import "list"

// evalv3 panic "incDependent: already closed" triggered by recursive
// disjunctions combined with list.FlattenN comprehensions.
// https://cuelang.org/issue/3750
issue3750: original: {
	out: #Foo & {
		sub: #Foo
	}

	#Foo: {
		sub: #Foo | #Bar
		meta: {
			strs: [...string]
			for _, w in list.FlattenN([strs], 1) {}
		}
	}


	#Bar: {
		kind: "bar"
		meta: strs: [...string]
	}
	@test(eq, {
		out: {
			sub: {
				sub: {
					sub: {
						sub: {kind: "bar", meta: {strs: []}}
						meta: {strs: []}
					} |{kind: "bar", meta: {strs: []}}
					meta: {strs: []}
				} | {kind: "bar", meta: {strs: []}}
				meta: {strs: []}
			}
			meta: {strs: []}
		}
		#Foo: {
			sub: {kind: "bar", meta: {strs: []}}
			meta: {strs: []}
		}
		#Bar: {kind: "bar", meta: {strs: []}}
	})
}

issue3750: reduced: {
	out: Foo & { sub: Foo }

	Foo: {
		sub: Foo | {a: b: _}
		a: {
			b: _
			for _, w in list.FlattenN([b], 1) {}
		}
	}
	@test(eq, {
		out: {
			sub: {
				sub: {sub: {sub: {a: {b: _}}, a: {b: _}} | {a: {b: _}}, a: {b: _}} | {a: {b: _}}
				a: {b: _}
			}
			a: {b: _}
		}
		Foo: {sub: {a: {b: _}}, a: {b: _}}
	})
}
-- issue3780.cue --
import "strings"

// evalv3 "negative reference counter" panic when combining pattern
// constraints with comprehensions and conditional logic.
// https://cuelang.org/issue/3780
issue3780: panic1: {
	objs: #Objects & {}
	param!: bool
	if param {
		objs: obj1: {
			one: 1
			two: 2
		}
	}
	#Objects: [strings.HasPrefix("obj")]: {
		kind: "object"
		...
	}
	@test(err, code=incomplete, hint="required field missing: param")
}
issue3780: panic2: {
	parent: {
		objs: #Objects & {}
		param?: bool
		if param != _|_ {
			objs: obj1: {
				one: 1
				two: 2
			}
		}
		#Objects: [strings.HasPrefix("obj")]: {
			kind: "object"
			...
		}
	}
	@test(eq, {
		parent: {objs: {}, param?: bool, #Objects: {}}
	})
}
-- issue3770.cue --
// evalv3 regression: fields generated by a for loop in a let binding were
// dropped after unifying with a disjunctive type constraint.
// https://cuelang.org/issue/3770
issue3770: task: {
	m: {
		let t = ["x"]
		for m in t {
			(m): a: 1
		}
		x: b: 1
	}
	m: null | {  }
	out: m.x.a
	@test(eq, {m: {x: {b: 1, a: 1}}, out: 1})
}
-- issue3824.cue --
// evalv3 panic: "unexpected uninitialized node" when combining if comprehensions
// with list comprehensions and disjunctive type constraints.
// https://cuelang.org/issue/3824
issue3824: panic: {
	thing: {
        spec: name: string
        outputField: string
	}

	val: string
	things: [_]: thing

	things: [_]: {
			spec: *{
					name: "self-signed"
			} | {...}
	}

	if true {
			things: "name": {}
			val: things["name"].outputField
	}
	@test(eq, {
		thing: {
			spec: {name: string}
			outputField: string
		}
		val: string
		things: {
			name: {
				spec: *{name: "self-signed"} | {name: string}
				outputField: string
			}
		}
	})
}
-- out/errors.txt --
[incomplete] issue3780.panic1: required field missing: param:
    ./issue3780.cue:9:5
-- out/eval/stats --
Leaks:  67
Freed:  154
Reused: 135
Allocs: 86
Retain: 0

Unifications: 164
Conjuncts:    267
Disjuncts:    36

NumCloseIDs: 60
-- out/todo.txt --
issue3750.original: v3 has more complex nested disjunction structure in sub field; v2 resolves to concrete value.
issue3750.reduced: v3 has different field ordering in disjunction sub-fields compared to v2.
issue3780.panic1: v3 error message is "required field missing: param"; v2 is "incomplete bool: bool".
