Skip to content

feat(lsp): resolution-first semantic tokens rework#3867

Open
codeshaunted wants to merge 18 commits into
canaryfrom
avery/sem-tok-cleanup
Open

feat(lsp): resolution-first semantic tokens rework#3867
codeshaunted wants to merge 18 commits into
canaryfrom
avery/sem-tok-cleanup

Conversation

@codeshaunted

@codeshaunted codeshaunted commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Reworks the BAML semantic-tokens classifier to be resolution-driven, mirroring rust-analyzer: walk the lossless CST for token positions + syntactic tokens (keywords/operators/punctuation), and resolve identifier meaning through the HIR/inference instead of guessing from the CST.

What's here

  • tokens/index.rs — span-keyed resolution index over every inference-bearing scope (function / lambda / let) via the new uniform tir::scope_body lookup, so identifiers inside spawn/block/closure bodies classify with their own scope's inference.
  • Interface members resolve like class membersresolve_interface_member now records MemberResolution::InterfaceMethod / InterfaceField. So .as<I>.method(), interface Self methods, and chained interface calls classify through the normal path; typos stay neutral. MIR-safe (new variants → None item-refs, fall through to existing interface dispatch; 323 runtime interface tests pass).
  • Highlighting fixes: as / with / is keywords, generators, generic type args + params (typeParameter), associated types (decl + binding), self member accesses (no longer namespace), methods after .as<Interface>, string escapes (escapeSequence), byte strings, qualified type paths, true/false/null, object/map keys vs values.
  • tools_semantic_tokens — standalone web viewer for the classifier (no VSCode needed).

Tests

78 semantic-token fixtures; 439 LSP + 323 runtime-interface + 172 tir/mir tests pass; clippy-clean.

Next steps / gaps

See crates/baml_lsp2_actions/src/tokens/GAPS.md — the priority is scaling like rust-analyzer (on-demand per-token resolution + semanticTokens/range viewport + delta), plus a couple remaining feature items (optional params at call site, a boolean literal token type).

Summary by CodeRabbit

  • New Features
    • Upgraded LSP semantic tokens with modifier support, EscapeSequence highlighting, and improved full/delta/range legends/encoding.
    • Added a local web viewer to inspect semantic tokens and update fixture expectations.
  • Bug Fixes
    • Improved semantic highlighting and “go to definition” for interface fields/methods.
    • Fixed contextual keyword/literal handling (as, type, true/false/null) and enhanced catch binding typing/highlighting.
    • Enhanced styling for string escape sequences.
  • Tests
    • Expanded semantic-token fixtures and added range-consistency, robustness, and delta-diff validation.

Rework the BAML semantic-tokens classifier to be resolution-driven
(rust-analyzer style): walk the lossless CST for token positions and
syntactic tokens (keywords/operators/punctuation), and resolve identifier
meaning through the HIR/inference rather than guessing from the CST.

- tokens/index.rs: span-keyed resolution index built over every
  inference-bearing scope (function / lambda / let) via the new uniform
  tir::scope_body lookup, so names in spawn/block/closure bodies classify
  with their own scope's inference.
- Interface members now resolve like class members: resolve_interface_member
  records MemberResolution::InterfaceMethod / InterfaceField. MIR-safe (new
  variants lower to None item-refs and fall through to interface dispatch).
- Highlighting fixes: as / with / is keywords, generators, generic type args
  and params (typeParameter), associated types (decl + binding), self member
  accesses, methods after .as<Interface>, string escapes (escapeSequence),
  byte strings, qualified type paths, true/false/null literals, object/map
  keys vs values.
- bitflags-backed ModifierSet; classifier shared with `baml describe`.
- tools_semantic_tokens: standalone web viewer for the classifier.

78 fixtures. See crates/baml_lsp2_actions/src/tokens/GAPS.md for the
scaling next-steps (on-demand resolution, range/viewport, delta) and the
remaining known gaps.
@vercel

vercel Bot commented Jun 27, 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 29, 2026 5:31pm
promptfiddle Ready Ready Preview, Comment Jun 29, 2026 5:31pm
promptfiddle2 Ready Ready Preview, Comment Jun 29, 2026 5:31pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR adds modifier-aware semantic tokens, contextual keyword and literal handling, interface-member and catch-binding resolution, and a semantic-tokens viewer with fixture snapshots, range queries, and delta support.

Changes

Semantic tokens, resolution, and viewer

Layer / File(s) Summary
Syntax and token kinds
baml_language/Cargo.toml, baml_language/crates/baml_lsp2_actions/Cargo.toml, baml_language/crates/baml_cli/src/paint.rs, baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs, baml_language/crates/baml_compiler_parser/src/parser.rs, baml_language/crates/baml_compiler_syntax/src/ast.rs, baml_language/crates/baml_fmt/src/ast/*, baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
KW_AS, KW_TYPE, KW_TRUE, KW_FALSE, KW_NULL, and EscapeSequence are added or reclassified, AST accessors and token wrappers are updated, and bitflags is added as a shared dependency.
Catch and interface resolution
baml_language/crates/baml_compiler2_hir/src/*, baml_language/crates/baml_compiler2_tir/src/*, baml_language/crates/baml_lsp2_actions/src/{completions.rs,definition.rs,describe.rs,type_info.rs,definition_at_tests.rs}
Catch bindings get their own DefinitionSite, interface members gain dedicated resolution variants, scope-body lookup and namespace/field/variant resolution helpers are added, and LSP definition/completion/type-info paths consume the new bindings.
Semantic token classifier and index
baml_language/crates/baml_lsp2_actions/src/{lib.rs,tokens.rs,tokens/classify.rs,tokens/index.rs}, baml_language/crates/baml_lsp2_actions/src/tokens/DESIGN.md, baml_language/crates/baml_lsp2_actions/src/tokens/GAPS.md
The semantic-token pipeline now emits ModifierSets, classifies escapes/booleans, builds a resolution index, walks CSTs in document order, and serves full/range tokens with the new legend and documented gaps.
Semantic token viewer and server
baml_language/crates/bex_project/src/bex_lsp/multi_project/*, baml_language/crates/tools_semantic_tokens/*
A local viewer app is added with fixture listing, scratchpad tokenization, snapshot acceptance, staleness reloads, and LSP semantic-token full/delta/range support.
Semantic token fixtures and tests
baml_language/crates/baml_lsp2_actions_tests/src/*, baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/*
The test harness and fixture corpus are expanded to cover modifiers, contextual keywords, interface members, catch bindings, range queries, and many language forms.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant AxumServer
  participant Analysis
  participant Staleness
  Browser->>AxumServer: /api/fixtures, /api/fixture, /api/tokens, /api/accept
  AxumServer->>Analysis: compute_tokens / load_fixture / accept_fixture
  AxumServer->>Staleness: build_id / status
  Staleness-->>Browser: rebuild state changes
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • BoundaryML/baml#3188: Both PRs modify the LSP semantic-tokens wiring in bex_project/src/bex_lsp/multi_project/request.rs (server capabilities and the textDocument/semanticTokens/* handlers/encoding).
  • BoundaryML/baml#3425: Both PRs touch the lexical-scope infrastructure used for binding resolution, including catch/pattern binding handling in LSP-facing paths.
  • BoundaryML/baml#3555: Both PRs are in the same interface-member resolution area, including new interface-member resolution variants and their downstream handling.

Poem

🐰 I hopped through tokens, bright and neat,
With escape-sequences for a treat.
I found the fields, the catches too,
And painted every span anew.
The viewer hums, the carrots glow—
A tidy hop through semantic snow.

🚥 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 matches the main change: a resolution-first rework of semantic token classification in LSP.
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 avery/sem-tok-cleanup

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
baml_language/crates/baml_compiler2_mir/src/lower.rs (1)

6111-6145: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle captured roots in interface-method value lowering.

This path only runs when the first segment is a local. A captured receiver in let f = x.eq skips the candidate-switch branch and falls through to lower_multi_segment_path_as_field_chain, so the method value gets lowered like a field/map lookup instead of a bound-method dispatch.

🤖 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_mir/src/lower.rs` around lines 6111 -
6145, The interface-method value lowering in the path that starts by checking
self.locals for the first segment only handles plain locals, so captured
receivers like let f = x.eq bypass bound-method dispatch and get treated as
field/map chains. Update the logic in lower.rs around the method-candidate
resolution branch to recognize captured roots as valid receivers, then route
them through lower_path_receiver_to_local and emit_bound_method_candidate_switch
just like local roots, instead of falling through to
lower_multi_segment_path_as_field_chain.
🧹 Nitpick comments (1)
baml_language/crates/tools_semantic_tokens/src/analysis.rs (1)

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

Add unit tests around the offset/parser helpers.

This file is mostly pure string/offset logic, so a small #[cfg(test)] module for UTF-16 offsets, escaped snapshot lines, and text-only diff cases would give faster and more targeted coverage than end-to-end fixtures alone. As per coding guidelines, "Prefer writing Rust unit tests over integration tests where possible."

🤖 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/tools_semantic_tokens/src/analysis.rs` around lines 46 -
244, Add a focused #[cfg(test)] module in analysis.rs to unit test the pure
helpers instead of relying only on fixture flows. Cover offset_to_line_col,
utf16_offset, parse_expected, and diff_count with cases for non-ASCII/UTF-16
positioning, escaped or quoted snapshot text lines, and text-only token diffs.
Use the existing helper symbols and Token shape to keep the tests local and
resilient to line changes.

Source: Coding guidelines

🤖 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_tir/src/builder.rs`:
- Around line 12397-12405: The default-method branch in builder.rs is writing a
redundant MemberResolution::InterfaceMethod into self.resolutions that is always
overwritten later by InterfaceDefaultMethod. Remove the insert in the
default-method loop around the bound check, and keep InterfaceMethod only in the
required-method loop where no later overwrite occurs; use the existing
iface_loc/method_name and func_loc resolution paths to keep the intended
behavior clear.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_throw.baml`:
- Line 10: The semantic tokens fixture for catch handling is missing coverage
for the catch binding identifier, so update the `catch_throw.baml` expectations
to include the bound name in the `MayFail(x) catch (e) {` case and the other
referenced catch blocks. Make sure the `semantic_tokens` test asserts token
classification for the catch variable itself, not just the `catch` keyword, so
the resolution-driven identifier behavior is verified through the existing
fixture.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/constructor_spread.baml`:
- Line 8: The semantic-tokens fixture for constructor spreads is missing the
spread operand token, so extend the expected token list in the semantic token
test around the MyClass constructor spread case to include the x in ...x. Update
the fixture used by the semantic_tokens test for constructor_spread.baml (and
the related cases in the same test block) so the spread operand is asserted and
regressions in operand classification are caught.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/dynamic_type_builder.baml`:
- Around line 21-27: The semantic-tokens fixture records `functions
[ExtractResume]` but never asserts that `ExtractResume` is classified as a
function reference, so add the missing token assertion in the
`dynamic_type_builder.baml` test around `test ReturnDynamicClassTest` using the
existing semantic token expectations for `functions[...]`. Make sure the
assertion explicitly covers the `ExtractResume` identifier so regressions in
function-reference classification inside `functions [...]` are caught, and apply
the same update to the matching fixture noted in the comment.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/field_alias.baml`:
- Around line 35-37: Update the semantic tokens fixture for field alias handling
so it asserts both alias endpoints, not just the `as` keyword. In
`field_alias.baml`, expand the expectations around the `name as display_name`
alias to include tokens for the source field (`name`) and the target alias
(`display_name`) alongside the existing `as` token, using the same semantic
token test pattern used elsewhere in these fixtures.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/index_access.baml`:
- Around line 45-46: The semantic tokens fixture is incorrectly marked as
diagnostic-free even though the preceding examples document validation errors.
Update the fixture around the diagnostics marker so it no longer uses
<no-diagnostics-expected> in the index_access.baml test content; either add the
expected diagnostics for the cases shown above or split the negative examples
into a separate fixture and keep this one truly diagnostic-free. Use the
existing semantic_tokens fixture structure and diagnostics comment block to
locate the change.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_images_pipeline.baml`:
- Around line 40-41: The semantic token test only asserts the client property
key in ns_images_pipeline.baml and misses the actual client symbol reference, so
regressions in client-reference classification could go unnoticed. Update the
expected tokens in the semantic tokens test data to also assert the
AiGatewayImagenImageClient reference inside the function config, using the
existing semantic token fixture around the client/prompt entries to keep the
check tied to the relevant symbols.

In
`@baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/requires_clause.baml`:
- Around line 1-30: The semantic-tokens fixture for requires-chain coverage does
not currently exercise the transitive Aged member through Person requires Named,
Aged. Update the test content in requires_clause.baml to add a Person-typed or
self.age access that resolves age via the requires chain, so the fixture
actually validates the grandparent-interface flow instead of only the concrete
Employee field. Use the existing Person, Aged, and get_age symbols to place the
new access alongside the current example.

In `@baml_language/crates/baml_lsp2_actions/src/definition.rs`:
- Around line 426-436: The interface member resolution in definition.rs is
currently collapsing both MemberResolution::InterfaceMethod and
MemberResolution::InterfaceField to Definition::Interface, which makes
go-to-definition jump to the interface header instead of the accessed member.
Update the definition lookup in the branch handling
MemberResolution::InterfaceMethod and MemberResolution::InterfaceField to use
the member-specific identifier from the resolution and resolve the corresponding
interface method/field span, following the same pattern used by the Field and
method branches above. Ensure utils::definition_span is called with the member
declaration target rather than the interface declaration.

In `@baml_language/crates/baml_lsp2_actions/src/tokens/index.rs`:
- Around line 56-63: The token indexing logic in the scope filter is skipping
template-body scopes entirely, which leaves template interpolations like string
tokens unprocessed. Update the scope handling in the token indexer to not
unconditionally continue on scope.is_template_body, and instead let those bodies
be indexed with the same inference context as the enclosing ExprBody. Keep the
existing function/lambda/let scope checks in the token indexing flow, but ensure
template-body synthetic scopes are still traversed so resolution-driven
highlighting works.
- Around line 157-176: In tokens/index.rs, the fallback in the
path-classification logic currently marks unresolved leaf segments as Namespace,
which incorrectly masks typos as valid identifiers. Update the resolve/classify
flow around the `resolve_path_at` and `classify::classify_resolved` branch so
only non-leaf prefixes can fall back to `SemanticTokenType::Namespace`, while
the final unresolved segment stays neutral when `inference.resolution(expr_id)`
is missing and `local_root` does not apply.

In `@baml_language/crates/tools_semantic_tokens/src/analysis.rs`:
- Around line 202-207: `load_fixture` and `list_fixture_names` are swallowing
load failures by fabricating empty results, so update them to return errors
instead of defaulting to empty source or empty names. In `load_fixture`, use the
parsed file presence in `parsed.files` as a required condition and surface an
`InvalidData` error when no virtual file is available; in `list_fixture_names`,
stop flattening away `read_dir` failures and propagate the underlying I/O error.
Keep the fix localized to the `load_fixture` and `list_fixture_names` paths so
callers can distinguish “no data” from “failed to load.”
- Around line 225-243: The diff_count function is only comparing token type and
modifiers for matching position/length, so text-only snapshot drift can be
missed even when the committed semantic_tokens fixture would still change.
Update diff_count in analysis.rs to also compare the normalized committed lexeme
or raw snapshot text for each token key, and treat any text-only mismatch as a
diff alongside the existing type/modifier checks.

In `@baml_language/crates/tools_semantic_tokens/src/index.html`:
- Around line 440-445: The load-failure handler in the fixture fetch flow should
clear stale state instead of only rendering the error pane. In the catch path
around getJson in index.html, reset detail, disable the Accept control, and
clear the inspector/status state so the UI does not keep reflecting the previous
fixture after a failed /api/fixture request.
- Around line 456-469: The accept button flow in the click handler for acceptEl
leaves the control disabled after a failed /api/accept request, so the user
cannot retry without reselecting a fixture. Update the async click handler to
restore the enabled state in a finally block after the getJson("/api/accept"),
refreshFixtures(), and select(selected) sequence, and base that restore on the
current selection state (for example the same condition used before disabling).
- Around line 296-312: Stop interpolating fixture names directly into HTML
attributes in renderList(). The current esc() usage in the fixture button markup
still leaves data-name and title vulnerable because quotes are not escaped.
Update the row-building logic in renderList() to set these attributes through
DOM APIs or use an attribute-safe escape for f.name before inserting it, while
keeping the Scratchpad row consistent.
- Around line 414-427: The renderScratch flow applies any finished /api/tokens
response even if it was started for an older scratchText value, so update it to
ignore stale results. Add a request version/sequence check inside renderScratch
around the getJson("/api/tokens") call and only assign scratchTokens and render
when the response still matches the latest request for the current scratchText,
using the existing renderScratch, scratchTokens, and selected/SCRATCH logic to
locate the fix.

In `@baml_language/crates/tools_semantic_tokens/src/main.rs`:
- Around line 87-95: The port selection logic in bind can overflow when adding
the scan offset to a high preferred port. Update the loop in bind to clamp the
upper bound at u16::MAX before probing ports, so the SocketAddr construction
never wraps or panics; keep the rest of the TcpListener::bind retry behavior
unchanged and preserve the existing error path when no port is available.

In `@baml_language/crates/tools_semantic_tokens/src/server.rs`:
- Around line 183-196: resolve_fixture currently trusts Path::is_file, which
follows symlinks and can let fixture names escape fixtures_dir; update the
validation in resolve_fixture to reject symlinked entries before returning the
path. Use the existing resolve_fixture helper and its dir.join(name) result to
check the resolved candidate itself is a regular file owned inside the fixture
tree, and return an error for any symlink or non-regular path before
/api/fixture or /api/accept can use it.

In `@baml_language/crates/tools_semantic_tokens/src/staleness.rs`:
- Around line 31-37: The staleness watcher in newest_source_mtime only tracks
this crate and baml_lsp2_actions, but semantic token behavior also depends on
baml_compiler2_tir, baml_compiler2_mir, and baml_compiler_syntax. Update the
roots list (and any related watcher logic in staleness.rs) so those compiler
crates are included in the mtime scan, ensuring edits there trigger the viewer
restart and keep semantic tokens fresh.

---

Outside diff comments:
In `@baml_language/crates/baml_compiler2_mir/src/lower.rs`:
- Around line 6111-6145: The interface-method value lowering in the path that
starts by checking self.locals for the first segment only handles plain locals,
so captured receivers like let f = x.eq bypass bound-method dispatch and get
treated as field/map chains. Update the logic in lower.rs around the
method-candidate resolution branch to recognize captured roots as valid
receivers, then route them through lower_path_receiver_to_local and
emit_bound_method_candidate_switch just like local roots, instead of falling
through to lower_multi_segment_path_as_field_chain.

---

Nitpick comments:
In `@baml_language/crates/tools_semantic_tokens/src/analysis.rs`:
- Around line 46-244: Add a focused #[cfg(test)] module in analysis.rs to unit
test the pure helpers instead of relying only on fixture flows. Cover
offset_to_line_col, utf16_offset, parse_expected, and diff_count with cases for
non-ASCII/UTF-16 positioning, escaped or quoted snapshot text lines, and
text-only token diffs. Use the existing helper symbols and Token shape to keep
the tests local and resilient to line changes.
🪄 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: 3f4c5b6e-52a8-4a11-bea9-e5d65b8d4846

📥 Commits

Reviewing files that changed from the base of the PR and between d5f68a6 and 775a89e.

⛔ Files ignored due to path filters (1)
  • baml_language/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (100)
  • baml_language/Cargo.toml
  • baml_language/crates/baml_cli/src/paint.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/baml_lsp2_actions/Cargo.toml
  • baml_language/crates/baml_lsp2_actions/src/definition.rs
  • baml_language/crates/baml_lsp2_actions/src/lib.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/GAPS.md
  • baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/runner.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/array_pattern.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/attributes.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/backtick_string.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/block_attributes.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/break_continue.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/byte_strings.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/cancel_token.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_all_keyword.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_throw.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/class.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/client.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/config_dictionary.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/const_binding.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/const_let_else_defer.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/constructor_spread.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/deep_method_call.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/dynamic_type_builder.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/enum_decls.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/enum_member_access.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/exhaustive.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/extends_chain.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/field_alias.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/for_loops.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/function.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/generators.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/generic_field_chain.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/generic_function_call.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/header_comments.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/http_config.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/if_else.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/if_expression.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/if_let_chain.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/implements_for.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/index_access.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interface_impl.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_inferred_generic_type_args.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_iter_core.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/is_operator.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/iterator.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/jinja_control_prompt.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/json_map_literal.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/json_parse_stringify_intrinsics.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/lambda_advanced.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/literal_types.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/llm_function.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/map_literal_keys.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/map_type_and_methods.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/match_expr.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/match_literal_types.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/method_explicit_type_args.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/multi_segment_path.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_agent_clients.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_ansi.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_game_clients.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_images_pipeline.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_sentiment.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/patterns_new.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/remap_role.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/requires_clause.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/retry_policy_valid_retry.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/self_qualified_call.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/signature_variety.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/stream_llm_inferred_typeargs.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/task_group.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/template_string.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/template_string_calls.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/test_block.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/test_expr_throwing_body.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/testset.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/testset_vibes_nested.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/throws_clause.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/top_level_binding.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/type_alias.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/type_aliases_jinja.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/watch_let.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/while_loop.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/with_keyword.baml
  • baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
  • baml_language/crates/tools_semantic_tokens/Cargo.toml
  • baml_language/crates/tools_semantic_tokens/README.md
  • baml_language/crates/tools_semantic_tokens/src/analysis.rs
  • baml_language/crates/tools_semantic_tokens/src/index.html
  • baml_language/crates/tools_semantic_tokens/src/main.rs
  • baml_language/crates/tools_semantic_tokens/src/server.rs
  • baml_language/crates/tools_semantic_tokens/src/staleness.rs

Comment thread baml_language/crates/baml_compiler2_tir/src/builder.rs Outdated
Comment thread baml_language/crates/tools_semantic_tokens/src/index.html
Comment thread baml_language/crates/tools_semantic_tokens/src/index.html
Comment thread baml_language/crates/tools_semantic_tokens/src/main.rs Outdated
Comment thread baml_language/crates/tools_semantic_tokens/src/server.rs
Comment thread baml_language/crates/tools_semantic_tokens/src/staleness.rs Outdated
…oolean literals

Move the semantic-tokens classifier toward the rust-analyzer architecture:

- scope_resolution_index: a per-ScopeId salsa-cached resolution index
  (RA's body-granularity memoization) — editing one scope only invalidates
  that scope's index, not the whole file. build() merges them for a full
  document; resolve_token_class resolves a single name on demand (RA's
  Semantics::resolve model), walking the scope chain.
- semantic_tokens_in_range: viewport highlighting (RA's highlight_range) —
  a range-gated walk that skips out-of-range subtrees and resolves on demand,
  so only the scopes the viewport touches are ever indexed. Proven equal to
  the full result filtered to the range across every sub-range (new
  range_tokens_test).
- boolean semantic-token type: true/false -> `boolean` (was keyword). The
  inert KW_TRUE/FALSE/NULL/AS/TYPE token kinds + is_ident_token/is_keyword
  updates are laid for the principled parser-token remap (deferred: it
  ripples into hover/formatter/CST snapshots — see tokens/DESIGN.md).
- tokens/DESIGN.md + GAPS.md: target RA architecture, prerequisite parser/AST
  changes, and remaining phases (LSP range/delta wiring, flat traversal,
  parser-token remap, typed-AST accessors).
…ing)

Advertise and implement the range request: convert the LSP range to byte
offsets, call semantic_tokens_in_range (on-demand, only resolves the scopes
the viewport touches), and delta-encode via a shared encoder factored out of
the full handler. Range query proven equal to full-filtered-to-range.
…okens)

Advertise Delta + cache the last-sent tokens per file under a monotonic
result_id. The delta handler diffs the new token array against the cached one
(common prefix/suffix trim at token granularity; offsets scaled by 5 since the
LSP stream is 5 u32 per token) and returns just the edits, falling back to the
full set on a result_id miss. The full handler now emits a result_id. Diff
covered by unit tests (identical/middle/append/truncate).
Replace the recursive Walk::node dispatch with rust-analyzer's flat traverse
shape: one preorder_with_tokens() loop (Walk::run) that range-gates each
subtree, hands subtree-spanning nodes (strings, comments, type exprs, object
literals, generators) to a wholesale handler then skip_subtree, and classifies
every other token from its parent kind via the free fn classify_token
(rust-analyzer's IdentClass::classify_token model). The stateful cases
(type-alias type-kw/name, object-field key, generic-param name) read off typed
ast accessors (ObjectField::key, GenericParam::name) instead of positional
sibling scanning.

Behavior-preserving: all 440 tests pass and the 78 semantic_tokens fixtures
are byte-identical.
Make the `as` cast/projection/field-link keyword and the `type` alias /
associated-type keyword real tokens (KW_AS / KW_TYPE) instead of bare WORDs, so
the semantic-tokens classifier reads them by kind rather than by text. Updates
every token-kind consumer (the principled cleanup the remap enables):

- ast.rs: TypeAliasDef::name no longer skips a leading `type` WORD (it's KW_TYPE
  now); the five `(WORD && text=="as")` checks read KW_AS.
- baml_fmt: add TypeKw / As keyword tokens; TypeAliasDecl + AssociatedTypeDecl
  `keyword` and InterfaceFieldLink + AssociatedProjectionType `as_token` fields
  read them (drops the "type is just a WORD" workaround).
- lsp classifier: `as` classifies via is_keyword (the text-match arm is gone);
  classify_type_decl_word detects KW_TYPE for the decl-vs-binding distinction.
- 28 parser CST snapshots regenerated — purely mechanical WORD -> KW_AS/KW_TYPE
  (the meta-type value `type` correctly stays WORD).

Validated: compiler2_ast 73/73, lsp 440/440, baml_tests 2661/2665 (the 4
generic_arg_soundness failures are pre-existing WIP red tests for a known TIR
generics gap, confirmed failing on base too).
Make the boolean and null literals real tokens instead of bare WORDs, so the
semantic-tokens classifier reads them by kind (the last text-match in the
classifier's value-literal path is now backed by a real token). Updates the
token-kind consumers the remap touches:

- ast.rs: the block tail-expression accessor accepts KW_TRUE/FALSE/NULL (a
  trailing `false`/`true`/`null` is the block's value — without this a
  bool-returning function tripped E0029 "missing return value").
- baml_fmt: a KeywordLiteral token (spanning the three kinds) + a
  Literal::Keyword variant; Expression::from_cst routes the bare literal
  tokens to it (they were formatted as bare-WORD Paths before).
- 39 parser CST snapshots regenerated — purely mechanical WORD -> KW_*.

Validated: lsp 440/440, compiler2_ast 73/73, baml_tests 2661/2665 (the 4
generic_arg_soundness failures are pre-existing, fail on base).
Value-position literals are now KW_TRUE/KW_FALSE/KW_NULL (classified by kind)
and type-position ones go through type_run, so the transitional WORD text match
in token() is unreachable. The classifier no longer text-matches any literal.

@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 (1)
baml_language/crates/baml_lsp2_actions_tests/src/range_tokens_test.rs (1)

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

Exercise the new keyword remaps in this parity fixture.

This sample never emits as, type, true, false, or null, so the range/full equivalence check still skips several token kinds this PR reclassified. Adding one cast plus one boolean/null literal here would make the new range path much harder to regress.

🤖 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_lsp2_actions_tests/src/range_tokens_test.rs` around
lines 39 - 49, The parity fixture in range_equals_filtered_full still does not
exercise the newly remapped keywords, so update the sample used by check to
include at least one cast and boolean/null literals. Use the
range_tokens_test::range_equals_filtered_full test and the existing sample block
to add expressions that emit as, type, true, false, or null so the range/full
token comparison covers the reclassified token kinds.
🤖 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_compiler_syntax/src/ast.rs`:
- Around line 197-203: ObjectField::key() is only accepting SyntaxKind::WORD, so
it misses valid keys tokenized as KW_CLIENT. Update the key() accessor in ast.rs
to recognize KW_CLIENT alongside WORD when extracting the first non-trivia token
from self.syntax, so object fields named client are returned correctly and
downstream consumers can see them.

In `@baml_language/crates/baml_lsp2_actions/src/tokens/index.rs`:
- Around line 61-65: `resolve_token_class()` is caching on the raw
`scope_at_offset()` scope id, which can differ for sibling nested scopes that
still map to the same owning body. Update the memoization key to use the
inference owner scope returned by `scope_resolution_index()`/`scope_body(...)`
(the owning Function/Lambda/Let body) so identical ranges share one Salsa entry.
Keep the lookup flow in `resolve_token_class()` and `scope_resolution_index()`
aligned, and ensure any cache access in the range path uses the normalized owner
scope rather than the original scope id.

---

Nitpick comments:
In `@baml_language/crates/baml_lsp2_actions_tests/src/range_tokens_test.rs`:
- Around line 39-49: The parity fixture in range_equals_filtered_full still does
not exercise the newly remapped keywords, so update the sample used by check to
include at least one cast and boolean/null literals. Use the
range_tokens_test::range_equals_filtered_full test and the existing sample block
to add expressions that emit as, type, true, false, or null so the range/full
token comparison covers the reclassified token kinds.
🪄 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: 3de4b39f-568d-4701-b741-8daacf8f9631

📥 Commits

Reviewing files that changed from the base of the PR and between 775a89e and 2f92e91.

⛔ Files ignored due to path filters (61)
  • baml_language/crates/baml_tests/snapshots/broken_syntax/optional_parameter_defaults/baml_tests__broken_syntax__optional_parameter_defaults__02_parser__function_type_defaults.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/pending_greaters_fix/baml_tests__broken_syntax__pending_greaters_fix__02_parser__extra_greater.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/test_invalid_contexts/baml_tests__broken_syntax__test_invalid_contexts__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/type_annotation_errors/baml_tests__broken_syntax__type_annotation_errors__02_parser__type_malformed.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/config_dictionary/baml_tests__compiles__config_dictionary__02_parser__valid_dictionary.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_alias_basic/baml_tests__compiles__json_alias_basic__02_parser__json_alias_basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_map_literal/baml_tests__compiles__json_map_literal__02_parser__json_map_literal.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lambda_advanced/baml_tests__compiles__lambda_advanced__02_parser__lambda_advanced.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lexical_scoping/baml_tests__compiles__lexical_scoping__02_parser__lexical_scoping.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/literal_union_arithmetic/baml_tests__compiles__literal_union_arithmetic__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/method_explicit_type_args/baml_tests__compiles__method_explicit_type_args__02_parser__method_explicit_type_args.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_type_resolution/baml_tests__compiles__namespaces_type_resolution__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_type_resolution/baml_tests__compiles__namespaces_type_resolution__02_parser__ns_auth_auth.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_type_resolution/baml_tests__compiles__namespaces_type_resolution__02_parser__ns_llm_models.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/optional_function_parameters/baml_tests__compiles__optional_function_parameters__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/parser_expressions/baml_tests__compiles__parser_expressions__02_parser__precedence.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/parser_statements/baml_tests__compiles__parser_statements__02_parser__break_continue.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/patterns_new/baml_tests__compiles__patterns_new__02_parser__patterns_new.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/stream_crossfile/baml_tests__compiles__stream_crossfile__02_parser__file_a.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_expr_name_concat/baml_tests__compiles__test_expr_name_concat__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_raw_string_name/baml_tests__compiles__test_raw_string_name__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_basic/baml_tests__compiles__testset_basic__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_dynamic/baml_tests__compiles__testset_dynamic__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_nested/baml_tests__compiles__testset_nested__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/type_annotation/baml_tests__compiles__type_annotation__02_parser__type_alias_interaction.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/type_annotation/baml_tests__compiles__type_annotation__02_parser__type_positions.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/type_builder_test/baml_tests__compiles__type_builder_test__02_parser__test.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/attr_disambiguation/baml_tests__diagnostic_errors__attr_disambiguation__02_parser__non_field.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/backtick_strict_types/baml_tests__diagnostic_errors__backtick_strict_types__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/basic_types/baml_tests__diagnostic_errors__basic_types__02_parser__types.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/builtin_io/baml_tests__diagnostic_errors__builtin_io__02_parser__io_ops.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/builtin_io/baml_tests__diagnostic_errors__builtin_io__02_parser__shell_ops.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/catch_return_type_mismatch/baml_tests__diagnostic_errors__catch_return_type_mismatch__02_parser__catch_return_type_mismatch.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/duplicate_class_span/baml_tests__diagnostic_errors__duplicate_class_span__02_parser__repro.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__02_parser__binary_expr.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__02_parser__config_decls.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__02_parser__loop_stmts.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__02_parser__match_exprs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__02_parser__other_exprs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__02_parser__type_alias_decls.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/function_type_throws/baml_tests__diagnostic_errors__function_type_throws__02_parser__negative.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/function_types/baml_tests__diagnostic_errors__function_types__02_parser__function_types.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/generics/baml_tests__diagnostic_errors__generics__02_parser__classes.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/headers_edge_cases/baml_tests__diagnostic_errors__headers_edge_cases__02_parser__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/match_exhaustiveness/baml_tests__diagnostic_errors__match_exhaustiveness__02_parser__match_exhaustiveness.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/null_handling/baml_tests__diagnostic_errors__null_handling__02_parser__null_handling.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__02_parser__unsupported_contexts.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/parser_constructors/baml_tests__diagnostic_errors__parser_constructors__02_parser__array_constructor.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/parser_constructors/baml_tests__diagnostic_errors__parser_constructors__02_parser__map_constructor.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/stream_types/baml_tests__diagnostic_errors__stream_types__02_parser__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/stream_types/baml_tests__diagnostic_errors__stream_types__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/stream_types/baml_tests__diagnostic_errors__stream_types__02_parser__ns_foo_with_top_level_refs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/test_expr_name_type_error/baml_tests__diagnostic_errors__test_expr_name_type_error__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/test_expr_wrong_runner/baml_tests__diagnostic_errors__test_expr_wrong_runner__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/test_with_runner_ambiguity/baml_tests__diagnostic_errors__test_with_runner_ambiguity__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/type_aliases/baml_tests__diagnostic_errors__type_aliases__02_parser__type_aliases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/type_aliases/baml_tests__diagnostic_errors__type_aliases__02_parser__type_aliases_json.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/unknown_type_error/baml_tests__diagnostic_errors__unknown_type_error__02_parser__unknown_type_error.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/void_return_type/baml_tests__diagnostic_errors__void_return_type__02_parser__function_type_throws.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/void_return_type/baml_tests__diagnostic_errors__void_return_type__02_parser__void_function_type.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/void_return_type/baml_tests__diagnostic_errors__void_return_type__02_parser__void_type_position_errors.snap is excluded by !**/*.snap
📒 Files selected for processing (23)
  • baml_language/crates/baml_cli/src/paint.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/baml_fmt/src/ast/declarations.rs
  • baml_language/crates/baml_fmt/src/ast/expressions.rs
  • baml_language/crates/baml_fmt/src/ast/tokens.rs
  • baml_language/crates/baml_fmt/src/ast/types.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/DESIGN.md
  • baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/lib.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/range_tokens_test.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/break_continue.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/cancel_token.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/config_dictionary.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_inferred_generic_type_args.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_iter_core.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/watch_let.baml
  • baml_language/crates/bex_project/src/bex_lsp/multi_project/mod.rs
  • baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
✅ Files skipped from review due to trivial changes (1)
  • baml_language/crates/baml_lsp2_actions/src/tokens/DESIGN.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • baml_language/crates/baml_cli/src/paint.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/cancel_token.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/break_continue.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/config_dictionary.baml
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/watch_let.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs

Comment thread baml_language/crates/baml_compiler_syntax/src/ast.rs
Comment thread baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
- enum-variant (`Enum.Variant` patterns) and interface-field-link
  (`name as display_name`) resolve through the same package-resolution
  system as namespace/item lookup (resolve_enum_variant, resolve_field),
  verified against the type's actual variants/fields
- builtin namespaces flagged defaultLibrary; primitives unified; named/
  optional call args, bigint literals, and catch bindings classified
- typing-robustness tests (never panic on incomplete/mid-edit input):
  curated + nested-scope always-run; full-fixture sweep #[ignore]d
- parser: find_token_after_hashes returns None at EOF, fixing two
  index-out-of-bounds panics on incomplete raw strings

@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

🤖 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_lsp2_actions/src/completions.rs`:
- Around line 1319-1321: The `DefinitionSite::CatchBinding(_)` handling is still
incomplete in local-type consumers, so hover/type display can disagree with
completions. Update the `type_info.rs` logic that currently returns `"unknown"`
for `DefinitionSite::CatchBinding(_)` to resolve the catch binding type the same
way as `completions.rs` does, likely by reusing `find_binding_ty_for_local` or
the shared local-type lookup path used for `PatternBinding` and `CatchBinding`
in `find_binding_ty_for_local`/`DefinitionSite` matching.

In `@baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs`:
- Around line 17-45: The builtin type allowlist in classify_primitive is
incomplete, so add the missing primitive names to PRIMITIVE_TYPES. Update the
PRIMITIVE_TYPES list in classify.rs to include void and type so
classify_primitive continues returning SemanticTokenType::Type with
ModifierSet::DEFAULT_LIBRARY for all builtin types.
🪄 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: 81e11b9c-3521-4821-96bc-4475180189f8

📥 Commits

Reviewing files that changed from the base of the PR and between 2f92e91 and 2d5b70f.

📒 Files selected for processing (39)
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/semantic_index.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_tir/src/resolve.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_lsp2_actions/src/completions.rs
  • baml_language/crates/baml_lsp2_actions/src/definition.rs
  • baml_language/crates/baml_lsp2_actions/src/describe.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
  • baml_language/crates/baml_lsp2_actions/src/type_info.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/lib.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/range_tokens_test.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/typing_robustness_test.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/bigint_literals.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/call_named_args.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/cancel_token.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_all_keyword.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_param.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_throw.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/exhaustive.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/field_alias.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_inferred_generic_type_args.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/iterator.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/json_parse_stringify_intrinsics.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_ansi.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_game_clients.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/patterns_new.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/stream_llm_inferred_typeargs.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/task_group.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/testset.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/testset_vibes_nested.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/with_keyword.baml
  • baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
  • baml_language/crates/tools_semantic_tokens/src/server.rs
  • baml_language/crates/tools_semantic_tokens/src/staleness.rs
✅ Files skipped from review due to trivial changes (1)
  • baml_language/crates/baml_lsp2_actions_tests/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (25)
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/testset.baml
  • baml_language/crates/baml_lsp2_actions_tests/src/range_tokens_test.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/field_alias.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_throw.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/json_parse_stringify_intrinsics.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/testset_vibes_nested.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/with_keyword.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/catch_all_keyword.baml
  • baml_language/crates/baml_lsp2_actions/src/definition.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/iterator.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/task_group.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/stream_llm_inferred_typeargs.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_ansi.baml
  • baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/exhaustive.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_game_clients.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/cancel_token.baml
  • baml_language/crates/tools_semantic_tokens/src/server.rs
  • baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/tools_semantic_tokens/src/staleness.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/patterns_new.baml
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs

Comment thread baml_language/crates/baml_lsp2_actions/src/completions.rs
Comment thread baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs
- builder.rs (tir): drop redundant InterfaceMethod resolution that is
  always clobbered by InterfaceDefaultMethod in the same iteration
- ast.rs: ObjectField::key() accepts KW_CLIENT (client-named object fields)
- definition.rs + item_tree/builder (hir): interface member go-to-def jumps
  to the member, not the interface header (interface field/method span
  plumbing mirroring the class-field/enum-variant pattern) + regression tests
- tokens/index.rs: normalize the range-path resolution cache key to the
  inference-owner scope so sibling block/template scopes share one entry
- viewer (tools_semantic_tokens): surface fixture load failures instead of
  empty results; count text-only snapshot drift as a diff; escape fixture
  names in HTML attributes; discard stale /api/tokens responses; clear state
  on load failure; re-enable Accept after a failed save; clamp port scan to
  u16::MAX; reject symlinked fixtures; watch the compiler crates
- requires_clause fixture: exercise the transitive requires-chain member

Skipped 5 stale/incorrect comments (classifier emits no token for the cited
positions, or the flagged sections are genuine auto-generated output).

@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

♻️ Duplicate comments (1)
baml_language/crates/tools_semantic_tokens/src/index.html (1)

498-498: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don't overwrite the Accept state with selected === SCRATCH.

Line 498 clobbers the state that select()/fixture rendering just computed. That can re-enable Accept after the load-failure path at Lines 463-472, and after a successful accept it can turn the button back on even when the refreshed fixture has no diffs.

Suggested fix
         } finally {
-          acceptEl.disabled = selected === SCRATCH;
+          acceptEl.disabled =
+            selected === SCRATCH || !detail || detail.diff_count === 0;
         }
🤖 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/tools_semantic_tokens/src/index.html` at line 498, The
Accept button state in the fixture rendering flow is being overwritten by the
`selected === SCRATCH` assignment, which clobbers the state already computed by
`select()` and the load-failure handling. Update the logic around `select()`,
the fixture rendering path, and the `acceptEl` state update so
`acceptEl.disabled` reflects the real computed acceptability instead of being
reset based on `SCRATCH`; keep the existing failure and post-accept refresh
behavior intact.
🤖 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_lsp2_actions/src/definition_at_tests.rs`:
- Around line 459-461: The definition-at tests are too permissive because
snippets like "-> fullname" and "-> encode" can match both the interface
declaration and other locations such as alias entries or impl methods. Update
the assertions in definition_at_tests to verify a unique target location/snippet
for each case, using the existing test helpers and descriptions around the
fullname and encode checks, so the tests only pass when navigation lands on the
interface declaration itself and not the impl site.

---

Duplicate comments:
In `@baml_language/crates/tools_semantic_tokens/src/index.html`:
- Line 498: The Accept button state in the fixture rendering flow is being
overwritten by the `selected === SCRATCH` assignment, which clobbers the state
already computed by `select()` and the load-failure handling. Update the logic
around `select()`, the fixture rendering path, and the `acceptEl` state update
so `acceptEl.disabled` reflects the real computed acceptability instead of being
reset based on `SCRATCH`; keep the existing failure and post-accept refresh
behavior intact.
🪄 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: b12c1d8f-fe97-4f01-bc94-68cbb9e92ef1

📥 Commits

Reviewing files that changed from the base of the PR and between 2d5b70f and beb3a0c.

📒 Files selected for processing (14)
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_lsp2_actions/src/definition.rs
  • baml_language/crates/baml_lsp2_actions/src/definition_at_tests.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/requires_clause.baml
  • baml_language/crates/tools_semantic_tokens/src/analysis.rs
  • baml_language/crates/tools_semantic_tokens/src/index.html
  • baml_language/crates/tools_semantic_tokens/src/main.rs
  • baml_language/crates/tools_semantic_tokens/src/server.rs
  • baml_language/crates/tools_semantic_tokens/src/staleness.rs
💤 Files with no reviewable changes (1)
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • baml_language/crates/baml_lsp2_actions/src/definition.rs
  • baml_language/crates/tools_semantic_tokens/src/main.rs
  • baml_language/crates/tools_semantic_tokens/src/staleness.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/requires_clause.baml
  • baml_language/crates/baml_lsp2_actions/src/tokens/index.rs
  • baml_language/crates/tools_semantic_tokens/src/server.rs
  • baml_language/crates/tools_semantic_tokens/src/analysis.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs

Comment thread baml_language/crates/baml_lsp2_actions/src/definition_at_tests.rs Outdated
Resolved the semantic_tokens fixture conflicts by regenerating their
snapshot blocks (//- sections only; fixture sources were identical on
both sides). Post-merge suite green (745 passed).
@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

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 21.6 MB 9.2 MB file 21.5 MB +57.0 KB (+0.3%) OK
packed-program Linux 🔒 15.7 MB 6.6 MB file 15.6 MB +56.0 KB (+0.4%) OK
baml-cli macOS 🔒 16.6 MB 8.0 MB file 16.6 MB +33.3 KB (+0.2%) OK
packed-program macOS 🔒 12.1 MB 5.8 MB file 12.1 MB +33.3 KB (+0.3%) OK
baml-cli Windows 🔒 18.2 MB 8.2 MB file 18.1 MB +45.6 KB (+0.3%) OK
packed-program Windows 🔒 13.1 MB 5.9 MB file 13.0 MB +45.3 KB (+0.3%) OK
bridge_wasm WASM 14.4 MB 🔒 4.1 MB gzip 4.1 MB +18.2 KB (+0.4%) 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

Latest canary (catch/match-arm `return` support, #3881). Clean merge with
no conflicts; workspace compiles and 750 affected-crate tests pass.
- classify.rs: add `void` to PRIMITIVE_TYPES so it highlights as a
  defaultLibrary builtin type like the other primitives (`type` is the
  KW_TYPE keyword, not a builtin type, so it is intentionally not added)
- type_info.rs: resolve catch/pattern binding types in hover via the shared
  inference lookup (was always "unknown"), so hover agrees with completions
- definition_at_tests.rs: assert the exact interface-declaration location
  (3:3 / 3:12) so the go-to-def tests can't pass on the alias/impl site
- regenerate ns_game_clients, test_expr_throwing_body (void) and the
  hover_catch_binding fixture (resolved error-union type)
- stow.toml: approve `semantic` prefix for the tools namespace
- Cargo.toml: register baml_lsp2_actions_tests as a workspace dependency;
  tools_semantic_tokens uses `{ workspace = true }` (stow validation)
- tokens.rs: fix two public->private intra-doc links so `cargo doc`
  passes under `-D warnings`
- tokens.rs: classify value-position `null` through the shared builtin
  classification (defaultLibrary `type`) so it matches its type position
  and every other builtin instead of reading as a keyword
- regenerate semantic_tokens fixtures for the null change
DESIGN.md and GAPS.md were working notes for the semantic-tokens rework.
validate-markdown only allows README.md or whitelisted long-term docs, so
drop them rather than whitelist throwaway notes.

@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_lsp2_actions/src/type_info.rs`:
- Around line 708-717: The binding-type lookup in type_info.rs is starting from
the enclosing function scope via infer_scope_types, which can return a
same-index PatId from the wrong body before the nested scope is checked. Update
the hover/type resolution logic in the binding-type lookup path to prefer
find_binding_ty_in_scopes(db, index, scope_id, pat_id) as the primary source and
avoid using func_scope_id-first probing for body-local pattern/catch bindings.
Keep the existing display_local_binding_ty formatting, but ensure the lookup
follows the current scope chain so closures and nested blocks resolve the
correct binding type.
🪄 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: 2fa702f1-64ea-4318-a5c2-102218f8b5a5

📥 Commits

Reviewing files that changed from the base of the PR and between 012f821 and ecc17a6.

📒 Files selected for processing (23)
  • baml_language/Cargo.toml
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/baml_fmt/src/ast/expressions.rs
  • baml_language/crates/baml_lsp2_actions/src/definition_at_tests.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs
  • baml_language/crates/baml_lsp2_actions/src/type_info.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_iter_core.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/json_map_literal.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/lambda_advanced.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/method_explicit_type_args.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_game_clients.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/test_expr_throwing_body.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/hover/catch_binding.baml
  • baml_language/crates/tools_semantic_tokens/Cargo.toml
  • baml_language/stow.toml
✅ Files skipped from review due to trivial changes (4)
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/hover/catch_binding.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/test_expr_throwing_body.baml
  • baml_language/stow.toml
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
🚧 Files skipped from review as they are similar to previous changes (16)
  • baml_language/crates/tools_semantic_tokens/Cargo.toml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/json_map_literal.baml
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_lsp2_actions/src/definition_at_tests.rs
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/method_explicit_type_args.baml
  • baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs
  • baml_language/crates/baml_fmt/src/ast/expressions.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/lambda_advanced.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/interfaces_sort_comparable.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/ns_game_clients.baml
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs

Comment on lines +708 to +717
let func_scope_id = index.scope_ids[enclosing_func_scope.index() as usize];
let inference = baml_compiler2_tir::inference::infer_scope_types(db, func_scope_id);
let ty_str = inference
.binding_type(pat_id)
.map(|ty| display_local_binding_ty(db, file, ty))
.or_else(|| {
find_binding_ty_in_scopes(db, index, scope_id, pat_id)
.map(|ty| display_local_binding_ty(db, file, &ty))
})
.unwrap_or_else(|| "unknown".to_string());

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Start this binding-type lookup from the current scope chain.

PatId is body-local, so probing infer_scope_types(db, func_scope_id) first can pick up a same-index binding from the enclosing function body before we ever reach the real nested scope. That gives the wrong hover type for pattern/catch bindings inside closures or nested blocks. find_binding_ty_in_scopes(db, index, scope_id, pat_id) is already the collision-safe path here.

Suggested fix
-            let func_scope_id = index.scope_ids[enclosing_func_scope.index() as usize];
-            let inference = baml_compiler2_tir::inference::infer_scope_types(db, func_scope_id);
-            let ty_str = inference
-                .binding_type(pat_id)
-                .map(|ty| display_local_binding_ty(db, file, ty))
-                .or_else(|| {
-                    find_binding_ty_in_scopes(db, index, scope_id, pat_id)
-                        .map(|ty| display_local_binding_ty(db, file, &ty))
-                })
+            let ty_str = find_binding_ty_in_scopes(db, index, scope_id, pat_id)
+                .map(|ty| display_local_binding_ty(db, file, &ty))
                 .unwrap_or_else(|| "unknown".to_string());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let func_scope_id = index.scope_ids[enclosing_func_scope.index() as usize];
let inference = baml_compiler2_tir::inference::infer_scope_types(db, func_scope_id);
let ty_str = inference
.binding_type(pat_id)
.map(|ty| display_local_binding_ty(db, file, ty))
.or_else(|| {
find_binding_ty_in_scopes(db, index, scope_id, pat_id)
.map(|ty| display_local_binding_ty(db, file, &ty))
})
.unwrap_or_else(|| "unknown".to_string());
let ty_str = find_binding_ty_in_scopes(db, index, scope_id, pat_id)
.map(|ty| display_local_binding_ty(db, file, &ty))
.unwrap_or_else(|| "unknown".to_string());
🤖 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_lsp2_actions/src/type_info.rs` around lines 708 -
717, The binding-type lookup in type_info.rs is starting from the enclosing
function scope via infer_scope_types, which can return a same-index PatId from
the wrong body before the nested scope is checked. Update the hover/type
resolution logic in the binding-type lookup path to prefer
find_binding_ty_in_scopes(db, index, scope_id, pat_id) as the primary source and
avoid using func_scope_id-first probing for body-local pattern/catch bindings.
Keep the existing display_local_binding_ty formatting, but ensure the lookup
follows the current scope chain so closures and nested blocks resolve the
correct binding type.

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