mirror of
https://github.com/imjasonh/nescript
synced 2026-07-10 17:52:51 +00:00
codegen: make var_addrs misses panic loudly and fix latent struct-field silent drop
Phase 1 of the post-PR-#31 audit. The PR #31 state-local bug had a specific shape: analyzer allocated a slot, codegen looked it up by VarId, silently emitted nothing on miss. Six sites in gen_op plus the global-initializer loop and the parameter-shuffle prologue all used the same `if let Some(&addr) = self.var_addrs.get(var) { ... }` pattern with no else branch. Any future allocation-map desync would slip through the same crack. Replace every site with a new `IrCodeGen::var_addr(VarId) -> u16` helper that panics with an explicit "compiler bug" message on miss. An IR op referencing an unmapped VarId is not valid input — it means the analyzer and lowerer disagreed on what to allocate, and we want that crash to surface in CI rather than be absorbed by whatever zero-filled RAM happened to sit at the read. Running cargo test against the hardened lookup surfaced exactly the bug shape the plan predicted: uninitialized struct globals (e.g. `var p: Point` with no literal initializer) never had their flattened field VarIds (`"p.x"`, `"p.y"`) registered in var_addrs. The IR lowerer's `get_or_create_var("p.x")` minted a VarId, the analyzer's `flatten_struct_fields` allocated an address for it, but IrCodeGen::new only populated var_addrs from `ir.globals`, which doesn't contain synthesized field entries for uninitialized structs. Every `p.x = N` silently compiled to nothing. Fix by exposing the IR lowerer's name→VarId map on IrProgram and joining it with the analyzer's allocations in IrCodeGen::new. Every allocated name that the lowerer knows about now gets a var_addrs entry. Example ROMs are byte-identical (no example relied on the dropped writes), but the bug was reachable — any user program with a plain `var pos: Point` declaration and field writes would have hit it silently. Add `uninitialized_struct_field_store_emits_sta_to_allocated_address` as a byte-level regression guard: compile `p.x = 123` and scan PRG for `LDA #\$7B / STA <addr>`. Fails against the old silently-dropping codegen. https://claude.ai/code/session_01AoQ678uVeqpyayvWHpfDhC
This commit is contained in:
parent
431f144be7
commit
f7012c6533
5 changed files with 144 additions and 60 deletions
|
|
@ -22,6 +22,7 @@ fn make_program(ops: Vec<IrOp>, terminator: IrTerminator) -> IrProgram {
|
|||
rom_data: vec![],
|
||||
states: vec![],
|
||||
start_state: String::new(),
|
||||
var_map: std::collections::HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,6 +421,7 @@ fn inline_removes_trivial() {
|
|||
rom_data: vec![],
|
||||
states: vec![],
|
||||
start_state: String::new(),
|
||||
var_map: std::collections::HashMap::new(),
|
||||
};
|
||||
|
||||
inline_small_functions(&mut prog);
|
||||
|
|
@ -502,6 +504,7 @@ fn const_fold_preserves_loadimm_used_by_sibling_branch() {
|
|||
rom_data: vec![],
|
||||
states: vec![],
|
||||
start_state: String::new(),
|
||||
var_map: std::collections::HashMap::new(),
|
||||
};
|
||||
|
||||
optimize(&mut prog);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue