Skip to content

Use trie for removeStringLiteralsMatchedByTemplateLiterals#63343

Open
eps1lon wants to merge 1 commit intomicrosoft:mainfrom
eps1lon:sebbie/ftl/batched-removal
Open

Use trie for removeStringLiteralsMatchedByTemplateLiterals#63343
eps1lon wants to merge 1 commit intomicrosoft:mainfrom
eps1lon:sebbie/ftl/batched-removal

Conversation

@eps1lon
Copy link
Copy Markdown
Contributor

@eps1lon eps1lon commented Apr 2, 2026

Started out as a guess that template literal checking should be done using a trie which led to removeStringLiteralsMatchedByTemplateLiterals being the major contributor in CPU traces.

Actual implementation is vibe-coded with Claude Opus 4.6 (1M context)

Tested this in our internal apps (~90s tsc duration before). Ideally we'd run this against TypeScript's extensive benchmarks since this a space vs runtime tradeoff so we might want to opt out of building the trie for small unions.

Optimize removeStringLiteralsMatchedByTemplateLiterals by building a prefix trie from TemplateLiteralType patterns and using O(L) trie traversal per string literal instead of O(m) linear scan across all templates. StringMappingType templates (which cannot be trie-indexed) are checked separately.

Fixes #63342

Optimize removeStringLiteralsMatchedByTemplateLiterals by building a
prefix trie from TemplateLiteralType patterns and using O(L) trie
traversal per string literal instead of O(m) linear scan across all
templates. StringMappingType templates (which cannot be trie-indexed)
are checked separately.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jakebailey
Copy link
Copy Markdown
Member

Is this different than #59759?

@eps1lon
Copy link
Copy Markdown
Contributor Author

eps1lon commented Apr 2, 2026

Looks like the same at a glance. Yours is already doing some size estimation it seems. I haven't accounted for opting out of trie-based search for small types.

@eps1lon eps1lon marked this pull request as ready for review April 2, 2026 20:19
Copilot AI review requested due to automatic review settings April 2, 2026 20:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes union reduction in the type checker by accelerating removeStringLiteralsMatchedByTemplateLiterals, reducing repeated template-literal matching work when many template literal types are present.

Changes:

  • Adds an internal TemplateLiteralTrieNode type to represent a prefix trie for template literal prefixes.
  • Builds a prefix trie from TemplateLiteralType.texts[0] and uses it to narrow candidate template literals per string literal.
  • Separates StringMappingType checks from trie-based template literal checks.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/compiler/types.ts Adds an internal trie node interface for template-literal prefix indexing.
src/compiler/checker.ts Implements trie construction and lookup, wiring it into removeStringLiteralsMatchedByTemplateLiterals.

Comment on lines +18223 to +18225
const templateLiterals = filter(templates, t => !!(t.flags & TypeFlags.TemplateLiteral)) as TemplateLiteralType[];
const stringMappings = filter(templates, t => !!(t.flags & TypeFlags.StringMapping)) as StringMappingType[];
const trie = templateLiterals.length >= 2 ? buildTemplateLiteralTrieFromTypes(templateLiterals) : undefined;
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

trie is built whenever there are ≥2 TemplateLiteralTypes, but if most/all templates have an empty texts[0] (e.g. patterns starting with a placeholder like ${string}...), they all end up in root.types and the trie provides little/no pruning while still paying the build + allocation cost. Consider gating trie construction on having enough non-empty prefixes (or splitting empty-prefix templates into a separate array checked linearly) so this optimization doesn't regress cases dominated by empty-prefix templates.

Copilot uses AI. Check for mistakes.
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.

type checking complexity with multiple template literals in unions

3 participants