; Bench fixture: explicit-mode pair of bench_list_sum.
;
; Same algorithm and same sizes as bench_list_sum.ail (build a list of
; 0..N-1, sum it, print) but with full `(borrow)` / `(own)` annotations
; on every fn-param signature in the hot path. Under --alloc=rc the
; codegen now emits `inc`/`dec` instructions: each cell allocated by
; `cons_n_acc` is dec'd as `sum_list_acc` walks the chain.
;
; The IntList is `(drop-iterative)` so the param drop on the LCons arm
; stays O(1) stack regardless of length — without this, dec-ing a
; 3M-cell chain at scope close would recursive-overflow.
;
; This is the "RC-fair" arm of the cross-language bench (21'f);
; pairs with bench/reference/list_sum_explicit_free.c which adds
; matching free() calls. Together they answer "what does RC's full
; alloc+dec cost look like vs C's full malloc+free cost?".
;
; Sizes match bench_list_sum exactly:
;   100_000   * 24 B =   2.4 MB
;   1_000_000 * 24 B =  24   MB
;   3_000_000 * 24 B =  72   MB
;
; Expected stdout (one int per line):
;   100_000   -> 4999950000
;   1_000_000 -> 499999500000
;   3_000_000 -> 4499998500000

(module bench_list_sum_explicit

  (data IntList
    (doc "Singly-linked Int list. drop-iterative so Own-param drops are O(1) stack.")
    (ctor INil)
    (ctor ICons (con Int) (con IntList))
    (drop-iterative))

  (fn cons_n_acc
    (doc "Tail-recursive: prepend (n-1, n-2, ..., 0) onto acc. Returns owned chain.")
    (type
      (fn-type
        (params (own (con Int)) (own (con IntList)))
        (ret (own (con IntList)))))
    (params n acc)
    (body
      (if (app eq n 0)
        acc
        (tail-app cons_n_acc
          (app - n 1)
          (term-ctor IntList ICons (app - n 1) acc)))))

  (fn cons_n
    (doc "Build [0..n-1] :: IntList. Returns owned chain; caller owns and consumes.")
    (type
      (fn-type
        (params (own (con Int)))
        (ret (own (con IntList)))))
    (params n)
    (body (app cons_n_acc n (term-ctor IntList INil))))

  (fn sum_acc
    (doc "Tail-recursive sum. Owns xs; consumes via LCons-arm move-into-tail-call.")
    (type
      (fn-type
        (params (own (con IntList)) (own (con Int)))
        (ret (own (con Int)))))
    (params xs acc)
    (body
      (match xs
        (case (pat-ctor INil) acc)
        (case (pat-ctor ICons h t)
          (tail-app sum_acc t (app + acc h))))))

  (fn sum_list
    (doc "Sum every element. Owns xs, hands it to sum_acc which consumes it.")
    (type
      (fn-type
        (params (own (con IntList)))
        (ret (own (con Int)))))
    (params xs)
    (body (app sum_acc xs 0)))

  (fn run_one
    (doc "Build, sum, print. The owned list flows from cons_n into sum_list and is fully consumed.")
    (type (fn-type (params (own (con Int))) (ret (own (con Unit))) (effects IO)))
    (params n)
    (body
      (app print (app sum_list (app cons_n n)))))

  (fn main
    (type (fn-type (params) (ret (own (con Unit))) (effects IO)))
    (params)
    (body
      (seq (app run_one 100000)
      (seq (app run_one 1000000)
           (app run_one 3000000))))))
