Skip to content

Fix compiler edge-case regressions - #4140

Merged
aaronvg merged 1 commit into
canaryfrom
codex/upstream-compiler-regressions
Jul 23, 2026
Merged

Fix compiler edge-case regressions#4140
aaronvg merged 1 commit into
canaryfrom
codex/upstream-compiler-regressions

Conversation

@aaronvg

@aaronvg aaronvg commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • materialize arbitrary lvalue projection bases correctly in MIR
  • preserve the interface view through non-recursive type aliases
  • parse named client = and prompt = call arguments as ordinary arguments instead of LLM function bodies

Why

These independent compiler edge cases surfaced while migrating the BEPv2 scenarios. Each bug now has focused regression coverage.

Validation

  • parser and MIR suites: 145 passed
  • interface type-alias iteration regression: 1 passed
  • projection-destination call regressions: 3 passed
  • cargo fmt --all --check
  • git diff --check origin/canary..HEAD

Note

Medium Risk
Touches MIR lvalue lowering, type-alias interface resolution, and function-body disambiguation; behavior changes are narrow but affect core compile paths.

Overview
Three independent compiler edge-case fixes, each with focused regression tests.

MIR lowering now evaluates the base expression of a projection assignment (e.g. store.require().info.title = ...) into a temp before building the lvalue, so call results can serve as nested assignment bases.

Interface iteration resolves non-recursive type aliases when looking up interface views (e.g. for over live.events() when the return type is type EventStream = Event[]), so iterable lowering works through transparent aliases.

Parser no longer treats client / prompt at the start of a function body as LLM directives when the next token is =, ,, or ), so bodies like Ask("hi", client = ...) parse as expression bodies instead of LLM bodies.

Reviewed by Cursor Bugbot for commit 90f66d4. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of type aliases when iterating over interface method results.
    • Fixed nested field assignments so method-call results are evaluated correctly before updating fields.
    • Improved detection of expression-based function bodies using client or prompt named arguments.
  • Tests

    • Added regression coverage for interface type aliases, nested field assignments, and expression-body parsing.

@vercel

vercel Bot commented Jul 23, 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 23, 2026 1:11am
promptfiddle Building Building Preview, Comment Jul 23, 2026 1:11am
promptfiddle2 Ready Ready Preview, Comment Jul 23, 2026 1:11am

Request Review

@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 23, 2026 01:04 Inactive
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The changes update MIR handling for non-recursive aliases and nested projection assignments, refine parser detection of expression-bodied calls using client or prompt named arguments, and add regression tests for both behaviors.

Changes

MIR lowering corrections

Layer / File(s) Summary
Non-recursive alias interface views
baml_language/crates/baml_compiler2_mir/src/lower.rs, baml_language/crates/baml_tests/tests/interface_type_alias_iteration.rs
Interface-view lowering resolves non-recursive aliases through the resolved alias map, and a regression test covers iterating over an interface method result using an array alias.
Single-evaluation projection assignments
baml_language/crates/baml_compiler2_mir/src/lower.rs, baml_language/crates/bex_vm/tests/projection_dest_calls.rs
Projection assignments lower their base expression into a temporary before nested projection, with coverage for a method-call base.

Function body detection

Layer / File(s) Summary
Named-argument body detection
baml_language/crates/baml_compiler_parser/src/parser.rs
Parser lookahead recognizes client = ... and prompt = ... as expression-body syntax, with tests asserting expression rather than LLM body classification.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: 2kai2kai2, codeshaunted

Poem

I hop through aliases, neat and bright,
Store each projection once just right.
“Client” and “prompt” now parse with care,
While tests bloom softly everywhere.
— A pleased little rabbit 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the PR’s compiler edge-case fixes, though it is broad and doesn’t name the specific regressions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/upstream-compiler-regressions

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.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 23, 2026 01:11 Inactive
@aaronvg
aaronvg enabled auto-merge July 23, 2026 01:12
@aaronvg
aaronvg added this pull request to the merge queue Jul 23, 2026

@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/bex_vm/tests/projection_dest_calls.rs`:
- Around line 105-128: Update
method_call_result_can_be_the_base_of_nested_field_assignment so the require
call has an observable side effect or returns distinguishable results, then
assert the call occurs exactly once while preserving the nested assignment
behavior. Use the existing SRC program and run_bool assertion, adding only the
minimal counter/state and expected-value checks needed to detect duplicate
evaluation.
🪄 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: d1788e9e-bfad-42c2-8753-7975f9b45277

📥 Commits

Reviewing files that changed from the base of the PR and between 5b9d45e and 90f66d4.

📒 Files selected for processing (4)
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_tests/tests/interface_type_alias_iteration.rs
  • baml_language/crates/bex_vm/tests/projection_dest_calls.rs

Comment on lines +105 to +128

// The base of a projection is itself allowed to be a call expression. MIR must
// evaluate that call into a local before appending field projections.
#[test]
fn method_call_result_can_be_the_base_of_nested_field_assignment() {
const SRC: &str = r#"
class Info { title: string? }
class Record { info: Info }
class Store {
record: Record
function require(self) -> Record { self.record }
}

function main() -> bool {
let store = Store {
record: Record { info: Info { title: null } },
};
store.require().info.title = "triage";
store.record.info.title == "triage"
}
"#;

assert!(run_bool(SRC, "user.main"));
}

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

Make the regression assert exactly-once evaluation.

require is pure and always returns self.record, so this test also passes if lowering invokes it twice. Add an observable call count or distinct result and assert that the base expression is evaluated exactly once.

🤖 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/bex_vm/tests/projection_dest_calls.rs` around lines 105
- 128, Update method_call_result_can_be_the_base_of_nested_field_assignment so
the require call has an observable side effect or returns distinguishable
results, then assert the call occurs exactly once while preserving the nested
assignment behavior. Use the existing SRC program and run_bool assertion, adding
only the minimal counter/state and expected-value checks needed to detect
duplicate evaluation.

@github-actions

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 25.6 MB 10.9 MB file 25.3 MB +353.7 KB (+1.4%) OK
packed-program Linux 🔒 17.2 MB 7.1 MB file 17.0 MB +164.3 KB (+1.0%) OK
baml-cli macOS 🔒 19.9 MB 9.5 MB file 19.6 MB +281.3 KB (+1.4%) OK
packed-program macOS 🔒 13.4 MB 6.2 MB file 13.2 MB +198.4 KB (+1.5%) OK
baml-cli Windows 🔒 21.4 MB 9.7 MB file 21.1 MB +303.6 KB (+1.4%) OK
packed-program Windows 🔒 14.3 MB 6.3 MB file 14.2 MB +159.7 KB (+1.1%) OK
bridge_wasm WASM 16.2 MB 🔒 4.4 MB gzip 4.4 MB +13.0 KB (+0.3%) 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

Merged via the queue into canary with commit 65ebcc0 Jul 23, 2026
67 of 68 checks passed
@aaronvg
aaronvg deleted the codex/upstream-compiler-regressions branch July 23, 2026 01:18
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 23, 2026 01:25 Inactive
meefs pushed a commit to meefs/baml that referenced this pull request Jul 23, 2026
## Summary
- make the nested projection assignment regression track calls to
`Store.require()`
- assert the assignment still mutates the expected nested field
- assert the projection base is evaluated exactly once

## Why
This is a test-only follow-up to the unresolved review on BoundaryML#4140. The
original regression used a pure `require()` method, so it could not
detect duplicate evaluation of the projection base.

## Impact
No production behavior changes. The strengthened regression now guards
both correct nested assignment and exactly-once evaluation.

## Validation
- `cargo nextest run -p bex_vm --test projection_dest_calls
method_call_result_can_be_the_base_of_nested_field_assignment`
- `cargo nextest run -p bex_vm --test projection_dest_calls`
- `cargo fmt --all --check`
- `git diff --check`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Only updates an integration test; no compiler, MIR, or runtime
behavior changes.
> 
> **Overview**
> **Test-only** change to
`method_call_result_can_be_the_base_of_nested_field_assignment` in
`projection_dest_calls.rs`.
> 
> The nested assignment `store.require().info.title = "triage"` still
must mutate the right field; the test now also proves the projection
base is evaluated **exactly once**. `Store` gains a `calls` counter
incremented inside `require()`, and `main` asserts `store.calls == 1` in
addition to the title check. A pure `require()` that only returned
`self.record` could pass even if MIR evaluated the call twice.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7f02714. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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