Skip to content

New API surface for tooling to query compiler - #4320

Merged
2kai2kai2 merged 11 commits into
canaryfrom
kai/baml_surface
Aug 4, 2026
Merged

New API surface for tooling to query compiler#4320
2kai2kai2 merged 11 commits into
canaryfrom
kai/baml_surface

Conversation

@2kai2kai2

@2kai2kai2 2kai2kai2 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Adds the baml_surface crate which provides a stable-ish surface for tools like baml describe to query compiler internals for program information. baml describe has been switched over to using it, allowing improved json output and a new baml describe --export which will provide the full surface area of a specified package (useful for chaining with jq to perform more complex queries)

Summary by CodeRabbit

  • New Features

    • Added JSON export for complete packages through baml describe --export.
    • Enhanced baml describe with documentation, generics, signatures, throws information, implementations, source locations, and member details.
    • Added stable symbol and member identifiers for machine-readable output.
    • Improved name resolution across user and built-in packages, showing all matching results when names are ambiguous.
  • Bug Fixes

    • Standardized CLI output across different environments.
    • Improved displayed function types and interface signature resolution.
    • Preserved documentation comments for supported declarations.

@vercel

vercel Bot commented Aug 3, 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 Aug 4, 2026 12:01am
promptfiddle2 Ready Ready Preview Aug 4, 2026 12:01am

Request Review

@github-actions

github-actions Bot commented Aug 3, 2026

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.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds the baml_surface crate as a compiler-backed semantic API. It adds stable symbol IDs, typed exports, surface handles, shared type resolution, source metadata, and new baml describe rendering and package export paths.

Changes

Semantic surface API

Layer / File(s) Summary
Surface handles, identity, and facts
baml_language/crates/baml_surface/src/*
Adds compiler-backed handles, symbol IDs, type rendering, namespace traversal, implementation attachment, and resolved-fact adapters.
Typed package and symbol exports
baml_language/crates/baml_surface/src/export.rs, baml_language/crates/baml_surface/src/export_tests.rs
Adds versioned JSON records and deterministic projections for packages, symbols, members, signatures, and implementations.
Surface API validation
baml_language/crates/baml_surface/src/*_tests.rs
Tests symbol lookup, IDs, signatures, documentation, implementations, and builtin packages.

Compiler surface contracts

Layer / File(s) Summary
Declaration metadata and source spans
baml_language/crates/baml_compiler2_ast/..., baml_language/crates/baml_compiler2_hir/..., baml_language/crates/baml_compiler2_ppir/...
Preserves docstrings and records declaration and name spans for semantic items.
Shared callable and interface resolution
baml_language/crates/baml_compiler2_tir/...
Centralizes callable signature lowering and exposes resolved interface fields and required methods.
Project database and compiler wiring
baml_language/crates/baml_project/..., baml_language/crates/baml_lsp2_actions/..., baml_language/stow.toml
Connects ProjectDatabase to baml_surface and exposes token lookup.
Compiler metadata validation
baml_language/crates/baml_tests/src/compiler2_*
Validates source spans, docstrings, symbolic interface resolution, and diagnostic output.

Describe CLI integration

Layer / File(s) Summary
Semantic describe rendering
baml_language/crates/baml_cli/src/describe_render.rs, baml_language/crates/baml_cli/src/lib.rs
Adds semantic rendering for declarations, members, signatures, implementations, and locations.
Package export and symbol lookup
baml_language/crates/baml_cli/src/describe_command.rs
Adds package export mode, exact-name lookup, typed JSON output, and surface-based text output.
CLI validation and output control
baml_language/crates/baml_cli/tests/*
Pins human output and tests stable JSON descriptions for builtin symbols and members.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Poem

A rabbit mapped each symbol’s trail,
With typed IDs in every pail.
Packages bloom in JSON light,
While spans keep names precise and bright.
“Describe” now shows the surface flow—
Hop, hop, and ship the code!

🚥 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 clearly summarizes the main change: adding a compiler-query API surface for tooling.
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.
✨ 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/baml_surface

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

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 27.8 MB 11.8 MB file 27.4 MB +397.9 KB (+1.5%) OK
packed-program Linux 🔒 18.0 MB 7.4 MB file 17.7 MB +281.6 KB (+1.6%) OK
baml-cli macOS 🔒 21.6 MB 10.3 MB file 21.3 MB +312.9 KB (+1.5%) OK
packed-program macOS 🔒 14.1 MB 6.5 MB file 13.8 MB +211.0 KB (+1.5%) OK
baml-cli Windows 🔒 23.2 MB 10.5 MB file 23.0 MB +273.8 KB (+1.2%) OK
packed-program Windows 🔒 15.0 MB 6.6 MB file 14.8 MB +210.9 KB (+1.4%) OK
bridge_wasm WASM 17.1 MB 🔒 4.7 MB gzip 4.6 MB +43.5 KB (+0.9%) 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

@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: 9

🧹 Nitpick comments (11)
baml_language/crates/baml_surface/src/handles_tests.rs (1)

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

Loosen the docstring assertion on the builtin baml.String.

The test asserts that the docstring contains the exact phrase "UTF-8 encoded string". The stated purpose is that baml.String keeps its docstring. A prose edit to the stdlib doc comment then fails a test in baml_surface for a reason unrelated to the handle layer.

Assert is_some() instead, or assert a non-empty docstring. The neighboring method-count assertion at line 198 already uses a loose threshold for the same reason.

🤖 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_surface/src/handles_tests.rs` around lines 191 -
200, Loosen the docstring check in the builtin baml.String test by replacing the
exact “UTF-8 encoded string” content assertion with a presence or non-empty
assertion, while leaving the neighboring methods(&db) count assertion unchanged.
baml_language/crates/baml_surface/src/handles.rs (1)

1099-1156: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider memoizing the project impl scan.

project_impls is a plain function. It walks every file in the project and rebuilds the full impl list on each call. Class::trait_impls, Enum::trait_impls, and Interface::implementors each call it once per invocation, and impls_attaching_to additionally calls facts::impl_data for every impl in the project on every lookup.

A package-wide export or a describe listing calls these methods once per item, so the total cost grows with items × project impls. The baml builtin package has many classes and many impls.

Make project_impls a Salsa query, or build a TyHead → impls index once and memoize it. This also matches the crate doc statement that handle methods are thin wrappers over individual Salsa queries.

🤖 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_surface/src/handles.rs` around lines 1099 - 1156,
Memoize the project-wide impl scan instead of rebuilding it for every handle
lookup. Update project_impls to be a Salsa query (or equivalent memoized
TyHead-to-impl index), then reuse its cached results in impls_attaching_to,
Class::trait_impls, Enum::trait_impls, and Interface::implementors while
preserving their existing filtering and ordering behavior.
baml_language/crates/baml_surface/src/ids_tests.rs (1)

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

Add cases for kind-directed resolution failures.

SymbolId::resolve cross-checks the id kind against the member it found (ids.rs lines 258-266). That guard is what stops an F: id from resolving to an enum variant. No test covers it, so a regression in the matches! arms would pass.

Add cases that parse successfully but must not resolve.

💚 Proposed test
/// A well-formed id whose kind disagrees with the member it names must not resolve.
#[test]
fn id_kinds_must_match_the_member_they_name() {
    let mut db = make_db();
    db.add_file("fixture.baml", FIXTURE);

    for bad in [
        "F:user.Color.Red",   // variant addressed as a field
        "E:user.Point.x",     // field addressed as a variant
        "M:user.Point.x",     // field addressed as a method
        "A:user.Encoder.encode", // method addressed as an assoc type
        "V:user.Point",       // type-space item addressed in value space
        "T:user.greet",       // value-space item addressed in type space
    ] {
        let id = SymbolId::from_str(bad).unwrap_or_else(|_| panic!("{bad} parses"));
        assert!(id.resolve(&db).is_none(), "{bad} must not resolve");
    }
}
🤖 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_surface/src/ids_tests.rs` around lines 129 - 146,
Extend the tests near id_strings_reject_malformed_input with a new
id_kinds_must_match_the_member_they_name test that builds the fixture database
and checks well-formed, kind-mismatched IDs such as F:user.Color.Red,
E:user.Point.x, M:user.Point.x, A:user.Encoder.encode, V:user.Point, and
T:user.greet. Parse each ID successfully, then assert SymbolId::resolve returns
None so the kind-directed matches! guard is covered.
baml_language/crates/baml_surface/src/export.rs (3)

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

Reuse helpers for variant and associated-type records.

These two arms repeat the record construction from export_item at lines 629-635 and 650-656. Extract variant_export(db, owner, variant) and assoc_type_export(db, owner, assoc) and call them from both places. The id, name, and docstring rules then stay in one place.

🤖 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_surface/src/export.rs` around lines 756 - 769,
Extract shared helpers named variant_export and assoc_type_export for
constructing VariantExport and AssocTypeExport records, preserving the existing
id, name, docstring, and default handling. Update both the export_item arms and
the corresponding Member::Variant and Member::AssocType arms to call these
helpers instead of duplicating record construction.

373-400: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Precompute impl heads in ImplIndex::build to avoid repeated lookups.

Both lookups re-resolve impl_data and recompute ty_head for every impl on every call. export_package calls them once per class, enum, and interface, so the total work is O(items × impls). Store the head and the interface location next to each export during build, then filter on the cached values.

♻️ Sketch of the cached-index shape
 struct ImplIndex<'db> {
-    exports: Vec<(Impl<'db>, ImplExport)>,
+    /// `(impl, for-type head, interface loc, export)` — heads resolved once.
+    exports: Vec<ImplEntry<'db>>,
 }

Then ids_for_class_head filters on the stored head and ids_for_interface compares the stored interface location.

🤖 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_surface/src/export.rs` around lines 373 - 400,
Update ImplIndex::build to precompute and store each export’s impl head and
interface location alongside its export data, using impl_data and ty_head once
during index construction. Refactor ids_for_class_head to filter on the cached
head and ids_for_interface to compare the cached interface location, removing
repeated impl_data and ty_head lookups while preserving sorting and matching
behavior.

708-728: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

export_symbol exports every project impl to keep a few.

ImplIndex::build runs export_impl for every impl in the project, including full method signatures and source spans, and the filter then discards all but the referenced blocks. The CLI calls export_symbol once per match in the exact-name fallback path in baml_language/crates/baml_cli/src/describe_command.rs, so the whole index is rebuilt for each match.

Two options: accept an optional prebuilt ImplIndex so callers can reuse one, or resolve the attached impls first and export only those blocks.

🤖 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_surface/src/export.rs` around lines 708 - 728,
Update export_symbol to avoid rebuilding and exporting the entire project impl
index for each symbol match: either accept and reuse an optional prebuilt
ImplIndex from callers such as the exact-name fallback in describe_command.rs,
or resolve the symbol’s referenced impl IDs first and export only those
implementations. Preserve the existing SymbolExport contents while ensuring
unrelated project impls are not processed unnecessarily.
baml_language/crates/baml_cli/src/describe_render.rs (2)

130-148: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

render_generics is bypassed in two places. Both sites re-implement the generic-bound formatting that render_generics already provides for the same &[(ParamTy, Vec<Interface>)] input, including the empty case. Any future change to the bound syntax must then be made three times.

  • baml_language/crates/baml_cli/src/describe_render.rs#L130-L148: replace the inline block with render_generics(&imp.generic_params(db).unwrap_or_default()).
  • baml_language/crates/baml_cli/src/describe_render.rs#L317-L334: replace the inline block with render_generics(&resolved.generic_params).
🤖 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_cli/src/describe_render.rs` around lines 130 - 148,
Replace both inline generic-formatting blocks in describe_render.rs at lines
130-148 and 317-334 with calls to render_generics, passing
imp.generic_params(db).unwrap_or_default() at the first site and
resolved.generic_params at the second; preserve the existing empty-generic
behavior through this shared helper.

239-257: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Guard the variants: header on a non-empty variant list.

An enum with no variants prints a bare variants: header. Every other section in this file checks is_empty() first.

♻️ Proposed refactor
-    let _ = writeln!(out, "\nvariants:");
-    for variant in enm.variants(db) {
-        let _ = writeln!(out, "  {}", variant.name(db));
-        if let Some(first) = variant.docstring(db).and_then(|d| d.lines().next()) {
-            let _ = writeln!(out, "      {first}");
+    let variants = enm.variants(db);
+    if !variants.is_empty() {
+        let _ = writeln!(out, "\nvariants:");
+        for variant in variants {
+            let _ = writeln!(out, "  {}", variant.name(db));
+            if let Some(first) = variant.docstring(db).and_then(|d| d.lines().next()) {
+                let _ = writeln!(out, "      {first}");
+            }
         }
     }
🤖 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_cli/src/describe_render.rs` around lines 239 - 257,
Update render_enum to emit the "\nvariants:" header and iterate variant details
only when enm.variants(db) is non-empty, matching the existing is_empty() guards
used by other sections; keep empty enums free of a bare variants header.
baml_language/crates/baml_cli/src/describe_command.rs (2)

61-71: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document or reject the --export plus --json combination.

--export always emits JSON. The code at lines 320-337 returns before the --json branches, so baml describe --export --json silently ignores --json. Add a conflicts_with = "json" attribute, or state in the help text that --export implies JSON.

♻️ Proposed change
-    #[arg(long, help_heading = "Output options")]
+    #[arg(long, conflicts_with = "json", help_heading = "Output options")]
     pub export: bool,
🤖 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_cli/src/describe_command.rs` around lines 61 - 71,
Update the export argument definition in the describe command, alongside the
export field, to explicitly reject combination with the json option using the
CLI’s conflict mechanism. Preserve the existing export behavior and avoid
changing the output branches.

330-336: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Propagate the serialization error instead of panicking.

Every other JSON branch in this function uses .context(...)?. Here a serialization failure panics through unreachable!, which prints a backtrace-style message instead of a CLI error. Use the same error path.

♻️ Proposed change
-            let export = baml_surface::export_package(&db, package);
-            println!(
-                "{}",
-                serde_json::to_string_pretty(&export)
-                    .unwrap_or_else(|_| unreachable!("export IR serializes"))
-            );
+            let export = baml_surface::export_package(&db, package);
+            println!(
+                "{}",
+                serde_json::to_string_pretty(&export)
+                    .context("failed to serialize package export as JSON")?
+            );
🤖 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_cli/src/describe_command.rs` around lines 330 -
336, Update the JSON export branch around baml_surface::export_package and
serde_json::to_string_pretty to propagate serialization failures with the
function’s existing contextual error path, replacing unwrap_or_else and
unreachable!. Match the other JSON branches by adding appropriate context and
using ? while preserving successful pretty-printed output and the Success
return.
baml_language/crates/baml_cli/src/test_command.rs (1)

997-1004: 📐 Maintainability & Code Quality | 🔵 Trivial

Track the duplicated test-discovery rule outside the code.

This BUG: note describes a real semantic divergence: the CLI copy qualifies function refs with the test's namespace, and neither copy uses the resolved function's namespace. The comment states the correct rule is not ratified yet, so the divergence stays until then.

Do you want me to open a tracking issue for unifying test discovery in baml_surface?

🤖 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_cli/src/test_command.rs` around lines 997 - 1004,
The duplicated test-discovery semantics are intentionally unresolved, so no code
change is requested. Preserve the existing BUG note and behavior in the test
discovery logic, and track the proposed baml_surface unification separately
rather than modifying either implementation.
🤖 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_cli/src/describe_command.rs`:
- Around line 409-424: The JSON describe paths handle resolved symbols
inconsistently when export_symbol returns None. In the single-symbol branch
around export_symbol, report a missing export instead of printing “no symbol
found” or suggestions; in the multi-symbol branch around filter_map, detect and
report non-exportable matches rather than silently dropping them into a
successful empty result. Apply one consistent failure policy across both sites.

In `@baml_language/crates/baml_compiler2_tir/src/callable.rs`:
- Around line 182-205: Update the self_ty construction before ScopeCtx in
function_signature_ty to handle MethodOwner::Interface and MethodOwner::FreeImpl
instead of returning None. Bind symbolic Self for interface methods, and lower
the free-implementation receiver type for FreeImpl methods, then pass the
resulting type through ScopeCtx so Self, Self.Assoc, and bare self lower
correctly.

In `@baml_language/crates/baml_surface/src/export_tests.rs`:
- Around line 8-21: Update make_db to set the project root to a newly created
temporary empty directory instead of the process working directory, keeping the
temporary directory alive for the database’s lifetime. In
assert_package_exports_fully, explicitly verify that Package::named resolves and
that export_package produces a non-empty expected export before invoking
insta::assert_snapshot!, while preserving the existing snapshot assertion.

In `@baml_language/crates/baml_surface/src/export.rs`:
- Around line 615-619: Update the module documentation in export.rs to describe
the actual ordering contract: methods and impl IDs are name-sorted, while member
lists—including fields, variants, assoc_types, and required_methods—preserve
declaration order. Do not change the ordering logic in field_export or the
surrounding export code.
- Around line 432-436: In baml_language/crates/baml_surface/src/export.rs,
update the fallback in export_impl around lines 432-436 to qualify free-impl
method ids with the owning ImplExport::id instead of using the non-identifying
name-only placeholder. At lines 470-472, 505-507, 630-632, 651-653, 757-759, and
764-766, remove unwrap_or_default() from member id serialization so missing ids
are omitted rather than emitted as empty strings.

In `@baml_language/crates/baml_surface/src/ids.rs`:
- Around line 221-243: Update member_id to return Option<Self> and return None
when owner.name(db) is unavailable instead of calling unreachable. Adjust
of_member and both of_symbol call sites to propagate member_id directly,
preserving Some for named owners and None for unnamed owners such as
Symbol::Impl.
- Around line 341-361: Update the single-item arm in the namespace scan around
namespace.type_named and namespace.value_named so a missing symbol causes
continue rather than propagating None with ?. Preserve returning
Resolved::Symbol when found, allowing shorter namespace prefixes to be tried on
misses consistently with the [item, member] arm.

In `@baml_language/crates/baml_tests/src/compiler2_hir.rs`:
- Around line 2204-2217: Extend the test near the existing free-implementation
assertion to retrieve the same-file MyClass implementation via class_impls and
assert its impl_block_data docstring is None. Keep the current cross-file
free_impl assertion unchanged, ensuring both docstring behaviors are covered.

In `@baml_language/crates/baml_tests/src/compiler2_tir/inference.rs`:
- Around line 1096-1102: In the test assertions for the generic method pick, add
a check that pick.diagnostics is empty and include the diagnostics in the
failure message. Keep the existing metadata and generic-bound assertions
unchanged.

---

Nitpick comments:
In `@baml_language/crates/baml_cli/src/describe_command.rs`:
- Around line 61-71: Update the export argument definition in the describe
command, alongside the export field, to explicitly reject combination with the
json option using the CLI’s conflict mechanism. Preserve the existing export
behavior and avoid changing the output branches.
- Around line 330-336: Update the JSON export branch around
baml_surface::export_package and serde_json::to_string_pretty to propagate
serialization failures with the function’s existing contextual error path,
replacing unwrap_or_else and unreachable!. Match the other JSON branches by
adding appropriate context and using ? while preserving successful
pretty-printed output and the Success return.

In `@baml_language/crates/baml_cli/src/describe_render.rs`:
- Around line 130-148: Replace both inline generic-formatting blocks in
describe_render.rs at lines 130-148 and 317-334 with calls to render_generics,
passing imp.generic_params(db).unwrap_or_default() at the first site and
resolved.generic_params at the second; preserve the existing empty-generic
behavior through this shared helper.
- Around line 239-257: Update render_enum to emit the "\nvariants:" header and
iterate variant details only when enm.variants(db) is non-empty, matching the
existing is_empty() guards used by other sections; keep empty enums free of a
bare variants header.

In `@baml_language/crates/baml_cli/src/test_command.rs`:
- Around line 997-1004: The duplicated test-discovery semantics are
intentionally unresolved, so no code change is requested. Preserve the existing
BUG note and behavior in the test discovery logic, and track the proposed
baml_surface unification separately rather than modifying either implementation.

In `@baml_language/crates/baml_surface/src/export.rs`:
- Around line 756-769: Extract shared helpers named variant_export and
assoc_type_export for constructing VariantExport and AssocTypeExport records,
preserving the existing id, name, docstring, and default handling. Update both
the export_item arms and the corresponding Member::Variant and Member::AssocType
arms to call these helpers instead of duplicating record construction.
- Around line 373-400: Update ImplIndex::build to precompute and store each
export’s impl head and interface location alongside its export data, using
impl_data and ty_head once during index construction. Refactor
ids_for_class_head to filter on the cached head and ids_for_interface to compare
the cached interface location, removing repeated impl_data and ty_head lookups
while preserving sorting and matching behavior.
- Around line 708-728: Update export_symbol to avoid rebuilding and exporting
the entire project impl index for each symbol match: either accept and reuse an
optional prebuilt ImplIndex from callers such as the exact-name fallback in
describe_command.rs, or resolve the symbol’s referenced impl IDs first and
export only those implementations. Preserve the existing SymbolExport contents
while ensuring unrelated project impls are not processed unnecessarily.

In `@baml_language/crates/baml_surface/src/handles_tests.rs`:
- Around line 191-200: Loosen the docstring check in the builtin baml.String
test by replacing the exact “UTF-8 encoded string” content assertion with a
presence or non-empty assertion, while leaving the neighboring methods(&db)
count assertion unchanged.

In `@baml_language/crates/baml_surface/src/handles.rs`:
- Around line 1099-1156: Memoize the project-wide impl scan instead of
rebuilding it for every handle lookup. Update project_impls to be a Salsa query
(or equivalent memoized TyHead-to-impl index), then reuse its cached results in
impls_attaching_to, Class::trait_impls, Enum::trait_impls, and
Interface::implementors while preserving their existing filtering and ordering
behavior.

In `@baml_language/crates/baml_surface/src/ids_tests.rs`:
- Around line 129-146: Extend the tests near id_strings_reject_malformed_input
with a new id_kinds_must_match_the_member_they_name test that builds the fixture
database and checks well-formed, kind-mismatched IDs such as F:user.Color.Red,
E:user.Point.x, M:user.Point.x, A:user.Encoder.encode, V:user.Point, and
T:user.greet. Parse each ID successfully, then assert SymbolId::resolve returns
None so the kind-directed matches! guard is covered.
🪄 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 Plus

Run ID: 101529fc-f71a-4a37-b250-1f6cc34db2b1

📥 Commits

Reviewing files that changed from the base of the PR and between f0f7ccf and 826d8f1.

⛔ Files ignored due to path filters (9)
  • baml_language/Cargo.lock is excluded by !**/*.lock
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_class_with_impls.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_interface.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_member_drill.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_user_items.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__help_command__tests__describe_detailed_help.snap is excluded by !**/*.snap
  • baml_language/crates/baml_surface/src/snapshots/baml_surface__export_tests__assert_package_exports_fully.snap is excluded by !**/*.snap
  • baml_language/crates/baml_surface/src/snapshots/baml_surface__handles_tests__typed_surface_resolves_signatures_throws_and_fields.snap is excluded by !**/*.snap
  • baml_language/crates/baml_surface/src/snapshots/baml_surface__handles_tests__user_surface_lists_every_kind_with_spans_and_docs.snap is excluded by !**/*.snap
📒 Files selected for processing (52)
  • baml_language/Cargo.toml
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/crates/baml_cli/src/describe_command.rs
  • baml_language/crates/baml_cli/src/describe_render.rs
  • baml_language/crates/baml_cli/src/lib.rs
  • baml_language/crates/baml_cli/src/project_load.rs
  • baml_language/crates/baml_cli/src/test_command.rs
  • baml_language/crates/baml_cli/tests/exit_code_e2e.rs
  • baml_language/crates/baml_cli/tests/pack_e2e.rs
  • baml_language/crates/baml_cli/tests/test_list_discovery_cache_e2e.rs
  • baml_language/crates/baml_cli/tests/test_profiles_e2e.rs
  • baml_language/crates/baml_cli/tests/update_e2e.rs
  • 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/item_tree/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/interfaces.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/source_map.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/type_aliases.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/classes.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/clients.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/enums.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/impls.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/interfaces.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/retry_policies.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/template_strings.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/test_items.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/type_aliases.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/callable.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_compiler2_tir/src/package_interface.rs
  • baml_language/crates/baml_lsp2_actions/src/lib.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/duplicate_names.baml
  • baml_language/crates/baml_project/Cargo.toml
  • baml_language/crates/baml_project/src/db.rs
  • baml_language/crates/baml_project/src/symbols.rs
  • baml_language/crates/baml_surface/Cargo.toml
  • baml_language/crates/baml_surface/src/display.rs
  • baml_language/crates/baml_surface/src/export.rs
  • baml_language/crates/baml_surface/src/export_tests.rs
  • baml_language/crates/baml_surface/src/facts.rs
  • baml_language/crates/baml_surface/src/handles.rs
  • baml_language/crates/baml_surface/src/handles_tests.rs
  • baml_language/crates/baml_surface/src/head.rs
  • baml_language/crates/baml_surface/src/ids.rs
  • baml_language/crates/baml_surface/src/ids_tests.rs
  • baml_language/crates/baml_surface/src/lib.rs
  • baml_language/crates/baml_tests/src/compiler2_hir.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
  • baml_language/stow.toml

Comment thread baml_language/crates/baml_cli/src/describe_command.rs
Comment thread baml_language/crates/baml_compiler2_tir/src/callable.rs
Comment thread baml_language/crates/baml_surface/src/export_tests.rs
Comment thread baml_language/crates/baml_surface/src/export.rs
Comment thread baml_language/crates/baml_surface/src/export.rs
Comment thread baml_language/crates/baml_surface/src/ids.rs
Comment thread baml_language/crates/baml_surface/src/ids.rs
Comment thread baml_language/crates/baml_tests/src/compiler2_hir.rs
Comment thread baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
@vercel
vercel Bot temporarily deployed to Preview – beps August 3, 2026 23:52 Inactive
@2kai2kai2
2kai2kai2 enabled auto-merge August 3, 2026 23:58
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 August 4, 2026 00:01 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: 1

🤖 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_surface/src/ids.rs`:
- Around line 249-258: Validate SymbolId shape before lookup by requiring
self.kind.is_member() to match whether self.member is present, returning None or
the established invalid-result behavior before the IdKind dispatch in resolve.
Add the same invariant to deserialization and any SymbolId construction paths so
type/value IDs cannot carry members and member IDs cannot omit them; anchor the
changes to SymbolId, resolve, and its Deserialize/construction implementations.
🪄 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 Plus

Run ID: 970fd7b2-7b2c-4389-b8cb-ddf81451da24

📥 Commits

Reviewing files that changed from the base of the PR and between 826d8f1 and 938a7cf.

⛔ Files ignored due to path filters (9)
  • baml_language/Cargo.lock is excluded by !**/*.lock
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_class_with_impls.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_interface.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_member_drill.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_user_items.snap is excluded by !**/*.snap
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__help_command__tests__describe_detailed_help.snap is excluded by !**/*.snap
  • baml_language/crates/baml_surface/src/snapshots/baml_surface__export_tests__assert_package_exports_fully.snap is excluded by !**/*.snap
  • baml_language/crates/baml_surface/src/snapshots/baml_surface__handles_tests__typed_surface_resolves_signatures_throws_and_fields.snap is excluded by !**/*.snap
  • baml_language/crates/baml_surface/src/snapshots/baml_surface__handles_tests__user_surface_lists_every_kind_with_spans_and_docs.snap is excluded by !**/*.snap
📒 Files selected for processing (52)
  • baml_language/Cargo.toml
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/crates/baml_cli/src/describe_command.rs
  • baml_language/crates/baml_cli/src/describe_render.rs
  • baml_language/crates/baml_cli/src/lib.rs
  • baml_language/crates/baml_cli/src/project_load.rs
  • baml_language/crates/baml_cli/src/test_command.rs
  • baml_language/crates/baml_cli/tests/exit_code_e2e.rs
  • baml_language/crates/baml_cli/tests/pack_e2e.rs
  • baml_language/crates/baml_cli/tests/test_list_discovery_cache_e2e.rs
  • baml_language/crates/baml_cli/tests/test_profiles_e2e.rs
  • baml_language/crates/baml_cli/tests/update_e2e.rs
  • 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/item_tree/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/interfaces.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/source_map.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/type_aliases.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/classes.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/clients.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/enums.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/impls.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/interfaces.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/retry_policies.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/template_strings.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/test_items.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/type_aliases.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/callable.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_compiler2_tir/src/package_interface.rs
  • baml_language/crates/baml_lsp2_actions/src/lib.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/duplicate_names.baml
  • baml_language/crates/baml_project/Cargo.toml
  • baml_language/crates/baml_project/src/db.rs
  • baml_language/crates/baml_project/src/symbols.rs
  • baml_language/crates/baml_surface/Cargo.toml
  • baml_language/crates/baml_surface/src/display.rs
  • baml_language/crates/baml_surface/src/export.rs
  • baml_language/crates/baml_surface/src/export_tests.rs
  • baml_language/crates/baml_surface/src/facts.rs
  • baml_language/crates/baml_surface/src/handles.rs
  • baml_language/crates/baml_surface/src/handles_tests.rs
  • baml_language/crates/baml_surface/src/head.rs
  • baml_language/crates/baml_surface/src/ids.rs
  • baml_language/crates/baml_surface/src/ids_tests.rs
  • baml_language/crates/baml_surface/src/lib.rs
  • baml_language/crates/baml_tests/src/compiler2_hir.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
  • baml_language/stow.toml
🚧 Files skipped from review as they are similar to previous changes (50)
  • baml_language/crates/baml_cli/src/lib.rs
  • baml_language/Cargo.toml
  • baml_language/crates/baml_cli/tests/pack_e2e.rs
  • baml_language/crates/baml_cli/src/project_load.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_cli/tests/test_profiles_e2e.rs
  • baml_language/crates/baml_project/src/symbols.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
  • baml_language/crates/baml_cli/tests/test_list_discovery_cache_e2e.rs
  • baml_language/crates/baml_cli/src/test_command.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/classes.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/retry_policies.rs
  • baml_language/crates/baml_surface/src/ids_tests.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/interfaces.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/impls.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/clients.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/enums.rs
  • baml_language/crates/baml_surface/src/head.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/source_map.rs
  • baml_language/crates/baml_lsp2_actions/src/lib.rs
  • baml_language/crates/baml_project/Cargo.toml
  • baml_language/crates/baml_cli/tests/update_e2e.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/builder.rs
  • baml_language/crates/baml_surface/src/facts.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_cli/src/describe_command.rs
  • baml_language/crates/baml_tests/src/compiler2_hir.rs
  • baml_language/stow.toml
  • baml_language/crates/baml_surface/src/display.rs
  • baml_language/crates/baml_surface/src/export_tests.rs
  • baml_language/crates/baml_surface/src/handles_tests.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/type_aliases.rs
  • baml_language/crates/baml_surface/Cargo.toml
  • baml_language/crates/baml_compiler2_ppir/src/item_data/template_strings.rs
  • baml_language/crates/baml_compiler2_tir/src/interfaces/impl_rules.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/interfaces.rs
  • baml_language/crates/baml_cli/Cargo.toml
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/package_interface.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/type_aliases.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/test_items.rs
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_tir/src/callable.rs
  • baml_language/crates/baml_surface/src/handles.rs
  • baml_language/crates/baml_surface/src/export.rs
  • baml_language/crates/baml_cli/tests/exit_code_e2e.rs
  • baml_language/crates/baml_project/src/db.rs
  • baml_language/crates/baml_compiler2_tir/src/interfaces.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/duplicate_names.baml
  • baml_language/crates/baml_cli/src/describe_render.rs

Comment thread baml_language/crates/baml_surface/src/ids.rs
@2kai2kai2
2kai2kai2 added this pull request to the merge queue Aug 4, 2026
Merged via the queue into canary with commit 86a2556 Aug 4, 2026
83 checks passed
@2kai2kai2
2kai2kai2 deleted the kai/baml_surface branch August 4, 2026 00:28
codeshaunted added a commit that referenced this pull request Aug 13, 2026
Brings the branch up to date with canary (146 conflicted files) and ports
every TIR-side change onto the hir_ty substrate:

- #4311 equirecursive types: canary's mu-automaton (phase-typed
  NormalTy<Named|Canonical>, de Bruijn binders, canonical_bottom_up)
  merged with this branch's B-1091 co-inductive assumption threading;
  the interned entry re-phased through the same pipeline. Same-shape
  recursive aliases now provably overlap (coherence twin updated).
- #4320 tooling surface: hir_ty gains callable::function_signature_ty
  (a view over function_signature; own generics only; Self resolved for
  interface-default and free-impl methods), interfaces::
  {InterfaceDeclScope, resolve_interface_fields,
  resolve_interface_required_methods, interfaces_declaring_associated_type},
  and package_interface::exported_function (one place pairing the
  signature query with the effective-throws oracle). baml_surface is
  re-pointed tir -> hir_ty with its facts.rs contract intact.
- #4308 catch-arm interface facts: reachability respects implements in
  both directions (the semantic contract compiles with zero diagnostics);
  the arm lowering keeps the modular Interface narrow rather than the
  closed-world concrete residual.
- #4291 intersection bounds, consumption side: GenericParamData conjunction
  shapes adopted end to end; class constructor sites register one
  Implements obligation per declared bound conjunct (register_class_bounds,
  rustc's ADT well-formedness discipline); interface-member lookup pools
  declarers across the bound conjunction, dedupes by realized identity
  through requires, and reports E0121/E0122 ambiguity (rustc's
  MethodError::Ambiguity shape) instead of first-conjunct-wins; a failing
  blanket-impl bound names the unsatisfied conjunct
  (BlanketBoundNotSatisfied) instead of a bare mismatch.
- #4352 @spec/ai builtins compile and emit on hir_ty. Four pre-existing
  engine gaps they exposed are fixed:
  * a bare AnyFunction's unpinned members read as their declared
    `unknown` defaults at the oracle and in the engine's same-interface
    unification (BEP-062 lazy default; no eager fill at lowering);
  * binding a bounded inference var by direct unification now REPLAYS its
    accumulated VarBounds against the solution (take_solved_class_bounds +
    replay in the finish fixpoint) instead of dropping them - the
    map-lambda + future.all shape no longer strands its type args;
  * an empty container literal flowing into a ground `unknown` demand
    commits its establishment slots to the top type (the demand is a
    consuming use); a literal with NO demand keeps the strict
    uninferrable-container error;
  * required interface methods (bodyless items under the unified method
    model) are excluded from the codegen symbol pool.
- Coherence: canary's PreparedImpl refactor adopted on Facts::with_bounds -
  the subject-validity gate now judges the same normalized spelling E0138
  judges, memoized per impl.
- baml_project CFG dispatch (canary's interface virtual-call resolution in
  the visualization) re-pointed onto hir_ty's InferenceResult and
  impls_for_type.
- check.rs: the legacy jinja prompt checker is deleted with canary's
  `client<llm>`/jinja removal; the associated-type declarer walk uses the
  conjunction-deduping interfaces_declaring_associated_type.
- Tests: fixtures migrated off removed builtins (baml.deep_equals ->
  ops.Equals `==`; a local generic pair fn where the fixture probes
  inference); snapshots re-blessed for the unified required-method model
  ([missing] items), canary's builtin/std content, and canonical union
  order.
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