You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Sloppy o.x += 1 on a frozen object over-throws: Expr::PropertySet carries no strictness field at all #9459
Over-throwing, not under-throwing — the mirror image of #9394 and #9422, on the object path.
+= lowers to Expr::PropertySet, which carries no strictness field at all, and its codegen reaches js_typed_feedback_object_set_field_by_name, which has no strict parameter and rejects by throwing unconditionally.
The contrast that proves it: o.x++ is correct, because it lowers to Expr::PropertyUpdate, which does carry ctx.current_strict. Two spellings of the same operation, one with the field and one without.
Why this is worse than it looks
A CommonJS bundle is sloppy code from top to bottom — that is where #9394 surfaced. A spurious TypeError on o.x += 1 against a frozen object stops a program that node runs to completion, so this is a hard failure rather than a wrong value.
Fix shape
Add the strictness field to Expr::PropertySet and thread it to the runtime entry, mirroring what Expr::PropertyUpdate already does and what #9426 did for Expr::IndexSet (assignment_strict: bool, rendered as (I32, strict_flag)).
Expr::PropertySet has 181 construction sites, which is why it was not folded into PR #9458 — it is its own change, and most of those sites are one-line updates that want a careful default rather than a blanket false.
The runtime side needs a sloppy twin for the rejection path, the same split #9426 made for array element stores (js_array_set_f64_extend_sloppy alongside the strict entry).
Verification bar
A .cts fixture (CommonJS in both runtimes — this repo is "type": "module", so a .ts is strict ESM and cannot express the sloppy arm) byte-compared to node --experimental-strip-types, demonstrated failing on unfixed origin/main. Assert both arms: every shape above in sloppy code where it must be silent, and in "use strict" code where it must throw. Asserting only one arm is exactly what let #9326 and #9394 through.
Cover +=, -=, *=, &&=, ||=, ??=, for (o.x of …), destructuring [o.x] = arr and ({a: o.x} = obj), on a frozen object, a sealed object, a non-writable own property, an inherited non-writable property, and a getter-only accessor.
Activity
fix(codegen): PropertySet rejections honour sloppy mode (#9459); a wr…
test(codegen): typed-shape mutation pin runs strict — #9459 routes sl…
fix(codegen): strict `o.x += 1` on an inherited non-writable / access…
fix(codegen): the sloppy tail stops excluding `caller`/`arguments` (P…