fix: class async / async-generator method test262 parity - #4768
Merged
Conversation
Brings the 8 in-class async-method / async-generator-method test262 dirs from 266/516 (51.6%) to 408/516 (79.1%) pass, zero regressions. Root causes fixed: 1. Async-generator instances had no [Symbol.asyncIterator]. `for await` over a class async-gen method hung/yielded nothing (GetIterator(obj, async) could not resolve the iterator). Install [Symbol.asyncIterator] (returning `this`) on %AsyncGenerator.prototype% (global_this.rs). The sync %Generator.prototype% deliberately gets none — the sync for-of path does not bind implicit-this, so a this-returning thunk would break `for (x of gen())`. 2. Async `yield*` delegated through the SYNC iterator protocol with no awaits. `yield* asyncIterable` inside an async generator silently produced nothing or threw "next is not a function". Made the yield* desugaring async-aware (linearize.rs): use GetAsyncIterator and `await` each delegated next()/result when the enclosing generator is async (threaded via a thread-local set in lower.rs). 3. GetIterator(obj, async) error semantics. A present-but-non-callable @@asynciterator, or a callable one returning a non-Object, must throw TypeError (not fall back to the sync iterator). Rewrote js_get_async_iterator to follow the spec ordering (iterator.rs). 4. Missing trailing arguments were padded with NaN instead of `undefined` in the dynamic vtable / static-method dispatch (class_registry.rs call_vtable_method + call_static_method). Default parameters lower to `param === undefined ? <default> : param`, so a hole padded with NaN never triggered the default (e.g. `C.prototype.method` called with fewer args). 5. Private methods never applied parameter defaults at all (direct OR via a `this.#m` value): lower_private_method built `param.default` but never prepended the `if (param === undefined) param = default` prologue that public methods/constructors emit. Added it (private_members.rs). Fixes all private method kinds (sync/async/gen/async-gen) and async-private-gen dstr default tests. 6. Latent: small typed arrays are raw-alloc'd with no object GcHeader, so js_object_is_extensible read garbage `_reserved` and non-deterministically reported `false`. Integer-indexed exotic objects are extensible by default; short-circuit TAs/buffers to extensible (object_ops_frozen.rs). Fixes #4 and #5 also lift the standalone language/statements/class/dstr private-method and default-parameter dirs (+23 there) with zero regressions across a built-ins+language regression shard.
proggeramlug
force-pushed
the
class-async-methods-parity
branch
from
June 7, 2026 20:23
4faa461 to
3f65361
Compare
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
Brings the 8 in-class async-method / async-generator-method test262 dirs from 266/516 (51.6%) → 408/516 (79.1%) pass.
Regression-checked against a
built-ins+languageshard (0/12): +24 net fixed, 0 real regressions (the one shard blip —TypedArray/prototype/forEach/returns-undefined— passes in isolation on both this branch and the merge-base; load-induced flakiness, not from this change). The default-parameter and private-method fixes also lift the standalonelanguage/statements/class/dstrdirs by +23 with zero regressions.Dirs covered:
language/{statements,expressions}/class/{async-method,async-method-static,async-gen-method,async-gen-method-static}.Root causes fixed
No
[Symbol.asyncIterator]on async-generator instances.for awaitover a class async-gen method hung / yielded nothing —GetIterator(obj, async)couldn't resolve the iterator. Install[Symbol.asyncIterator](returningthis) on%AsyncGenerator.prototype%. (The sync%Generator.prototype%deliberately gets none — the syncfor-ofpath doesn't bind implicit-this, so athis-returning thunk would breakfor (x of gen()).)Async
yield*delegated through the sync iterator protocol with no awaits —yield* asyncIterablein an async generator produced nothing or threw "next is not a function". Theyield*desugaring is now async-aware: usesGetAsyncIteratorandawaits each delegatednext()when the enclosing generator is async.GetIterator(obj, async)error semantics. A present-but-non-callable@@asyncIterator, or a callable one returning a non-Object, must throwTypeError— not fall back to the sync iterator. Rewrotejs_get_async_iteratorto the spec ordering.Missing trailing args padded with
NaNinstead ofundefinedin dynamic vtable / static-method dispatch. Default params lower toparam === undefined ? <default> : param, so a hole padded withNaNnever triggered the default (e.g. a detachedC.prototype.methodcalled with fewer args).Private methods never applied parameter defaults (direct or via a
this.#mvalue):lower_private_methodbuiltparam.defaultbut never prepended theif (param === undefined) param = defaultprologue public methods emit. Fixes all private method kinds.Latent: small typed arrays are raw-
alloc'd with no objectGcHeader, soObject.isExtensibleread garbage_reservedand non-deterministically reportedfalse. Integer-indexed exotic objects are extensible by default; short-circuit TAs/buffers.Files
perry-transform/src/generator/linearize.rs,lower.rs— async-awareyield*delegationperry-runtime/src/object/global_this.rs—%AsyncGenerator.prototype%[Symbol.asyncIterator]perry-runtime/src/array/iterator.rs— specGetIterator(obj, async)perry-runtime/src/object/class_registry.rs—undefined(notNaN) arg paddingperry-hir/src/lower_decl/private_members.rs— private-method default prologueperry-runtime/src/object/object_ops_frozen.rs— TA/bufferisExtensibleNotes for the maintainer
cf56a6faf; currentmainhas#4766(dstr + dflt-params). Fix useEffect + setState panics with RefCell already borrowed on macOS ARM64 #4 (call_vtable_methodNaN→undefined) is still needed on current main and shouldn't conflict.yield*execution-order tests (custom getter/thenable ordering) that conflict with Perry's synchronous-await-drain model, plus static-methodthisbinding (a separate, broad pre-existing gap: static methods seethis === undefined).