Summary
Perry silently succeeds in many places where the spec mandates a throw. Test262's recurring "Expected a <X> to be thrown but no exception was thrown at all" failures across built-ins/* and language/* come from this. Real code also depends on these throws for control flow / validation.
Concrete gaps (Perry vs Node)
// 1. Member access / method call on null|undefined must throw TypeError
var u;
u.toString(); // Perry: NO THROW (silently returns) Node: TypeError
u.x; // (property GET already throws — OK) — but method CALL does not
(null).foo(); // Node: TypeError
// 2. Non-callable callback must throw TypeError
[1,2,3].map(5); // Node: TypeError "5 is not a function"
[1,2,3].forEach(undefined); // Node: TypeError
// 3. TypedArray spec throws
new Int32Array(-1); // Node: RangeError
// detached-buffer / out-of-range / non-callable comparator → TypeError/RangeError
// 4. Numeric/range validation
(123).toString(40); // Node: RangeError (radix out of range)
The "Expected a TypeError/RangeError to be thrown" Test262 messages map directly to these missing throws.
Where the code lives
- Method-call-on-undefined: the
js_native_call_method / member-call dispatch path (crates/perry-runtime/src/object/native_call_method.rs) and the codegen call site — undefined.m() must raise TypeError instead of no-op. (Property get on undefined already throws; mirror that for calls.)
- Non-callable callback: the
js_array_* / js_typed_array_* iterators (array/iter_methods.rs, typedarray.rs) should validate the callback is a closure before iterating.
- TypedArray range/detached:
crates/perry-runtime/src/typedarray.rs constructors + element ops.
- Error construction helpers already exist (
TypeErrorNew/RangeErrorNew, see expr_new.rs).
Recommended approach
Add the spec-required validation throws at the dispatch/runtime entry points. Prefer one shared helper per error shape. Keep the happy path branch-light. Scope conservatively to avoid throwing where Perry intentionally tolerates (the --experimental-strip-types differential is the oracle).
Acceptance criteria
undefined.toString() / null.foo() throw TypeError; arr/TA iterators throw TypeError on a non-callable callback.
new Int32Array(-1) throws RangeError; (123).toString(40) throws RangeError.
- Measure:
"no exception was thrown" count drops in scripts/test262_subset.py --dir built-ins/TypedArray built-ins/Number built-ins/String --sample-cap 99999.
- No new false throws (regular happy-path code unaffected).
Refs: Test262 radar #799, Node+TS roadmap #793.
Summary
Perry silently succeeds in many places where the spec mandates a
throw. Test262's recurring"Expected a <X> to be thrown but no exception was thrown at all"failures acrossbuilt-ins/*andlanguage/*come from this. Real code also depends on these throws for control flow / validation.Concrete gaps (Perry vs Node)
The
"Expected a TypeError/RangeError to be thrown"Test262 messages map directly to these missing throws.Where the code lives
js_native_call_method/ member-call dispatch path (crates/perry-runtime/src/object/native_call_method.rs) and the codegen call site —undefined.m()must raiseTypeErrorinstead of no-op. (Property get on undefined already throws; mirror that for calls.)js_array_*/js_typed_array_*iterators (array/iter_methods.rs,typedarray.rs) should validate the callback is a closure before iterating.crates/perry-runtime/src/typedarray.rsconstructors + element ops.TypeErrorNew/RangeErrorNew, seeexpr_new.rs).Recommended approach
Add the spec-required validation throws at the dispatch/runtime entry points. Prefer one shared helper per error shape. Keep the happy path branch-light. Scope conservatively to avoid throwing where Perry intentionally tolerates (the
--experimental-strip-typesdifferential is the oracle).Acceptance criteria
undefined.toString()/null.foo()throwTypeError; arr/TA iterators throwTypeErroron a non-callable callback.new Int32Array(-1)throwsRangeError;(123).toString(40)throwsRangeError."no exception was thrown"count drops inscripts/test262_subset.py --dir built-ins/TypedArray built-ins/Number built-ins/String --sample-cap 99999.Refs: Test262 radar #799, Node+TS roadmap #793.