-- in.cue --
a:  *1 | int
aa: *1 | *2 | int

b: {
	name: "int"
	val:  int
} | {
	name: "str"
	val:  string
}

d: b & {val: 3}
c: b & {name: "int", val: 3}
e: b & {val: "foo"}
f: b & {name: "str", val: 3}

// Disjunct elimination based on type.
e1: {
	a: null | {bar: 2}
	b: (a & {}).bar
}

d1: {
	a: (null | {c: 1}) & {}
	b: {} & (null | {c: 1})
}

d2: {
	a: ([...] | {c: 1}) & {}
	b: {} & ([...] | {c: 1})
}

d3: {
	a: (string | {c: 1}) & {}
	b: {} & (string | {c: 1})
}

d4: {
	a: (string | {c: 1}) & {}
	b: {} & (string | {c: 1})
}

d5: {
	a: (number | {c: 1}) & {}
	b: {} & (number | {c: 1})
}

d6: {
	a: (int | {c: 1}) & {}
	b: {} & (int | {c: 1})
}

t10: p1: {
	// @test(permute, count=120) // TODO(inline): we could reduce this by grouping fields.
	schema: test
	schema: string | {name: string}
	#A: {string | {name: string}}

	test: name: "Test"
	test: #A
}

t10: p2: {
	schema: string | {name: string}
	schema: test
	#A: {string | {name: string}}

	test: name: "Test"
	test: #A
}

t10: p3: {
	#A: {string | {name: string}}

	test: name: "Test"
	test: #A

	schema: string | {name: string}
	schema: test
}

t11: p1: {
	a: #A
	a: b

	b: #A & ["b"]
	#A: ["a" | "b"] | {}
}

t11: p2: {
	b: #A & ["b"]
	#A: ["a" | "b"] | {}

	a: b
	a: #A
}

cross: {
	a: *"word" | string
	a: string | *"word"
}

d100: {
	// Should we allow a selector to imply a struct or list? Would be convenient.
	// This would be a spec change. Disallow for now.
	i: null | {bar: 2}
	j: i.bar
}

// Regression test for empty disjunction with combined definitions and
// template constraints where valid unification was incorrectly rejected.
// https://cuelang.org/issue/641
issue641: {
	#A: {
		type: "a"
		x:    ""
	}

	#B: {
		type: "b"
		x:    string
	}

	#C: {
		b: #A | #B
	}

	e: [string]: #C & {
		b: #A | #B
	}

	e: foobar: #C & {
		b: #B & {
			x: "foobar"
		}
	}
}
-- issue3406.cue --
// evalv3 panic with inconsistent state when unifying a struct with itself
// embedded via a disjunction field.
// https://cuelang.org/issue/3406
issue3406: {
	out: d & {d}
	d: kind: "foo" | "bar"
	d: {kind: "foo"} | {kind: "bar"}
}
-- issue3411.cue --
// evalv3 nil pointer dereference when unifying optional fields with defaults.
// https://cuelang.org/issue/3411
issue3411: {
	x: y?: [...string]
	x: {y: ["foo"]} | *{y: ["bar"]}
}
-- issue3490.cue --
// evalv3 "incDependent: already closed" panic regression involving disjunctions.
// https://cuelang.org/issue/3490
issue3490: nested: p1: {
	("a" | "b") | "b"
	"a" | "b"
}
issue3490: nested: p2: {
	"a" | "b"
	("a" | "b") | "b"
}
issue3490: full: {
	data: [...#Schema]
	data: [#Schema & {}]
	#Schema: {
		runs?: "foo" | ([#D1] | [#D1, #D2])
		#D1: "d1"
		#D2: "d2"
	}
}
-- issue3434.cue --
// evalv3 panic "unexpected overlay in next" with disjunctions inside definitions.
// https://cuelang.org/issue/3434
issue3434: t1: {
	({} | {})
	{["x"]: 1}
	{["y"]: 2}
}
issue3434: full: {
	out: #Schema & {
		steps: [{run: "example"}]
	}
	#Schema: {
		steps: [...{run: string}]
		#matrixConfig: string | [...#matrixConfig]
		matrix?: ({...} | string) & {
			{[=~"^foo"]: [...{[string]: #matrixConfig}]}
			{[=~"^bar"]: [...#matrixConfig] | string}
		}
	}
}
-- issue3597.cue --
// evalv3 index out of range panic in overlayContext.allocCC with let inside
// a disjunction within a definition applied via a pattern constraint.
// https://cuelang.org/issue/3597
issue3597: t1: {
	#Schema: {
		_ok: bool
		{} | {
			_ok: true
			let Ok = _ok
			{} | {x: Ok}
		}
	}

	[string]: #Schema

	foo: bar
	bar: {}
}
issue3597: t2: {
	ok: true
	X: _ | {
		let Ok = ok
		_ | {x: Ok}
	}
	foo: X & {X}
}
-- dependencies.cue --
// evalv3 incorrectly allowed a field inside a struct disjunction that should
// have been rejected as "field not allowed".
// https://cuelang.org/issue/3606
issue3606: {
	data: {
		notAllowed: true
	} & #S

	#S: string | {}
}

// evalv3 gives a different result vs evalv2 when openinline is enabled; list
// element count is wrong after unifying nested disjunctions through definitions.
// https://cuelang.org/issue/3672
issue3672: {
	#A: string | {y: true}
	#B: #A | {a: "append"} | {b: "prepend"}

	#fn: {
		#C: #B
		#out: x: [...#C]
	}

	// The unification inline appears to be critical
	#def: (#fn & {}).#out

	v: #def
	v: x: [{y: true}] // Should be one element
}
// Regression giving "non-concrete value _ (type _)" error when interpolating
// a string default from a disjunction via a definition alias.
// https://cuelang.org/issue/3681
issue3681: {
	// Order dependent! These two fields need to go first.
	out: one: #strDefaultDef
	out: two: "\(strDefault)"

	strDefault:     *"fallback" | string
	#strDefaultDef: strDefault
}
// evalv3 "undefined field" regression when a comprehension condition references
// a field whose default is provided by a disjunction.
// https://cuelang.org/issue/3699
issue3699: {
	reduced: p1: {
		y: {if x.z {1}}
		x: *{z: true} | {}
	}
	reduced: p2: {
		y: {if x.z {1}}
		x: *{z: true} | {}
	}
	reduced: full: {
		_res: {
			_fooTrue: {} | *{foo: true}
			_msgSwitch: [
				if _fooTrue.foo {msg: "foo"},
				{msg: "bar"},
			][0]
			out: _msgSwitch.msg
		}
		let res = {
			out: (_res & {}).out
		}
		out: res.out
	}
}
-- indexelim.cue --
import "math/bits"

indexElimination: {
	inStruct: x: {a: *x[0] | 0}.a
	inList1: x: [x[0]][0]
	inList2: x: [*x[0] | 0][0]
	// evalv3 strange behavior with chaining of list comprehensions,
	// incorrect results when indexing the output of a for loop.
	// https://cuelang.org/issue/3124
	issue3124: full: {
		x: [...bool]
		x: [true, false, true, true]
		y: [for _, v in x {[if v {1}, 0][0]}]
		z: [for i, v in y {bits.Set(*z[i-1] | 0, len(y)-i-1, v)}][3]
	}
}
-- issue3899.cue --
// evalv3 "invalid type _" regression that is order-dependent, triggered when
// a string interpolation references an optional field inside a disjunction.
// https://cuelang.org/issue/3899
issue3899: reduced: {
	b:  c+"" | string
	c?: string
}
issue3899: full: {
	out: #Schema & {
		name: "foo"
	}
	#Schema: {
		_versions: foo: "123"
		spec: limits:   true
		name!: string
		spec: image: string | *"\(name)"
		deployImage: _versions[spec.image]
	}
}
-- issue3891.cue --
// evalv3 "incomplete value" regression with repeated disjunctions where a
// field referencing a default via another field yields an incomplete error.
// https://cuelang.org/issue/3891
issue3891: reduced: {
	{x: _} | null
	{x: _} | null
	x: *a.y | _
	a: b
	b: y: 1
}
issue3891: full: {
	out: #Foo | "never"
	out: #Foo | "never"
	out: _fooTemplate & {
		_input: (_transform & {in: sub1: sub2: "bar"}).out
	}
	_transform: {
		in:  _
		out: in
	}
	#Foo: foo?: _
	_fooTemplate: {
		_input: _
		foo:    *_input.sub1.sub2 | _
	}
}
-- out/compile --
--- dependencies.cue
{
  issue3606: {
    data: ({
      notAllowed: true
    } & 〈0;#S〉)
    #S: (string|{})
  }
  issue3672: {
    #A: (string|{
      y: true
    })
    #B: (〈0;#A〉|{
      a: "append"
    }|{
      b: "prepend"
    })
    #fn: {
      #C: 〈1;#B〉
      #out: {
        x: [
          ...〈2;#C〉,
        ]
      }
    }
    #def: (〈0;#fn〉 & {}).#out
    v: 〈0;#def〉
    v: {
      x: [
        {
          y: true
        },
      ]
    }
  }
  issue3681: {
    out: {
      one: 〈1;#strDefaultDef〉
    }
    out: {
      two: "\(〈1;strDefault〉)"
    }
    strDefault: (*"fallback"|string)
    #strDefaultDef: 〈0;strDefault〉
  }
  issue3699: {
    reduced: {
      p1: {
        y: {
          if 〈1;x〉.z {
            1
          }
        }
        x: (*{
          z: true
        }|{})
      }
    }
    reduced: {
      p2: {
        y: {
          if 〈1;x〉.z {
            1
          }
        }
        x: (*{
          z: true
        }|{})
      }
    }
    reduced: {
      full: {
        _res: {
          _fooTrue: ({}|*{
            foo: true
          })
          _msgSwitch: [
            if 〈1;_fooTrue〉.foo {
              msg: "foo"
            },
            {
              msg: "bar"
            },
          ][0]
          out: 〈0;_msgSwitch〉.msg
        }
        let res#1 = {
          out: (〈1;_res〉 & {}).out
        }
        out: 〈0;let res#1〉.out
      }
    }
  }
}
--- in.cue
{
  a: (*1|int)
  aa: (*1|*2|int)
  b: ({
    name: "int"
    val: int
  }|{
    name: "str"
    val: string
  })
  d: (〈0;b〉 & {
    val: 3
  })
  c: (〈0;b〉 & {
    name: "int"
    val: 3
  })
  e: (〈0;b〉 & {
    val: "foo"
  })
  f: (〈0;b〉 & {
    name: "str"
    val: 3
  })
  e1: {
    a: (null|{
      bar: 2
    })
    b: (〈0;a〉 & {}).bar
  }
  d1: {
    a: ((null|{
      c: 1
    }) & {})
    b: ({} & (null|{
      c: 1
    }))
  }
  d2: {
    a: (([
      ...,
    ]|{
      c: 1
    }) & {})
    b: ({} & ([
      ...,
    ]|{
      c: 1
    }))
  }
  d3: {
    a: ((string|{
      c: 1
    }) & {})
    b: ({} & (string|{
      c: 1
    }))
  }
  d4: {
    a: ((string|{
      c: 1
    }) & {})
    b: ({} & (string|{
      c: 1
    }))
  }
  d5: {
    a: ((number|{
      c: 1
    }) & {})
    b: ({} & (number|{
      c: 1
    }))
  }
  d6: {
    a: ((int|{
      c: 1
    }) & {})
    b: ({} & (int|{
      c: 1
    }))
  }
  t10: {
    p1: {
      schema: 〈0;test〉
      schema: (string|{
        name: string
      })
      #A: {
        (string|{
          name: string
        })
      }
      test: {
        name: "Test"
      }
      test: 〈0;#A〉
    }
  }
  t10: {
    p2: {
      schema: (string|{
        name: string
      })
      schema: 〈0;test〉
      #A: {
        (string|{
          name: string
        })
      }
      test: {
        name: "Test"
      }
      test: 〈0;#A〉
    }
  }
  t10: {
    p3: {
      #A: {
        (string|{
          name: string
        })
      }
      test: {
        name: "Test"
      }
      test: 〈0;#A〉
      schema: (string|{
        name: string
      })
      schema: 〈0;test〉
    }
  }
  t11: {
    p1: {
      a: 〈0;#A〉
      a: 〈0;b〉
      b: (〈0;#A〉 & [
        "b",
      ])
      #A: ([
        ("a"|"b"),
      ]|{})
    }
  }
  t11: {
    p2: {
      b: (〈0;#A〉 & [
        "b",
      ])
      #A: ([
        ("a"|"b"),
      ]|{})
      a: 〈0;b〉
      a: 〈0;#A〉
    }
  }
  cross: {
    a: (*"word"|string)
    a: (string|*"word")
  }
  d100: {
    i: (null|{
      bar: 2
    })
    j: 〈0;i〉.bar
  }
  issue641: {
    #A: {
      type: "a"
      x: ""
    }
    #B: {
      type: "b"
      x: string
    }
    #C: {
      b: (〈1;#A〉|〈1;#B〉)
    }
    e: {
      [string]: (〈1;#C〉 & {
        b: (〈2;#A〉|〈2;#B〉)
      })
    }
    e: {
      foobar: (〈1;#C〉 & {
        b: (〈2;#B〉 & {
          x: "foobar"
        })
      })
    }
  }
}
--- indexelim.cue
{
  indexElimination: {
    inStruct: {
      x: {
        a: (*〈1;x〉[0]|0)
      }.a
    }
    inList1: {
      x: [
        〈1;x〉[0],
      ][0]
    }
    inList2: {
      x: [
        (*〈1;x〉[0]|0),
      ][0]
    }
    issue3124: {
      full: {
        x: [
          ...bool,
        ]
        x: [
          true,
          false,
          true,
          true,
        ]
        y: [
          for _, v in 〈1;x〉 {
            [
              if 〈2;v〉 {
                1
              },
              0,
            ][0]
          },
        ]
        z: [
          for i, v in 〈1;y〉 {
            〈import;"math/bits"〉.Set((*〈3;z〉[(〈1;i〉 - 1)]|0), ((len(〈3;y〉) - 〈1;i〉) - 1), 〈1;v〉)
          },
        ][3]
      }
    }
  }
}
--- issue3406.cue
{
  issue3406: {
    out: (〈0;d〉 & {
      〈1;d〉
    })
    d: {
      kind: ("foo"|"bar")
    }
    d: ({
      kind: "foo"
    }|{
      kind: "bar"
    })
  }
}
--- issue3411.cue
{
  issue3411: {
    x: {
      y?: [
        ...string,
      ]
    }
    x: ({
      y: [
        "foo",
      ]
    }|*{
      y: [
        "bar",
      ]
    })
  }
}
--- issue3434.cue
{
  issue3434: {
    t1: {
      ({}|{})
      {
        ["x"]: 1
      }
      {
        ["y"]: 2
      }
    }
  }
  issue3434: {
    full: {
      out: (〈0;#Schema〉 & {
        steps: [
          {
            run: "example"
          },
        ]
      })
      #Schema: {
        steps: [
          ...{
            run: string
          },
        ]
        #matrixConfig: (string|[
          ...〈1;#matrixConfig〉,
        ])
        matrix?: (({
          ...
        }|string) & {
          {
            [=~"^foo"]: [
              ...{
                [string]: 〈4;#matrixConfig〉
              },
            ]
          }
          {
            [=~"^bar"]: ([
              ...〈3;#matrixConfig〉,
            ]|string)
          }
        })
      }
    }
  }
}
--- issue3490.cue
{
  issue3490: {
    nested: {
      p1: {
        (("a"|"b")|"b")
        ("a"|"b")
      }
    }
  }
  issue3490: {
    nested: {
      p2: {
        ("a"|"b")
        (("a"|"b")|"b")
      }
    }
  }
  issue3490: {
    full: {
      data: [
        ...〈1;#Schema〉,
      ]
      data: [
        (〈1;#Schema〉 & {}),
      ]
      #Schema: {
        runs?: ("foo"|([
          〈1;#D1〉,
        ]|[
          〈1;#D1〉,
          〈1;#D2〉,
        ]))
        #D1: "d1"
        #D2: "d2"
      }
    }
  }
}
--- issue3597.cue
{
  issue3597: {
    t1: {
      #Schema: {
        _ok: bool
        ({}|{
          _ok: true
          let Ok#2 = 〈0;_ok〉
          ({}|{
            x: 〈1;let Ok#2〉
          })
        })
      }
      [string]: 〈0;#Schema〉
      foo: 〈0;bar〉
      bar: {}
    }
  }
  issue3597: {
    t2: {
      ok: true
      X: (_|{
        let Ok#3 = 〈1;ok〉
        (_|{
          x: 〈1;let Ok#3〉
        })
      })
      foo: (〈0;X〉 & {
        〈1;X〉
      })
    }
  }
}
--- issue3891.cue
{
  issue3891: {
    reduced: {
      ({
        x: _
      }|null)
      ({
        x: _
      }|null)
      x: (*〈0;a〉.y|_)
      a: 〈0;b〉
      b: {
        y: 1
      }
    }
  }
  issue3891: {
    full: {
      out: (〈0;#Foo〉|"never")
      out: (〈0;#Foo〉|"never")
      out: (〈0;_fooTemplate〉 & {
        _input: (〈1;_transform〉 & {
          in: {
            sub1: {
              sub2: "bar"
            }
          }
        }).out
      })
      _transform: {
        in: _
        out: 〈0;in〉
      }
      #Foo: {
        foo?: _
      }
      _fooTemplate: {
        _input: _
        foo: (*〈0;_input〉.sub1.sub2|_)
      }
    }
  }
}
--- issue3899.cue
{
  issue3899: {
    reduced: {
      b: ((〈0;c〉 + "")|string)
      c?: string
    }
  }
  issue3899: {
    full: {
      out: (〈0;#Schema〉 & {
        name: "foo"
      })
      #Schema: {
        _versions: {
          foo: "123"
        }
        spec: {
          limits: true
        }
        name!: string
        spec: {
          image: (string|*"\(〈1;name〉)")
        }
        deployImage: 〈0;_versions〉[〈0;spec〉.image]
      }
    }
  }
}
