Skip to content

Mutually recursive nested function declarations abort at runtime with no diagnostic (exit 133, no output) #32

Description

@ryoppippi

Two function declarations nested inside another function that call each other abort at runtime. The build succeeds with no diagnostic, and the binary produces no output and no error message — just exit 133 (SIGTRAP).

The same pair of functions at module top level works correctly, so the trigger is the nesting.

Repro

export {}
function outer(n: number): number {
  function even(k: number): number {
    if (k === 0) return 1
    return odd(k - 1)
  }
  function odd(k: number): number {
    if (k === 0) return 0
    return even(k - 1)
  }
  return even(n)
}
function main() {
  console.log(`r=${outer(4)}`)
}
main()
$ bun recA.ts
r=1

$ scriptc build recA.ts -o recA     # no diagnostic
$ ./recA
$ echo $?
133

Nothing is printed on stdout or stderr.

Narrowing

shape result
mutual recursion between nested declarations abort, exit 133
the same mutual recursion at top level works (r=1)
nested, plain forward reference (first() calls second(), no cycle) works
nested, backward reference only works

So it is specifically the cycle among nested declarations, not a forward reference on its own:

// works
function outer(): number {
  function first(): number { return second() + 1 }
  function second(): number { return 41 }
  return first()
}

Where I hit it

A recursive-descent parser written the conventional way — primary/comparison/and/or nested inside parse(), with primary() calling or() for a parenthesised sub-expression. Compiled clean, aborted on every input. Restructuring to top-level functions over an explicit cursor object fixed it.

Impact

Silent, message-free abort is the worst failure mode: there is nothing to search for and nothing to point at. Even if the fix takes a while, a compile-time refusal naming the cycle would make this tractable.

Environment

  • scriptc 0.0.17, @scriptc/compiler 0.0.17
  • macOS 26.5.2, arm64, Node v24.18.0
  • Static build (no --dynamic), default backend

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions