-- x.cue --
// variants of fib

inline: small: {
	f: {
		n: int
		out: (f & {"n": n - 1}).out @test(err, code=structural_cycle, contains="structural cycle", pos=[0:9])
	}
}

inline: medium: {
	f2:  (f & {n: 2}).out @test(err, code=structural_cycle, contains="structural cycle", pos=[1:24])
	fRec: {nn: int, out: (f & {n: nn}).out}
	@test(err, at=fRec.out, code=structural_cycle, contains="structural cycle", pos=[6:9])
	f: {
		n: int
		out: (fRec & {nn: n - 1}).out @test(err, code=structural_cycle, contains="structural cycle", pos=[0:9])
	}
}

inline: patterns: {
	f: n: (f & {n: {}}).n
	f: n: {}  @test(err, code=structural_cycle, contains="structural cycle", pos=[-1:9])
	[string]: {n: {}}
	f: [string]: {}
	f: {}
}

inline: acrossFields: fail1: {
	f: {
		in:  number
		out: in + 1
	}
	k00: 0
	k10: (f & {in: k00}).out
	k20: (f & {in: k10}).out
	k30: (f & {in: k20}).out

	// invalid recursion is here.
	k10: (f & {in: k30}).out
	@test(eq, {
		f: {
			in: number
			out: _|_ @test(err, code=incomplete, contains="inline.acrossFields.fail1.f.out: non-concrete value number in operand to +", pos=[3:8, 2:8])
		}
		k00: 0
		k10: _|_ @test(err, code=incomplete, contains="in: non-concrete value number in operand to +", pos=[3:8, 2:8, 8:17])
		k20: _|_ @test(err, code=incomplete, contains="in: non-concrete value number in operand to +", pos=[3:8, 2:8, 11:17])
		k30: _|_ @test(err, code=incomplete, contains="in: non-concrete value number in operand to +", pos=[3:8, 2:8, 7:17])
	})
}

// Issue #2163
inline: acrossFields: ok1: {
	f: {
		in:  number
		out: in
	}
	k00: 0
	k10: (f & {in: k00}).out
	k20: (f & {in: k10}).out
	k30: (f & {in: k20}).out

	// TODO: what is correct behavior here.
	// This is borderline okay.
	k10: (f & {in: k30}).out
	@test(eq, {
		f: {in: number, out: number}
		k00: 0
		k10: 0
		k20: 0
		k30: 0
	}, hint="might be okay to fail")
}
-- inlineexpand.cue --
inlined: {
	X: {
		input: a: _
		output: input.a
	}
	root: a: (X & {input: root}).output
	@test(eq, {
		X: {input: {a: _}, output: _}
		root: {a: _}
	})
}
expanded1: hasCycle: {
	X: {
		input: a: _
		output: input.a
	}
	root: {
		a: _a.output
		_a: X & {input: root}
	}
	@test(err, code=structural_cycle, at=root._a.input._a.input, contains="structural cycle", pos=[])
}
expanded2: noCycle: {
	X: {
		input: a: _
		output: input.a
	}
	root: a: _a.output
	_a: X & {input: root}
	@test(eq, {
		X: {input: {a: _}, output: _}
		root: {a: _}
		_a: {input: {a: _}, output: _}
	})
}
issue3731: reduced: {
	#lookup: {
		input: {...}
		output: [
			for _, v in input if v.show != _|_ { v },
		]
	}

	root: {
		self: show: true
		others: (#lookup & {input: root}).output
	}
	@test(eq, {
		#lookup: {input: {}, output: []}
		root: {
			self: {show: true}
			others: [{show: true}]
		}
	})
}
issue3731: expanded: {
	#lookup: {
		input: {...}
		output: [
			for _, v in input if v.show != _|_ { v },
		]
	}

	root: {
		self: show: true
		others: _others.output
		_others: #lookup & {input: root}
	}
	@test(err, code=structural_cycle, at=root._others.input._others.input, contains="structural cycle", pos=[])
}
issue3731: full: {
	#Workspace: {
		workspaceA?: {}
		workspaceB?: {}
	}

	#AccountConfig: {
		workspaces: #Workspace
		siblings?: [...string]
	}

	#AccountConfigSub1: {
		#AccountConfig
		workspaces: "workspaceA": {}
	}
	
	#AccountConfigSub2: {
		#AccountConfig
		workspaces: "workspaceB": {}
	}
	
	tree: env1: {
		"region1": {
			"env1-r1-account-sub1": #AccountConfigSub1
			"env1-r1-account-sub2-1": #AccountConfigSub2
		}
	}
	
	#lookupSiblings: {
		envtree: {...}
		out: [
			for region, v in envtree
			for account, config in v
			if config.workspaces."workspaceB" != _|_ { account },
		]
	}
	
	tree: ENVTREE=env1: [_]: [_]: #AccountConfig & {
		siblings: (#lookupSiblings & {envtree: ENVTREE}).out
	}
	@test(eq, {
		#Workspace: {workspaceA?: {}, workspaceB?: {}}
		#AccountConfig: {
			workspaces: {workspaceA?: {}, workspaceB?: {}}
			siblings?: []
		}
		#AccountConfigSub1: {
			workspaces: {workspaceA: {}, workspaceB?: {}}
			siblings?: []
		}
		#AccountConfigSub2: {
			workspaces: {workspaceB: {}, workspaceA?: {}}
			siblings?: []
		}
		tree: {
			env1: {
				region1: {
					"env1-r1-account-sub1": {
						siblings: ["env1-r1-account-sub2-1"]
						workspaces: {workspaceA: {}, workspaceB?: {}}
					}
					"env1-r1-account-sub2-1": {
						siblings: ["env1-r1-account-sub2-1"]
						workspaces: {workspaceB: {}, workspaceA?: {}}
					}
				}
			}
		}
		#lookupSiblings: {envtree: {}, out: []}
	})
}
-- out/errors.txt --
[structural_cycle] expanded1.hasCycle.root._a.input._a.input: structural cycle
[structural_cycle] issue3731.expanded.root._others.input._others.input: structural cycle
[structural_cycle] structural cycle:
    ./x.cue:6:9
[structural_cycle] structural cycle:
    ./x.cue:12:24
[structural_cycle] structural cycle:
    ./x.cue:16:9
[structural_cycle] structural cycle:
    ./x.cue:16:9
[structural_cycle] structural cycle:
    ./x.cue:21:9
[incomplete] inline.acrossFields.fail1.f.out: non-concrete value number in operand to +:
    ./x.cue:31:8
    ./x.cue:30:8
[incomplete] in: non-concrete value number in operand to +:
    ./x.cue:31:8
    ./x.cue:30:8
    ./x.cue:36:17
[incomplete] in: non-concrete value number in operand to +:
    ./x.cue:31:8
    ./x.cue:30:8
    ./x.cue:39:17
[incomplete] in: non-concrete value number in operand to +:
    ./x.cue:31:8
    ./x.cue:30:8
    ./x.cue:35:17
-- out/todo.txt --
inline.acrossFields.fail1: v2 had structural cycle error, v3 succeeds with incomplete errors on k10/k20/k30.
inline.medium.f2: different structural cycle error position in v2 (x.cue:15:9) vs v3 (x.cue:12:24).
issue3731.reduced.root.others.0: v2 shows (struct), v3 shows (#struct).
issue3731.expanded.root.others: v2 expanded list, v3 uses structure sharing ~(_others.output).
issue3731.full.#AccountConfig.workspaces: v2 expands fields, v3 uses structure sharing ~(#Workspace).
issue3731.full.tree.env1.region1.*: siblings/workspaces field ordering differs between v2 and v3.
-- out/eval/stats --
Leaks:  5
Freed:  311
Reused: 273
Allocs: 43
Retain: 0

Unifications: 248
Conjuncts:    623
Disjuncts:    0

NumCloseIDs: 201
