-- in.cue --
// Important that the test cases below fail with more than just
// an incomplete error, as we want to track the quality of errors.

// Disjunctions where multiple (or zero) disjuncts match by kind,
// so we cannot discriminate.
noKind: {
	manyWithStructEmbed: {
		#Def: {<10, _hidden: "field"} | >200 | string

		// The data is an int, but the struct embeds a matching scalar kind too.
		out: #Def & 123
	}
	manyStructsEmpty: {
		#Def: {f1!: int} | {f2!: int} | string

		// The data is a struct, which matches multiple disjunct struct kinds.
		out: #Def & {}
	}
	manyScalars: {
		#Def: 1 | 2 | 3

		// The data is an int, which matches all of the disjunct kinds.
		out: #Def & 123
	}
	zeroScalars: {
		#Def: int | string | null

		// The data is a bool, which matches none of the disjunct scalar kinds.
		out: #Def & true
	}
}

// Disjunctions where just one disjunct matches by kind,
// so we can discriminate.
byKind: {
	nullableStructRegular: {
		#Def1: {f1: null | #Def2}
		#Def2: {f2: null | #Def3}
		#Def3: {f3: null | int}

		// The data is a struct, not a null.
		out: #Def1 & {f1: f2: f3: "not an int"}
	}

	nullableStructRequired: {
		#Def1: {f1!: null | #Def2}
		#Def2: {f2!: null | #Def3}
		#Def3: {f3!: null | int}

		// The data is a struct, not a null.
		out: #Def1 & {f1: f2: f3: "not an int"}
	}

	nullableStructOptional: {
		#Def1: {f1?: null | #Def2}
		#Def2: {f2?: null | #Def3}
		#Def3: {f3?: null | int}

		// The data is a struct, not a null.
		out: #Def1 & {f1: f2: f3: "not an int"}
	}

	nullableList: {
		#Def1: [...null | #Def2]
		#Def2: [...null | #Def3]
		#Def3: [...null | int]

		// The data is a list, not a null.
		out: #Def1 & [[["not an int"]]]
	}

	scalarConstraints: {
		#Def: >10 | "" | null | false

		// The data is an integer, not any other scalar type.
		out: #Def & 5
	}
}
-- out/compile --
--- in.cue
{
  noKind: {
    manyWithStructEmbed: {
      #Def: ({
        <10
        _hidden: "field"
      }|>200|string)
      out: (〈0;#Def〉 & 123)
    }
    manyStructsEmpty: {
      #Def: ({
        f1!: int
      }|{
        f2!: int
      }|string)
      out: (〈0;#Def〉 & {})
    }
    manyScalars: {
      #Def: (1|2|3)
      out: (〈0;#Def〉 & 123)
    }
    zeroScalars: {
      #Def: (int|string|null)
      out: (〈0;#Def〉 & true)
    }
  }
  byKind: {
    nullableStructRegular: {
      #Def1: {
        f1: (null|〈1;#Def2〉)
      }
      #Def2: {
        f2: (null|〈1;#Def3〉)
      }
      #Def3: {
        f3: (null|int)
      }
      out: (〈0;#Def1〉 & {
        f1: {
          f2: {
            f3: "not an int"
          }
        }
      })
    }
    nullableStructRequired: {
      #Def1: {
        f1!: (null|〈1;#Def2〉)
      }
      #Def2: {
        f2!: (null|〈1;#Def3〉)
      }
      #Def3: {
        f3!: (null|int)
      }
      out: (〈0;#Def1〉 & {
        f1: {
          f2: {
            f3: "not an int"
          }
        }
      })
    }
    nullableStructOptional: {
      #Def1: {
        f1?: (null|〈1;#Def2〉)
      }
      #Def2: {
        f2?: (null|〈1;#Def3〉)
      }
      #Def3: {
        f3?: (null|int)
      }
      out: (〈0;#Def1〉 & {
        f1: {
          f2: {
            f3: "not an int"
          }
        }
      })
    }
    nullableList: {
      #Def1: [
        ...(null|〈1;#Def2〉),
      ]
      #Def2: [
        ...(null|〈1;#Def3〉),
      ]
      #Def3: [
        ...(null|int),
      ]
      out: (〈0;#Def1〉 & [
        [
          [
            "not an int",
          ],
        ],
      ])
    }
    scalarConstraints: {
      #Def: (>10|""|null|false)
      out: (〈0;#Def〉 & 5)
    }
  }
}
