#802·Bend

JS lane: List.length over a long list dies with a stack overflow (the base recursion is not in tail position); a tail counter over the same list completes

Author: phenomenon0Created Sep 18, 2026Updated Sep 18, 2026

What you did

A 200,000-element list (built by a tail-recursive helper, no large literals), counted two ways:

  • bend llist.bend (JS lane), List.length
  • bend llist.bend -o llist && ./llist (native C lane)
  • same with an inner tail counter instead of List.length

What happened

JS lane, List.length:

bend: memory fault (machine stack overflow?)

JS lane, tail counter over the same list: len=200000. Native, both: len=200000.

Threshold on the JS lane: 10,000 elements count fine, 50,000 fails. Base.List.length is not tail-recursive (1n+List.length(a, A, t), bend2/base.bend:742-747 at 0b7e2b11), so the emitted JS keeps one frame per element. Same class as #798 for String.split/String.length (which is why our parser lane avoids it with a counter), but this is the List helper. Reproduces on 2.0.4 and 2.0.5.

The file

bend
import Base

def gen(n: Nat, acc: List<&2, U32>) -> List<&2, U32>:
  match n:
    case 0n:
      acc
    case 1n+p:
      gen(p, 1 <> acc)

def main() -> IO(Unit):
  do IO<Unit>:
    IO.print("len=" ++ Nat.show(List.length(&2, U32, gen(Nat.mul(100n, 2000n), Nil{}))))

The counter variant replaces List.length(...) with count.go(gen(...), 0n); count.go is Nil{} -> n; h <> t -> count.go(t, 1n+n).

bend --version

bend 2.0.5 (2.0.4 the same)

uname -sm

Linux x86_64

clang --version (the first line)

clang version 21.1.7 (Fedora 21.1.7-1.fc43)