1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-10 09:42:37 +00:00

codegen+CLAUDE: harden Call arity and document the silent-drop review checklist

Phase 3/4 of the post-PR-#31 audit.

### Call args > 4 is now an assert

`IrOp::Call` silently `.take(4)`-d the arg list with a comment
claiming the analyzer's E0506 check made the extras unreachable.
Replace with an explicit `assert!(args.len() <= 4, ...)` so if
the analyzer ever regresses, the codegen crashes loudly instead
of miscompiling the call. Iterate over all args (not just the
first 4) since the assert guarantees correctness.

### CLAUDE.md: new-feature PR checklist

Document the lesson the audit taught: every new language-feature
PR must include (1) an example exercising it, (2) a runtime
*behaviour* assertion (not just a "ROM validates" shape check),
(3) a negative test for invalid use. Call out the specific
address-map lookup pattern (`if let Some(&addr) = map.get(..)`
with no else) that shipped the state-local bug, and recommend
the `IrCodeGen::var_addr` / explicit `.unwrap_or_else(|| panic!)`
idiom instead.

Chose not to add a regex-based CI tripwire for "silently" /
"for now" comments because the false-positive rate against
legitimate design decisions ("silently truncate to 8 bits per
the cast spec", etc.) would train contributors to ignore it.
The durable checklist in CLAUDE.md is what next agents need.

https://claude.ai/code/session_01AoQ678uVeqpyayvWHpfDhC
This commit is contained in:
Claude 2026-04-18 00:09:34 +00:00
parent 48bae97c51
commit 00f1305564
No known key found for this signature in database
2 changed files with 53 additions and 4 deletions

View file

@ -1397,10 +1397,17 @@ impl<'a> IrCodeGen<'a> {
}
IrOp::Call(dest, name, args) => {
// Pass up to 4 arguments via zero-page slots $04-$07.
// Arguments beyond the fourth are silently dropped
// (the analyzer has already validated arity against
// the declared signature).
for (i, arg) in args.iter().enumerate().take(4) {
// E0506 rejects function declarations with more than
// four parameters, so a call with >4 args is a
// compiler-internal inconsistency — panic rather than
// silently drop the extras (PR-#31-shaped miscompile).
assert!(
args.len() <= 4,
"internal compiler error: Call to {name:?} with \
{} args (max 4); E0506 should have caught this",
args.len()
);
for (i, arg) in args.iter().enumerate() {
self.load_temp(*arg);
self.emit(STA, AM::ZeroPage(0x04 + i as u8));
}