Skip to content

BEP-062 AnyFunction slice: baml.AnyFunction + reflect.signature/call_any - #4099

Merged
codeshaunted merged 14 commits into
canaryfrom
avery/anyfunction
Jul 22, 2026
Merged

BEP-062 AnyFunction slice: baml.AnyFunction + reflect.signature/call_any#4099
codeshaunted merged 14 commits into
canaryfrom
avery/anyfunction

Conversation

@codeshaunted

@codeshaunted codeshaunted commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Implements the AnyFunction-only portion of BEP-062 (Function Interfaces). Excluded by design: tuples, named tuples, the Function builtin, spread/rest, and reflect.call.

Surface

interface AnyFunction { type Returns = unknown; type Throws = unknown }  // baml.AnyFunction, compiler builtin

reflect.signature(f: baml.AnyFunction) -> reflect.Signature
reflect.call_any<R, E>(f: baml.AnyFunction<Returns = R, Throws = E>, args: unknown[], kwargs: map<string, unknown> = {})
    -> R throws E | reflect.InvalidArgumentError

class reflect.Signature { args Arg[], kwargs map<string, Arg>, returns type, throws type }
class reflect.Arg { name string?, docstring string?, type type }
class reflect.InvalidArgumentError { expected type, got type }
  • Every function type implements baml.AnyFunction via a derived rule in the subtype engine (works identically for the compiler and the VM's runtime context); pins are covariant. implements baml.AnyFunction is E0153; extends baml.AnyFunction bounds are E0154.
  • call_any R/E infer from the argument's pins, so a pinned tool map gets typed results and an exhaustive catch; a bare AnyFunction degrades to unknown/throws unknown. Absent kwargs fire the callee's own defaults (OMITTED_ARG prologue); the callee's typed throw propagates as throws E.
  • Arg.docstring is always null for now: the compiler does not record parameter docstrings yet; the field keeps tool-schema renderers shape-stable.

Internals of note

  • Function values unified on the heap: a plain function reference now emits a pooled, interned empty-type-args GenericFunction wrapper (identity stays pointer-stable), so a raw Object::Function is never a data value. Non-function global item reads (clients, top-level lets) split off as Constant::GlobalItem -> plain LoadGlobal.
  • Lambda signatures existed nowhere at runtime before this: lower_lambda now records mir::RuntimeSignature, and one emit path (apply_signature_metadata) stamps both lambdas and top-level declarations.
  • throws is now valid as a field/member name (sig.throws), following the existing ctx.client contextual-keyword pattern.
  • Snapshot churn is three benign categories: the two new stdlib stubs joining full-program listings, load_global -> load_const for function references, and const fn -> const item in MIR pretty for non-function items.

Known follow-ups

  • LLM boundary does not reject -> AnyFunction (pre-existing: plain arrow returns are not rejected either).
  • is-narrowing to concrete arrow types stays coarse (blocked on the void/never convention FIXME; reflect natives normalize it locally).
  • Sys-op callees with non-constant defaults under call_any are untested territory.

Summary by CodeRabbit

  • New Features
    • Added baml.AnyFunction interface with typed Returns/Throws pins.
    • Introduced BEP-062 runtime reflection: reflect.signature and reflect.call_any, including reconstructed args/opts, $argN positional support, defaults handling, and dispatch for lambdas and bound methods.
  • Bug Fixes
    • Improved reflection accuracy, including runtime docstring reporting in reflect.signature.
  • Diagnostics
    • Added compiler errors for invalid AnyFunction usage (E0153/E0154) and runtime reflect.InvalidArgumentError with expected-vs-got details.
  • Tests
    • Expanded compiler and VM coverage for typing, defaults, validation, and error cases.

…t.signature/call_any

- baml.AnyFunction builtin interface (Returns/Throws pins, both default
  unknown): conformance derived in the subtype engine for every function
  type, pins covariant; implements blocks rejected (E0153), generic bounds
  rejected (E0154)
- reflect.signature(f) -> Signature { args: Arg[], kwargs: map<string, Arg>,
  returns, throws }; Arg { name, docstring, type } (docstring null until
  parameter docstrings exist)
- reflect.call_any<R, E>(f, args, kwargs = {}) -> R throws E |
  InvalidArgumentError: runtime-checked dynamic call; absent kwargs fire the
  callee's own defaults; R/E infer from the argument's pins
- function values unified on the heap: a plain reference emits a pooled,
  interned empty-type-args GenericFunction wrapper (identity preserved), so
  a raw Function object is never a data value; non-function global item
  reads split off as Constant::GlobalItem
- lambda signatures recorded at MIR lowering (mir::RuntimeSignature) and
  stamped by the same emit path as top-level declarations
- throws usable as a field/member name (Signature.throws)
@vercel

vercel Bot commented Jul 21, 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 22, 2026 1:09am
promptfiddle Ready Ready Preview, Comment Jul 22, 2026 1:09am
promptfiddle2 Ready Ready Preview, Comment Jul 22, 2026 1:09am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds BEP-062 AnyFunction typing, runtime signature metadata, reflective inspection and invocation, pooled function values, compiler diagnostics, VM integration, cache versioning, and compiler/runtime coverage.

Changes

AnyFunction contracts and typing

Layer / File(s) Summary
AnyFunction contracts and subtype rules
baml_language/crates/baml_builtins2/baml_std/..., baml_language/crates/baml_type/src/...
Defines AnyFunction, reflection result/error types, reflective APIs, pin-based subtyping, and normalization tests.

Builtin-interface restrictions and diagnostics

Layer / File(s) Summary
Builtin-interface restrictions and diagnostics
baml_language/crates/baml_compiler2_tir/src/..., baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs, baml_language/crates/baml_lsp2_actions/src/check.rs, baml_language/crates/baml_tests/projects/diagnostic_errors/...
Rejects hand-written implementations and generic bounds for AnyFunction, and adds diagnostic identifiers, messages, mappings, and test cases.

Compiler function values and signatures

Layer / File(s) Summary
Compiler function values and runtime metadata
baml_language/crates/baml_compiler2_mir/src/..., baml_language/crates/baml_compiler2_emit/src/..., baml_language/crates/bex_vm_types/src/..., baml_language/crates/bex_cache/src/lib.rs
Adds runtime signatures and docstrings, lowers lambda metadata, distinguishes function/global constants, pools generic function wrappers, preserves metadata, and bumps the bytecode cache format.

Runtime reflection and dynamic calls

Layer / File(s) Summary
Runtime reflection and dynamic calls
baml_language/crates/bex_vm/src/..., baml_language/crates/bex_engine/src/lib.rs, baml_language/crates/baml_builtins2_codegen/src/...
Reconstructs callable signatures, implements reflect.signature and reflect.call_any, validates arguments, generates package-specific native dispatch, and dispatches generic function wrappers.

Reflective invocation and typing coverage

Layer / File(s) Summary
Reflective invocation and typing coverage
baml_language/crates/baml_tests/projects/compiles/..., baml_language/crates/baml_tests/tests/reflect_call_any.rs
Tests pinned and heterogeneous function values, signature access, argument validation, typed throws, lambdas, bound methods, generic callables, and dynamic dispatch.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ReflectNative
  participant BexVm
  participant Callee
  Caller->>ReflectNative: pass AnyFunction and argument map
  ReflectNative->>BexVm: reconstruct callable signature
  BexVm-->>ReflectNative: return parameters and metadata
  ReflectNative->>ReflectNative: validate arguments and types
  ReflectNative->>Callee: dispatch ordered arguments
  Callee-->>Caller: return result or typed error
Loading

Possibly related PRs

  • BoundaryML/baml#3640: Modifies pooled generic-function emission and runtime handling used by this change.
  • BoundaryML/baml#3852: Introduces the implements-rule infrastructure used by the new AnyFunction diagnostics.
  • BoundaryML/baml#3924: Introduces the bytecode cache format whose version is updated for Function.docstring.

Suggested reviewers: hellovai, 2kai2kai2

Poem

A rabbit hops through types so bright,
Reflecting calls in moonlit light.
Args line up, defaults appear,
Errors whisper, “I’m typed here!”
AnyFunction makes them go.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: BEP-062 AnyFunction support plus reflect.signature and reflect.call_any.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch avery/anyfunction

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: 2

🧹 Nitpick comments (2)
baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/bans.baml (1)

1-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing "impl generics" case from the stated coverage.

The header comment claims E0154 coverage on "functions, classes, impl generics, or associated types," but the file only exercises function (pick), class (Holder), and associated-type (Registry.Callee) bounds. There's no case for a generic bound on an impl block itself (e.g. impl<T extends baml.AnyFunction> SomeIface for SomeType<T> {}).

If impl_rules.rs diagnostics for this specific shape aren't already covered elsewhere, consider adding a case here to match the doc comment's claim.

🤖 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_tests/projects/diagnostic_errors/anyfunction/bans.baml`
around lines 1 - 22, The diagnostic fixture lacks coverage for E0154 on
impl-block generics. Add a representative impl declaration with a generic
parameter bounded by baml.AnyFunction, such as an impl of an existing interface
for a generic type, and ensure it exercises the expected diagnostic without
changing the existing function, class, or associated-type cases.
baml_language/crates/bex_vm/src/package_reflect/mod.rs (1)

1-345: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider colocated unit tests for the new dispatch/validation logic.

The core validation logic (value_fits, call_shape_ty, arity/optional-argument matching in call_any) is pure enough to unit test directly in this crate, rather than relying solely on the integration-style coverage in baml_tests. As per path instructions, **/*.rs: "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/bex_vm/src/package_reflect/mod.rs` around lines 1 - 345,
Add colocated Rust unit tests in the same module for the new validation helpers
and call_any argument matching. Cover value_fits type compatibility,
call_shape_ty construction, positional arity mismatches, unknown named
arguments, and valid optional-argument handling, using existing crate test
utilities and preserving the current dispatch behavior.

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 523-528: Extend unquoted key recognition for TokenKind::Throws
throughout object literal parsing: update brace_content_looks_like_fields,
parse_object_literal_body, and parse_object_field to use at_member_name() or
explicitly accept Throws alongside Word and Client. Also update parse_map_entry
and looks_like_map if they independently gate unquoted map keys, preserving
existing behavior for all other keys.

In `@baml_language/crates/bex_vm/src/vm.rs`:
- Around line 1229-1280: Update function_callable_signature to preserve
unresolved TypeVar entries from stored function signatures instead of routing
every parameter, return type, and throws type through realized_arg, which
currently causes generic callables to return None. Use the existing coarse
generic representation expected by the GenericFunction reflection path, without
substituting gf.type_args, while retaining current receiver dropping and
parameter metadata behavior.

---

Nitpick comments:
In
`@baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/bans.baml`:
- Around line 1-22: The diagnostic fixture lacks coverage for E0154 on
impl-block generics. Add a representative impl declaration with a generic
parameter bounded by baml.AnyFunction, such as an impl of an existing interface
for a generic type, and ensure it exercises the expected diagnostic without
changing the existing function, class, or associated-type cases.

In `@baml_language/crates/bex_vm/src/package_reflect/mod.rs`:
- Around line 1-345: Add colocated Rust unit tests in the same module for the
new validation helpers and call_any argument matching. Cover value_fits type
compatibility, call_shape_ty construction, positional arity mismatches, unknown
named arguments, and valid optional-argument handling, using existing crate test
utilities and preserving the current dispatch behavior.
🪄 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: 70b07890-1632-4d62-83e6-2de41ad278ff

📥 Commits

Reviewing files that changed from the base of the PR and between 070b3a3 and 6ef6535.

⛔ Files ignored due to path filters (115)
  • baml_language/crates/baml_tests/snapshots/baml_src/_root.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/baml_src/closures.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/baml_src/exceptions.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/baml_src/functions.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/baml_src/optional_function_parameters.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__01_lexer__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__02_parser__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/anyfunction_reflect/baml_tests__compiles__anyfunction_reflect__10_formatter__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_dedent/baml_tests__compiles__backtick_dedent__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_strings/baml_tests__compiles__backtick_strings__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/bigint_arith/baml_tests__compiles__bigint_arith__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/bigint_cmp/baml_tests__compiles__bigint_cmp__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/bigint_literal/baml_tests__compiles__bigint_literal__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/byte_string_literals/baml_tests__compiles__byte_string_literals__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/catch_all_keyword/baml_tests__compiles__catch_all_keyword__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/catch_all_panics/baml_tests__compiles__catch_all_panics__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/catch_arm_return/baml_tests__compiles__catch_arm_return__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/catch_throw/baml_tests__compiles__catch_throw__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/closure_loop_variable/baml_tests__compiles__closure_loop_variable__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/closures/baml_tests__compiles__closures__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/comment_after_string_in_config/baml_tests__compiles__comment_after_string_in_config__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/comment_in_type/baml_tests__compiles__comment_in_type__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/comment_in_type/baml_tests__compiles__comment_in_type__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/config_dictionary/baml_tests__compiles__config_dictionary__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/config_model_string/baml_tests__compiles__config_model_string__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/deep_method_call/baml_tests__compiles__deep_method_call__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/function_call/baml_tests__compiles__function_call__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/generic_field_chain/baml_tests__compiles__generic_field_chain__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/generic_match_typevar_arm/baml_tests__compiles__generic_match_typevar_arm__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/host_callable_call/baml_tests__compiles__host_callable_call__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/is_operator/baml_tests__compiles__is_operator__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_alias_basic/baml_tests__compiles__json_alias_basic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_cross_namespace_static_call/baml_tests__compiles__json_cross_namespace_static_call__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_llm_return_type/baml_tests__compiles__json_llm_return_type__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_llm_return_type/baml_tests__compiles__json_llm_return_type__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_map_literal/baml_tests__compiles__json_map_literal__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_parse_stringify_intrinsics/baml_tests__compiles__json_parse_stringify_intrinsics__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_to_from_string_composite_generic/baml_tests__compiles__json_to_from_string_composite_generic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_to_from_string_concrete/baml_tests__compiles__json_to_from_string_concrete__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_to_from_string_generic_forwarding/baml_tests__compiles__json_to_from_string_generic_forwarding__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/json_to_from_string_three_level/baml_tests__compiles__json_to_from_string_three_level__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lambda_advanced/baml_tests__compiles__lambda_advanced__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lambda_basic/baml_tests__compiles__lambda_basic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lambda_fat_arrow/baml_tests__compiles__lambda_fat_arrow__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lambda_field_access/baml_tests__compiles__lambda_field_access__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/lexical_scoping/baml_tests__compiles__lexical_scoping__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/literal_union_arithmetic/baml_tests__compiles__literal_union_arithmetic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/literal_union_widening/baml_tests__compiles__literal_union_widening__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/llm_image_outputs/baml_tests__compiles__llm_image_outputs__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/llm_image_outputs/baml_tests__compiles__llm_image_outputs__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/llm_parse_catchable_parse_error/baml_tests__compiles__llm_parse_catchable_parse_error__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/llm_parse_catchable_parse_error/baml_tests__compiles__llm_parse_catchable_parse_error__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/method_explicit_type_args/baml_tests__compiles__method_explicit_type_args__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_basic/baml_tests__compiles__namespaces_basic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_nested/baml_tests__compiles__namespaces_nested__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_root_fallback/baml_tests__compiles__namespaces_root_fallback__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_shadow/baml_tests__compiles__namespaces_shadow__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/namespaces_type_resolution/baml_tests__compiles__namespaces_type_resolution__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/numeric_invariance_ok/baml_tests__compiles__numeric_invariance_ok__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/numeric_literal_method_call/baml_tests__compiles__numeric_literal_method_call__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/o1_allowed_roles/baml_tests__compiles__o1_allowed_roles__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/optional_function_parameters/baml_tests__compiles__optional_function_parameters__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/optional_function_parameters/baml_tests__compiles__optional_function_parameters__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/paren_union_test/baml_tests__compiles__paren_union_test__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/parser_expressions/baml_tests__compiles__parser_expressions__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/parser_statements/baml_tests__compiles__parser_statements__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/patterns_class_destructure_namespaces/baml_tests__compiles__patterns_class_destructure_namespaces__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/patterns_new/baml_tests__compiles__patterns_new__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/reflect_type_of_user_generic/baml_tests__compiles__reflect_type_of_user_generic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/retry_policy/baml_tests__compiles__retry_policy__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/scientific_notation_float/baml_tests__compiles__scientific_notation_float__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/stream_crossfile/baml_tests__compiles__stream_crossfile__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/stream_llm_inferred_typeargs/baml_tests__compiles__stream_llm_inferred_typeargs__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/stream_llm_inferred_typeargs/baml_tests__compiles__stream_llm_inferred_typeargs__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/string_methods/baml_tests__compiles__string_methods__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_expr_basic/baml_tests__compiles__test_expr_basic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_expr_name_concat/baml_tests__compiles__test_expr_name_concat__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_expr_throwing_body/baml_tests__compiles__test_expr_throwing_body__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_expr_with_runner/baml_tests__compiles__test_expr_with_runner__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_old_and_new/baml_tests__compiles__test_old_and_new__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_raw_string_name/baml_tests__compiles__test_raw_string_name__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/test_with_not_keyword/baml_tests__compiles__test_with_not_keyword__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_basic/baml_tests__compiles__testset_basic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_dynamic/baml_tests__compiles__testset_dynamic__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_nested/baml_tests__compiles__testset_nested__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_vibes_nested/baml_tests__compiles__testset_vibes_nested__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_vibes_nested/baml_tests__compiles__testset_vibes_nested__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/testset_with_setup/baml_tests__compiles__testset_with_setup__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/top_level_header_comment/baml_tests__compiles__top_level_header_comment__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/top_level_let/baml_tests__compiles__top_level_let__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/type_annotation/baml_tests__compiles__type_annotation__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/type_builder_errors/baml_tests__compiles__type_builder_errors__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/type_builder_test/baml_tests__compiles__type_builder_test__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__01_lexer__bans.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__01_lexer__coercion.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__02_parser__bans.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__02_parser__coercion.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__10_formatter__bans.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__10_formatter__coercion.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/engine/baml_tests__engine__tests__optional_dropping_adapter_preserves_source_defaults_bytecode.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_textual.snap is excluded by !**/*.snap
📒 Files selected for processing (26)
  • baml_language/crates/baml_builtins2/baml_std/baml/core.baml
  • baml_language/crates/baml_builtins2/baml_std/reflect/reflect.baml
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler2_emit/src/emit.rs
  • baml_language/crates/baml_compiler2_emit/src/lib.rs
  • baml_language/crates/baml_compiler2_mir/src/builder.rs
  • baml_language/crates/baml_compiler2_mir/src/ir.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_mir/src/pretty.rs
  • baml_language/crates/baml_compiler2_tir/src/infer_context.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_compiler2_tir/src/interfaces/impl_rules.rs
  • baml_language/crates/baml_compiler_diagnostics/src/diagnostic.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/check.rs
  • baml_language/crates/baml_tests/projects/compiles/anyfunction_reflect/main.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/bans.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/coercion.baml
  • baml_language/crates/baml_tests/tests/reflect_call_any.rs
  • baml_language/crates/baml_type/src/normalize.rs
  • baml_language/crates/baml_type/src/normalize/tests.rs
  • baml_language/crates/bex_vm/src/lib.rs
  • baml_language/crates/bex_vm/src/package_baml/mod.rs
  • baml_language/crates/bex_vm/src/package_reflect/mod.rs
  • baml_language/crates/bex_vm/src/vm.rs

Comment thread baml_language/crates/baml_compiler_parser/src/parser.rs Outdated
Comment thread baml_language/crates/bex_vm/src/vm.rs
…teral key

CodeRabbit findings on #4099:
- function_callable_signature: a stored signature slot that does not
  realize (a generic's TypeVar, a symbolic projection) erases to unknown
  for that slot instead of dropping the whole callable, so
  reflect.signature / reflect.call_any work on generic function values
- parser: object literals accept throws as an unquoted field key
  (Signature { throws: ... }), completing the field-name carve-out
# Conflicts:
#	baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap
#	baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap
…ignature

Per review: the Signature/call_any named-args field is opts (not kwargs);
the error-channel field is errors, dropping the throws-as-field-name
carve-outs entirely (member access, field decls, and object-literal keys
all reverted to the pre-existing keyword rules); Arg loses its always-null
docstring; Signature gains the function's own docstring, threaded as a new
borsh field on the runtime Function object (bex_cache FORMAT_VERSION 2).

Also: the engine's call_callable now accepts the pooled GenericFunction
wrapper (fallout from the function-value heap unification), and the canary
merge's bytecode-display snapshots are regenerated.
A positional parameter with no recorded name (a host callable from a
language without parameter-name introspection) reports the $argN
placeholder for its position instead of null. $ cannot appear in a user
identifier, so a placeholder can never collide with a declared parameter
or named-argument key; nameless optionals stay excluded from opts
(nothing to pass them by), so placeholders never enter by-name matching.
@github-actions

github-actions Bot commented Jul 21, 2026

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.8 MB file 25.3 MB +274.9 KB (+1.1%) OK
packed-program Linux 🔒 17.2 MB 7.1 MB file 17.0 MB +153.1 KB (+0.9%) OK
baml-cli macOS 🔒 19.8 MB 9.4 MB file 19.6 MB +231.5 KB (+1.2%) OK
packed-program macOS 🔒 13.4 MB 6.2 MB file 13.2 MB +198.3 KB (+1.5%) OK
baml-cli Windows 🔒 21.3 MB 9.7 MB file 21.1 MB +230.9 KB (+1.1%) OK
packed-program Windows 🔒 14.3 MB 6.3 MB file 14.2 MB +146.4 KB (+1.0%) OK
bridge_wasm WASM 16.3 MB 🔒 4.4 MB gzip 4.4 MB +19.4 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

@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.

- lower_lambda: one lower_sig_ty helper for param/return/throws
  annotations (was an inlined ScopeCtx duplicate); param names/defaults
  built as direct projections instead of parallel vecs
- reflect natives: standard RealizedTy::unknown()/string() constructors
  replace hand-rolled ones; unreachable post-arity-check guard collapsed
- vm: coarse-truth rationale documented once on
  function_callable_signature, cross-referenced elsewhere
- normalize: covariant-pin lookup folded into one .any() predicate
- tests: bare-AnyFunction dispatch test folded into the generic-callable
  test, non-throwing signature assert folded into the bound-method test,
  and the two diagnostic corpus files merged into one (the project-wide
  diagnostics snapshot already combined them); all behaviors keep a test

Net -123 lines, no behavior change.
Not the qualified path: `greet`, `bump`, `println`. Also adapts the
reflect native to canary's runtime type-algebra rework (#4046), where
the VM itself is the `TypeContext` and `RuntimeTypeContext` is gone.
Adding a native to a stdlib package should be one edit to the package's
.baml plus the implementation it demands. The codegen already gave the
baml package that property; reflect hand-rolled a string match that
nothing kept in sync. Three changes make the generator package-generic:

- extract/codegen take the package: extract_native_builtins_for and
  generate_native_trait_for emit that package's BamlPackage<Pascal> root
  trait and prefix-stripping dispatcher. The media helpers now index
  segments from the end, so they need no package knowledge at all.
- generated identifiers are raw-escaped for Rust keywords, so a BAML
  field named "type" (reflect.Arg) emits a raw identifier instead of
  failing to parse. Panic text keeps the BAML spelling.
- package_reflect implements the generated BamlPackageReflect and builds
  every instance through the generated copy:: structs, so a field added
  to reflect.baml is a compile error until the native supplies it (the
  positional alloc_instance vecs are gone).

reflect.signature/call_any declare their VM needs as //baml:mut_vm,
//baml:fallible, //baml:may_yield directives, the same contract the baml
package uses.
attach_builtins had a hand-written if/else chain over package prefixes,
plus a second hand-maintained prefix list for the missing-native check.
One VM_NATIVE_PACKAGES table now drives both, so adding a package is a
single entry here alongside its build.rs generation.

reflect joins the fail-fast set: the old exemption claimed reflect.type_of
needed it, but an intrinsic never produces a function object (emit skips
it), so a missing reflect native is now a load error like any other.
@codeshaunted
codeshaunted enabled auto-merge July 22, 2026 00:54
@codeshaunted
codeshaunted added this pull request to the merge queue Jul 22, 2026
Merged via the queue into canary with commit 0773980 Jul 22, 2026
64 of 65 checks passed
@codeshaunted
codeshaunted deleted the avery/anyfunction branch July 22, 2026 01:04
meefs pushed a commit to meefs/baml that referenced this pull request Jul 22, 2026
Follow-up to BoundaryML#4099, which made `baml_builtins2_codegen` package-generic
and moved `reflect` onto it. `boundary` was the last package still
hand-wiring its natives.

## What it was

```rust
pub fn get_native_fn(path: &str) -> Option<NativeFunction> {
    match path.strip_prefix("boundary.")? {
        "id" => Some(id::new),
        "id.current" => Some(id::current),
        "LocalId.capture" => Some(id::capture),
        _ => None,
    }
}
```

Nothing kept that in sync with the `.baml` declarations: adding a
`$rust_function` and forgetting an arm gave a runtime lookup miss, not a
build error. Each native also hand-rolled the boilerplate the generated
glue already writes: arity checks, argument conversion, and the `Result`
-> `NativeCallResult` match.

## What it is now

`boundary` generates its `BamlPackageBoundary` / `BamlNamespaceId` /
`BamlClassLocalId` hierarchy like `baml` and `reflect` (three lines in
`bex_vm/build.rs`), so:

- the three natives are required trait methods, and a declared
`$rust_function` without an implementation is a compile error;
- arguments arrive converted, so `LocalId.capture` takes `Option<bool>`
triples instead of unpacking raw `Value`s, and the hand-written
`optional_bool` helper is deleted;
- the `LocalId` constructor builds through the generated `copy::LocalId`
struct instead of a positional `alloc_instance(vec![...])`;
- `VM_NATIVE_PACKAGES` now points every package at a generated
dispatcher, so no entry in it can drift.

## Scope

I checked the other stdlib packages: `log` is entirely
`$compiler_intrinsic` (no natives), and `assert` and `testing` declare
none, so `boundary` was the only remaining offender.

Net +10 lines (the generation loop entry and trait scaffolding, minus
the deleted dispatch and glue). Verified: `bex_vm` + `baml_tests` 2929
passing, `baml_cli` + `bex_engine` 976 passing, clippy clean.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Updated the Boundary runtime package to use the same generated
native-function dispatch as other standard-library packages.
* Improved handling of Boundary IDs and local ID capture through typed
interfaces.
* Preserved local ID capture behavior while simplifying argument
handling and state management.
* Added generated Boundary native-function support to the build process.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
aaronvg added a commit that referenced this pull request Jul 22, 2026
# Conflicts:
#	baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____06_codegen.snap
#	baml_language/crates/bex_vm/src/type_match.rs
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