Skip to content

Runtime: throw TypeError on property access against undefined / null #462

Description

@proggeramlug

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed defect or regressionparityCompatibility gap with Node.js, ECMAScript, or the supported ecosystem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions