Skip to content

Match Strada's behavior to allow satisfying recursive indexed access#4430

Open
RyanCavanaugh wants to merge 1 commit into
microsoft:mainfrom
RyanCavanaugh:fix63568
Open

Match Strada's behavior to allow satisfying recursive indexed access#4430
RyanCavanaugh wants to merge 1 commit into
microsoft:mainfrom
RyanCavanaugh:fix63568

Conversation

@RyanCavanaugh

Copy link
Copy Markdown
Member

Authored by copilot

Fixes microsoft/TypeScript#63568

Analysis

The regression came from Corsa not matching Strada’s base-constraint cache model.

In Strada, base-constraint resolution has two distinct caches:

The key Strada implementation is getResolvedBaseConstraint. It computes resolvedBaseConstraint by calling an inner getImmediateBaseConstraint, and recursive base-constraint walks go through an inner getBaseConstraint helper. Circularity tracking is also keyed to TypeSystemPropertyName.ImmediateBaseConstraint, and resolutionTargetHasProperty checks immediateBaseConstraint at checker.ts#L11525-L11526.

Corsa had collapsed this into a single resolvedBaseConstraint cache and passed an explicit recursion stack through getResolvedBaseConstraint(t, stack). That made conditional/indexed-access constraint recovery diverge in recursive cases like:

FromSchema<Context, Context[keyof Context]>["values"]

In the reduced repro, the checker needs to keep advancing the conditional/indexed-access constraint chain far enough to see the values: string shape. The old Corsa model treated one of those recursive conditional constraints as circular too early, so Wrapped<FromSchema<...>> failed the Type constraint even though Strada accepts the type parameter default.

Fix

This ports Corsa’s base-constraint machinery closer to Strada

The main changes are:

  1. Added immediateBaseConstraint to Corsa’s ConstrainedType, matching Strada’s separate immediate/resolved cache split:

  2. Renamed the type-resolution property from resolved-base-constraint tracking to immediate-base-constraint tracking:

  3. Refactored Corsa’s getResolvedBaseConstraint to mirror Strada’s structure:

  4. Updated computeBaseConstraint to use the inner getBaseConstraint helper, matching the Strada flow through type parameters, unions/intersections, index types, indexed accesses, substitutions, and tuples:

  5. Kept Corsa’s existing safeguard for pathological recursive conditional constraints, but adjusted indexed-access check types to use the regular constraint path when appropriate. This preserves the existing infinite-constraint behavior while allowing the #63568 recursive mapped/default constraint case to resolve like Strada.

  6. Added a regression test:

The baseline update also improves the existing infiniteConstraints submodule output by removing one excessive-stack-depth diagnostic while retaining the intended indexing error.

@RyanCavanaugh RyanCavanaugh changed the title Match Strada's behavior to allow satisfying recursive index signature Match Strada's behavior to allow satisfying recursive indexed access Jun 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports the TypeScript-Go checker’s base-constraint caching and recursion handling to more closely match upstream TypeScript (“Strada”), fixing a regression where recursive indexed-access/conditional constraints were treated as circular too early and caused constraint satisfaction failures (TypeScript#63568).

Changes:

  • Split base-constraint caching into immediateBaseConstraint vs resolvedBaseConstraint, and key circularity tracking off the immediate cache.
  • Refactor getResolvedBaseConstraint/computeBaseConstraint to mirror Strada’s structure and recursion flow, including a targeted tweak for indexed-access constraints inside distributive conditional constraints.
  • Add a regression test and update baselines (including reducing one previously-emitted “Excessive stack depth” diagnostic in infiniteConstraints).
Show a summary per file
File Description
internal/checker/checker.go Reworks base-constraint computation/caching and circularity tracking to align with Strada and fix premature circularity.
internal/checker/types.go Adds immediateBaseConstraint to ConstrainedType alongside resolvedBaseConstraint.
internal/checker/utilities.go Updates call site for the new getResolvedBaseConstraint signature.
testdata/tests/cases/compiler/recursiveMappedTypeDefaultConstraint.ts New regression repro covering recursive mapped/default constraint satisfaction.
testdata/baselines/reference/compiler/recursiveMappedTypeDefaultConstraint.* Adds baselines for the new compiler test.
testdata/baselines/reference/submodule/compiler/infiniteConstraints.errors.txt* Updates submodule baseline to reflect diagnostic changes from the new constraint behavior.

Copilot's findings

  • Files reviewed: 9/9 changed files
  • Comments generated: 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: 7.0.1-RC Unable to Satisfy Recursive Mapped Type Constraint

2 participants