fix(types,parser): TS conformance Track-1 continuation — symbol member modeling + ParseError cluster#1259
Merged
Conversation
…osition Extends #168's type-position parser hardening past type position: class fields/interface members/inline-object-type members with a computed key ([Symbol.iterator], [Symbol()], ...) now allow an omitted type annotation (implicit any, matching identifier-keyed members) instead of unconditionally requiring ':'. Method/call/construct signatures similarly allow an omitted return type. Also accepts 'Symbol' and other contextual keywords as a namespace name and in typeof-type-position dotted names, both previously routed through a bare IDENTIFIER-only Consume. Flips 17 of 24 outstanding TS conformance ParseErrors (symbolProperty*/ symbolType* cluster) to Pass/Fail.
…merged index Object literals and interfaces collapsed every computed well-known-symbol member ([Symbol.iterator], [Symbol.toStringTag], [Symbol.toPrimitive], ...) into a single merged symbol index signature, losing per-symbol precision. This produced spurious TS7053s reading/calling a specific symbol member, spurious TS2741s assigning an object literal with several distinct symbol members to an interface, and a spurious TS2322 writing through a symbol key that has its own accessor. CheckObject now records each well-known-symbol member under its canonical "@@name" (matching how interfaces/classes already model them); the index get/set paths check for that named member before falling back to the merged signature. Also, three smaller fixes surfaced by the same test cluster: - Interface string-index-signature compatibility (TS2411) no longer flags computed well-known-symbol members — a symbol key can never collide with a string index at runtime. - `declare const x: unique symbol;` (ambient, no initializer) no longer hits the "must be initialized with Symbol()" check, which only makes sense for a real initializer; gated on a new Stmt.Var.IsDeclare flag (not a null-initializer heuristic, which also matches non-ambient `let x: unique symbol;` and would wrongly let that through too). - typeof-narrowing now recognizes numeric/string enum members as matching "number"/"string" respectively; a union typeof-guard with no matching member now narrows to `never` instead of defining the binding as a literal null type (which read back as "undefined variable").
131 -> 203 Pass, 24 -> 7 ParseError, 0 regressions.
This was referenced Jul 5, 2026
Merged
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
Continuation of epic #99 / #80 Track-1 (TS conformance). Picks up where PR #1258 left off, per the follow-up comment on #99.
Round 1: symbol member modeling + ParseError cluster
[Symbol.iterator],[Symbol()], ...) on class fields, interface members, and inline object-type members now allow an omitted type annotation / return type (implicitany), matching identifier-keyed members. Also acceptsSymbol(and other contextual keywords) as a namespace name and intypeof-type-position dotted names.@@name(matching how interfaces/classes already do), with the index get/set paths checking that named member first.declare const x: unique symbol;wrongly required aSymbol()initializer;typeof-narrowing didn't recognize numeric/string enum members, and a union typeof-guard with no matching member defined the narrowed binding as a literalnulltype instead ofnever(surfaced as a bogus "undefined variable").Round 2: the remaining ParseError long tail
Seven unrelated, independently-scoped parser gaps found while clearing what was left of the ParseError bucket:
=, compound, and logical-assignment operators ((a.b) &&= v) — unwrap parens before dispatch.asyncis a contextual keyword: only commit to parsing an async function/arrow when it's immediately followed byfunction/</(; otherwise it's a plain identifier (if (async)).import.metaused as a statement was routed to the static import-declaration parser, which only excluded dynamic-import'simport(, notimport..export { x as y }(bare specifier list) insidedeclare global/declare modulebodies was unhandled.export * as ns from './mod'(ES2020 namespace re-export) wasn't recognized.Result: TS conformance subset baseline 188 → 207 Pass, 24 → 0 ParseError, 0 regressions. The ParseError bucket for this subset is now empty.
Test plan
dotnet test(SharpTS.Tests) — 15452/15452 passing (both rounds)SharpTS.Test262interpreted + compiled baselines — 0 failures (both rounds)SharpTS.TypeScriptConformancebaseline — 207 Pass / 71 Fail / 0 ParseError / 17 Skipped / 1 TypeCheckError, 0 regressions vs. committed baseline