Skip to content

Improved implements rules representation in compiler - #3852

Merged
2kai2kai2 merged 5 commits into
canaryfrom
kai/impl-rule-salsa
Jun 25, 2026
Merged

2kai2kai2 merged 5 commits into
canaryfrom
kai/impl-rule-salsa

Conversation

@2kai2kai2

@2kai2kai2 2kai2kai2 commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

This PR is part of a larger effort to improve the soundness of interfaces. The code it adds is currently mostly unused, but is intended to enable a unified way to represent and lookup interface implements rules in the compiler.

  • Representation in the HIR: ImplBlock
  • Representation in the TIR: ImplData
  • At most one implements rule exists for each tuple (realized concrete type, realized interface) so we can now lookup the ImplData that represents the implementation of that interface for that concrete type.
    • Still todo on this is the ability to lookup for non-realized type/interfaces, which will allow use in generic functions: first the question "for all T, does some implements rule exist where C<T> implements I<T>?" and on top of that, if we can narrow down at compile time which implements rule is used, then that may be able to be baked at compile type instead of dynamic lookup.
  • (unused) MIR get_implements_block now uses the lookup

Summary by CodeRabbit

  • New Features

    • Improved support for interface implementations with multiple generic bounds.
    • Added better handling for blanket and in-class implementations, including more reliable resolution and method lookup.
  • Bug Fixes

    • Fixed duplicate or missing diagnostics when implementation targets or generic bounds are invalid.
    • Added a clearer error when a generic bound is not an interface.
    • Improved validation for unresolved type arguments and implementation constraints.
  • Tests

    • Added regression coverage for implementation resolution, bound checking, and diagnostic behavior.

Makes an referenceable representation of an `implement` block. In this
commit it is unused.
It is a bandaid to handle the unfortunate fact that we type erase in
many cases. Once we eliminate type erasure, the variant will be removed.
@vercel

vercel Bot commented Jun 25, 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 Jun 25, 2026 9:24pm
promptfiddle Ready Ready Preview, Comment Jun 25, 2026 9:24pm
promptfiddle2 Ready Ready Preview, Comment Jun 25, 2026 9:24pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR changes implements generic bounds to lists, introduces unified HIR/TIR impl-block storage and resolution, routes MIR and LSP consumers through the new impl data, and adds diagnostics plus regression tests.

Changes

Implements pipeline

Layer / File(s) Summary
AST multi-bound lowering
baml_language/crates/baml_compiler2_ast/src/ast.rs, baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
ImplementsForDef::generic_params now stores a list of bounds per parameter, and CST lowering collects every &-separated bound.
HIR impl storage and allocation
baml_language/crates/baml_compiler2_hir/src/{builder.rs,ids.rs,item_tree.rs,loc.rs}, baml_language/crates/baml_tests/src/compiler2_hir.rs
Stable impl IDs, unified impl blocks, and builder allocation for in-class and free impls are added, with a HIR consistency test.
TIR impl resolution and registry
baml_language/crates/baml_compiler2_tir/src/{infer_context.rs,interfaces.rs,interfaces/impl_rules.rs}, baml_language/crates/baml_tests/src/compiler2_hir.rs
ImplData resolves implements blocks, interface rules are built from the new HIR impl stores, and bounded blanket lookup is covered by a resolver test.
Diagnostics surfacing and validation
baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs, baml_language/crates/baml_lsp2_actions/src/check.rs, baml_language/crates/baml_tests/tests/interfaces.rs
GenericBoundNotInterface maps to E0145, check_interfaces surfaces impl_data diagnostics, and regression tests cover duplicate and unresolved implements errors.
MIR impl consumers
baml_language/crates/baml_compiler2_mir/src/lower.rs
ResolvedImplBlock now wraps TIR ResolvedImpl, and MIR blanket lookup and method resolution read the shared impl data instead of re-lowering interface details.
Template deprecation annotations
baml_language/crates/baml_type/src/template.rs, baml_language/crates/bex_vm/src/package_baml/resolve.rs, baml_language/crates/bex_vm/src/vm.rs
TypeArgRefOrWildcard match arms now carry deprecation expectations in the type template and VM code paths.

Sequence Diagram(s)

sequenceDiagram
  participant lower_implements_for
  participant ItemTree
  participant package_implements_registry
  participant impl_data
  participant check_interfaces
  participant get_implements_block
  participant ResolvedImpl

  lower_implements_for->>ItemTree: alloc_impl(...) stores ImplBlock
  package_implements_registry->>impl_data: build InterfaceImplRule entries
  check_interfaces->>impl_data: surface impl diagnostics
  get_implements_block->>impl_data: resolve coherent impl and bindings
  get_implements_block->>ResolvedImpl: return ResolvedImpl
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

  • BoundaryML/baml#3555 — Also changes the implements … for … AST/lowering path and generic-bound handling.
  • BoundaryML/baml#3788 — Also updates the TIR interface-implementation registry and coherence logic around InterfaceImplRule.
  • BoundaryML/baml#3647 — Also changes MIR interface-method lowering that consumes resolved impl data.

Poem

🐇 I hopped through bounds and found the thread,
where every &-bound lined up ahead.
The impls now hum in tidy rows,
and even my whiskers know the flows.
Hop! Hop! 🌙

🚥 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 is concise and accurately reflects the main compiler change around implements rule representation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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/impl-rule-salsa

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.

@github-actions

Copy link
Copy Markdown

No description provided.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 25, 2026 21:24 Inactive

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
baml_language/crates/baml_type/src/template.rs (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Narrow the file-level deprecation expectation.

The blanket #![expect(deprecated)] is broader than the actual deprecated use sites and can mask unrelated deprecation warnings in this module. The arm-level expectations already localize the exception.

Suggested change
-#![expect(deprecated, reason = "TypeArgRefOrWildcard")]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baml_language/crates/baml_type/src/template.rs` at line 1, The file-level
deprecated expectation in template.rs is too broad and can hide unrelated
warnings; narrow or remove the module-level `#![expect(deprecated, reason =
"TypeArgRefOrWildcard")]` and rely on the existing localized arm-level
expectations instead. Update the `template.rs` module so only the specific
deprecated use sites around `TypeArgRefOrWildcard` are covered, keeping the
exception scoped to the relevant match arms or items.
baml_language/crates/baml_compiler2_ast/src/lower_cst.rs (1)

1228-1276: 📐 Maintainability & Code Quality | 🔵 Trivial

Optional: collapse the two bound extractors to reduce duplication.

extract_generic_params_with_all_bounds and extract_generic_params_with_bounds share nearly all traversal logic, differing only in whether they keep all bounds or the first. The single-bound variant could delegate (...with_all_bounds(node).into_iter().map(|(n, b)| (n, b.into_iter().next()))), keeping one source of truth for the CST walk. Deferable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baml_language/crates/baml_compiler2_ast/src/lower_cst.rs` around lines 1228 -
1276, `extract_generic_params_with_all_bounds` and
`extract_generic_params_with_bounds` duplicate almost the same CST traversal
logic. Refactor the single-bound helper to delegate to
`extract_generic_params_with_all_bounds` and then keep only the first bound per
param, while preserving the existing behavior for empty bounds and names. Keep
the shared node-walking and name extraction in one place so both helpers stay
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@baml_language/crates/baml_compiler2_hir/src/item_tree.rs`:
- Around line 599-607: The legacy `ImplementsFor.generic_param_bounds`
population in `item_tree.rs` is truncating each generic parameter to only the
first `&`-bound, so downstream users can miss additional constraints. Update the
`ImplementsFor` construction to preserve the full bound set, or first migrate
all consumers that still read `implements_for.generic_param_bounds` to the new
`ImplBlock`/`GenericParam.bounds` source before keeping this legacy field
truncated. Use the `ImplementsFor` builder in `item_tree.rs` and any
MIR/lowering code paths that depend on `implements_for.generic_param_bounds` to
ensure they see every bound.

In `@baml_language/crates/baml_compiler2_tir/src/interfaces.rs`:
- Around line 1381-1397: The generic-bound lowering in the impl registration
path is only using g.bounds.first(), so multi-bound generics are being treated
as single-bound rules. Update the logic around the names/bounds collection in
this section to use all bounds carried by ImplData::generic_params instead of
reconstructing one lowered Ty from the first bound only, and make sure the free
impl rule registration preserves the full bound list for lookup/compatibility.

---

Nitpick comments:
In `@baml_language/crates/baml_compiler2_ast/src/lower_cst.rs`:
- Around line 1228-1276: `extract_generic_params_with_all_bounds` and
`extract_generic_params_with_bounds` duplicate almost the same CST traversal
logic. Refactor the single-bound helper to delegate to
`extract_generic_params_with_all_bounds` and then keep only the first bound per
param, while preserving the existing behavior for empty bounds and names. Keep
the shared node-walking and name extraction in one place so both helpers stay
consistent.

In `@baml_language/crates/baml_type/src/template.rs`:
- Line 1: The file-level deprecated expectation in template.rs is too broad and
can hide unrelated warnings; narrow or remove the module-level
`#![expect(deprecated, reason = "TypeArgRefOrWildcard")]` and rely on the
existing localized arm-level expectations instead. Update the `template.rs`
module so only the specific deprecated use sites around `TypeArgRefOrWildcard`
are covered, keeping the exception scoped to the relevant match arms or items.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d89d1862-dfcc-4d0c-912d-b3c1e847d21b

📥 Commits

Reviewing files that changed from the base of the PR and between dce0e79 and 4de2514.

📒 Files selected for processing (17)
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/ids.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree.rs
  • baml_language/crates/baml_compiler2_hir/src/loc.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_tir/src/infer_context.rs
  • baml_language/crates/baml_compiler2_tir/src/interfaces.rs
  • baml_language/crates/baml_compiler2_tir/src/interfaces/impl_rules.rs
  • baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs
  • baml_language/crates/baml_lsp2_actions/src/check.rs
  • baml_language/crates/baml_tests/src/compiler2_hir.rs
  • baml_language/crates/baml_tests/tests/interfaces.rs
  • baml_language/crates/baml_type/src/template.rs
  • baml_language/crates/bex_vm/src/package_baml/resolve.rs
  • baml_language/crates/bex_vm/src/vm.rs

@2kai2kai2
2kai2kai2 added this pull request to the merge queue Jun 25, 2026
Merged via the queue into canary with commit 1f8c730 Jun 25, 2026
52 checks passed
@2kai2kai2
2kai2kai2 deleted the kai/impl-rule-salsa branch June 25, 2026 21:55
@coderabbitai coderabbitai Bot mentioned this pull request Jul 30, 2026

This branch was previously deployed

3 inactive deployments
Preview – promptfiddle — 4de25149 Deployed Jun 25, 2026 by vercel[bot]
Preview – promptfiddle2 — 4de25149 Deployed Jun 25, 2026 by vercel[bot]
Preview – beps — 4de25149 Deployed Jun 25, 2026 by vercel[bot]
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