# Tests that cyclic arithmetic constraints (#TimeSpan: start = end - duration
# etc.) within a task set unify and report errors correctly. The original
# issue involved a hang or very slow evaluation with interdependent tasks.
# https://cuelang.org/issue/3517
-- main.cue --
package p

#TimeSpan: {
	start:    float
	duration: float
	end:      float

	start:    end - duration
	duration: end - start
	end:      start + duration

	start: <=end
}

#Task: {
	action:   string
	timeSpan: #TimeSpan
}

#TaskSet: {
	action: string
	#tasks: [string]: #Task
	tasks: [for _, v in #tasks {v}]
	tasks: [...#Task]
	timeSpan?: #TimeSpan
}

#T1: #Task & {
	action: "Task 1"
	timeSpan: #TimeSpan & {
		duration: 4.2
	}
}

#T2: #Task & {
	action: "Task 2"
	timeSpan: #TimeSpan & {
		duration: 120.0
	}
}

ts: #TaskSet
ts: this={
	action: "Task 1 and Task 2"
	#tasks: {
		t1: #T1 & {
			timeSpan: end: this.#tasks.t2.timeSpan.start
		}
		t2: #T2 & {
			timeSpan: end: 119 // this.timeSpan.end
		}
	}
	timeSpan: start: this.#tasks.t1.timeSpan.start
}
-- out/compile --
--- main.cue
{
  #TimeSpan: {
    start: float
    duration: float
    end: float
    start: (〈0;end〉 - 〈0;duration〉)
    duration: (〈0;end〉 - 〈0;start〉)
    end: (〈0;start〉 + 〈0;duration〉)
    start: <=〈0;end〉
  }
  #Task: {
    action: string
    timeSpan: 〈1;#TimeSpan〉
  }
  #TaskSet: {
    action: string
    #tasks: {
      [string]: 〈2;#Task〉
    }
    tasks: [
      for _, v in 〈1;#tasks〉 {
        〈1;v〉
      },
    ]
    tasks: [
      ...〈2;#Task〉,
    ]
    timeSpan?: 〈1;#TimeSpan〉
  }
  #T1: (〈0;#Task〉 & {
    action: "Task 1"
    timeSpan: (〈1;#TimeSpan〉 & {
      duration: 4.2
    })
  })
  #T2: (〈0;#Task〉 & {
    action: "Task 2"
    timeSpan: (〈1;#TimeSpan〉 & {
      duration: 120.0
    })
  })
  ts: 〈0;#TaskSet〉
  ts: {
    action: "Task 1 and Task 2"
    #tasks: {
      t1: (〈2;#T1〉 & {
        timeSpan: {
          end: 〈4〉.#tasks.t2.timeSpan.start
        }
      })
      t2: (〈2;#T2〉 & {
        timeSpan: {
          end: 119
        }
      })
    }
    timeSpan: {
      start: 〈2〉.#tasks.t1.timeSpan.start
    }
  }
}
