Skip to content

Codegen: cond ? await a() : b() evaluates BOTH ternary branches #342

Description

@proggeramlug

What happened

When a conditional expression has await on one branch and a synchronous call on the other, Perry's codegen evaluates both branches at runtime, regardless of the condition.

What you expected

Only the branch matching the condition should be evaluated, matching JS/TS semantics.

Minimal reproduction

async function a(): Promise<number> { console.log('ran a'); return 1; }
function       b():        number    { console.log('ran b'); return 2; }

async function main(): Promise<void> {
  const cmd: string = 'digest';
  const r = cmd === 'fetch' ? await a() : b();
  console.log('r=' + r);
  process.exit(0);
}
main().catch((e) => { console.log(e); process.exit(1); });

Command:

perry compile repro.ts -o repro
./repro

Observed output:

ran a
ran b
r=2

Expected output (matches Node):

ran b
r=2

(Only b should run; cmd === 'fetch' is false.)

A purely-sync ternary cond ? a() : b() works correctly — only one branch runs. The bug is specific to await appearing on one side.

Workaround that works:

let r: number;
if (cmd === 'fetch') {
  r = await a();
} else {
  r = b();
}

Environment

  • Perry version: 0.5.395
  • Host OS: macOS 26.4 (arm64)
  • Target: native
  • Installed via: cargo (~/.cargo/bin/perry)

Diagnostic output

No errors or warnings.

Found while compiling skelpo-listener: dispatching args.command === 'fetch' ? await runFetch(args) : runDigest(args) — under Perry, runFetch ran during a digest invocation, contaminating the digest output with fetch progress.

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