-- in.cue --
a:  *1 | int       @test(eq, *1 | int)
aa: *1 | *2 | int  @test(eq, *1 | *2 | int)

b: {
	name: "int"
	val:  int
} | {
	name: "str"
	val:  string
} @test(eq, {name: "int", val: int} | {name: "str", val: string})

d: b & {val:  3}             @test(eq, {val: 3, name: "int"})
c: b & {name: "int", val: 3} @test(eq, {name: "int", val: 3})
e: b & {val:  "foo"}         @test(eq, {val: "foo", name: "str"})
f: b & {name: "str", val: 3} @test(err,
	suberr=(code=eval, contains="conflicting values", pos=[-10:8, 0:4, 0:15]),
	suberr=(code=eval, contains="conflicting values", pos=[-6:8, 0:4, 0:27]))

// Disjunct elimination based on type.
e1: {
	a: null | {bar: 2}
	b: (a & {}).bar
	@test(eq, {a: null | {bar: 2}, b: 2})
}

d1: {
	a: (null | {c:      1}) & {}
	b: {} & (null | {c: 1})
	@test(eq, {a: {c: 1}, b: {c: 1}})
}

d2: {
	a: ([...] | {c:      1}) & {}
	b: {} & ([...] | {c: 1})
	@test(eq, {a: {c: 1}, b: {c: 1}})
}

d3: {
	a: (string | {c:      1}) & {}
	b: {} & (string | {c: 1})
	@test(eq, {a: {c: 1}, b: {c: 1}})
}

d4: {
	a: (string | {c:      1}) & {}
	b: {} & (string | {c: 1})
	@test(eq, {a: {c: 1}, b: {c: 1}})
}

d5: {
	a: (number | {c:      1}) & {}
	b: {} & (number | {c: 1})
	@test(eq, {a: {c: 1}, b: {c: 1}})
}

d6: {
	a: (int | {c:      1}) & {}
	b: {} & (int | {c: 1})
	@test(eq, {a: {c: 1}, b: {c: 1}})
}

t10: p1: {
	// @test(permute, count=120) // TODO(inline): we could reduce this by grouping fields.
	schema: test
	schema: string | {name: string}
	#A: {string | {name: string}}

	test: name: "Test"
	test: #A
	@test(eq, {
		schema: {name: "Test"}
		#A: string | {name: string}
		test: {name: "Test"}
	})
}

t10: p2: {
	schema: string | {name: string}
	schema: test
	#A: {string | {name: string}}

	test: name: "Test"
	test: #A
	@test(eq, {
		schema: {name: "Test"}
		#A: string | {name: string}
		test: {name: "Test"}
	})
}

t10: p3: {
	#A: {string | {name: string}}

	test: name: "Test"
	test: #A

	schema: string | {name: string}
	schema: test
	@test(eq, {
		#A: string | {name: string}
		test: {name: "Test"}
		schema: {name: "Test"}
	})
}

t11: p1: {
	a: #A
	a: b

	b:  #A & ["b"]
	#A: ["a" | "b"] | {}
	@test(eq, {
		a: ["b"]
		b: ["b"]
		#A: ["a" | "b"] | {}
	})
}

t11: p2: {
	b:  #A & ["b"]
	#A: ["a" | "b"] | {}

	a: b
	a: #A
	@test(eq, {
		b: ["b"]
		#A: ["a" | "b"] | {}
		a: ["b"]
	})
}

cross: {
	a: *"word" | string
	a: string | *"word"
	@test(eq, {a: *"word" | string})
}

d100: {
	// Should we allow a selector to imply a struct or list? Would be convenient.
	// This would be a spec change. Disallow for now.
	i: null | {bar: 2}
	j: i.bar
	@test(eq, {
		i: null | {bar: 2}
		j: _|_ @test(err, code=incomplete, contains="d100.j: unresolved disjunction null | {bar:2} (type (null|struct))", pos=[4:5])
	})
}

// Regression test for empty disjunction with combined definitions and
// template constraints where valid unification was incorrectly rejected.
// https://cuelang.org/issue/641
issue641: {
	#A: {
		type: "a"
		x:    ""
	}

	#B: {
		type: "b"
		x:    string
	}

	#C: {
		b: #A | #B
	}

	e: [string]: #C & {
		b: #A | #B
	}

	e: foobar: #C & {
		b: #B & {
			x: "foobar"
		}
	}
	@test(eq, {
		#A: {type: "a", x: ""}
		#B: {type: "b", x: string}
		#C: {
			b: {type: "a", x: ""} | {type: "b", x: string}
		}
		e: {foobar: {b: {x: "foobar", type: "b"}}}
	})
}
-- issue3406.cue --
// evalv3 panic with inconsistent state when unifying a struct with itself
// embedded via a disjunction field.
// https://cuelang.org/issue/3406
issue3406: {
	out: d & { d }
	d: kind: "foo" | "bar"
	d: { kind: "foo" } | { kind: "bar" }
	@test(eq, {
		out: {kind: "foo"} | {kind: "bar"}
		d: {kind: "foo"} | {kind: "bar"}
	})
}
-- issue3411.cue --
// evalv3 nil pointer dereference when unifying optional fields with defaults.
// https://cuelang.org/issue/3411
issue3411: {
	x: y?: [...string]
	x: {y: ["foo"]} | *{y: ["bar"]}
	@test(eq, {x: *{y: ["bar"]} | {y: ["foo"]}})
}
-- issue3490.cue --
// evalv3 "incDependent: already closed" panic regression involving disjunctions.
// https://cuelang.org/issue/3490
issue3490: nested: p1: {
	("a"|"b") | "b"
	"a"|"b"
	@test(eq, {
		"a"
		@test(eq)
	} | {
		"b"
		@test(eq)
	})
}
issue3490: nested: p2: {
	"a"|"b"
	("a"|"b") | "b"
	@test(eq, {
		"a"
		@test(eq)
	} | {
		"b"
		@test(eq)
	})
}
issue3490: full: {
	data: [...#Schema]
	data: [#Schema & {}]
	#Schema: {
		runs?: "foo" | ([#D1] | [#D1, #D2])
		#D1: "d1"
		#D2: "d2"
	}
	@test(eq, {
		data: [{
			runs?: "foo" | ["d1"] | ["d1", "d2"]
			#D1: "d1"
			#D2: "d2"
		}]
		#Schema: {
			runs?: "foo" | ["d1"] | ["d1", "d2"]
			#D1: "d1"
			#D2: "d2"
		}
	})
}
-- issue3434.cue --
// evalv3 panic "unexpected overlay in next" with disjunctions inside definitions.
// https://cuelang.org/issue/3434
issue3434: t1: {
	({} | {})
	{["x"]: 1}
	{["y"]: 2}
	@test(eq, {["x"]: 1, ["y"]: 2})
}
issue3434: full: {
	out: #Schema & {
		steps: [{run: "example"}]
	}
	#Schema: {
		steps: [...{run: string}]
		#matrixConfig: string | [...#matrixConfig]
		matrix?: ({...} | string) & {
			{[=~"^foo"]: [...{[string]: #matrixConfig}]}
			{[=~"^bar"]: [...#matrixConfig] | string}
		}
	}
	@test(eq, {
		out: {
			steps: [{ run: "example" }]
			#matrixConfig: string | []
			matrix?: {}
		}
		#Schema: {
			steps: []
			#matrixConfig: string | []
			matrix?: {}
		}
	})
}
-- issue3597.cue --
// evalv3 index out of range panic in overlayContext.allocCC with let inside
// a disjunction within a definition applied via a pattern constraint.
// https://cuelang.org/issue/3597
issue3597: t1: {
	#Schema: {
		_ok: bool
		{} | {
			_ok: true
			let Ok = _ok
			{} | {x: Ok}
		}
	}

	[string]: #Schema

	foo: bar
	bar: {}
	@test(eq, {
		#Schema: {_ok: bool} | {_ok: true} | {_ok: true, x: true}
		foo: {_ok: bool} | {_ok: true} | {_ok: true, x: true}
		bar: {_ok: bool} | {_ok: true} | {_ok: true, x: true}
	})
}
issue3597: t2: {
	ok: true
	X: _ | {
		let Ok = ok
		_ | {x: Ok}
	}
	foo: X & {X}
	@test(eq, {
		ok: true
		X: _ | _ | {x: true}
		foo: _ | _ | {x: true}
	})
}
-- dependencies.cue --
// evalv3 incorrectly allowed a field inside a struct disjunction that should
// have been rejected as "field not allowed".
// https://cuelang.org/issue/3606
issue3606: {
	data: {
		notAllowed: true
	} & #S

	#S: string | {}

	@test(err, code=eval,
		suberr=(code=eval, path=data, contains="conflicting values %s and %s (mismatched types %s and %s)",
			args=[{notAllowed:true}, string, struct, string], pos=[1:8, 3:6, 5:6]),
		suberr=(code=eval, path=data.notAllowed, contains="field not allowed", pos=[2:3]))
}

// evalv3 gives a different result vs evalv2 when openinline is enabled; list
// element count is wrong after unifying nested disjunctions through definitions.
// https://cuelang.org/issue/3672
issue3672: {
	#A: string | {y: true}
	#B: #A | {a: "append"} | {b: "prepend"}

	#fn: {
		#C: #B
		#out: x: [...#C]
	}

	// The unification inline appears to be critical
	#def: (#fn & {}).#out
	
	v: #def
	v: x: [{y: true}] // Should be one element
	@test(eq, {
		#A: string | {y: true}
		#B: string | {y: true} | {a: "append"} | {b: "prepend"}
		#fn: {
			#C: string | {y: true} | {a: "append"} | {b: "prepend"}
			#out: {x: []}
		}
		#def: {x: []}
		v: {x: [{
		y: true
	}]}
	})
}
// Regression giving "non-concrete value _ (type _)" error when interpolating
// a string default from a disjunction via a definition alias.
// https://cuelang.org/issue/3681
issue3681: {
	// Order dependent! These two fields need to go first.
	out: one: #strDefaultDef
	out: two: "\(strDefault)"

	strDefault: *"fallback" | string
	#strDefaultDef: strDefault
	@test(eq, {
		out: {
			one: *"fallback" | string
			two: "fallback"
		}
		strDefault: *"fallback" | string
		#strDefaultDef: *"fallback" | string
	})
}
// evalv3 "undefined field" regression when a comprehension condition references
// a field whose default is provided by a disjunction.
// https://cuelang.org/issue/3699
issue3699: {
	reduced: p1: {
		y: { if x.z { 1 } }
		x: *{z: true} | {}
	}
	reduced: p2: {
		y: { if x.z { 1 } }
		x: *{z: true} | {}
	}
	reduced: full: {
		_res: {
			_fooTrue: {} | *{foo: true}
			_msgSwitch: [
				if _fooTrue.foo { msg: "foo" },
				{ msg: "bar" },
			][0]
			out: _msgSwitch.msg
		}
		let res = {
			out: (_res & {}).out
		}
		out: res.out
	}
	@test(eq, {
		reduced: {
			p1: {y: 1, x: *{z: true} | {}}
			p2: {y: 1, x: *{z: true} | {}}
			full: {
				_res: {
					_fooTrue: *{foo: true} | {}
					_msgSwitch: {msg: "foo"}
					out: "foo"
				}
				out: "foo"
			}
		}
	})
}
-- indexelim.cue --
import "math/bits"

indexElimination: {
	inStruct: x: { a: *x[0] | 0 }.a @test(eq, 0)
	inList1: x: [x[0]][0]           @test(eq, _)
	inList2: x: [*x[0] | 0][0]      @test(eq, 0)
	// evalv3 strange behavior with chaining of list comprehensions,
	// incorrect results when indexing the output of a for loop.
	// https://cuelang.org/issue/3124
	issue3124: full: {
		x: [...bool]
		x: [true, false, true, true]
		y: [for _, v in x {[if v {1}, 0][0]}]
		z: [for i, v in y {bits.Set(*z[i-1] | 0, len(y)-i-1, v)}][3]
		@test(eq, {
			x: [true, false, true, true]
			y: [1, 0, 1, 1]
			z: 1
		})
	}
}
-- issue3899.cue --
// evalv3 "invalid type _" regression that is order-dependent, triggered when
// a string interpolation references an optional field inside a disjunction.
// https://cuelang.org/issue/3899
issue3899: reduced: {
	@test(permute, count=2)
	b: c + "" | string
	c?: string
	@test(eq, {b: string, c?: string})
}
issue3899: full: {
	out: #Schema & {
		name: "foo"
   }
   #Schema: {
	   _versions: foo: "123"
	   spec: limits: true
	   name!: string
	   spec: image: string | *"\(name)"
	   deployImage: _versions[spec.image] @test(err, code=incomplete,
			contains="invalid non-ground value %s (must be concrete %s)",
			args=[string, string], pos=[-1:18])
   }
	@test(eq, {
		out: {
			name: "foo"
			_versions: {foo: "123"}
			spec: {limits: true, image: *"foo" | string}
			deployImage: "123"
		}
		#Schema: {
			_versions: {foo: "123"}
			spec: {limits: true, image: string}
			name!: string
			deployImage: _|_
		}
	})
}
-- issue3891.cue --
// evalv3 "incomplete value" regression with repeated disjunctions where a
// field referencing a default via another field yields an incomplete error.
// https://cuelang.org/issue/3891
issue3891: reduced: {
	{x: _} | null
	{x: _} | null
	x: *a.y | _
	a: b @test(shareID=r3891ab)
	@test(shareID=r3891ab, at=b)
	b: y: 1
	@test(eq, {x: *1 | _, a: {y: 1}, b: {y: 1}})
}
issue3891: full: {
	out: #Foo | "never"
	out: #Foo | "never"
	out: _fooTemplate & {
		_input: (_transform & {in: sub1: sub2: "bar"}).out
	}
	_transform: {
		in: _
		out: in
	}
	#Foo: foo?: _
	_fooTemplate: {
		_input: _
		foo: *_input.sub1.sub2 | _
	}
	@test(eq, {
		out: {
			_input: {sub1: {sub2: "bar"}}
			foo: *"bar" | _
		}
		_transform: {in: _, out: _}
		#Foo: {foo?: _}
		_fooTemplate: {_input: _, foo: _}
	})
}
-- out/errors.txt --
[eval] issue3606.data: 2 errors in empty disjunction:
issue3606.data: conflicting values {notAllowed:true} and string (mismatched types struct and string):
    ./dependencies.cue:5:8
    ./dependencies.cue:7:6
    ./dependencies.cue:9:6
issue3606.data.notAllowed: field not allowed:
    ./dependencies.cue:6:3
[eval] f: 2 errors in empty disjunction:
f.name: conflicting values "int" and "str":
    ./in.cue:5:8
    ./in.cue:15:4
    ./in.cue:15:15
f.val: conflicting values 3 and string (mismatched types int and string):
    ./in.cue:9:8
    ./in.cue:15:4
    ./in.cue:15:27
[incomplete] d100.j: unresolved disjunction null | {bar:2} (type (null|struct)):
    ./in.cue:142:5
[incomplete] issue3899.full.#Schema.deployImage: invalid non-ground value string (must be concrete string):
    ./issue3899.cue:18:18
-- out/todo.txt --
v3 uses structure sharing (~) for issue3891.reduced.a (~(issue3891.reduced.b)) where v2 expanded the value inline. v3 reports conflicting values for issue3606.data in opposite order vs v2 (struct then string vs string then struct), with different position info. v3 shows different position info for f sub-errors. v3 shows indexElimination.inList1.x as _ instead of cycle error. v3 shows issue3597.t1 let Ok as concrete value instead of unresolved reference.
-- out/eval/stats --
Leaks:  115
Freed:  561
Reused: 518
Allocs: 158
Retain: 0

Unifications: 316
Conjuncts:    797
Disjuncts:    229
Notifications: 1

NumCloseIDs: 141
