#803·Bend

JS lane: Char.to_upper throws on control characters ('\n', '\t') because the mapped Chr is built outside the selected Bool.pick branch

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

What you did

bend upper.bend (JS lane) and bend upper.bend -o upper && ./upper (native C lane), where main uppercases a string that contains a newline.

What happened

JS lane:

bend: 4294967274 is not a Unicode scalar value

(exit 1, thrown before any output)

C lane:

upper_nl=[AZ
9é]
lower_nl=[az
9é]

Char.to_upper('\n') alone reproduces it; Char.to_upper('\t') throws 4294967273. The mapped character is built before Bool.pick selects its branch: U32.sub(code, 32) underflows for any non-lowercase code below 32, and the emitted JS char_new rejects the wrapped value even though that branch is not taken. Char.to_lower has the same Bool.pick(Char, cond, Chr{...}, c) shape. Reproduces on 2.0.4 and 2.0.5.

The file

bend
import Base

def main() -> IO(Unit):
  do IO<Unit>:
    IO.print("upper_nl=[" ++ String.to_upper("aZ\n9é") ++ "]")
    IO.print("lower_nl=[" ++ String.to_lower("aZ\n9é") ++ "]")

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)

A fix for this exists on the fork phenomenon0/bend, branch archive/strings (the mapped Chr is built only in the selected branch).