Skip to content

Much faster type checker#3305

Draft
konnov wants to merge 20 commits into
mainfrom
igor/typechecker-perf
Draft

Much faster type checker#3305
konnov wants to merge 20 commits into
mainfrom
igor/typechecker-perf

Conversation

@konnov

@konnov konnov commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator

Our current type checker EtcTypeChecker is known to be slow on large specifications. I've hit a brick wall on a 2300 LOC spec. The type checker was taking 12 minutes.

The first contribution of this PR is a performance improvement by Claude + Sonnet 4.6. It cut the running times of the type checker on the large benchmark to about 6 minutes. However, we needed a more systematic rewrite.

The second contribution of this PR is a new implementation EtcTypeCheckerFast by Codex + GPT 5.4 medium. With this type checker, it finishes on our large benchmark in 12-13 seconds. It took Codex 7-8 iterations, since we have a large test suite.

Leaving this PR in the draft mode for now. It needs a careful review. For now, we can experiment with this new type checker on this branch.

  • Tests added for any new code
  • Ran make fmt-fix (or had formatting run automatically on all files edited)
  • Entries added to ./unreleased/ for any new functionality

konnov and others added 7 commits April 7, 2026 12:50
The type checker was spending ~12 min / ~1 GB RAM on large specs.
JFR profiling identified three dominant allocation sources:

  #2  BitmapIndexedMapNode  (20 690 samples) — varToClass HashMap rebuilt
      per unify() call by copying all EqClass objects O(k·n)
  #6  EqClass               (983 samples)    — fresh copy per class per call
  #7  UID                   (975 samples)    — one UID per EqClass copy

This commit replaces the EqClass object graph with a union-find over
flat int arrays (parent[], rank[]) inside TypeUnifier:
- find() uses iterative path compression
- mergeReprs() always makes the smallest-index variable the representative
  (preserving the existing invariant relied on by callers)
- unifyImpl() resets only the activeVars set instead of allocating a new
  HashMap per call; snapshot/restore is a single array clone

Additional changes bundled in this commit:
- Substitution: key type changed from Map[EqClass, TlaType1] to
  Map[Int, TlaType1] (representative var index as key); varToClassMap
  accessor added for TypeUnifier; fromEqClasses() compatibility factory
  retained for tests
- VarT1: intern first 1024 instances to eliminate 886 allocation samples
  from mkCanonicalSub
- ConstraintSolver: boundVars rebuilt via solution.allVarNums (O(1))
  instead of flatMap over EqClass.typeVars
- EtcTypeChecker, ToEtcExpr, Inliner: removed EqClass(v) wrappers;
  Inliner composition fixed to resolve callee vars through unifierSub
  before composing (required by the new flat Int-key mapping)
- TypeCheckerProfiler: new lightweight profiling object, auto-enabled
  via -Dapalache.typechecker.profile=true

All 765 tests in tlair/tla_typechecker/tla_pp pass.
Benchmark on MC3_system.tla (1962 lines): 12 min → 11 min 11 sec (~7%).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@konnov konnov changed the title Much faster typechecker Much faster type checker Apr 7, 2026
konnov and others added 12 commits April 7, 2026 17:11
Fix several correctness gaps in EtcTypeCheckerFast compared to the legacy ETC solver: speculative overload probes no longer mutate live inference state, LET-local overload resolution only fails ambiguities created inside the LET, and record/sparse tuple unification now follows legacy structural behavior.

Add regression coverage for record joins, sparse tuple bounds, speculative overload leakage, and enclosing-context overload resolution.

Co-authored-by: Codex <codex@openai.com>
Add a researcher-oriented internal note on EtcTypeCheckerFast, covering the live inference graph, unification, LET polymorphism, delayed overload resolution, export compatibility, and expected regression coverage.

Co-authored-by: Codex <codex@openai.com>
Add a researcher-oriented internal note on EtcTypeCheckerFast, covering the live inference graph, unification, LET polymorphism, delayed overload resolution, export compatibility, and expected regression coverage.

Co-authored-by: Codex <codex@openai.com>
@konnov konnov marked this pull request as ready for review May 13, 2026 17:52
@konnov konnov requested a review from Kukovec as a code owner May 13, 2026 17:52
@thpani thpani marked this pull request as draft May 22, 2026 16:25
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.

1 participant