Skip to content

Self-recursive function with a ternary miscompiles: i64 specialization has empty body (ret i64 0) #6221

Description

@dlee

What happened

A named function whose self-recursive call appears anywhere in a ?:
(either branch, the condition, or via a const) always returns 0. The same
function with if/else is correct. Arrow-function and mutual recursion are
unaffected (no _i64 specialization emitted).

What you expected

idDown(5)100 (Node agrees). Perry prints 0.

Minimal reproduction

function idDown(n: number): number {
  return n <= 0 ? 100 : idDown(n - 1);
}
console.log(idDown(5)); // node: 100 — perry: 0

Command you ran:

perry run idDown.ts

Environment

  • Perry version: 0.5.1220
  • Host OS: macOS 27.0 (arm64)
  • Target: native (also reproduces with --output-type dylib)
  • Installed via: npm

Diagnostic output

HIR is correct (--trace hir shows the conditional with the recursive call).
--trace llvm (dump in .perry-trace/llvm/idDown_ts.ll) shows the i64
specialization is empty and the boxed entry delegates to it:

define i64 @perry_fn_idDown_ts__idDown_i64(i64 %arg0) alwaysinline {
entry.0:
  %r1 = alloca i64
  store i64 %arg0, ptr %r1
  ret i64 0
}

define double @perry_fn_idDown_ts__idDown(double %arg0) alwaysinline {
entry.0:
  %r1 = fptosi double %arg0 to i64
  %r2 = call i64 @perry_fn_idDown_ts__idDown_i64(i64 %r1)
  %r3 = sitofp i64 %r2 to double
  ret double %r3
}

Anything else

Reproduces with PERRY_NO_CACHE=1. perry check and
--verify-native-regions both pass silently on the miscompiled program.
Workaround: if/else. Checked for dupes; #5784 and #342 are related but
distinct.

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