Avatar for the BoundaryML user
BoundaryML
baml
BlogDocsChangelog

Performance History

Latest Results

Bump BAML language canary to 0.11.1 (#3679) Bumps the BAML language canary release intent. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Released version 0.11.1 for the Python SDK, Node.js SDK, and VS Code extension. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
canary
2 hours ago
Make baml.toml opt-in for the BAML CLI (#3676) ## Why The most expensive thing an agent can do is try a command and have it fail fast. Previously every project command bailed with `doesn't look like a BAML project` unless the exact directory contained a `baml.toml` — so `baml describe baml.String` couldn't even read the stdlib without a project, and `baml run`/`test`/`generate`/`pack` refused to run a plain `baml_src/` directory. This makes **`baml.toml` opt-in**: it's only needed when you actually use one of its features (dependencies, version lock, `[scripts]`, multiple packages). A bare `baml_src/` is a complete project. ## Behavior | Command | No project at all | `baml_src/` only, no `baml.toml` | |---|---|---| | `describe` / `grep` | ✅ stdlib-only default state (walks up for an ancestor `baml.toml`) | ✅ | | `fmt` | ✅ no-op success | ✅ | | `run` / `test` / `generate` / `pack` | ❌ error → hints `baml_src/`, `baml init`, `--file` | ✅ | | `run --file` / `pack --file` | ✅ hermetic (unchanged) | ✅ | Key points: - **describe / grep** use a lenient loader: walk ancestors for a `baml.toml`; if none, fall back to a stdlib-only database (the `baml.*` stdlib loads regardless of user files, so `baml describe baml.String` works in any directory with zero user files). - **fmt** returns a no-op success when there's no project marker, instead of erroring. It deliberately does **not** walk up, since it mutates files. - **run / test / generate / pack** now treat a directory as a project if it has *either* a `baml.toml` *or* a `baml_src/`. A manifest-less project loads sources **only** from `baml_src/`, so discovery stays scoped and can never slurp an unmarked tree — the workspace-shaped salsa hang the old hard requirement guarded against. `run -e` picks up a `baml_src/`-only project's context too. - **pack** names the artifact after `[package].name` when a manifest is present, else the project directory name (Cargo-style); `--file` still uses the file stem. - A present `baml.toml` is still validated (`[package].name` required). The only remaining hard failure is a directory with neither marker. ## Slurp-hang invariant A whole-root walk only happens for a **declared** project (a `baml.toml` present with no `baml_src/`) — intentional, matching what `run`/`test` already did. Every manifest-less path is scoped to `baml_src/` and provably cannot slurp. ## Testing `cargo nextest run -p baml_cli --no-default-features --features ring-crypto` → **195 passing**. Added: - Unit: loader decision table (all four marker cases), walk-up, stdlib default state, `resolve_project_name` dir-name fallback. - E2E: project-less `describe`/`grep`/`fmt`; manifest-less `run <fn>` (executes), `run -e`, `run --list`, `test` (→ NoTestsRun), `generate`, and `pack` (builds + runs the binary). fmt + clippy `--all-targets` clean. ## Open question A `baml.toml` present but **without** `[package].name` (e.g. a manifest added *only* for `[scripts]`/`[dependencies]`) is still rejected — Cargo-consistent, but mildly in tension with "only needed when you use a feature," since `pack` can now fall back to the directory name. Left strict for now; easy to relax if we'd prefer. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Projects may be defined by a baml_src/ directory alone (no baml.toml required). * CLI read-only commands (describe, grep, fmt) operate in a stdlib-only default when no project is present. * **Improvements** * Formatter is a no-op outside projects and prints a friendly message on success. * Packaging: clearer output basename rules and stricter handling of nameless file paths. * **Tests** * New end-to-end and unit tests cover manifest-less and baml_src-only scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
canary
4 hours ago
feat: generic instantiation expressions (`let f = foo<int>`) (#3640) ## Summary Adds **generic instantiation expressions** — referencing a generic callable with explicit type arguments as a *value* (not a call): ```baml function foo<T>(x: T) -> T { x } let f = foo<int> // typed (int) -> int; f("s") is a type error foo<int>(x) // (call form, already supported) ``` Previously `foo<int>` in value position silently dropped the type args (parsed as a `<` comparison or lowered to a fully-generic ref), so `let f = foo<int>; f("s")` was wrongly accepted. ## Behavior ```baml let f = foo<int> // (int) -> int let g = foo // still <T>(x: T) -> T (bare ref unchanged) foo<int> === foo<int> // true (interned, pointer-stable) foo<int> !== foo<string> // distinct specializations let f = baml.json.from_string<User>; f(s) // works (T=User reified at runtime) let g = describe<User>; g() // reflect.type_of<T> -> "User" function fwd<T>() { let g = describe<T>; g() } // param-dependent: resolves T at runtime ``` Plus enforcement and lowering fixes that fall out of this: - **BEP-044 generic bounds** are now enforced on instantiation *values*, not only at call sites. - Generic calls on **non-`PATH` receivers** (`(b).foo<int>`, `arr[0].foo<int>`, `self.subs[i].m<T>(...)`) previously lowered to `<missing>`; now lowered correctly (this fixed two latent std-lib `<missing>` bugs). ## Implementation **Front-end** - Parser: ports typescript-go's `canFollowTypeArgumentsInExpression` to disambiguate `<…>` in value position vs. a `<` comparison (reuses the existing balanced-`>` scan). - AST: new `Expr::GenericApply { base, type_args }`; lowering captures `GENERIC_ARGS` (with a consumed-args marker so `foo<int>(x)` doesn't double-count). - TIR: specializes the signature and **clears `generic_params`**, so a later call checks args against the concrete params. **Runtime** — a generic-function value carries its type args so an indirect call behaves exactly like the direct `foo<int>(...)`: - New `Object::GenericFunction { function: GlobalIndex, type_args }`. Stored by global slot (not `HeapPtr`), so it's a compile-time-poolable, GC-leaf value. - **Concrete** instantiations → a pooled, interned `Constant::GenericFunction` (dedup by `(function, type_args)` → one object → pointer-stable identity). - **Param-dependent** instantiations (`foo<T>` where `T` is the enclosing frame's type param) → a new `MakeGenericFunction` opcode that resolves the type-arg templates against the current frame's `type_args` at runtime. - The call path seeds both `frame.type_args` (for `reflect.type_of<T>` / bytecode bodies) and `pending_call_type_args` (for type-reifying natives). ## Testing - Parser disambiguation matrix; TIR snapshot tests (specialization, `f("s")` rejection, arity, bounds, multi-arg). - Runtime fixture `ns_instantiation_expr` covering: end-to-end call, pointer identity, json-native-through-value, reflect-through-value (concrete + param-dependent), bound violation, deep-copy equality. - Full workspace test sweep green (4945 tests). - An adversarial review pass surfaced 3 real issues (equality of non-pooled copies, a latent entry-point panic, the param-dependent-reflect hole) — all fixed and regression-tested. ## Notes This is forward-compatible with function mocking: a generic-callable value carries its `(function, type_args)` structurally, and the VM seeds those at the call — exactly the key mock dispatch needs. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Instantiate generic functions as first-class values (e.g., `let f = identity<int>;`) so specialized callables can be stored, passed, and invoked later. * Parser now better distinguishes `<...>` generic-argument lists from comparison operators in value position. * **Improvements** * End-to-end support: type checking, bytecode, runtime representation, and VM dispatch for generic-function values and reflection. * **Tests** * Added extensive compile-time and runtime tests and formatter coverage for generic instantiation forms. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
canary
6 hours ago
[codex] Add class generic bounds (#3672) ## Summary Adds generic bounds to class generic parameters, including parsing/lowering support, TIR validation, and runtime lowering support for class methods that rely on bounded type variables. ## What changed - Stores class generic bounds in AST/HIR and propagates them into TIR/MIR. - Centralizes TIR bounded-generic environment handling through a shared `GenericEnv` path. - Validates bounded generic class/interface type arguments in annotations, constructors, throws clauses, lambda annotations, patterns, type aliases, interface fields, and required interface method signatures. - Extends nominal interface subtyping through structural containers such as lists, maps, futures, and non-generic function types. - Adds focused tests for class generic bounds, unions, compound bounds, function-type bounds, nested nominal bounds, and runtime method access. ## Root cause Class generic parameters could be parsed as names, but their bounds were not represented consistently through the AST/HIR/TIR/MIR pipeline. Several TIR annotation paths also lowered types without validating class/interface generic argument bounds, and MIR method lowering did not carry enclosing class bounds when erasing bounded type variables for runtime field/member access. ## Validation - `cargo test -p baml_tests --test interfaces_class_generics` - `cargo test -p baml_tests --test interfaces generic_bound` - `cargo test -p baml_tests --test interfaces bounded` - `cargo test -p baml_compiler2_tir` - `cargo test -p baml_tests --test interfaces` - `cargo test -p baml_compiler2_mir` Note: the working tree still has unrelated pre-existing generated Go changes and `rig_tests/`; they are not included in this PR. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Large changes to generic bound propagation, subtyping, interface impl indexing, and MIR method lowering in the core compiler pipeline; mistakes could cause false positives/negatives in type-checking or runtime dispatch. > > **Overview** > **Class generic parameters now carry `extends` bounds end-to-end** (AST/HIR `generic_param_bounds`, class lowering via `extract_generic_params_with_bounds`), and TIR enforces those bounds wherever class/interface type arguments appear—not only at explicit call-site type args. > > **TIR** introduces a shared **`GenericEnv`** for merging enclosing class/interface/`implements` generics with function and lambda scopes, validates bounds on resolved types (constructors, aliases, patterns, throws, interface signatures), and tightens **subtyping** (type-var reflexivity, structural checks through lists/maps/futures/functions, container `Array`/`Map` args without spurious nominal rules). **Interface compatibility** now evaluates impl rules against lowered class bounds and only caches nominal `class_implements` when bounds are empty. > > **MIR** accumulates generic bounds from `implements` blocks, parent class/interface scopes, and the function when lowering methods; **interface impl inference** also unifies associated-type bindings on interface-to-interface matches. > > New **`interfaces_class_generics`** tests and extensions to associated-type / runtime dispatch tests cover bounded class type args and cross-namespace defaults. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4c7031a5cd50175b7fcf9a8e9c3926d31f246022. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Class generic parameter bounds are supported and flow to methods, lambdas, throws, object expressions, type aliases, and associated-type bindings. * **Behavior Changes / Bug Fixes** * Generic-bound validation applied more broadly (including interface/associated-type checks), with tighter subtype/container/function compatibility and clearer diagnostics at source spans. * Runtime dispatch respects substituted associated-type bindings. * **Tests** * Large test suite added for bounds enforcement, inference failures, associated types, runtime dispatch, and many typing contexts. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
canary
8 hours ago
fix: thread inferred generic type args through interface dispatch (#3667) ## Problem A generic class instance whose `<T>` is **inferred** (not written explicitly) must carry the correct runtime `class_type_args`, and a method dispatched through a multi-implementor interface must receive the resolved class/interface type args in its frame. The interface-dispatch switch (`emit_method_candidate_switch`) called the matched implementor's method with **only the explicit call-site `<...>` type args** — it never seeded the callee frame. So an interface **default method** (e.g. a lazy iterator's `map` building `Map<T, U>`), or any dispatched method that reads its enclosing `T` at runtime (`reflect.type_of<T>()`, constructing `Other<T>{}`), saw an empty `frame.type_args`. It then built instances with `class_type_args = [unknown]`, and the downstream `IsType` dispatch guard fell through to the **wrong implementor** — a silent wrong answer, or a field-access panic when the sibling class has a different layout. This was the core compiler blocker for the `baml.iter` lazy-iterator protocol. ### Minimal reproduction (before this fix) ```baml interface Cursor<T> { function head(self) -> T throws unknown // default method builds a NEW generic from the interface's T function take_one(self) -> Cursor<T> throws unknown { return SingleCursor<T> { value: self.head() } } } class ArrayCursor<T> { arr T[] idx int function of(items: T[]) -> ArrayCursor<T> { return ArrayCursor<T> { arr: items, idx: 0 } } implements Cursor<T> { function head(self) -> T throws unknown { return self.arr[0] } } } class SingleCursor<T> { value T implements Cursor<T> { function head(self) -> T throws unknown { return self.value } } } function take_one_then_head() -> int throws unknown { let cursor: Cursor<int> = ArrayCursor.of([10, 20, 30]); // <int> inferred let single: Cursor<int> = cursor.take_one(); // builds SingleCursor<?> single.head() // expected 10 } ``` Before: `take_one()` (a default method) had empty `frame.type_args`, so `SingleCursor<T>` was built with `class_type_args = [unknown]`. `single.head()` then failed the `SingleCursor<int>` guard and dispatched to `ArrayCursor.head`, which indexed a non-existent `arr` field. After: returns `10`. ## Fix (in `baml_compiler2_mir::lower`) 1. **`enclosing_generic_params()`** now includes the **interface's** generic params for interface default methods. They are lowered as standalone functions whose bodies reference the interface's `T`; without this, `TypeVar(T)` lowered to `Concrete(Void)` instead of `TypeArgRef(N)`. 2. **The interface-dispatch switch** seeds each candidate's callee frame (De Bruijn order: class/iface params first, then explicit call-site args): - a **class-owned** method gets the implementor's class args — **statically** when the guard fully pins them (common/hot path, allocation-free, unchanged bytecode), otherwise from the **matched runtime instance** via a `BoundMethod` (covers `Any`/partial guards, e.g. a generic class behind a *non-generic* interface); - an **inherited interface default** gets the resolved interface view's args (these can differ from the implementor's class args when the `implements` block renames/reorders params). 3. **`default.<method>()`** (the super-like form that forwards into the interface default) seeds the default frame with the interface's type args too. ## Tests New in-BAML regression namespace `crates/baml_tests/baml_src/ns_inferred_generic_type_args`: - `showcase_lazy_cursor_pipeline` — the lazy-cursor example above, end-to-end. - `inferred_static_ctor_dispatches_to_correct_implementor` — inferred static ctor + non-generic interface. - `inferred_static_ctor_dispatches_through_generic_interface` — inferred static ctor + generic interface, mismatched field shapes. - `interface_default_method_sees_interface_type_var` — default method reads `T` via `reflect.type_of<T>()` at runtime. - `class_method_builds_generic_via_class_type_var` — class-owned method builds a generic from its class `T`. - `default_method_forward_reads_interface_type_var` — `default.<method>()` forwarding into a generic default. - `generic_class_behind_nongeneric_interface_reads_type_var` — `Any`-guard case, seeded from the runtime instance. Full `baml_tests` suite green. Existing bytecode snapshots unchanged — only the new namespace's `.snap` changed (no existing namespace exercised this path; the `BoundMethod` path fires only for previously-broken `Any`/partial-guard generic arms). ## Known limitation (separate, pre-existing — not addressed here) A generic class whose **only** field is `T[]`, built via a static constructor with inferred `T`, gets wrong `class_type_args` from the *producer* side (a TIR inference issue in the struct literal, independent of this dispatch fix). Adding any second field (as every real iterator has, e.g. `idx: int`) avoids it, so it does not affect the `ArrayIterator`-shaped use case. Worth a separate investigation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed generic type-argument propagation for interface dispatch so dispatched calls—including default-method forwards and class-owned implementations—receive correct runtime type arguments. * **Tests** * Added end-to-end tests validating inferred generic type args flow through interface dispatch, default-method forwarding, class-owned vs instance-seeded cases, and regressions for varied implementor layouts. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
canary
10 hours ago
[codex] Implement BEP-57 associated types (#3652) ## Summary Implements BEP-57 associated types for interfaces across parsing, AST/HIR/TIR/MIR, formatter, LSP diagnostics, and codegen-facing surfaces. Key pieces: - Adds associated type declarations, defaults, bounds, and body-side witnesses in `implements` blocks. - Supports associated type bindings on interface value types and generic bounds. - Adds associated type projection syntax, including qualified `(Type as Interface<...>).Member` disambiguation. - Keeps `.as<T>` as upcast-equivalent while enforcing associated binding compatibility. - Rejects target-side witnesses like `implements Iterator<Item = int>`; witnesses must be declared inside the block (`type Item = int`) Rust/Swift-style. - Covers union, match/destructure narrowing, ambiguity, aliases, diagnostics, formatter, and runtime dispatch cases. ## Root Cause / Design Notes The parser can recognize `Iterator<Item = int>` as a type expression, but BEP-57 semantics reserve associated type witnesses for the body of an implementation. The implementation therefore preserves interface type bindings for values/bounds/projections while rejecting bindings on `implements` targets. ## Validation - `cargo fmt` - `cargo check -p baml_compiler2_tir -p baml_compiler2_mir -p baml_lsp2_actions -p baml_compiler2_ast -p baml_compiler_parser -p baml_fmt` - `cargo build -p baml_cli` - `cargo test -p baml_tests --test interfaces_associated_types -- --nocapture` (93 passed) - `cargo test -p baml_tests --test interfaces -- --nocapture` (379 passed, 2 ignored) - `cargo test -p baml_tests` (full package passed) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Large, cross-cutting compiler and runtime changes to interface typing, dispatch, and reflection; incorrect binding matching could cause subtle dispatch or pattern-match bugs. > > **Overview** > Adds **BEP-057 associated types** end-to-end: interfaces can declare associated types (bounds/defaults), and `implements` blocks can witness them with `type Name = …` instead of putting bindings on the `implements` target. > > The AST/HIR layer gains **`AssociatedTypeBinding`**, **`associated_type_bindings` on `TypeExpr::Path`**, **`AssociatedTypeProjection`** (`Base.Item` / `(Base as Interface).Item`), and matching fields on interfaces, `implements` blocks, class destructuring, and method-to-interface metadata. Lowering wires CST `TYPE_ARGS` / associated decls through `lower_type_expr` and `lower_cst`. > > **MIR and emit** stop erasing interfaces to classes: `Ty::Interface` keeps type args plus associated bindings; interface dispatch, field access, pattern matching, `is`-type tests, and the runtime **implementor registry** all compare **generic args and associated bindings** (e.g. `Source<Item = int>` vs `Item = string`). Builtin codegen treats projections as unknown types for native extraction. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit cecf4f4bfcbebb130d0039392420d76f49091a95. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added associated types on interfaces (BEP-057): syntax, projections, named bindings; type checking, dispatch, pattern matching, and exhaustiveness honor associated bindings. * **Tests** * Extensive new and updated unit/integration tests covering parsing, lowering, inference, matching, dispatch, and runtime behavior for associated types. * **Tooling** * Parser, formatter, LSP symbols, diagnostics, snapshots, and pretty-printers updated to recognize and display associated-type syntax and errors. * **Runtime & Serialization** * Runtime reflection, serialization, FFI wire formats, and program metadata now include associated-bindings. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
canary
15 hours ago
Overhaul BAML language release pipeline (#3639) ## Summary Overhauls the BAML language release path around the new wrapper/toolchain split. - adds the `baml` wrapper crate plus shared `baml_release` and stamped `baml_version` crates - replaces the alpha release workflows with a channel-aware release graph, PyPI publish workflow, dry-run manifests, and wrapper-only Homebrew/AUR publishing paths - moves language/toolchain version authority to `baml_language/release.toml` and `scripts/baml-language-version` - makes the VSIX platform-neutral, launches `baml lsp` through the wrapper, and adds LSP/playground compatibility metadata - adds curl/PowerShell installers, package-manager artifact generation scripts, and in-repo docs for install/release/toolchain behavior ## Validation - pre-commit hooks passed, including: - `cargo fmt` - `cargo stow` - `cargo clippy --workspace --all-targets --all-features -- -D warnings` - YAML checks - `actionlint .github/workflows/release-baml-language.yml .github/workflows/publish-python-pypi.yml .github/workflows/build-python-sdk.reusable.yaml` - `cargo check --manifest-path baml_language/Cargo.toml -p baml -p baml_release -p baml_cli` - `cargo test --manifest-path baml_language/Cargo.toml -p baml_release` - `scripts/baml-language-version check` - `scripts/baml-wrapper-version check` - `typescript2/app-vscode-ext`: `./node_modules/.bin/tsc --noEmit` ## Release Follow-ups Before enabling production publishes: - update or validate the PyPI trusted publisher binding for `.github/workflows/publish-python-pypi.yml` - verify `scripts/install.ps1` on Windows/PowerShell - confirm production GitHub Actions secrets/OIDC paths for PyPI, AWS, Homebrew, and AUR - review whether the included `TASK/*` planning files should remain in the branch <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * New standalone baml wrapper/launcher with toolchain commands, self-update, IDE VSIX installer, per-project VS Code clients, and protocol/handshake compatibility. * **Installers & Packaging** * POSIX and Windows installers; Homebrew/AUR formula and packaging artifact generators; packaging adjusted to ship the wrapper binary. * **Documentation** * Expanded install, toolchain, release, maintainer, failure-modes, command-surface, migration, and merge-to-canary guides. * **CI / Releases** * Channel-aware release pipelines, release-plan stamping/manifest generation, reusable workflow inputs added, legacy alpha workflows removed; SDKs bumped to 0.11.0. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
canary
16 hours ago

Latest Branches

CodSpeed Performance Gauge
N/A
ci(perf): opt-in perf on PRs, run after merge, adaptive bench sampling#3651
1 day ago
9ff494e
hellovai/perf-fixes
CodSpeed Performance Gauge
+1%
ci: R2-backed cache-cargo-home action for cargo download caches#3624
3 days ago
8300850
sam/cache-cargo-home
CodSpeed Performance Gauge
0%
© 2026 CodSpeed Technology
Home Terms Privacy Docs