Repository navigation
fix(hir): operator-expression semantics test262 tail (inc/dec ToNumber, != bigint/object, instanceof) - #4850
Merged
Merged
Conversation
…r, != bigint/object, instanceof)
Operator-expression parity in language/expressions/* (8 dirs): 617→669 pass
(82.6%→89.6%), 0 regressions on the broad `built-ins language` shard 0/12
(+6 bonus fixes in equals/ and strict-does-not-equals/).
Root causes fixed:
1. inc/dec ToNumber (postfix/prefix increment/decrement, ~30 tests). `x++`/`--x`
did a raw `fadd` on the loaded NaN-boxed bits and returned the *original*
operand, so `var x=true; x++` left x as `true`. Now the operand is
ToNumber-coerced (js_number_coerce: bool/null/string/object-valueOf) before
the step, and the postfix result is the coerced number. Gated to skip
statically-integer loop counters so the hot path stays a single `fadd`.
2. i32-bounded Update gating (A4 tests, ~8). `is_strictly_i32_bounded_expr`
treated *any* `Expr::Update` as i32-bounded, so `var y = x++` got an i32 slot
and truncated the postfix result (`var x=1.1; var y=x++` stored y=1). Now only
bounded when the updated local is itself a known integer.
3. `!=` / `==` with BigInt and objects (does-not-equals 13→0). The codegen
bigint fast path fired when *either* side was BigInt and fed `js_bigint_cmp`
a non-BigInt operand (`0n != undefined` dereffed undefined as a BigIntHeader);
narrowed to both-sides-BigInt. Added full BigInt abstract equality
(BigInt↔BigInt/Number/String/Boolean) + Object→ToPrimitive + Object-vs-Object
reference equality (`new Boolean(true) != new Boolean(true)`) to js_loose_eq.
4. instanceof non-constructor RHS (S11.8.6_A3 etc). A primitive/`this`/call RHS
was silently rewritten to `instanceof Object` and returned false; now lowered
to a value and routed through js_instanceof_dynamic, which throws the spec
TypeError on a non-callable right-hand side.
Deferred (genuinely harder, noted in code): compound-assignment A7 left-before-
right single-evaluation (needs an expression-level temp-slot machinery / shared
expr_assign.rs), instanceof OrdinaryHasInstance `.prototype`-must-be-object +
undefined-ident ReferenceError, BigInt `++`/`--` strict-eq (needs Update-result
static type inferred as BigInt), and the `with`/eval/global compound + update
compile-fails.
Files: perry-codegen/src/expr/{literals_vars,compare}.rs,
collectors/i32_locals.rs, perry-hir/src/lower/lower_expr.rs,
perry-runtime/src/builtins/arithmetic.rs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Operator-expression parity across
language/expressions/*(the 8 assigned dirs):617→669 pass (82.6%→89.6%), with 0 regressions on the broad
built-ins languageshard 0/12 (and +6 bonus fixes in
equals/andstrict-does-not-equals/from theBigInt equality work).
Per-dir (rt-fail before→after): does-not-equals 13→0; postfix-increment 14→4;
postfix-decrement 14→4; prefix-increment 13→4; prefix-decrement 13→4; instanceof 11→10;
compound-assignment 33→33 (deferred); logical-assignment 3→3 (deferred).
Root causes fixed
inc/dec ToNumber (
expr/literals_vars.rs, ~30 tests).x++/--xdid a rawfaddon the loaded NaN-boxed bits and returned the original operand, sovar x=true; x++leftxastrue. The operand is now ToNumber-coerced(
js_number_coerce) before the step and the postfix result is the coerced number.Gated to skip statically-integer loop counters so the hot path stays a single
fadd.i32-bounded Update gating (
collectors/i32_locals.rs, ~8 tests).is_strictly_i32_bounded_exprtreated anyExpr::Updateas i32-bounded, sovar y = x++got an i32 slot and truncated the postfix result(
var x=1.1; var y=x++storedy=1). Now i32-bounded only when the updated localis itself a known integer.
!=/==with BigInt and objects (expr/compare.rs+builtins/arithmetic.rs,does-not-equals 13→0). The codegen BigInt fast path fired when either side was
BigInt and fed
js_bigint_cmpa non-BigInt operand (0n != undefineddereferencedan undefined NaN-box as a
BigIntHeader); narrowed to both-sides BigInt. Added fullBigInt abstract equality (BigInt↔BigInt/Number/String/Boolean), Object→ToPrimitive,
and Object-vs-Object reference equality (
new Boolean(true) != new Boolean(true)) tojs_loose_eq.instanceofnon-constructor RHS (lower/lower_expr.rs). A primitive/this/callright-hand side was silently rewritten to
instanceof Objectand returnedfalse;it is now lowered to a value and routed through
js_instanceof_dynamic, which throwsthe spec
TypeError(true instanceof true,({}) instanceof this).Deferred (noted in code)
temp-slot machinery in the shared
expr_assign.rs).instanceofOrdinaryHasInstance.prototype-must-be-object + undefined-ident ReferenceError.++/--strict-eq (runtime value is already correct BigInt, but===usesfcmpbecause the Update-result static type is inferred as Number).with/eval/global compound + update compile-fails.Validation
cargo fmt --allapplied; file-size gate passes.origin/mainbuild over--dir built-ins language --shard 0/12(2645 judged).