Skip to content

TS Conformance: parse call/construct/index signatures in type literals & class bodies (#119 follow-up) #121

@nickna

Description

@nickna

Part of #80. Follow-up to #119 (parser is the conformance bottleneck). After the #119/#120 fixes landed via #118, the committed Phase-1 baseline is 54 ParseError / 15 Fail / 10 Pass — the parser still gates ~68% of the subset. The single largest remaining ParseError cluster is signatures inside type literals / class bodies.

Context

The interface body parser (Parser.Declarations.cs:259-293) already handles call signatures, construct signatures, and index signatures via TryParseCallSignature / TryParseConstructorSignature / TryParseIndexSignature. Two other parser sites do not, and that's where these tests die:

  1. Inline object type literalsParseInlineObjectType (Parser.Types.cs:514) only handles properties, methods, and index signatures. A leading ( or new falls into the else branch at :568 which hard-requires Consume(IDENTIFIER, "Expect property name in object type.").
  2. Class-body index signaturesclass A { [x: string]: T } is parsed by the class-member loop (Parser.Classes.cs:306-325), which treats [...] as a computed property name and then fails on the string key type with Expect ']' after computed property name.

Both are pure parser gaps — the type checker is already ahead (per #119).

Repros (all verified ParseError on main @ 00b8246)

// Gap A — call signature in inline object type
let a: { (x: number): void };            // Parse Error: Expect property name in object type.

// Gap A — construct signature in inline object type
let b: { new (x: number): object };      // Parse Error: Expect property name in object type.

// Gap B — class-body index signature
class A { [x: string]: object }          // Parse Error: Expect ']' after computed property name.

Counter-example that already parses (interface form), showing the asymmetry:

interface T { (x: number): void }        // OK

Affected tests (in tests/cases/conformance/types/typeRelationships/assignmentCompatibility/)

  • Call signatures (~7): assignmentCompatWithCallSignatures{,3,4,5}.ts, ...WithOptionalParameters.ts, ...WithRestParameters.ts, callSignatureAssignabilityInInheritance{,2,3,4,5}.ts
  • Construct signatures (~9): assignmentCompatWithConstructSignatures{,2,3,4,5,6}.ts, ...WithOptionalParameters.ts, constructSignatureAssignabilityInInheritance{,2,3,4,5,6}.ts
  • Index signatures (~6): assignmentCompatWith{String,Numeric}Indexer{,2,3}.ts

That's ~20+ tests, the bulk of the remaining ParseError bucket in the committed subset.

Suggested approach

  • Gap A: in ParseInlineObjectType, before the property else branch, add the same dispatch the interface loop uses — Check(NEW) → construct signature, Check(LEFT_PAREN) (or < call-generic start) → call signature, plus a readonly modifier check. Ideally factor the interface's TryParse{Call,Constructor,Index}Signature helpers so both sites share them rather than duplicating. (Note: ParseInlineObjectType currently returns a string type representation, so the helpers may need a string-producing path or the inline representation needs to carry these members — pick the lower-friction shape.)
  • Gap B: in the class-member loop (Parser.Classes.cs:306), distinguish an index signature ([ ident : string|number|symbol ]) from a computed property name ([ expr ]) — lookahead for IDENT COLON after [, and route to index-signature parsing.

Acceptance

  • All three repros above parse without error.
  • Re-running with SHARPTS_TSCONFORMANCE_UPDATE_BASELINE=1 moves the call/construct/index-signature tests out of ParseError into Pass/Fail.
  • Conformance suite stays green (no regressions); baseline delta committed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions