# A let chain derived from a value with a circular self-reference resolved
# incorrectly depending on the order of the concrete data fields. The result
# must not depend on field ordering.
# https://cuelang.org/issue/4357
-- in.cue --
import "strings"

// xFirst declares the field referencing the shared let (x) before the source
// field (id); this is the ordering that used to fail.
xFirst: {
	x:  "B"
	id: "A:B"

	let s = strings.Split(id, ":")
	let b = s[1]

	id!: "\(s[0]):\(b)"
	x!:  "\(b)"
} @test(eq, {
	x:  "B"
	id: "A:B"
})

// idFirst declares the source field (id) first; this ordering always passed.
idFirst: {
	id: "A:B"
	x:  "B"

	let s = strings.Split(id, ":")
	let b = s[1]

	id!: "\(s[0]):\(b)"
	x!:  "\(b)"
} @test(eq, {
	id: "A:B"
	x:  "B"
})

// requiredCycle exercises a let whose value resolves through required fields
// to a genuine cycle: x is a.b, which only ever exists as a cycle placeholder
// because its required subfields never become concrete. Recomputing such a
// cached placeholder on every access used to loop indefinitely; evaluation
// must terminate (here with "required field not present" errors).
requiredCycle: {
	a!: b!: {c!: d!: _}
	a: {}
	let x = a.b
	o: x.c.d @test(err, code=incomplete, contains="required field missing: %s", args=[c], pos=[0:7])
}
-- out/errors.txt --
[incomplete] requiredCycle.o: required field missing: c:
    ./in.cue:43:7
-- out/eval/stats --
Leaks:  14
Freed:  24
Reused: 17
Allocs: 21
Retain: 0

Unifications: 35
Conjuncts:    47
Disjuncts:    0

NumCloseIDs: 7
