Skip to content

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

@proggeramlug

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

    bugSomething isn't workingparityNode.js compatibility / parity gaps

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions