fix(hir): iteration-statement protocol test262 parity#4750
Merged
Conversation
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.
Improves
language/statements/for-in,for-of, andfor-await-oftest262 parity by making the iterator/enumeration protocol spec-compliant in the runtime fallback paths. +10 tests fixed, 0 regressions across all five iteration-statement directories.Root causes fixed
1.
for (key in …)enumeration wasObject.keys, not the spec EnumerateObjectProperties (for-in).The for-in desugar emitted
Expr::ObjectKeys→js_object_keys_value, which (a) throwsTypeErroronnull/undefinedand (b) returns only own enumerable keys. Per ECMA-262 §14.7.5,for (k in null/undefined) {}is a no-op (no throw) and inherited enumerable string keys on the prototype chain must be visited (deduplicated). Added a dedicatedExpr::ForInKeysHIR node lowering to a new runtimejs_for_in_keys_value, which: returns[]for nullish; reusesjs_object_keys_valueper level for the enumerable subset (so arrays→indices, strings→indices, typed arrays, proxies, class instances all keep working); and walks the[[Prototype]]chain. Shadowing follows the spec exactly — a name that is an own property at a closer level (even a non-enumerable one) hides the same name farther up, so each level marks all own names (js_object_get_own_property_names) as seen after emitting its enumerable subset.2. Non-iterable primitives silently no-op'd instead of throwing (
for-of).js_for_of_to_arrayreturned an empty array fornull/undefined/number/boolean, sofor (x of null)/for (x of 37)ran zero times instead of throwingTypeError(GetIterator → ToObject/GetMethod). Now throwsthrow_not_iterable.3.
IteratorNextaccepted non-object results (for-of).js_iterator_to_arraytreated a non-objectnext()result as "done" and broke. Per §7.4.2 step 3,Type(result)not Object must throwTypeError. Now throws when the result isn't aPOINTER_TAGheap object (excluding registered symbols, which are pointer-tagged but not objects).Before → after (parity)
Zero regressions: every test that passed before still passes (verified by diffing the per-dir failure sets across all five directories). The one transient for-in regression introduced by a first-cut prototype walk (
12.6.4-2, non-enumerable own key must still shadow) was fixed before finalizing. Spread /Math.max(...)/[...map]/[...set]/[...string]/ generator spread all verified byte-identical to Node.Files
New IR node
ForInKeyswired through perry-hir (ir/expr.rs, lower/stmt_loops.rs, lower_decl/body_stmt.rs, analysis, js_transform, monomorph, stable_hash, walkers) and perry-codegen (logical_collections, expr/mod, type_analysis, boxed_vars, 4 collectors, runtime_decls/strings, codegen-js). Runtime: newjs_for_in_keys_value(object/field_get_set.rs) and the two for-of throws (array/iterator.rs).