-- in.cue --
import "list"

[string]: [string]: list.UniqueItems()

#a: {a: 1}
#ab: {a: 1, b?: int}
#abErr: #ab & {b?: string} // erroneous optional field b.

#b: {b: 1}
#c: {c: int}

ok: {
	t1: [1, 2, 3]
	t2: [int, string, bool]
	t3: ["1", 1]
	t4: ["1", "2"]
	t5: [#a, #b]
}

// These have all equal elements, but
incomplete: {
	top: [_, _]

	// These two elements are considered equal, but the error is an "incomplete"
	// errors, as the items may still differ once they become more specific.
	withOptional1: [{a: int}, {a: int, b?: string}]

	// Ditto. This is an incomplete error, even though the matching elements
	// are "final": there is still an optional field.
	withOptional2: [{a: 1}, {a: 1, b?: string}]

	// Ditto. This time with actually closed fields.
	withOptional3: [#a, #ab]

	// Ditto. There are not optional fields, but the structs are open.
	openSpecific: [{a: 1}, {a: 1}]

	// Fully identical closed structs, but with non-concrete values.
	structs: [#c, #c]

}

fail: {
	ints: [1, 2, 1]
	structs: [#a, #a]

	// Hidden values do not play a role in the comparisson.
	ignoreHidden: [1, {1, _foo: 3}]

	// This can be a permanent error, as the optional field of the second
	// element is erroneous an cannot match.
	ignoreOptError: [#a, #abErr]

	// A list embedded alongside a hidden field or let binding shares a single
	// vertex with those non-element arcs. The error message must only print the
	// integer-indexed list elements, not the hidden field or let binding.
	withHidden: {
		_h: int
		[1, 1]
	}
	withLet: {
		let X = 3
		[X, 1, 1]
	}
}

// Value could still become more specific, and thus different.
incomplete: ints: [int, int]

// Struct field order is irrelevant, but these structs
// are open and hence they might gain more fields later
// which would make the values unique.
incomplete: openStructs: [{
	b: 1
	a: 0
}, {
	a: 0
	b: 1
}]

// Struct field order is irrelevant. We simulate finalising
// these values here via close(), which gives the same behaviour
// as 'cue vet -c' on otherwise open values.
fail: structOrderIrrelevant: [close({
	b: 1
	a: 0
}), close({
	a: 0
	b: 1
})]
-- out/list-v3 --
Errors:
fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:48:16
fail.ignoreOptError: invalid value [~(#a),~(#abErr)] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:52:18
fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2:
    ./in.cue:3:21
    ./in.cue:44:8
fail.structOrderIrrelevant: invalid value [{b:1,a:0},{a:0,b:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:84:30
fail.structs: invalid value [~(#a),~(#a)] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:45:11
fail.withHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:57:14
fail.withLet: invalid value [3,1,1] (does not satisfy list.UniqueItems): equal value (1) at position 1 and 2:
    ./in.cue:3:21
    ./in.cue:61:11

Result:
import "list"

#a: {
	a: 1
}
#ab: {
	a:  1
	b?: int
}
#abErr: {
	a:  1
	b?: int & string
}
#b: {
	b: 1
}
#c: {
	c: int
}
ok: {
	t1: [1, 2, 3]
	t2: [int, string, bool]
	t3: ["1", 1]
	t4: ["1", "2"]
	t5: [{
		a: 1
	}, {
		b: 1
	}]
}

// These have all equal elements, but
incomplete: {
	top: list.UniqueItems() & [_, _]

	// These two elements are considered equal, but the error is an "incomplete"
	// errors, as the items may still differ once they become more specific.
	withOptional1: list.UniqueItems() & [{
		a: int
	}, {
		a:  int
		b?: string
	}]

	// Ditto. This is an incomplete error, even though the matching elements
	// are "final": there is still an optional field.
	withOptional2: list.UniqueItems() & [{
		a: 1
	}, {
		a:  1
		b?: string
	}]

	// Ditto. This time with actually closed fields.
	withOptional3: list.UniqueItems() & [#a, #ab]

	// Ditto. There are not optional fields, but the structs are open.
	openSpecific: list.UniqueItems() & [{
		a: 1
	}, {
		a: 1
	}]

	// Fully identical closed structs, but with non-concrete values.
	structs: list.UniqueItems() & [#c, #c]

	// Value could still become more specific, and thus different.
	ints: list.UniqueItems() & [int, int]

	// Struct field order is irrelevant, but these structs
	// are open and hence they might gain more fields later
	// which would make the values unique.
	openStructs: list.UniqueItems() & [{
		b: 1
		a: 0
	}, {
		a: 0
		b: 1
	}]
}
fail: {
	ints:    _|_ // fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2
	structs: _|_ // fail.structs: invalid value [~(#a),~(#a)] (does not satisfy list.UniqueItems): equal values at position 0 and 1

	// Hidden values do not play a role in the comparisson.
	ignoreHidden: _|_ // fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1

	// This can be a permanent error, as the optional field of the second
	// element is erroneous an cannot match.
	ignoreOptError: _|_ // fail.ignoreOptError: invalid value [~(#a),~(#abErr)] (does not satisfy list.UniqueItems): equal values at position 0 and 1

	// A list embedded alongside a hidden field or let binding shares a single
	// vertex with those non-element arcs. The error message must only print the
	// integer-indexed list elements, not the hidden field or let binding.
	withHidden: _|_ // fail.withHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1
	withLet:    _|_ // fail.withLet: invalid value [3,1,1] (does not satisfy list.UniqueItems): equal value (1) at position 1 and 2

	// Struct field order is irrelevant. We simulate finalising
	// these values here via close(), which gives the same behaviour
	// as 'cue vet -c' on otherwise open values.
	structOrderIrrelevant: _|_ // fail.structOrderIrrelevant: invalid value [{b:1,a:0},{a:0,b:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1
}
-- diff/-out/list-v3<==>+out/list --
diff old new
--- old
+++ new
@@ -2,7 +2,7 @@
 fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1:
     ./in.cue:3:21
     ./in.cue:48:16
-fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
+fail.ignoreOptError: invalid value [~(#a),~(#abErr)] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
     ./in.cue:3:21
     ./in.cue:52:18
 fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2:
@@ -10,10 +10,16 @@
     ./in.cue:44:8
 fail.structOrderIrrelevant: invalid value [{b:1,a:0},{a:0,b:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
     ./in.cue:3:21
-    ./in.cue:72:30
-fail.structs: invalid value [{a:1},{a:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
+    ./in.cue:84:30
+fail.structs: invalid value [~(#a),~(#a)] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
     ./in.cue:3:21
     ./in.cue:45:11
+fail.withHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1:
+    ./in.cue:3:21
+    ./in.cue:57:14
+fail.withLet: invalid value [3,1,1] (does not satisfy list.UniqueItems): equal value (1) at position 1 and 2:
+    ./in.cue:3:21
+    ./in.cue:61:11
 
 Result:
 import "list"
@@ -98,7 +104,7 @@
 }
 fail: {
 	ints:    _|_ // fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2
-	structs: _|_ // fail.structs: invalid value [{a:1},{a:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1
+	structs: _|_ // fail.structs: invalid value [~(#a),~(#a)] (does not satisfy list.UniqueItems): equal values at position 0 and 1
 
 	// Hidden values do not play a role in the comparisson.
 	ignoreHidden: _|_ // fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1
@@ -105,7 +111,13 @@
 
 	// This can be a permanent error, as the optional field of the second
 	// element is erroneous an cannot match.
-	ignoreOptError: _|_ // fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1
+	ignoreOptError: _|_ // fail.ignoreOptError: invalid value [~(#a),~(#abErr)] (does not satisfy list.UniqueItems): equal values at position 0 and 1
+
+	// A list embedded alongside a hidden field or let binding shares a single
+	// vertex with those non-element arcs. The error message must only print the
+	// integer-indexed list elements, not the hidden field or let binding.
+	withHidden: _|_ // fail.withHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1
+	withLet:    _|_ // fail.withLet: invalid value [3,1,1] (does not satisfy list.UniqueItems): equal value (1) at position 1 and 2
 
 	// Struct field order is irrelevant. We simulate finalising
 	// these values here via close(), which gives the same behaviour
-- out/list --
Errors:
fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:48:16
fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:52:18
fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2:
    ./in.cue:3:21
    ./in.cue:44:8
fail.structOrderIrrelevant: invalid value [{b:1,a:0},{a:0,b:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:72:30
fail.structs: invalid value [{a:1},{a:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1:
    ./in.cue:3:21
    ./in.cue:45:11

Result:
import "list"

#a: {
	a: 1
}
#ab: {
	a:  1
	b?: int
}
#abErr: {
	a:  1
	b?: int & string
}
#b: {
	b: 1
}
#c: {
	c: int
}
ok: {
	t1: [1, 2, 3]
	t2: [int, string, bool]
	t3: ["1", 1]
	t4: ["1", "2"]
	t5: [{
		a: 1
	}, {
		b: 1
	}]
}

// These have all equal elements, but
incomplete: {
	top: list.UniqueItems() & [_, _]

	// These two elements are considered equal, but the error is an "incomplete"
	// errors, as the items may still differ once they become more specific.
	withOptional1: list.UniqueItems() & [{
		a: int
	}, {
		a:  int
		b?: string
	}]

	// Ditto. This is an incomplete error, even though the matching elements
	// are "final": there is still an optional field.
	withOptional2: list.UniqueItems() & [{
		a: 1
	}, {
		a:  1
		b?: string
	}]

	// Ditto. This time with actually closed fields.
	withOptional3: list.UniqueItems() & [#a, #ab]

	// Ditto. There are not optional fields, but the structs are open.
	openSpecific: list.UniqueItems() & [{
		a: 1
	}, {
		a: 1
	}]

	// Fully identical closed structs, but with non-concrete values.
	structs: list.UniqueItems() & [#c, #c]

	// Value could still become more specific, and thus different.
	ints: list.UniqueItems() & [int, int]

	// Struct field order is irrelevant, but these structs
	// are open and hence they might gain more fields later
	// which would make the values unique.
	openStructs: list.UniqueItems() & [{
		b: 1
		a: 0
	}, {
		a: 0
		b: 1
	}]
}
fail: {
	ints:    _|_ // fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2
	structs: _|_ // fail.structs: invalid value [{a:1},{a:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1

	// Hidden values do not play a role in the comparisson.
	ignoreHidden: _|_ // fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1

	// This can be a permanent error, as the optional field of the second
	// element is erroneous an cannot match.
	ignoreOptError: _|_ // fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1

	// Struct field order is irrelevant. We simulate finalising
	// these values here via close(), which gives the same behaviour
	// as 'cue vet -c' on otherwise open values.
	structOrderIrrelevant: _|_ // fail.structOrderIrrelevant: invalid value [{b:1,a:0},{a:0,b:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1
}
