Repository navigation
Description
Audited on master at 5630d74ec9cd912d4e2f325349f1943cbc15bcc6. This is a scoped implementation item under #147, based on the typed control/dataflow/effect audit. Proposed syntax below is illustrative unless explicitly marked as a current reproducer.
Problem and current evidence
Python silently drops a valid call used only for its effects or failure behavior. nlsc/emitter.py:574–632 only emits assignments/output bindings, and nlsc/emitter.py:413–420 turns other steps into comments. TypeScript does emit unbound expression statements via nlsc/emitter_typescript.py:288–302.
Current reproducer:
@module discarded_call
[reject]
PURPOSE: Always raise when called
GUARDS:
- False -> ValueError("called")
RETURNS: 0
[probe]
PURPOSE: Call reject
LOGIC:
1. [reject]()
DEPENDS: [reject]
RETURNS: 0
Validation succeeds. Generated Python contains # [reject](), and probe() returns 0 instead of raising. Payment/logging/notification calls can likewise disappear simply because the caller does not bind a result.
Implementation hints
- Add a real expression-statement / discarded-call node. Its output is unused; its execution, effects, and errors remain semantically required.
- For the immediate patch, recognize complete supported calls independently of
output_binding, using a parser with balanced arguments. Do not make arbitrary English executable. - Route conditional and unconditional discarded calls through the same mechanism. Preserve source order and execute exactly once per reached step.
- In the later IR migration, retain these nodes during dead-value elimination unless the operation is proven removable under the full effect/failure contract.
- Do not require users to add meaningless temporary variables as a workaround.
Acceptance criteria
- The reproducer raises
ValueError("called")under Python. - A local fake operation appending to an event log is invoked once with and without an output binding.
- A false conditional does not invoke its discarded call; a true conditional invokes it once.
- Returned values remain discardable, and
voidoperations do not need fake bindings. - Backend tests compare ordered events and normalized errors, not just source substrings.
The failure here is call execution itself; the separate error-contract item addresses TypeScript's undefined ValueError class.
Implementation ordering
Can begin immediately; integrate with the checked IR work under #147. Add the regression fixtures before implementation.
Activity