# This issue addresses evaluation in nested lets.
-- nested.cue --
issue3801: let: reduced: {
	let F = {
		base: {
			in: string
			let X = {a: "\(in)" }.a
			out: X
		}
		filled: base & {in: "foo"} // failure is here
	}
	z: F.filled.out
	@test(eq, {z: "foo"})
}
issue3801: nonRooted: reduced: {
	#Output: output: {
		#base: {
			val0: string
			msgObj: {a: val0}.a
			value: msgObj
		}
		out: #base & {val0: "foo"}
	}
	out: (#Output & {}).output // non-concrete
	@test(eq, {
		#Output: {
			output: {
				#base: {
					val0: string
					msgObj: string
					value: string
				}
				out: {
					val0: "foo"
					msgObj: "foo"
					value: "foo"
				}
			}
		}
		out: {
			#base: {
				val0: string
				msgObj: string
				value: string
			}
			out: {
				val0: "foo"
				msgObj: "foo"
				value: "foo"
			}
		}
	})
}
issue3801: let: full: {
	#Resource: {
		someMsg: string
		obs: {} | *{missing: true}

		let pickMsg = [
			if obs.missing {msg: "\(someMsg)"},
			{msg: "bar"},
		][0]
		patches: [{
			op:    "add"
			path:  "/metadata"
			value: pickMsg.msg
		}]
	}

	#Patches: [string]: _
	#JSONPatch: {
		namespace?: string
		patch: [...#JSONOp]
		output: #Patches & {(namespace): patch}
	}
	#JSONOp: {
		op:    "add"
		path:  string
		value: _
	} | {
		op:   "remove"
		path: string
	}

	#Main: {
		NS=namespace: string

		output: jsonPatch.output

		let jsonPatch = #JSONPatch & {
			let base = #Resource & {}
			let withMsg = base & {someMsg: "foo"}

			namespace: NS

			patch: withMsg.patches
		}
	}
	out: (#Main & {namespace: "ns1"}).output
	@test(eq, {
		#Resource: {
			someMsg: string
			obs: *{missing: true} | {}
			patches: [{op: "add", path: "/metadata", value: _ @test(ignore)}]
		}
		#Patches: {}
		#JSONPatch: {
			namespace?: string
			patch: []
			output: _|_ @test(err, code=incomplete, contains="key value of dynamic field must be concrete", pos=[20:24])
		}
		#JSONOp: {op: "add", path: string, value: _} | {op: "remove", path: string}
		#Main: {
			namespace: string
			output: _|_ @test(err, code=incomplete)
		}
		out: {
			ns1: [{op: "add", path: "/metadata", value: "foo"}]
		}
	})
}
issue3801: nonRooted: full: {
	#Output: {
		NS=namespace: string
		output: (#SubOutput & {
			namespace: NS
			let base2 = {
				let base = #Base & {}
				output: base & {val0: "foo"}
			}
			patch: base2.output.value
		}).output @test(err, code=incomplete, contains="key value of dynamic field must be concrete, found %v", args=[string], pos=[15:12, 12:15])
	}
	out: (#Output & {namespace: "ns1"}).output

	#SubOutput: {
		namespace?: string

		patch: _
		output: (namespace): patch

		// TODO(eval): our message is substituted as a string instead of being wrapped as an error.
		@test(err, at=output, code=incomplete,
			suberr=(code=incomplete, contains="key value of dynamic field must be concrete, found %v",
				args=[_|_(issue3801.nonRooted.full.#SubOutput.output: cannot reference optional field: namespace)], pos=[4:12]),
			suberr=(code=incomplete, contains="cannot reference optional field: %s", args=[namespace], pos=[4:12]))
	}

	#Base: {
		val0: string
		let msgObj = [val0][0]
		value: msgObj
	}
	@test(eq, {
		#Output: {
			namespace: string
			output: _|_
		}
		out: {ns1: "foo"}
		#SubOutput: {
			namespace?: string
			patch: _
			output: _|_
		}
		#Base: {val0: string, value: string}
	})
}
-- out/errors.txt --
[incomplete] issue3801.let.full.#Resource.pickMsg.msg: invalid interpolation: non-concrete value string (type string):
    ./nested.cue:58:25
    ./nested.cue:54:12
[incomplete] issue3801.let.full.#JSONPatch.output: cannot reference optional field: namespace:
    ./nested.cue:72:24
issue3801.let.full.#JSONPatch.output: key value of dynamic field must be concrete, found _|_(issue3801.let.full.#JSONPatch.output: cannot reference optional field: namespace):
    ./nested.cue:72:24
[incomplete] issue3801.let.full.#Main.jsonPatch.output: key value of dynamic field must be concrete, found string:
    ./nested.cue:72:24
    ./nested.cue:70:15
[incomplete] issue3801.nonRooted.full.#Output.output: key value of dynamic field must be concrete, found string:
    ./nested.cue:138:12
    ./nested.cue:135:15
[incomplete] issue3801.nonRooted.full.#SubOutput.output: cannot reference optional field: namespace:
    ./nested.cue:138:12
issue3801.nonRooted.full.#SubOutput.output: key value of dynamic field must be concrete, found _|_(issue3801.nonRooted.full.#SubOutput.output: cannot reference optional field: namespace):
    ./nested.cue:138:12
-- out/eval/stats --
Leaks:  40
Freed:  200
Reused: 171
Allocs: 69
Retain: 0

Unifications: 169
Conjuncts:    327
Disjuncts:    14

NumCloseIDs: 77
-- out/todo.txt --
v3 differences in error messages and closedness for nonRooted.reduced.out (#struct vs struct).
