Fix #661/#658 (inferred class method return propagation), #593 (class-instance iterability)#695
Merged
Merged
Conversation
…ass-instance iterability) #661/#658 — inferred class method return types now reach call sites. CheckClassBody resolves a method's inferred (un-annotated) return type during the body pass and writes it to the mutable class, but the class was already frozen with <inferred> placeholders before that pass, so `new C().m()` read <inferred> (~any): ordinary methods skipped assignability checks and a generator method's result was rejected as non-iterable by spread/for...of/yield*. After the body pass, when any inferred method return was resolved, the frozen Class/GenericClass (and the TypeMap the compiler reads) are now rebuilt from the resolved mutable state and re-published; the structural compatibility cache is cleared so results computed against the placeholder (keyed by the stable DeclarationId) are not reused. New MutableClass.ResetFrozenCache() drops the cached frozen forms for the rebuild. - `class C { *m() { yield 1; } }` → `[...new C().m()]` type-checks (was "got '<inferred>'"). - `class C { name() { return "hi"; } }` → `const n: number = new C().name()` is now TS2322. Covers static/async/private methods and recursion. #593 — class-instance iterability. A class is iterable only via an inherited [Symbol.iterator]; `extends Array<number>` resolved Array to a name-only placeholder that dropped the element type, so for...of bound `any` on a plain instance (under-rejecting) and yield* threw a spurious TS2488 on an `extends Array` instance (over-rejecting). Now `extends Array/Set/Map/String/TypedArray` records the element type as an @@iterator on the placeholder, which the structural iterable probe reads by walking the hierarchy directly (the placeholder superclass is a name-only MutableClass the normal member walk skips), so for...of/yield*/spread bind the real element type. A plain class instance with no inherited [Symbol.iterator] is now TS2488 — matching tsc and the runtime, which already throws "for...of requires an iterable". #487/#532 were already fixed by 533d0cf; added explicit Generator/AsyncGenerator 3-arg lib-spelling regression tests (#487) — #532's nested-generator tests already exist. Updated MethodCompletionValueTests to probe the undefined sentinel through `as any`, since an off-the-end method now correctly infers `void` and `void + 10` is the TS2365 tsc reports. Filed #685 (array destructuring desugars to index access, fails over non-indexable iterables) and #692 (compiled static generator method lowering) for pre-existing gaps surfaced here. Full suite 12714/0; TSConformance 31/31 (no baseline change). Changes are type-checker-only, so Test262 (runs .js untyped by default) is unaffected.
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.
Completes four related generator/iterator type-checker issues.
#661 / #658 — inferred class method return types now reach call sites
CheckClassBodyresolves a method's inferred (un-annotated) return type during the body pass and writes it to the mutable class, but the class had already been frozen with<inferred>placeholders before that pass — sonew C().m()read<inferred>(~any). Now, when any inferred method return was resolved, the frozenClass/GenericClass(and theTypeMapthe compiler reads) are rebuilt from the resolved mutable state and re-published after the body pass. The structural compatibility cache is cleared afterward so results computed against the placeholder (keyed by the stableDeclarationId) aren't reused.class C { *m() { yield 1; } }→[...new C().m()]now type-checks (was "must be an iterable type … got ''") — the Type checker: class generator method without an explicit return type is treated as non-iterable (both modes) #661 headline.class C { name() { return "hi"; } }→const n: number = new C().name()is now the TS2322tscreports — Inferred class method return types leak<inferred>/any at call sites (not propagated) #658, the non-generator face of the same gap.#593 — class-instance iterability
A class is iterable only via an inherited
[Symbol.iterator].extends Array<number>resolvedArrayto a name-only placeholder that dropped the element type, so SharpTS boundanyfor a plain instance infor...of(under-rejecting) and threw a spurious TS2488 for anextends Arrayinstance inyield*(over-rejecting).extends Array/Set/Map/String/TypedArrayrecords the element type as an@@iteratoron the placeholder;for...of/yield*/ spread now bind the real element type (number, notany).[Symbol.iterator]) is now TS2488 — matchingtscand the runtime, which already throws "for...of requires an iterable". The#592-dependent direction (user[Symbol.iterator](), which doesn't parse yet) is out of scope and forward-compatible.#487 / #532 — already fixed by 533d0cf; regression coverage added/confirmed
Both were resolved by commit 533d0cf (#548/#532/#487/#483). Added explicit
Generator/AsyncGenerator3-arg lib-spelling regression tests (#487); #532's nested-generator tests already exist. Verified both repros pass in both modes.Issues filed for pre-existing gaps surfaced here
Set,Map). Surfaced because Type checker: class generator method without an explicit return type is treated as non-iterable (both modes) #661 now produces a realGenerator<T>; independent of it (freefunction*and explicitly-typed generators fail identically).static *m()) fails with "Yield not supported in this context" #692 — compiled static generator method (static *m()) fails "Yield not supported in this context" (pre-existing lowering gap; an explicit return type fails identically).Testing
.jsuntyped by default. Corpus isn't initialized in this worktree.MethodCompletionValueTeststo probe theundefinedsentinel throughas any, since an off-the-end method now correctly infersvoidandvoid + 10is the TS2365tscreports.Fixes #661
Fixes #658
Fixes #593
Closes #487
Closes #532