-- in.cue --
// Given the existence of this field, embedDefault is a struct. This
// means that embedding this conjunction into `embedDefault` itself should
// make it resolve to `{a: 2}`.

default: {
	y: *1 | {a: 2}
	y
}

unambiguous: {
	y: 1 | {a: 2}
	y
}

forDefault: {
	y: *1 | {a: 2}
	for x in [1] {y}
}

// Carry over default to first disjunct.
openDefault: {
	#y: *1 | {a: 2}
	#y
}

openAmbiguous: {
	#y: 1 | {a: 2}
	#y
}

forceStruct: {
	#y: 1 | {a: 2}
	#y
	{}
}

defaultsMulti: {
	a: {
		#def: {
			*{} | {a: string} | {b: string}
			*{} | {c: string} | {d: string}
		}

		a: #def & {a: "foo"}
	}

	b: {
		#def: {
			*{} | {a: string} | {b: string}
			*{} | {c: string} | {d: string}
			*{} | {d: string} | {e: string}
		}

		a: #def & {a: "foo", e: "bar"}
	}
}

nested: {
	a: 1 | 2 | *(
		(3 | 4 | *( 5 | 6 | *7)) & ( 3 | 4 | ( *7 | 8 )))
}
-- out/eval/stats --
Leaks:  1
Freed:  416
Reused: 381
Allocs: 36
Retain: 1

Unifications: 257
Conjuncts:    478
Disjuncts:    417
-- out/eval --
(struct){
  default: (struct){
    y: ((int|struct)){ |(*(int){ 1 }, (struct){
        a: (int){ 2 }
      }) }
    a: (int){ 2 }
  }
  unambiguous: (struct){
    y: ((int|struct)){ |((int){ 1 }, (struct){
        a: (int){ 2 }
      }) }
    a: (int){ 2 }
  }
  forDefault: (struct){
    y: ((int|struct)){ |(*(int){ 1 }, (struct){
        a: (int){ 2 }
      }) }
    a: (int){ 2 }
  }
  openDefault: ((int|struct)){ |(*(int){
      1
      #y: ((int|struct)){ |(*(int){ 1 }, (#struct){
          a: (int){ 2 }
        }) }
    }, (#struct){
      #y: ((int|struct)){ |(*(int){ 1 }, (#struct){
          a: (int){ 2 }
        }) }
      a: (int){ 2 }
    }) }
  openAmbiguous: ((int|struct)){ |((int){
      1
      #y: ((int|struct)){ |((int){ 1 }, (#struct){
          a: (int){ 2 }
        }) }
    }, (#struct){
      #y: ((int|struct)){ |((int){ 1 }, (#struct){
          a: (int){ 2 }
        }) }
      a: (int){ 2 }
    }) }
  forceStruct: (#struct){
    #y: ((int|struct)){ |((int){ 1 }, (#struct){
        a: (int){ 2 }
      }) }
    a: (int){ 2 }
  }
  defaultsMulti: (struct){
    a: (struct){
      #def: (#struct){ |(*(#struct){
        }, (#struct){
          c: (string){ string }
        }, (#struct){
          d: (string){ string }
        }, (#struct){
          a: (string){ string }
        }, (#struct){
          a: (string){ string }
          c: (string){ string }
        }, (#struct){
          a: (string){ string }
          d: (string){ string }
        }, (#struct){
          b: (string){ string }
        }, (#struct){
          b: (string){ string }
          c: (string){ string }
        }, (#struct){
          b: (string){ string }
          d: (string){ string }
        }) }
      a: (#struct){ |(*(#struct){
          a: (string){ "foo" }
        }, (#struct){
          a: (string){ "foo" }
          c: (string){ string }
        }, (#struct){
          a: (string){ "foo" }
          d: (string){ string }
        }) }
    }
    b: (struct){
      #def: (#struct){ |(*(#struct){
        }, (#struct){
          d: (string){ string }
        }, (#struct){
          e: (string){ string }
        }, (#struct){
          c: (string){ string }
        }, (#struct){
          c: (string){ string }
          d: (string){ string }
        }, (#struct){
          c: (string){ string }
          e: (string){ string }
        }, (#struct){
          d: (string){ string }
          e: (string){ string }
        }, (#struct){
          a: (string){ string }
        }, (#struct){
          a: (string){ string }
          d: (string){ string }
        }, (#struct){
          a: (string){ string }
          e: (string){ string }
        }, (#struct){
          a: (string){ string }
          c: (string){ string }
        }, (#struct){
          a: (string){ string }
          c: (string){ string }
          d: (string){ string }
        }, (#struct){
          a: (string){ string }
          c: (string){ string }
          e: (string){ string }
        }, (#struct){
          a: (string){ string }
          d: (string){ string }
          e: (string){ string }
        }, (#struct){
          b: (string){ string }
        }, (#struct){
          b: (string){ string }
          d: (string){ string }
        }, (#struct){
          b: (string){ string }
          e: (string){ string }
        }, (#struct){
          b: (string){ string }
          c: (string){ string }
        }, (#struct){
          b: (string){ string }
          c: (string){ string }
          d: (string){ string }
        }, (#struct){
          b: (string){ string }
          c: (string){ string }
          e: (string){ string }
        }, (#struct){
          b: (string){ string }
          d: (string){ string }
          e: (string){ string }
        }) }
      a: (#struct){ |(*(#struct){
          a: (string){ "foo" }
          e: (string){ "bar" }
        }, (#struct){
          a: (string){ "foo" }
          e: (string){ "bar" }
          c: (string){ string }
        }, (#struct){
          a: (string){ "foo" }
          e: (string){ "bar" }
          d: (string){ string }
        }) }
    }
  }
  nested: (struct){
    a: (int){ |(*(int){ 7 }, (int){ 2 }, (int){ 3 }, (int){ 4 }, (int){ 1 }) }
  }
}
-- out/compile --
--- in.cue
{
  default: {
    y: (*1|{
      a: 2
    })
    〈0;y〉
  }
  unambiguous: {
    y: (1|{
      a: 2
    })
    〈0;y〉
  }
  forDefault: {
    y: (*1|{
      a: 2
    })
    for _, x in [
      1,
    ] {
      〈2;y〉
    }
  }
  openDefault: {
    #y: (*1|{
      a: 2
    })
    〈0;#y〉
  }
  openAmbiguous: {
    #y: (1|{
      a: 2
    })
    〈0;#y〉
  }
  forceStruct: {
    #y: (1|{
      a: 2
    })
    〈0;#y〉
    {}
  }
  defaultsMulti: {
    a: {
      #def: {
        (*{}|{
          a: string
        }|{
          b: string
        })
        (*{}|{
          c: string
        }|{
          d: string
        })
      }
      a: (〈0;#def〉 & {
        a: "foo"
      })
    }
    b: {
      #def: {
        (*{}|{
          a: string
        }|{
          b: string
        })
        (*{}|{
          c: string
        }|{
          d: string
        })
        (*{}|{
          d: string
        }|{
          e: string
        })
      }
      a: (〈0;#def〉 & {
        a: "foo"
        e: "bar"
      })
    }
  }
  nested: {
    a: (1|2|*((3|4|*(5|6|*7)) & (3|4|(*7|8))))
  }
}