Spun out of #455 (DX feedback from @justin0mcateer).
Problem
Property access on undefined or null should throw TypeError: Cannot read properties of undefined (reading 'foo') per JS spec. Today Perry silently returns undefined and execution continues, which turns loud bugs into invisible ones — the original report describes a JWS/AES PoC that "ran to completion" while every line was no-oping against an unimplemented crypto.subtle.
This is a correctness bug, not just DX: it's a spec violation that masks real failures.
Repro
const x: any = undefined;
console.log(x.foo); // node: TypeError. perry: prints undefined and continues.
console.log(x.foo.bar()); // node: TypeError. perry: ?
Proposed fix
PropertyGet lowering in crates/perry-hir/src/lower.rs (and the corresponding codegen path in crates/perry-codegen/src/expr.rs) should emit a receiver tag check before the field load. If the receiver is TAG_UNDEFINED or TAG_NULL, call into a runtime helper:
// crates/perry-runtime/src/error.rs (new or existing)
#[no_mangle]
pub extern "C" fn js_throw_type_error_property_access(
receiver_tag: u64,
prop_name_ptr: *const u8,
prop_name_len: usize,
source_file: *const u8,
source_line: u32,
source_col: u32,
) -> !
The thrower should print a node-shaped message and abort (or, once exception machinery is in place, throw a real TypeError). Threading source location through HIR → codegen is the bigger lift here; we already have Span on AST nodes, just need to plumb it.
Optional chaining (a?.b) and nullish coalescing must continue to short-circuit — the check only fires on bare ./[] access.
Out of scope
Spun out of #455 (DX feedback from @justin0mcateer).
Problem
Property access on
undefinedornullshould throwTypeError: Cannot read properties of undefined (reading 'foo')per JS spec. Today Perry silently returnsundefinedand execution continues, which turns loud bugs into invisible ones — the original report describes a JWS/AES PoC that "ran to completion" while every line was no-oping against an unimplementedcrypto.subtle.This is a correctness bug, not just DX: it's a spec violation that masks real failures.
Repro
Proposed fix
PropertyGetlowering incrates/perry-hir/src/lower.rs(and the corresponding codegen path incrates/perry-codegen/src/expr.rs) should emit a receiver tag check before the field load. If the receiver isTAG_UNDEFINEDorTAG_NULL, call into a runtime helper:The thrower should print a node-shaped message and abort (or, once exception machinery is in place, throw a real
TypeError). Threading source location through HIR → codegen is the bigger lift here; we already haveSpanon AST nodes, just need to plumb it.Optional chaining (
a?.b) and nullish coalescing must continue to short-circuit — the check only fires on bare./[]access.Out of scope