Skip to content

Deduplicate repeated Rust logic in baml_language - #4126

Closed
codeshaunted wants to merge 73 commits into
canaryfrom
code-dedup-audit
Closed

Deduplicate repeated Rust logic in baml_language#4126
codeshaunted wants to merge 73 commits into
canaryfrom
code-dedup-audit

Conversation

@codeshaunted

@codeshaunted codeshaunted commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Centralize 65 accepted instances of duplicated Rust logic in baml_language.
  • Preserve existing behavior, APIs, and features.
  • Remove 2,366 lines overall (+1,818/-4,184) against current canary.
  • Add no new regression tests or fixtures; rely on the existing suites.
  • Leave conditional and rejected audit items unchanged.

Validation

  • mise exec -- env -u RUSTC_WRAPPER cargo check --workspace --all-targets --all-features --locked
  • cargo fmt --all -- --check
  • Existing affected compiler, parser, type, runtime, CLI, bridge, LSP, and SDK test suites
  • git diff --check
  • Final semantic and ASCII-only review

Summary by CodeRabbit

  • User Experience
    • Reduced verbose progress and timing output from baml run for cleaner command-line results.
    • Improved value-capture-loss diagnostics in runtime and playground traces.
    • Standardized formatting for function calls, declarations, expressions, and type definitions.
  • Bug Fixes
    • Improved parsing of nested generics, raw strings, quoted strings, maps, and object fields.
    • Improved optional chaining, type conversion fallbacks, and unresolved-member handling.
    • Improved HTTP response logging and media handling across supported integrations.
  • SDKs
    • Improved generated documentation for thrown errors and Python package stubs.
    • Unified function-call argument handling across language bridges.

@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jul 24, 2026 1:53am
promptfiddle Ready Ready Preview, Comment Jul 24, 2026 1:53am
promptfiddle2 Ready Ready Preview, Comment Jul 24, 2026 1:53am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR consolidates duplicated helpers across compiler, parser, formatter, runtime, event, bridge, LLM, SDK, and tooling crates. It also removes obsolete CLI logging, cached string hashes, unused dependencies, and repeated unsafe Salsa update implementations.

Changes

Compiler and runtime consolidation

Layer / File(s) Summary
Shared compiler and type helpers
baml_base/..., baml_compiler2_*, baml_type/...
Salsa updates, type attributes, nullable unions, signatures, lowering, inference, and MIR traversal now use shared helpers.
Parser, syntax, and formatter helpers
baml_compiler_parser/..., baml_compiler_syntax/..., baml_fmt/...
Generic delimiters, string parsing, AST names, key-value parsing, and list formatting are centralized.
Runtime and event paths
bex_events/..., bex_heap/..., bex_vm/...
Framing, history writes, diagnostics, heap traversal, forwarding, coercion, and array continuations reuse common implementations.

Bridges, SDKs, and tooling

Layer / File(s) Summary
Bridge and system operations
bridge_cffi/..., bridge_wasm/..., sys_native/..., sys_ops/...
Call decoding, media handles, JS errors, run setup, HTTP bodies, output writes, and HTTP slot wiring are shared.
LLM and SDK generation
sys_llm/..., sdkgen_*/...
Media conversion, response parsing, token usage, throws metadata, imports, stubs, and generated documentation use common helpers.
CLI, LSP, and reporting cleanup
baml_cli/..., baml_lsp2_actions/..., baml_lsp_server/..., tools_size_gate/...
Verbose CLI output, semantic-token mapping, listings, reference locations, glob handling, and size-gate formatting are consolidated or removed.

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

Possibly related PRs

Suggested reviewers: aaronvg, hellovai, antoniosarosi

Poem

I’m a rabbit with helpers to share,
Tidying pointers and parsers with care.
Logs fade away, hashes take flight,
Bridges and SDKs now hop just right.
Fewer loops, one path to the moon—
The compiler hums a cleaner tune.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: broad deduplication of repeated Rust logic across baml_language.
✨ 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 code-dedup-audit

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

❤️ Share

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

@github-actions

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

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

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

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

@vercel
vercel Bot temporarily deployed to Preview – beps July 22, 2026 21:19 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 22, 2026 21:26 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 22, 2026 21:27 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 22, 2026 21:35 Inactive
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 26.9 MB 11.5 MB file 26.2 MB +738.6 KB (+2.8%) OK
packed-program Linux 🔒 17.4 MB 7.2 MB file 17.0 MB +388.8 KB (+2.3%) OK
baml-cli macOS 🔒 20.9 MB 10.0 MB file 20.3 MB +579.6 KB (+2.9%) OK
packed-program macOS 🔒 13.6 MB 6.3 MB file 13.2 MB +330.8 KB (+2.5%) OK
baml-cli Windows 🔒 22.5 MB 10.2 MB file 21.9 MB +633.3 KB (+2.9%) OK
packed-program Windows 🔒 14.5 MB 6.4 MB file 14.2 MB +334.1 KB (+2.4%) OK
bridge_wasm WASM 16.4 MB 🔒 4.5 MB gzip 4.4 MB +70.3 KB (+1.6%) 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

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 22, 2026 21:48 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 18:55 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 23, 2026 19:02 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 23, 2026 19:23 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 20:35 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 23, 2026 20:43 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 23, 2026 20:55 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 21:09 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 21:11 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 22:42 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 22:49 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 22:57 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 23:03 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 23:10 Inactive
@codeshaunted codeshaunted changed the title Remove inert code paths identified by audit Deduplicate repeated Rust logic in baml_language Jul 23, 2026
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 23, 2026 23:18 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 23, 2026 23:31 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps July 24, 2026 00:53 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 24, 2026 01:00 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 24, 2026 01:13 Inactive
# Conflicts:
#	baml_language/crates/baml_cli/src/run_command.rs
#	baml_language/crates/baml_codegen_types/src/symbols.rs
#	baml_language/crates/baml_compiler2_mir/src/optimize.rs
#	baml_language/crates/baml_compiler2_ppir/src/lib.rs
#	baml_language/crates/baml_compiler_parser/src/parser.rs
#	baml_language/crates/baml_compiler_syntax/src/ast.rs
#	baml_language/crates/baml_type/src/runtime_ty.rs
#	baml_language/crates/bex_events/src/run.rs
#	baml_language/crates/sys_native/src/registry.rs
#	baml_language/crates/sys_ops/src/lib.rs
@vercel
vercel Bot temporarily deployed to Preview – beps July 24, 2026 01:33 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: 4

🧹 Nitpick comments (2)
baml_language/crates/baml_fmt/src/ast/mod.rs (2)

26-102: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

New shared formatter helpers introduced without unit tests. Both sites extract previously-duplicated printing logic into new, widely-reused private helpers, but the PR adds no new tests (per PR objectives, only existing suites are relied on). As per path instructions (**/*.rs: "Prefer writing Rust unit tests over integration tests where possible"), these are good candidates for direct unit tests given their reuse across many Printable impls.

  • baml_language/crates/baml_fmt/src/ast/mod.rs#L26-L102: add unit tests for try_print_single_line_comma_separated and print_multi_line_parenthesized_comma_separated covering comma/trivia edge cases (explicit vs. synthesized comma, width overflow bail-out, trailing trivia after last item).
  • baml_language/crates/baml_fmt/src/ast/declarations.rs#L14-L49: add unit tests for print_braced_declaration_items covering empty-items, single-item, and leading-blank-trim-on-first-item cases.
🤖 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_fmt/src/ast/mod.rs` around lines 26 - 102, Add
focused Rust unit tests for try_print_single_line_comma_separated and
print_multi_line_parenthesized_comma_separated in
baml_language/crates/baml_fmt/src/ast/mod.rs, covering explicit and synthesized
commas, width-overflow bailout, and trailing trivia after the final item. Also
add tests for print_braced_declaration_items in
baml_language/crates/baml_fmt/src/ast/declarations.rs covering empty items, a
single item, and trimming leading blank space from the first item.

Source: Path instructions


26-63: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

New shared comma-separated list printers lack dedicated unit tests.

try_print_single_line_comma_separated and print_multi_line_parenthesized_comma_separated are now the single source of truth for comma-separated printing across AttributeArgs, CallArgs, FunctionType params, ObjectInitializer, and MapLiteral. As per path instructions, prefer unit tests for new Rust logic; a bug here would ripple across all of these printers simultaneously.

Also applies to: 64-102

🤖 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_fmt/src/ast/mod.rs` around lines 26 - 63, Add
dedicated unit tests for try_print_single_line_comma_separated and
print_multi_line_parenthesized_comma_separated, covering comma handling, trivia,
empty and single-item lists, and multiline fallback behavior. Exercise the
shared printers directly or through representative AttributeArgs/CallArgs-style
inputs, ensuring expected single-line and parenthesized multiline output.

Source: Path instructions

🤖 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_parser/src/parser.rs`:
- Around line 1863-1898: Update parse_quoted_content’s escape handling to use
bump_one_token_raw() for consuming the token after a backslash, matching
parse_backtick_content and ensuring escaped whitespace immediately before a
closing quote is consumed without skipping trivia. Preserve the existing escape
and termination behavior, and add Rust unit coverage for both "\<space>" and
b"\<space>" cases.

In `@baml_language/crates/baml_lsp_server/src/playground_http.rs`:
- Around line 59-87: Update the fetch handling around the asynchronous match arm
to apply the same ingest_fetch_updated and FetchLogUpdate side effects when
read(response) returns a successful synchronous SysOpOutput::Ready value.
Preserve the existing response body and metadata handling, and ensure both
wrapped output modes (text and json) are covered while errors and asynchronous
results retain their current behavior.

In `@baml_language/crates/baml_type/src/lib.rs`:
- Around line 345-377: The `strip_null` contract conflicts with its fast path,
which unwraps single-member non-null unions. Either preserve such unions
unchanged by removing or adjusting the fast path, or, if normalization is
intentional, update `strip_null`’s documentation and add a targeted Rust unit
test covering `Ty::union([Ty::Int])` becoming `Ty::Int`.

In `@baml_language/crates/bridge_cffi/src/ffi/handle.rs`:
- Around line 200-203: Update the safety documentation for the FFI function
around out_key and out_type, including the corresponding contracts at the
additionally affected declarations, to state that both output pointers are
required and must be valid for writing one pointee value; remove the allowance
that either pointer may be null, matching the existing UnexpectedNullptr
validation.

---

Nitpick comments:
In `@baml_language/crates/baml_fmt/src/ast/mod.rs`:
- Around line 26-102: Add focused Rust unit tests for
try_print_single_line_comma_separated and
print_multi_line_parenthesized_comma_separated in
baml_language/crates/baml_fmt/src/ast/mod.rs, covering explicit and synthesized
commas, width-overflow bailout, and trailing trivia after the final item. Also
add tests for print_braced_declaration_items in
baml_language/crates/baml_fmt/src/ast/declarations.rs covering empty items, a
single item, and trimming leading blank space from the first item.
- Around line 26-63: Add dedicated unit tests for
try_print_single_line_comma_separated and
print_multi_line_parenthesized_comma_separated, covering comma handling, trivia,
empty and single-item lists, and multiline fallback behavior. Exercise the
shared printers directly or through representative AttributeArgs/CallArgs-style
inputs, ensuring expected single-line and parenthesized multiline output.
🪄 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: 1495ec11-9221-47e8-8892-52b0f87bbc49

📥 Commits

Reviewing files that changed from the base of the PR and between b632533 and 5273ad5.

⛔ Files ignored due to path filters (1)
  • baml_language/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (83)
  • baml_language/crates/baml/src/main.rs
  • baml_language/crates/baml_base/src/attr.rs
  • baml_language/crates/baml_base/src/salsa_update.rs
  • baml_language/crates/baml_cli/src/paint.rs
  • baml_language/crates/baml_codegen_types/src/symbols.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler2_hir/src/signature.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_mir/src/optimize.rs
  • baml_language/crates/baml_compiler2_ppir/src/lib.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_fmt/src/ast/attributes.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/mod.rs
  • baml_language/crates/baml_fmt/src/ast/types.rs
  • baml_language/crates/baml_lsp2_actions/src/describe.rs
  • baml_language/crates/baml_lsp2_actions/src/lib.rs
  • baml_language/crates/baml_lsp2_actions/src/listing.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens/classify.rs
  • baml_language/crates/baml_lsp_server/Cargo.toml
  • baml_language/crates/baml_lsp_server/src/native_vfs.rs
  • baml_language/crates/baml_lsp_server/src/playground_http.rs
  • baml_language/crates/baml_lsp_server/src/playground_server.rs
  • baml_language/crates/baml_project/src/db.rs
  • baml_language/crates/baml_release/src/skills.rs
  • baml_language/crates/baml_type/src/codegen_ty.rs
  • baml_language/crates/baml_type/src/lib.rs
  • baml_language/crates/baml_type/src/runtime_ty.rs
  • baml_language/crates/baml_type/src/simplify_sap.rs
  • baml_language/crates/baml_type_runtime/src/lib.rs
  • baml_language/crates/bex_engine/src/value_capture.rs
  • baml_language/crates/bex_events/src/framing.rs
  • baml_language/crates/bex_events/src/history/mod.rs
  • baml_language/crates/bex_events/src/lib.rs
  • baml_language/crates/bex_events/src/prof/read.rs
  • baml_language/crates/bex_events/src/run.rs
  • baml_language/crates/bex_events/src/value/read.rs
  • baml_language/crates/bex_heap/src/gc.rs
  • baml_language/crates/bex_project/src/fs.rs
  • baml_language/crates/bex_project/src/lib.rs
  • baml_language/crates/bex_sap/src/deserializer/coercer/coerce_literal.rs
  • baml_language/crates/bex_sap/src/deserializer/coercer/mod.rs
  • baml_language/crates/bex_vm/src/package_baml/array.rs
  • baml_language/crates/bex_vm/src/package_baml/json.rs
  • baml_language/crates/bex_vm/src/package_baml/mod.rs
  • baml_language/crates/bex_vm/src/package_baml/root.rs
  • baml_language/crates/bridge_cffi/src/ffi/handle.rs
  • baml_language/crates/bridge_cffi/src/lib.rs
  • baml_language/crates/bridge_wasm/src/error.rs
  • baml_language/crates/bridge_wasm/src/lib.rs
  • baml_language/crates/bridge_wasm/src/wasm_http.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/pretty_print.rs
  • baml_language/crates/sys_llm/src/build_request/openai/chat_completions.rs
  • baml_language/crates/sys_llm/src/build_request/openai/mod.rs
  • baml_language/crates/sys_llm/src/build_request/openai/responses.rs
  • baml_language/crates/sys_llm/src/parse_response/google.rs
  • baml_language/crates/sys_llm/src/parse_response/openai/chat_completions.rs
  • baml_language/crates/sys_llm/src/parse_response/openai/mod.rs
  • baml_language/crates/sys_llm/src/parse_response/openai/responses.rs
  • baml_language/crates/sys_native/src/io_impls.rs
  • baml_language/crates/sys_native/src/registry.rs
  • baml_language/crates/sys_ops/src/lib.rs
  • baml_language/crates/tools_size_gate/src/compare.rs
  • baml_language/crates/tools_size_gate/src/main.rs
  • baml_language/crates/tools_size_gate/src/output.rs
  • baml_language/sdks/java/bridge_java/Cargo.toml
  • baml_language/sdks/java/bridge_java/src/lib.rs
  • baml_language/sdks/java/sdkgen_java/src/emit.rs
  • baml_language/sdks/python/rust/bridge_python/Cargo.toml
  • baml_language/sdks/python/rust/bridge_python/src/runtime.rs
  • baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/emit/mod.rs
  • baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs
  • baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/lib.rs
  • baml_language/sdks/rust/sdkgen_rust/src/emit/function.rs
  • baml_language/sdks/typescript/bridge_typescript/Cargo.toml
  • baml_language/sdks/typescript/bridge_typescript/src/runtime.rs
  • baml_language/sdks/typescript/sdkgen_typescript_shared/src/emit/mod.rs
  • baml_language/sdks/typescript/sdkgen_typescript_shared/src/leaf.rs
💤 Files with no reviewable changes (5)
  • baml_language/sdks/java/bridge_java/Cargo.toml
  • baml_language/sdks/typescript/bridge_typescript/Cargo.toml
  • baml_language/crates/baml_lsp_server/Cargo.toml
  • baml_language/crates/baml_base/src/salsa_update.rs
  • baml_language/sdks/python/rust/bridge_python/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (3)
  • baml_language/crates/baml_compiler2_ppir/src/lib.rs
  • baml_language/crates/bex_heap/src/gc.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs

Comment on lines +1863 to 1898
p.parse_quoted_content(
"String parsing exceeded iteration limit",
"Unclosed string literal",
);
});

// Collect all tokens until closing quote.
// Use at_end_raw / at_raw / bump_raw throughout so that `*/`
// and `//` inside the string are kept as literal content instead
// of being mis-recognised as comment delimiters.
let mut loop_counter = 0;
while !p.at_end_raw() {
loop_counter += 1;
if loop_counter > 100_000 {
p.error_unexpected_token("String parsing exceeded iteration limit".to_string());
return;
}
true
}

if p.at_raw(TokenKind::Backslash) {
p.bump_raw(); // Consume backslash
if p.current < p.tokens.len() {
p.bump_raw(); // Consume the escaped character (whatever it is)
}
continue;
}
/// Uses raw token navigation so comment-looking content remains literal text.
fn parse_quoted_content(&mut self, iteration_limit_error: &str, unclosed_error: &str) {
let mut loop_counter = 0;
while !self.at_end_raw() {
loop_counter += 1;
if loop_counter > 100_000 {
self.error_unexpected_token(iteration_limit_error.to_string());
return;
}

if p.at_raw(TokenKind::Quote) {
p.bump_raw(); // Consume closing quote
return;
if self.at_raw(TokenKind::Backslash) {
self.bump_raw();
if self.current < self.tokens.len() {
self.bump_raw();
}
p.bump_raw();
continue;
}

p.error_unexpected_token("Unclosed string literal".to_string());
});
if self.at_raw(TokenKind::Quote) {
self.bump_raw();
return;
}
self.bump_raw();
}

true
self.error_unexpected_token(unclosed_error.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 | 🟡 Minor | ⚡ Quick win

parse_quoted_content's escape handling can overshoot into the closing quote.

The second bump_raw() for the escape target doesn't consume exactly one token — bump_raw/bump_impl(false) still skips leading basic trivia (whitespace/newline) before landing on a real token. So a literal like "\<space>" (escaped trailing space right before the closing quote) will have the space skipped as "leading trivia" and the closing " consumed as the escape target instead, leaving the string unclosed/mis-tokenized.

This is the exact same class of bug already found and fixed elsewhere in this file for backtick strings (parse_backtick_content, "ultrareview bug_011"), which deliberately uses bump_one_token_raw() for this reason. parse_quoted_content (now shared by parse_string and parse_byte_string) should do the same.

🐛 Proposed fix
             if self.at_raw(TokenKind::Backslash) {
                 self.bump_raw();
                 if self.current < self.tokens.len() {
-                    self.bump_raw();
+                    self.bump_one_token_raw();
                 }
                 continue;
             }

As per path instructions, **/*.rs: "Prefer writing Rust unit tests over integration tests where possible" — a regression test for "\<space>" and b"\<space>" right before the closing quote would pin this fix.

Also applies to: 1925-1929

🤖 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_compiler_parser/src/parser.rs` around lines 1863 -
1898, Update parse_quoted_content’s escape handling to use bump_one_token_raw()
for consuming the token after a backslash, matching parse_backtick_content and
ensuring escaped whitespace immediately before a closing quote is consumed
without skipping trivia. Preserve the existing escape and termination behavior,
and add Rust unit coverage for both "\<space>" and b"\<space>" cases.

Source: Path instructions

Comment on lines +59 to +87
match (fetch_info, read(response)) {
(Some((host_call_id, fetch_id)), SysOpOutput::Async(fut)) => {
SysOpOutput::async_op_with_throw(async move {
let body = fut.await?;
let (body_size, response_body) = describe(&body);
if let Some(patch) = state.run_store.ingest_fetch_updated(
&HostCallId::Native(host_call_id),
fetch_id,
None,
None,
Vec::new(),
Some(body_size),
None,
) {
broadcast_run_patch(&state.broadcast_tx, &patch);
}
let _ = state.broadcast_tx.send(WsOutMessage::FetchLogUpdate {
call_id: host_call_id.0,
log_id: fetch_id,
status: None,
duration_ms: None,
response_headers: None,
response_body: Some(response_body),
error: None,
});
Ok(body)
})
}
(_, native_result) => native_result,

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 4 'enum SysOpOutput|SysOpOutput::Ready|fn read_response_body' baml_language

Repository: BoundaryML/baml

Length of output: 13917


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant playground_http implementation around the wrapper and caller paths.
sed -n '1,120p' baml_language/crates/baml_lsp_server/src/playground_http.rs
echo '--- caller section ---'
sed -n '360,405p' baml_language/crates/baml_lsp_server/src/playground_http.rs

# Find tests for read_response_body/playground http wrappers.
printf '\nTests matching read_response_body/playground_http:\n'
rg -n "read_response_body|PlaygroundHttp|FetchLogUpdate|ingest_fetch_updated" baml_language/crates/baml_lsp_server/tests baml_language/crates/baml_lsp_server/src || true

Repository: BoundaryML/baml

Length of output: 9494


Handle successful synchronous fetch responses.

The text and json wrapper branches convert successful synchronous responses to SysOpOutput::Ready, so successful synchronous reads fall through read_response_body without ingest_fetch_updated/FetchLogUpdate updates. Apply the same side effects to the ready-success path and cover both output modes.

🤖 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_lsp_server/src/playground_http.rs` around lines 59
- 87, Update the fetch handling around the asynchronous match arm to apply the
same ingest_fetch_updated and FetchLogUpdate side effects when read(response)
returns a successful synchronous SysOpOutput::Ready value. Preserve the existing
response body and metadata handling, and ensure both wrapped output modes (text
and json) are covered while errors and asynchronous results retain their current
behavior.

Comment on lines +345 to 377
/// Returns the non-null payload of a nullable union.
///
/// `Union([Null])` and unions without a direct `Null` member return `None`.
/// Member order and rebuilt-union attributes are preserved without flattening nested unions.
pub fn nullable_non_null_part(&self) -> Option<Ty> {
let Ty::Union(members, attr) = self else {
return None;
};
if !members.iter().any(Ty::is_null) {
return None;
}
let non_null: Vec<Ty> = members.iter().filter(|m| !m.is_null()).cloned().collect();
match non_null.len() {
0 => None,
1 => non_null.into_iter().next(),
_ => Some(Ty::Union(non_null, attr.clone())),
}
}

/// Remove `null` from a nullable union, collapsing the result: `T | null`
/// → `T`, `A | B | null` → `A | B`, a non-nullable type → unchanged. The
/// inverse direction of [`Ty::optional`]; used where the non-null payload
/// of an optional is needed (e.g. union-member metadata).
pub fn strip_null(&self) -> Ty {
match self {
Ty::Union(members, attr) => {
let non_null: Vec<Ty> = members.iter().filter(|m| !m.is_null()).cloned().collect();
match non_null.len() {
0 => self.clone(),
1 => non_null.into_iter().next().expect("len checked"),
_ => Ty::Union(non_null, attr.clone()),
}
Ty::Union(members, _) if members.len() == 1 && !members[0].is_null() => {
members[0].clone()
}
_ => self.clone(),
_ => self
.nullable_non_null_part()
.unwrap_or_else(|| self.clone()),
}
}

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: check for existing single-element Ty::Union construction sites and strip_null tests.
rg -nP 'Ty::union\(\[[^,\]]+\]\)|Ty::Union\(vec!\[[^,\]]+\]' baml_language/crates -g '*.rs'
rg -n 'fn strip_null_|nullable_non_null_part' baml_language/crates/baml_type/src/lib.rs -A3 -B3

Repository: BoundaryML/baml

Length of output: 722


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== baml_type lib relevant lines =="
sed -n '1,120p' baml_language/crates/baml_type/src/lib.rs
sed -n '300,390p' baml_language/crates/baml_type/src/lib.rs

echo "== Ty union definitions/usages =="
rg -n 'pub fn union|pub fn from_union|fn union|pub enum Ty|struct.*Union|is_nullable_union|nullable_non_null_part|strip_null|Ty::Union' baml_language/crates/baml_type/src/lib.rs baml_language/crates -g '*.rs' | head -200

Repository: BoundaryML/baml

Length of output: 30491


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Ty dedup_and_collapse implementation =="
sed -n '100,150p' baml_language/crates/baml_type/src/lib.rs

echo "== Ty union() implementation and reachable direct constructors =="
sed -n '440,465p' baml_language/crates/baml_type/src/lib.rs

echo "== single-element nullable_non_null_part behavior behavior probe =="
python3 - <<'PY'
from pathlib import Path
p = Path("baml_language/crates/baml_type/src/lib.rs")
s = p.read_text()

# Behavioral probe mirroring the documented/implemented contract from source.
def is_nullable_union(members):
    return any(m == "Null" for m in members)

def nullable_non_null_part(members, attr):
    if not is_nullable_union(members):
        return None
    non_null = [m for m in members if m != "Null"]
    if not non_null:
        return None
    if len(non_null) == 1:
        return non_null[0]
    return ("Union", non_null, attr)

def strip_null(members, attr):
    if len(members) == 1 and members[0] != "Null":
        return members[0], attr
    payload = nullable_non_null_part(members, attr)
    return (payload, attr) if payload is not None else (("Union", members, attr), attr)

cases = {
    "non_nullable_Single": (["Int"], "attr"),
    "nullable_single_after_null_strip": (["Int", "Null"], "attr"),
    "nullable_multi_after_null_strip": (["Int", "Null", "String"], "attr"),
}
for name, (members, attr) in cases.items():
    nullable = is_nullable_union(members)
    result, out_attr = strip_null(members, attr)
    changed = result != (("Union", members, attr))
    print(f"{name}: nullable={nullable}, input={members}, output={result}, changed={changed}")
PY

echo "== existing strip_null unit tests in baml_type =="
rg -n 'strip_null|nullable_non_null_part|dedup_and_collapse' baml_language/crates/baml_type/src -g '*.rs'

Repository: BoundaryML/baml

Length of output: 3841


Align strip_null’s behavior with its contract or update the contract.

strip_null documents “a non-nullable type → unchanged,” but the fast path unwraps a single-member non-null union, e.g. Ty::union([Ty::Int]) -> Ty::Int. If this normalization is intentional, update the doc comment and add a targeted Rust unit test; otherwise preserve degenerate one-member unions unchanged.

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

In `@baml_language/crates/baml_type/src/lib.rs` around lines 345 - 377, The
`strip_null` contract conflicts with its fast path, which unwraps single-member
non-null unions. Either preserve such unions unchanged by removing or adjusting
the fast path, or, if normalization is intentional, update `strip_null`’s
documentation and add a targeted Rust unit test covering `Ty::union([Ty::Int])`
becoming `Ty::Int`.

Source: Path instructions

Comment on lines 200 to +203
/// # Safety
/// `path` and `mime_type_or_null`, when non-null, must point to valid
/// NUL-terminated C strings. `out_key` and `out_handle_type` must be either
/// null or valid for writing one value of their pointee type.
/// `url` and `mime`, when non-null, must point to valid NUL-terminated C
/// strings. `out_key` and `out_type` must be either null or valid for
/// writing one value of their pointee type.

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 | 🟡 Minor | ⚡ Quick win

Correct the output-pointer safety contract.

Lines 202-203 allow null output pointers, but Line 176 rejects either null pointer with UnexpectedNullptr. Document out_key and out_type as required valid output pointers.

Proposed fix
-/// strings. `out_key` and `out_type` must be either null or valid for
-/// writing one value of their pointee type.
+/// strings. `out_key` and `out_type` must be valid for writing one value
+/// of their pointee type.

Also applies to: 215-218, 230-233

🤖 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/bridge_cffi/src/ffi/handle.rs` around lines 200 - 203,
Update the safety documentation for the FFI function around out_key and
out_type, including the corresponding contracts at the additionally affected
declarations, to state that both output pointers are required and must be valid
for writing one pointee value; remove the allowance that either pointer may be
null, matching the existing UnexpectedNullptr validation.

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