#inlinetest:exclude skip — we need to represent structure sharing across disjunctions
# properly to encode this test. We probably need to auto-insert shareIDs as well.
# TODO(inline): implement structure sharing checks across disjunctions.
-- in.cue --
// Test that cyclic references do not break structure sharing. This was the
// underlying problem of Issue #3587. Note that this is not a problem related
// to disjunctions.

// These definitions represent a large tree of disjunctions.
#D1: {a: #D2} | {b: #D2} | {c: #D2}
#D2: {a: #D3} | {b: #D3} | {c: #D3}
#D3: {
    one: {a: int} | {b: int} | {c: int}
    two: {a: string} | {b: string} | {c: string}
    three: {a: bool} | {b: bool} | {c: bool}
}

root: y: #D1 | [#D1] | {x: #D1} // Expensive path
root: x: empty: {}

root: "0": data: root_0.x.empty
root: "1": data: root_1.x.empty
root: "2": data: root_2.x.empty
root: "3": data: root_3.x.empty

 // We want root to be shared in all of these cases.
let root_0 = root
let root_1 = root
root_2: root
root_3: root
-- out/eval/stats --
Leaks:  3
Freed:  63
Reused: 40
Allocs: 26
Retain: 0

Unifications: 45
Conjuncts:    72
Disjuncts:    21

NumCloseIDs: 1
-- out/eval --
(struct){
  #D1: (#struct){ |((#struct){
      a: (#struct){ |((#struct){
          a: ~(#D3)
        }, (#struct){
          b: ~(#D3)
        }, (#struct){
          c: ~(#D3)
        }) }
    }, (#struct){
      b: (#struct){ |((#struct){
          a: ~(#D3)
        }, (#struct){
          b: ~(#D3)
        }, (#struct){
          c: ~(#D3)
        }) }
    }, (#struct){
      c: (#struct){ |((#struct){
          a: ~(#D3)
        }, (#struct){
          b: ~(#D3)
        }, (#struct){
          c: ~(#D3)
        }) }
    }) }
  #D2: (#struct){ |((#struct){
      a: ~(#D3)
    }, (#struct){
      b: ~(#D3)
    }, (#struct){
      c: ~(#D3)
    }) }
  #D3: (#struct){
    one: (#struct){ |((#struct){
        a: (int){ int }
      }, (#struct){
        b: (int){ int }
      }, (#struct){
        c: (int){ int }
      }) }
    two: (#struct){ |((#struct){
        a: (string){ string }
      }, (#struct){
        b: (string){ string }
      }, (#struct){
        c: (string){ string }
      }) }
    three: (#struct){ |((#struct){
        a: (bool){ bool }
      }, (#struct){
        b: (bool){ bool }
      }, (#struct){
        c: (bool){ bool }
      }) }
  }
  root: (struct){
    y: ((list|struct)){ |((#struct){
        a: (#struct){ |((#struct){
            a: ~(#D3)
          }, (#struct){
            b: ~(#D3)
          }, (#struct){
            c: ~(#D3)
          }) }
      }, (#struct){
        b: (#struct){ |((#struct){
            a: ~(#D3)
          }, (#struct){
            b: ~(#D3)
          }, (#struct){
            c: ~(#D3)
          }) }
      }, (#struct){
        c: (#struct){ |((#struct){
            a: ~(#D3)
          }, (#struct){
            b: ~(#D3)
          }, (#struct){
            c: ~(#D3)
          }) }
      }, (#list){
        0: (#struct){ |((#struct){
            a: (#struct){ |((#struct){
                a: ~(#D3)
              }, (#struct){
                b: ~(#D3)
              }, (#struct){
                c: ~(#D3)
              }) }
          }, (#struct){
            b: (#struct){ |((#struct){
                a: ~(#D3)
              }, (#struct){
                b: ~(#D3)
              }, (#struct){
                c: ~(#D3)
              }) }
          }, (#struct){
            c: (#struct){ |((#struct){
                a: ~(#D3)
              }, (#struct){
                b: ~(#D3)
              }, (#struct){
                c: ~(#D3)
              }) }
          }) }
      }, (struct){
        x: (#struct){ |((#struct){
            a: (#struct){ |((#struct){
                a: ~(#D3)
              }, (#struct){
                b: ~(#D3)
              }, (#struct){
                c: ~(#D3)
              }) }
          }, (#struct){
            b: (#struct){ |((#struct){
                a: ~(#D3)
              }, (#struct){
                b: ~(#D3)
              }, (#struct){
                c: ~(#D3)
              }) }
          }, (#struct){
            c: (#struct){ |((#struct){
                a: ~(#D3)
              }, (#struct){
                b: ~(#D3)
              }, (#struct){
                c: ~(#D3)
              }) }
          }) }
      }) }
    x: (struct){
      empty: (struct){
      }
    }
    "0": (struct){
      data: (struct){
      }
    }
    "1": (struct){
      data: (struct){
      }
    }
    "2": (struct){
      data: (struct){
      }
    }
    "3": (struct){
      data: (struct){
      }
    }
  }
  let root_0#1 = ~(root)
  let root_1#2 = ~(root)
  root_2: ~(root)
  root_3: ~(root)
}
