Skip to content

Quadratic duplicate declaration accumulation in intersection constructor properties can crash with RangeError #63560

@canonic-epicure

Description

@canonic-epicure

Bug Report

Intersection constructor types can repeatedly synthesize union/intersection properties with duplicate declaration arrays. In a diamond-like class/interface inheritance shape this causes quadratic/explosive declaration accumulation and can crash in addRange with:

RangeError: Invalid array length

Repro

A standalone compiler testcase is available here:

https://github.com/canonic-epicure/TypeScript/blob/fix-intersection-property-declarations-stacked/tests/cases/compiler/intersectionConstructorReductionCrash.ts

The shape is roughly:

  • generated base classes use constructor-side intersections
  • each constructor-side intersection includes previous mixin static sides via Omit<typeof MixinN, "prototype">
  • merged interfaces carry instance inheritance
  • checking the base constructor type repeatedly synthesizes intersection properties

Observed

Before the fix, with the related base-type traversal fix applied, the testcase still crashes:

RangeError: Invalid array length
    at Array.push
    at addRange
    at createUnionOrIntersectionProperty
    at getUnionOrIntersectionProperty
    at getPropertyOfUnionOrIntersectionType
    at getPropertiesOfUnionOrIntersectionType
    at getReducedType
    at getReducedApparentType
    at getSignaturesOfType
    at isConstructorType

Elapsed time before crash: about 4 seconds.

This also affects Language Service / tsserver semantic diagnostics. In the original larger scenario, semanticDiagnosticsSync timed out before this fix. With the fix, the same scenario completed in about 18ms for initial diagnostics and about 7ms for edit diagnostics.

Expected

The compiler should not repeatedly accumulate duplicate declarations while synthesizing intersection properties.

Candidate fix

Deduplicate declarations when creating synthetic union/intersection properties:

canonic-epicure@7e6d30a

With the fix:

  • direct tsc check time: about 0.05s
  • elapsed time: about 0.22s
  • targeted compiler tests pass

Note

This fix is currently stacked on top of the related base-type traversal fix from:

#63555

Without that related fix, the same testcase no longer crashes after declaration deduplication, but still spends significant time in the separate base-type traversal path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions