Skip to content

Delete old TIR type algebra - #4032

Merged
2kai2kai2 merged 2 commits into
canaryfrom
kai/compiler-perf
Jul 15, 2026
Merged

Delete old TIR type algebra#4032
2kai2kai2 merged 2 commits into
canaryfrom
kai/compiler-perf

Conversation

@2kai2kai2

@2kai2kai2 2kai2kai2 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

This migrates the remaining users of the old TIR StructuralTy-based type algebra logic to use the canonical baml_type algebra. It also provides a major performance improvement by avoiding the costly recursive alias checker in the hot path: compiling the baml_tests/baml_src suite is now several times faster on my laptop.

Summary by CodeRabbit

  • Bug Fixes

    • Improved alias-aware type equivalence across interface, generic binding, dispatch, and implementation checks.
    • Corrected invariant wrapper matching for Array and Map (key/value/element types now require equivalence).
    • Enhanced detection of recursive alias issues and invalid class definition cycles.
    • Refined function subtype behavior for thrown/exception types and optional/required parameter compatibility.
  • Tests

    • Added unit tests covering variance, parameter name/optionality matching, and recursive type-alias detection.

@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jul 15, 2026 12:42am
promptfiddle Ready Ready Preview, Comment Jul 15, 2026 12:42am
promptfiddle2 Ready Ready Preview, Comment Jul 15, 2026 12:42am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4cc0ac55-8ec7-4e0f-b7cf-b471b5b0b362

📥 Commits

Reviewing files that changed from the base of the PR and between 51f15dc and 02eaaf5.

📒 Files selected for processing (3)
  • baml_language/crates/baml_compiler2_tir/src/normalize.rs
  • baml_language/crates/baml_compiler2_tir/src/type_context.rs
  • baml_language/crates/baml_type/src/normalize/tests.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • baml_language/crates/baml_compiler2_tir/src/type_context.rs
  • baml_language/crates/baml_type/src/normalize/tests.rs
  • baml_language/crates/baml_compiler2_tir/src/normalize.rs

📝 Walkthrough

Walkthrough

The compiler adds alias-aware structural equivalence, migrates TIR and MIR matching logic to use it, narrows TIR normalization to cycle detection, and adds tests for recursive aliases and function subtyping rules.

Changes

Type equivalence and cycle detection

Layer / File(s) Summary
Alias equivalence context and invariant matching
baml_language/crates/baml_compiler2_tir/src/type_context.rs, baml_language/crates/baml_compiler2_tir/src/builder.rs, baml_language/crates/baml_type/src/normalize/tests.rs
Adds AliasEquivCtx with alias expansion only, applies equivalence to invariant Array and Map matching, and tests function throws variance and parameter-shape rules.
TIR interface and impl matching
baml_language/crates/baml_compiler2_tir/src/interfaces*
Replaces normalized-type equality with alias-aware equivalence in pattern matching, coherence checks, union comparisons, and associated-type agreement.
MIR interface dispatch matching
baml_language/crates/baml_compiler2_mir/src/lower.rs
Uses alias-aware equivalence for interface argument matching, dispatch requests, existing bindings, and union inference fallbacks.
Normalization module cycle detection
baml_language/crates/baml_compiler2_tir/src/normalize.rs
Removes structural normalization and subtyping helpers, retains cycle detection, and adds tests for direct and generic recursive aliases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • BoundaryML/baml#3933: Updates list/map matching by comparing element, key, and value types by equivalence.
  • BoundaryML/baml#4016: Refactors alias environments through compiler2 type-matching paths touched by this migration.

Poem

I hopped through aliases, neat and bright,
Making type matches fit just right.
Lists and maps now check with care,
Cycles reveal their tangled snare.
“Equivalent!” cried I with glee—
A cleaner type forest for thee.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches a major change in the PR: removing the old TIR type algebra implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kai/compiler-perf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

Also added versions of some of its tests to the `baml_type`
normalization tests
@2kai2kai2
2kai2kai2 force-pushed the kai/compiler-perf branch from 51f15dc to 02eaaf5 Compare July 15, 2026 00:20
@2kai2kai2
2kai2kai2 enabled auto-merge July 15, 2026 00:20
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 22.1 MB 9.4 MB file 22.1 MB +15.2 KB (+0.1%) OK
packed-program Linux 🔒 15.8 MB 6.7 MB file 15.8 MB +8.2 KB (+0.1%) OK
baml-cli macOS 🔒 17.0 MB 8.2 MB file 17.0 MB +48 B (+0.0%) OK
packed-program macOS 🔒 12.2 MB 5.9 MB file 12.2 MB +32 B (+0.0%) OK
baml-cli Windows 🔒 18.5 MB 8.4 MB file 18.5 MB +6.1 KB (+0.0%) OK
packed-program Windows 🔒 13.1 MB 6.0 MB file 13.1 MB +7.1 KB (+0.1%) OK
bridge_wasm WASM 14.6 MB 🔒 4.1 MB gzip 4.1 MB +4.7 KB (+0.1%) OK

🔒 = the size this artifact is GATED on (ceiling + delta). Binaries gate on file size (installed binary); WASM gates on gzip (download size). The other size is shown for information only.


Generated by cargo size-gate · workflow run

@2kai2kai2
2kai2kai2 added this pull request to the merge queue Jul 15, 2026
Merged via the queue into canary with commit ab43021 Jul 15, 2026
52 checks passed
@2kai2kai2
2kai2kai2 deleted the kai/compiler-perf branch July 15, 2026 00:51
meefs pushed a commit to meefs/baml that referenced this pull request Jul 16, 2026
…rness (BoundaryML#4038)

## Summary

- Adds `baml_language/crates/tools_compile_profile`, a standalone
black-box profiling harness for the compiler pipeline (parse → HIR →
PPIR → TIR → MIR → emit). It reports wall-clock per phase,
per-Salsa-query execution / cache-hit / blocked counts, cold-run
variance, cold-vs-warm comparison (`--warm-runs`), and JSON output.
- Ported verbatim from PR BoundaryML#4016 (`perf/compiler2-cold-compile`), with
two adaptations: the `PROF_*` TIR audit counters (which only existed on
that branch) are removed rather than ported, and the "July 2026
cold-compile audit" README section is annotated as a historical record
predating BoundaryML#4032 / BoundaryML#3924.
- Workspace changes: `mimalloc = "0.1.52"` added to workspace deps (used
only by this tool, as its global allocator — noted in the README), and
`"compile"` added to the `tools` namespace `approved_prefixes` in
`stow.toml`.

Provenance: BoundaryML#4016. The remaining findings from that audit are being
re-landed as small independent PRs measured with this tool.

## Baseline on current canary (2660b8b)

Protocol: `cargo build --release -p tools_compile_profile`, then
`./target/release/tools_compile_profile
baml_language/crates/baml_tests/baml_src --repeat 5`
with `BAML_NO_BYTECODE_CACHE=1` and `BAML_CACHE_DIR` pointed at a fresh
temp dir (so BoundaryML#3924's disk cache is out of the picture). Corpus: 77
files, 25,212 lines. Apple Silicon, single-threaded, medians of 5 cold
runs.

| phase | median |
|---|---|
| check | 1.089 s |
| emit (bytecode) | 1.330 s |
| **total** | **2.420 s** (min 2.385, mean 2.442, max 2.524) |

For comparison, BoundaryML#4016's pre-optimization baseline on this corpus was
16.0s and its final state ~0.50s. Canary's own movement (BoundaryML#4032 deleting
the old TIR type algebra, BoundaryML#3924's caching work) already brought cold
compile from 16.0s to ~2.4s; the still-orthogonal optimizations from
BoundaryML#4016 target the remainder.

### Top 10 queries by executions (cold, representative run)

| exec | query |
|---|---|
| 15,590 | `infer_scope_types` |
| 2,262 | `function_in_scope_generic_param_bounds` |
| 2,256 | `function_body` |
| 2,131 | `callable_throws` |
| 625 | `class_generic_param_bounds` |
| 477 | `resolve_class_fields` |
| 419 | `function_parameter_defaults` |
| 419 | `function_signature` |
| 147 | `impl_data` |
| 147 | `impl_data_source_map` |

25,972 total query executions; TIR is 18,697 of them (72%).

## Test plan

- [x] `cargo build --release -p tools_compile_profile` clean
- [x] Clean run against `baml_language/crates/baml_tests/baml_src`
(`--repeat 5`)
- [x] Pre-commit hooks: cargo fmt, workspace clippy (`-D warnings`),
cargo stow, markdown validation

Made with [Cursor](https://cursor.com)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced a standalone compiler profiling harness to measure
compilation phase timings and query execution/caching behavior,
including cold vs warm runs.
* Generates human-readable and JSON reports, with optional compact
summary output and validation-only mode.
* **Documentation**
* Added comprehensive documentation covering CLI usage, report
interpretation, flamegraph pairing guidance, and profiling methodology.
* **Tests**
  * Added tests for query-to-phase mapping and report-related behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
meefs pushed a commit to meefs/baml that referenced this pull request Jul 16, 2026
…ns (2.4s → 0.81s cold) (BoundaryML#4058)

Re-lands the still-orthogonal cold-compile optimizations from BoundaryML#4016,
re-derived from
scratch against current `canary` (which moved underneath BoundaryML#4016 via BoundaryML#4032
and BoundaryML#3924).
Not a rebase of BoundaryML#4016 — every change was re-derived and re-measured.
BoundaryML#4016's single
biggest win (recursive-alias hoist) is intentionally **not** here: BoundaryML#4032
already captured
it by deleting the old TIR `StructuralTy` algebra. The profiler itself
already landed
separately as BoundaryML#4038.

## Measurement

Corpus: `crates/baml_tests/baml_src` (77 files, 25,212 lines). Protocol:
`tools_compile_profile ... --repeat 5`, disk cache disabled
(`BAML_NO_BYTECODE_CACHE=1`,
fresh `BAML_CACHE_DIR`). Cold-cache medians of 5 runs, single-threaded.

| | check | emit | **total** |
|---|---|---|---|
| canary (`8c29c827e`) | 1.114 s | 1.277 s | **2.392 s** (min 2.354 /
max 2.537) |
| this branch | 0.462 s | 0.345 s | **0.808 s** (min 0.791 / max 0.828)
|

**3.0x faster** cold check+emit, single-threaded.

(For reference, the pre-BoundaryML#4032 baseline this work originally started from
was ~16 s; BoundaryML#4032
alone brought cold compile to a few seconds, and this branch takes it
under ~1 s.)

Key query-count deltas (cold, corpus): `infer_scope_types` 15,590 →
**13,331** (PPIR→HIR
`file_semantic_index` delegation removes duplicate scope inference);
`package_resolved_aliases`
/ `package_impl_locs` no longer rebuilt inside every one of those
inference calls (now a
handful of per-package executions); new memoized queries `file_ast`
(131, once/file),
`callee_generics_for_func` (1,834), tracked PPIR `function_body`.

## What's in it (one commit per track)

- **`file_ast` tracked query** — lower CST→AST once per file (items +
lowering diagnostics +
env refs), shared by both `file_semantic_index` queries,
`ppir_expansion_items`, the
project-wide expansion collectors, and the LSP check path; PPIR
`file_semantic_index`
delegates to HIR's when a file has no `$stream` expansions; PPIR
`function_body` tracked.
- **package-level TIR queries** — `package_resolved_aliases` (+
`cycle_initial` seeding an
empty env, mirroring `infer_scope_types` — it sits in a real salsa cycle
via
associated-type-projection alias RHS) and `package_impl_locs` as tracked
queries, plus
`callee_generics_for_func`, so the alias map / impl-block list / callee
generics stop
  being rebuilt per inference call.
- **nested-lambda inference projection** — lambda bodies were inferred
twice (inline in the
owner scope, then again by the standalone `ScopeKind::Lambda` query),
which also emitted
duplicate diagnostics inside lambdas. The inline pass now captures the
lambda's tables and
the Lambda arm projects them; synthetic desugared `test`/`testset`
bodies fall through to
standalone inference so their diagnostics are still emitted. Snapshot
updates where the
  duplicate lambda diagnostics disappear are the point.
- **MIR dispatch prefilter + subtype fast paths** —
`dispatch_target_for_concrete` gates its
per-call impl enumeration behind a package-wide `FxHashSet` of
interface-declared method
names (own package + dependency closure); `baml_type::normalize` gets a
reflexivity +
`heads_definitely_differ` fast-reject in `equivalent()` (conservative:
same-kind nominal
pairs only — List/EvolvingList collapse to the same canonical head
post-BoundaryML#4032) and
restricts `is_subtype_of` co-inductive assumption bookkeeping to the
expanding arms
(Mu / TypeVar / AssociatedTypeProjection) via `is_subtype_of_inner`,
with a termination
argument in-comment. Re-derived onto the post-BoundaryML#4032 `baml_type` algebra
(the only
  equivalence path now).
- **memoized `class_type_tags_for_project`** — the project-wide class →
type-tag map was
rebuilt (every file's item tree walked, every class name re-rendered and
re-hashed)
inside every `LoweringContext` construction, i.e. once per lowered
function (~420x on
the corpus; the hottest MIR frame in a CPU sample). Now a
`#[salsa::tracked]` query
keyed on the `Project` input; `LoweringContext` borrows it. This is
BoundaryML#4016 audit item BoundaryML#4,
initially assumed superseded by BoundaryML#3924's content-addressed tags — BoundaryML#3924
changed the tag
*values* but left the per-function rebuild in place. Also adds this PR
chain's new
  tracked queries to the profiler's `phase_for_query` table.
- **match usefulness report reuse + emit buffer pre-sizing** — match
checking ran the full
usefulness matrix twice per `match` (exhaustiveness, then an identical
second pass for
unreachable-arm detection whenever no arm had a pattern error); the
reachability pass now
reuses the exhaustiveness report (exhaustiveness: ~11% -> ~1.7% of CPU
inclusive).
`StackifyCodegen` pre-sizes its bytecode/meta buffers and local/block
maps from the MIR's
  shape instead of growing from empty per function.
- **CLI mimalloc + diagnostic rendering** — mimalloc as `baml_cli`'s
global allocator; build
the ariadne `SourceCache` once per diagnostic batch instead of once per
diagnostic. Verified
byte-for-byte identical rendered diagnostics and clean
`BAML_CACHE_VERIFY=1` (so BoundaryML#3924's
  cached-diagnostic replay does not diverge).

## Deliberately not re-landed

- The BoundaryML#4016 recursive-alias hoist — superseded by BoundaryML#4032.
- Skip-builtin-diagnostics — superseded by BoundaryML#3924's per-toolchain
builtin-diagnostics cache.

## Testing

Full workspace test suite green except two pre-existing/environmental
failures unrelated to
this change: a Python cancellation pytest that fails identically on
clean `canary` (local
Python < 3.11: `ExceptionGroup`/`CancelledError.reason`). `cargo fmt` +
`clippy -D warnings`
clean.

Provenance: BoundaryML#4016 (reference implementation, kept as reference, not
merged).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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