Skip to content

Fix TS1515 not reported when duplicate named group is nested inside a group - #4881

Merged
Jake Bailey (jakebailey) merged 4 commits into
mainfrom
copilot/fix-ts1515-nested-group
Aug 14, 2026
Merged

Fix TS1515 not reported when duplicate named group is nested inside a group#4881
Jake Bailey (jakebailey) merged 4 commits into
mainfrom
copilot/fix-ts1515-nested-group

Conversation

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

scanDisjunction dropped an alternative's named-capture scope as soon as the alternative (or enclosing group) ended, so a duplicate (?<name>...) defined inside a nested group never reached the enclosing alternative's duplicate check.

/(?<a>x)(?<a>y)/       // TS1515 (already worked)
/(?:(?<a>x))(?<a>z)/   // no error before this fix — should be TS1515
/(?=(?<a>x))(?<a>z)/   // no error before this fix — should be TS1515
/(?<a>x)|(?<a>y)/      // legal, must stay quiet

Root cause

  • scanDisjunction pushed a fresh scope per alternative (including alternatives inside nested groups/assertions), but discarded that scope entirely once the alternative or group closed, instead of folding it back into the enclosing alternative.

Fix

  • scanDisjunction (internal/scanner/regexp.go) now unions the names defined across all alternatives of a disjunction, and when that disjunction is the content of a nested group, merges the union up into the parent alternative's scope before returning.
  • This makes names defined inside non-capturing groups, capturing groups, and lookahead/lookbehind assertions visible to later sibling terms in the same alternative, while leaving names confined to separate branches of a | disjunction untouched (still legal per ES2025).

Tests

  • Added testdata/tests/cases/compiler/regexNamedGroupDuplicateNestedInGroup.ts covering all patterns from the issue, with accepted baselines showing TS1515 now fires for the previously-missed nested cases and remains silent for the legal alternation cases.

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix TS1515 reporting for nested named groups Fix TS1515 not reported when duplicate named group is nested inside a group Aug 11, 2026
@RyanCavanaugh

Copy link
Copy Markdown
Member

Paging graphemecluster (@graphemecluster), this is above my regex paygrade

@graphemecluster graphemecluster (graphemecluster) 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.

I checked my old fix from microsoft/TypeScript@c435526 (#60249) (yes sorry I should've extracted the change and fired a separate PR in the past) and it implements the same logic (unioning the nested alternatives into the parent when the disjunction closes), so this should be fine.

I also verified using the test case file I made up in the past (microsoft/TypeScript@24c16f9 (#60249)) and it passes. The current PR's test coverage is quite narrow (e.g. it does not test reverse direction), so I would suggest adding my cases in that commit, or at least:

// Named group in non-first alternative
/(?:x|(?<a>y))(?<a>z)/;

// Outer named group before nested named group
/(?<a>x)(?:(?<a>y)|z)/;

// Named group inside modifier group
/(?i:(?<a>x))(?<a>y)/;

// Multiple nesting levels
/(?:(?:(?<a>x)))(?<a>y)/;

// Legal: Outer disjunction separates non-nested and nested named groups
/(?:(?<a>x))|(?<a>y)/;

// Legal: Outer disjunction separates each duplicate pair
/(?<a>x)(?<b>y)|(?<a>z)(?<b>w)/;

On the other side, (?<\u0061>...) currently fails with TS1514 but not normalised to a and participated in the duplicate check. I am porting microsoft/TypeScript#61042 to fix this.

@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) marked this pull request as ready for review August 14, 2026 16:12
Copilot AI balanced review requested due to automatic review settings August 14, 2026 16:12

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

Fixes nested named-capture scope propagation so TS1515 is correctly reported without affecting legal alternations.

Changes:

  • Unions nested disjunction capture names into the enclosing alternative.
  • Adds regression coverage for nested groups and assertions.
  • Adds generated compiler baselines confirming five diagnostics.
Show a summary per file
File Description
internal/scanner/regexp.go Propagates nested capture names.
testdata/tests/cases/compiler/regexNamedGroupDuplicateNestedInGroup.ts Adds regression cases.
testdata/baselines/reference/compiler/regexNamedGroupDuplicateNestedInGroup.errors.txt Records expected diagnostics.
testdata/baselines/reference/compiler/regexNamedGroupDuplicateNestedInGroup.js Records emitted JavaScript.
testdata/baselines/reference/compiler/regexNamedGroupDuplicateNestedInGroup.symbols Records symbol baseline.
testdata/baselines/reference/compiler/regexNamedGroupDuplicateNestedInGroup.types Records type baseline.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 6/6 changed files
  • Comments generated: 0
  • Review effort level: Balanced

Comment thread internal/scanner/regexp.go Outdated
// This ensures a name defined inside a nested group (e.g. `(?:(?<a>x))`) is
// still visible to a duplicate check for a sibling group later in the same
// enclosing alternative (e.g. `(?:(?<a>x))(?<a>z)`).
var disjunctionNames map[string]bool

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This really should have been var disjunctionNames collections.Set[string] but it's whatever I geuss

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
@jakebailey
Jake Bailey (jakebailey) added this pull request to the merge queue Aug 14, 2026
Merged via the queue into main with commit 8ffb4ef Aug 14, 2026
21 checks passed
@jakebailey
Jake Bailey (jakebailey) deleted the copilot/fix-ts1515-nested-group branch August 14, 2026 20:06
Jake Bailey (jakebailey) pushed a commit to jakebailey/TypeScript that referenced this pull request Aug 14, 2026
… group (microsoft/typescript-go#4881)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: Ryan Cavanaugh <RyanCavanaugh@users.noreply.github.com>
Dayong Lee (dayongkr) added a commit to dayongkr/typescript-go that referenced this pull request Aug 15, 2026
microsoft#4881 registered this test's diff in submoduleAccepted.txt, so the diff
belongs in submoduleAccepted rather than in submodule.
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.

TS1515 is not reported when the earlier duplicate named group is inside a nested group

5 participants