// Tests comprehension evaluation including for-loop filters, let bindings in
// comprehensions, if-conditioned field insertions, and field-match ordering
// in structs. Also covers panic fixes for nested comprehensions with pattern
// constraints (issue 3691).
-- in.cue --
import "strings"

a: {x: 10, y: 100, z: 50} @test(eq, {x: 10, y: 100, z: 50})
b: {
	for k, v in a if v <= 50 {
		"\(k)": v
	}
	x: int
	if x > 3 {
		k: 20
	}
	k: int
	if k > 0 {
		l: 40
	}
	@test(eq, {x: 10, k: 20, l: 40, z: 50})
}

c: {
	for k, v in a let y = v + 10 if y > 50 {
		"\(k)": y
	}
	@test(eq, {y: 110, z: 60})
}

A: {
	X: run: "dfoo"
	@test(eq, {X: {run: "dfoo", files: "dfoo"}})
}

if true {
	A: X: {
		run:   string
		files: "\(strings.Join([ run], "\n"))"
	}
}

matchOrder: {
  a1: {
    out: [string]: Val: 1
    out: in.a

    in: a: {
      if true {
        b: {}
      }
    }
    @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}})
  }
  a2: {
    out: [string]: Val: 1

    in: a: {
      if true {
        b: {}
      }
    }

    out: in.a
    @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}})
  }
  a3: {

    in: a: {
      if true {
        b: {}
      }
    }

    out: [string]: Val: 1
    out: in.a
    @test(eq, {in: {a: {b: {}}}, out: {b: {Val: 1}}})
  }
  a4: {
    out: in.a
    out: [string]: Val: 1

    in: a: {
      if true {
        b: {}
      }
    }
    @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}})
  }
  a5: {
    out: in.a

    in: a: {
      if true {
        b: {}
      }
    }

    out: [string]: Val: 1
    @test(eq, {out: {b: {Val: 1}}, in: {a: {b: {}}}})
  }
  a6: {
    in: a: {
      if true {
        b: {}
      }
    }

    out: in.a
    out: [string]: Val: 1
    @test(eq, {in: {a: {b: {}}}, out: {b: {Val: 1}}})
  }
}
-- issue3691.cue --
// evalv3 panic: incDependent "already closed" when processing conditional
// field definitions inside a comprehension with nested object structures.
// https://cuelang.org/issue/3691
// Ensure that parent nodes are properly processed, even when a pending arc
// is evaluated early.
issue3691: original: {
	X: [string]: string
	a: [string]: X
	a: {
		if true {
			b: c: 1
		}
	}
	@test(err, code=eval, at=a.b.c, contains="conflicting values", args=[string, 1], pos=[1:15, 2:15, 3:5, 4:3, 5:10])
}
// Structural cycles follow a different code path.
issue3691: structuralCycle: {
	X: [string]: string
	a: [string]: X
	a: {
		if true {
			b: c: a
		}
	}
	@test(err, code=eval, at=a.b.c, contains="conflicting values", pos=[1:15, 2:5, 2:15, 3:5, 4:3, 5:10])
}
-- out/errors.txt --
[eval] issue3691.original.a.b.c: conflicting values 1 and string (mismatched types int and string):
    ./issue3691.cue:7:15
    ./issue3691.cue:8:15
    ./issue3691.cue:9:5
    ./issue3691.cue:10:3
    ./issue3691.cue:11:10
[eval] issue3691.structuralCycle.a.b.c: conflicting values string and {[string]:X} (mismatched types string and struct):
    ./issue3691.cue:18:15
    ./issue3691.cue:19:5
    ./issue3691.cue:19:15
    ./issue3691.cue:20:5
    ./issue3691.cue:21:3
    ./issue3691.cue:22:10
-- out/eval/stats --
Leaks:  6
Freed:  74
Reused: 56
Allocs: 24
Retain: 0

Unifications: 79
Conjuncts:    136
Disjuncts:    0

NumCloseIDs: 48
-- out/todo.txt --
A.X.files: v3 correctly resolves to "dfoo" (strings.Join(["dfoo"], "\n")); annotated at top level.
issue3691.structuralCycle: v3 has different structural cycle representation in error output.
