# Tests that recursive secret/nested-map structures (#secrets) unify correctly
# without exponential conjunct expansion. Performance regression originally
# caused quadratic growth when #secrets disjunctions were repeatedly applied.
# https://cuelang.org/issue/1684

// TODO: significantly reduce the number of counts in this evaluation.
-- in.cue --
#Secret: {
	$secret: id: string
}
#secrets: #Secret | {[string]: #secrets}

out: #secrets & {
	FOO: $secret: id: "100"
	ONE: TWO: THREE: $secret: id: "123"
}

#Secret: {
	$secret: _id: string
}
#secrets: #Secret | {[string]: #secrets}

out: #secrets & {
	FOO: $secret: _id: "100"
	ONE: TWO: THREE: $secret: _id: "123"
}
-- perf.cue --
nestedCross: closed: {
	#D: {id: string} | {[string]: #D}
	#D: {id: string} | {[string]: #D}
	#D: {id: string} | {[string]: #D}
}

nestedCross: open: {
	D: {id: string} | {[string]: D}
	D: {id: string} | {[string]: D}
	D: {id: string} | {[string]: D}
}

// TODO(perf): support this case.  This is currently exponential, although the
// tight bound on the detection of structural cycles mitigates the situation.
//
// An additional improvement would be to stop processing disjunctions if we see
// there are more than two solutions.
nestedClosed: passing: {
	D: {id: {}} | {[string]: D}
	D: {id: {}} | {[string]: D}
	D: {id: {}} | {[string]: D}
}
-- out/compile --
--- in.cue
{
  #Secret: {
    $secret: {
      id: string
    }
  }
  #secrets: (〈0;#Secret〉|{
    [string]: 〈1;#secrets〉
  })
  out: (〈0;#secrets〉 & {
    FOO: {
      $secret: {
        id: "100"
      }
    }
    ONE: {
      TWO: {
        THREE: {
          $secret: {
            id: "123"
          }
        }
      }
    }
  })
  #Secret: {
    $secret: {
      _id: string
    }
  }
  #secrets: (〈0;#Secret〉|{
    [string]: 〈1;#secrets〉
  })
  out: (〈0;#secrets〉 & {
    FOO: {
      $secret: {
        _id: "100"
      }
    }
    ONE: {
      TWO: {
        THREE: {
          $secret: {
            _id: "123"
          }
        }
      }
    }
  })
}
--- perf.cue
{
  nestedCross: {
    closed: {
      #D: ({
        id: string
      }|{
        [string]: 〈1;#D〉
      })
      #D: ({
        id: string
      }|{
        [string]: 〈1;#D〉
      })
      #D: ({
        id: string
      }|{
        [string]: 〈1;#D〉
      })
    }
  }
  nestedCross: {
    open: {
      D: ({
        id: string
      }|{
        [string]: 〈1;D〉
      })
      D: ({
        id: string
      }|{
        [string]: 〈1;D〉
      })
      D: ({
        id: string
      }|{
        [string]: 〈1;D〉
      })
    }
  }
  nestedClosed: {
    passing: {
      D: ({
        id: {}
      }|{
        [string]: 〈1;D〉
      })
      D: ({
        id: {}
      }|{
        [string]: 〈1;D〉
      })
      D: ({
        id: {}
      }|{
        [string]: 〈1;D〉
      })
    }
  }
}
