fix(hir): non-class statement-semantics test262 remnant#4920
Merged
Conversation
Three root-cause fixes across the language/statements tail (function / for-of / do-while / while), +7 tests, zero regressions (verified vs main on all 16 statement dirs and the built-ins+language 0/12 shard). 1. typeof(x) with a parenthesized operand. The typeof AST folds matched a bare Ident/Member, so `typeof(zzz)` fell through to a normal operand lowering and emitted a ReferenceError-throwing get instead of folding an unresolved identifier to "undefined" (spec GetValue-skips-on-typeof). Peel transparent Paren wrappers before the folds. Fixes do-while/S12.6.1_A10, while/S12.6.2_A10. 2. for-of IteratorClose on a throw completion. The lazy iterator-protocol loop ran IteratorClose for break/return/labeled abrupts but not when the body threw (explicit `throw` or a runtime exception). Wrap only the user body in a try/catch that runs an unvalidated, exception-swallowing IteratorClose and re-throws; the element-.value read and binding stay outside, since spec IteratorValue throwing sets the iterator done WITHOUT closing. Applied to both for-of lowering paths (module-init and body/block). Fixes for-of/iterator-close-via-throw, for-of/generator-close-via-throw. 3. f.prototype.constructor read returned undefined. The inline nested read folds to GetFunctionPrototypeMethod, whose runtime entry only served registered methods + a builtin allowlist and returned undefined for "constructor" (and never materialized the prototype, so cid was 0). Add a constructor arm that routes through js_function_prototype_value_for_read (respecting a replaced f.prototype = X) and reads its constructor field. Fixes function/S13.2_A4_T1, function/S13.2_A4_T2, function/13.2-17-1.
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.
Cleans up the non-class statement tail of the test262
language/statementssuite. Three root-cause fixes, +7 tests, zero regressions.Results
Verified against
main(bea4f5c) byte-for-byte vsnode v26:language/statementsdirs (non-class): 1286 → 1293 pass (+7), parity 93.9% → 94.4%, 0 regressions.built-ins language--shard 0/12cross-check: 0 regressions (+2 within the shard slice).cargo test -p perry-hir: all green.Fixed:
do-while/S12.6.1_A10,while/S12.6.2_A10,for-of/iterator-close-via-throw,for-of/generator-close-via-throw,function/S13.2_A4_T1,function/S13.2_A4_T2,function/13.2-17-1.Root causes
1.
typeof(x)with a parenthesized operandThe
typeofAST-level folds matched a bareIdent/Member, sotypeof(zzz)(parens) bypassed them and fell through to a normal operand lowering — emitting a ReferenceError-throwing get instead of folding an unresolved identifier to"undefined"(spec GetValue-is-skipped-under-typeof). Peel transparentParenwrappers before the folds run.2. for-of IteratorClose on a throw completion
The lazy iterator-protocol loop ran IteratorClose for
break/return/labeled abrupts (insert_iterator_close_on_abrupt) but not when the body completed abruptly via a throw — an explicitthrow, a throwing LHS setter, a destructuring error, an assertion failure, or a generator.throw(). Wrap only the user body in atry/catchthat runs an unvalidated, exception-swallowing IteratorClose and re-throws the caught error. The element-.valueread and binding statements stay outside the wrapper, because per spec IteratorValue throwing sets the iterator done without closing it (iterator-next-result-value-attr-error). The close itself — including the.returngetter read — is inside a swallowingtryso a throwingreturn/getter does not replace the original error (iterator-close-throw-get-method-abrupt). Applied to both for-of lowering paths (module-initstmt_loops.rsand body/blockbody_stmt.rs).3.
f.prototype.constructorreturnedundefinedThe inline nested read folds to HIR
GetFunctionPrototypeMethod, whose runtime entry (js_get_function_prototype_method) only served registered prototype methods plus a small builtin-method allowlist — it returnedundefinedfor"constructor"and never materialized the prototype object (so the synthetic class id was 0). Add aconstructorarm that routes throughjs_function_prototype_value_for_read(which respects a replacedf.prototype = Xand otherwise materializes the auto-created prototype whoseconstructorback-pointer is the function) and reads itsconstructorfield.Files
crates/perry-hir/src/lower/lower_expr.rs— typeof paren-peelcrates/perry-hir/src/lower/stmt_loops.rs,lower_decl/body_stmt.rs,lower/mod.rs— for-of IteratorClose-on-throwcrates/perry-runtime/src/object/class_registry.rs—f.prototype.constructorNo version/CHANGELOG bump (maintainer folds those in at merge).