Skip to content

bridge-cpp: typed literal types - baml::Lit + one polymorphic BAML_LIT macro - #4079

Merged
codeshaunted merged 2 commits into
avery/cpp-asyncfrom
avery/cpp-literals
Jul 17, 2026
Merged

bridge-cpp: typed literal types - baml::Lit + one polymorphic BAML_LIT macro#4079
codeshaunted merged 2 commits into
avery/cpp-asyncfrom
avery/cpp-literals

Conversation

@codeshaunted

@codeshaunted codeshaunted commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Stacked on #4078 (retargets to canary when it merges).

BAML literal types stop widening to their base scalars: each literal value is a distinct C++ type, so literal unions dispatch and exhaustively match at compile time, and misspellings do not compile. Pure C++17.

Surface

One macro classifies its argument via overloaded constexpr helpers (overload resolution is the dispatch):

BAML_LIT("draft")              // string -> Lit<'d','r','a','f','t'>  (Boost.Metaparse char-pack trick, 64-char cap)
BAML_LIT(42)                   // int    -> Lit<int64_t{42}>  (normalized: a bare int cannot mint a twin type)
BAML_LIT(true)                 // bool   -> Lit<true>
BAML_LIT(Sentiment::Positive)  // enum-variant type (Ty::EnumVariant), no longer widened to the enum
// status "draft" | "sent" | "paid"
baml::match(invoice.status,
  [](BAML_LIT("draft")) { ... },
  [](BAML_LIT("sent"))  { ... },
  [](BAML_LIT("paid"))  { ... });   // exhaustive; add a value in .baml -> build breaks

Every Lit carries its value statically (::value, plus implicit conversion to string_view/int64_t/bool/enum). Any non-blessed shape (Lit<1> int-typed, floats, mixed packs, pointers...) lands on a teaching static_assert. Generated code never uses the macro - the emitter spells char packs directly.

Mechanics

  • lit.h: template <auto... Vs> struct Lit with LitShape tag-dispatch (no partial-spec ambiguity), TrimNulls canonicalization so every spelling of a string lands on one instantiation, IntLit/BoolLit macro-free alternates.
  • Codec: encode = the plain scalar/enum arm; decode = base-codec arm handling + exact-value check (mismatch rejects the union arm). Union decode gains a literal pass ahead of strict/lenient, so Lit<"auto"> beats a std::string sibling.
  • Emitter: Ty::Literal + Ty::EnumVariant emit ::baml::Lit<...> (proper char escaping incl. \xNN and the i64::MIN spelling trick); float literals stay widened (float NTTPs are C++20; BAML has none in practice).
  • Lit unions ride the existing order-canonical + dedup baml::Union machinery unchanged.

Tests

  • test_literals.cc rewritten to typed semantics (returns/round-trips/class-of-literals + implicit-conversion ergonomics + type-level static_asserts).
  • New shared-fixture coverage, python-first per ground rules: mixed-base literal union type Flag = "active" | 1 | true round trip (test_round_trip_flag_mixed_literal_union in python, exact-alternative dispatch + match in C++).
  • test_complex_models.cc/test_enums.cc updated (Invoice.status literal union, EnumVariant-as-type now a singleton Lit).
  • unions_static.cc: BAML_LIT canonical-identity + int-normalization + Lit-union order-canonicality pins.

cpp fixtures 12/12 locally; python + the rest on CI.

Summary by CodeRabbit

  • New Features

    • Added support for strongly typed literal values in generated C++ SDKs.
    • Added literal handling for strings, integers, booleans, and enum variants.
    • Added support for mixed literal unions such as "active", 1, and true.
    • Added compile-time validation and exact literal round-trip behavior.
  • Bug Fixes

    • Improved union value decoding to prioritize exact literal matches before applying broader type conversions.

…T macro

BAML literal types stop widening: each value is a distinct C++ type
(Lit<'d','r','a','f','t'>, Lit<int64_t{42}>, Lit<true>,
Lit<Sentiment::Positive> for enum-variant types), so literal unions
dispatch and exhaustively match at compile time and misspellings do not
compile. C++17 throughout: strings ride a char-pack via the
Boost.Metaparse constant-indexing technique (64-char cap), scalars and
enums are plain auto NTTPs, and a single BAML_LIT(x) macro classifies
its argument through overloaded constexpr helpers - BAML_LIT("draft"),
BAML_LIT(42) (normalized to int64_t so a bare int cannot mint a twin
type), BAML_LIT(true), BAML_LIT(Sentiment::Positive). Any other shape
lands on a teaching static_assert.

The union decode gains a literal pass before the strict/lenient passes,
so Lit<"auto"> beats a std::string sibling for its exact value. Float
literals stay widened (float NTTPs are C++20; BAML has none in
practice). New shared-fixture coverage: mixed-base literal union
("active" | 1 | true) round trip, python-first.
@vercel

vercel Bot commented Jul 17, 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 17, 2026 10:39pm
promptfiddle Ready Ready Preview, Comment Jul 17, 2026 10:39pm
promptfiddle2 Ready Ready Preview, Comment Jul 17, 2026 10:39pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f9bcaa86-433c-46ba-ae3a-c73073c4aea2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch avery/cpp-literals

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.

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

Binary size checks failed

4 violations · ✅ 3 passed

⚠️ Please fix the size gate issues or acknowledge them by updating baselines.

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 25.3 MB 10.7 MB file 24.5 MB +760.3 KB (+3.1%) FAIL
packed-program Linux 🔒 17.0 MB 7.0 MB file 17.0 MB -4.1 KB (-0.0%) OK
baml-cli macOS 🔒 19.5 MB 9.3 MB file 18.9 MB +644.9 KB (+3.4%) FAIL
packed-program macOS 🔒 13.2 MB 6.2 MB file 13.2 MB +0 B (+0.0%) OK
baml-cli Windows 🔒 21.1 MB 9.5 MB file 20.4 MB +644.1 KB (+3.2%) FAIL
packed-program Windows 🔒 14.1 MB 6.2 MB file 14.1 MB -512 B (-0.0%) OK
bridge_wasm WASM 16.2 MB 🔒 4.4 MB gzip 4.3 MB +130.5 KB (+3.1%) FAIL

🔒 = 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.

Details & how to fix

Violations:

  • baml-cli (Linux) file_bytes: 25.3 MB exceeds limit of 25.2 MB (exceeded by +25.0 KB, policy: max_file_bytes)
  • baml-cli (Linux) file_delta_pct: +3.1% exceeds limit of 3.0% (exceeded by +0.1pp, policy: max_delta_pct)
  • baml-cli (macOS) file_bytes: 19.5 MB exceeds limit of 19.5 MB (exceeded by +77.9 KB, policy: max_file_bytes)
  • baml-cli (macOS) file_delta_pct: +3.4% exceeds limit of 3.0% (exceeded by +0.4pp, policy: max_delta_pct)
  • baml-cli (Windows) file_bytes: 21.1 MB exceeds limit of 21.0 MB (exceeded by +31.3 KB, policy: max_file_bytes)
  • baml-cli (Windows) file_delta_pct: +3.2% exceeds limit of 3.0% (exceeded by +0.2pp, policy: max_delta_pct)
  • bridge_wasm (WASM) gzip_bytes: 4.4 MB exceeds limit of 4.4 MB (exceeded by +2.3 KB, policy: max_gzip_bytes)
  • bridge_wasm (WASM) gzip_delta_pct: +3.1% exceeds limit of 3.0% (exceeded by +0.1pp, policy: max_delta_pct)

Add/update baselines:

.ci/size-gate/aarch64-apple-darwin.toml:

[artifacts.baml-cli]
file_bytes = 19545072
stripped_bytes = 19545120
gzip_bytes = 9329751

.ci/size-gate/wasm32-unknown-unknown.toml:

[artifacts.bridge_wasm]
file_bytes = 16160508
gzip_bytes = 4402886

.ci/size-gate/x86_64-pc-windows-msvc.toml:

[artifacts.baml-cli]
file_bytes = 21070848
stripped_bytes = 21070848
gzip_bytes = 9539693

.ci/size-gate/x86_64-unknown-linux-gnu.toml:

[artifacts.baml-cli]
file_bytes = 25267920
stripped_bytes = 25267912
gzip_bytes = 10728953

Generated by cargo size-gate · workflow run

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

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

Inline comments:
In `@baml_language/sdks/cpp/bridge_cpp/include/baml/lit.h`:
- Around line 80-86: Update the static_assert diagnostic in the Lit shape
validation to remove the undefined BAML_LIT_INT, BAML_LIT_BOOL, and
BAML_LIT_ENUM macro references. Describe the supported integer, boolean, and
enum forms using the existing baml::IntLit and baml::Lit syntax, while retaining
the BAML_LIT recommendation for strings.
- Around line 163-191: Update LitValueOf(T) to validate unsigned integral values
are representable in int64_t before normalization, using the original type/value
in a compile-time assertion, then perform the cast. Ensure out-of-range values
such as UINT64_MAX are rejected while signed and representable unsigned literals
retain the existing canonical int64_t 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: cf6d69a1-dd97-40a8-9746-6fc8bfbf495b

📥 Commits

Reviewing files that changed from the base of the PR and between 839e6ab and 32828a8.

📒 Files selected for processing (11)
  • baml_language/sdk_tests/crates/cpp/function_calls/customizable/tests/test_main.cc
  • baml_language/sdk_tests/crates/cpp/type_shapes/customizable/tests/test_complex_models.cc
  • baml_language/sdk_tests/crates/cpp/type_shapes/customizable/tests/test_enums.cc
  • baml_language/sdk_tests/crates/cpp/type_shapes/customizable/tests/test_literals.cc
  • baml_language/sdk_tests/crates/cpp/type_shapes/customizable/tests/unions_static.cc
  • baml_language/sdk_tests/crates/python_pydantic2/type_shapes/customizable/roundtrip_tests/test_literals.py
  • baml_language/sdk_tests/fixtures/type_shapes/baml_src/ns_literals/types.baml
  • baml_language/sdks/cpp/bridge_cpp/include/baml/baml.h
  • baml_language/sdks/cpp/bridge_cpp/include/baml/codec.h
  • baml_language/sdks/cpp/bridge_cpp/include/baml/lit.h
  • baml_language/sdks/cpp/sdkgen_cpp/src/lib.rs

Comment thread baml_language/sdks/cpp/bridge_cpp/include/baml/lit.h Outdated
Comment thread baml_language/sdks/cpp/bridge_cpp/include/baml/lit.h Outdated
…iterals

The shape static_assert still named the BAML_LIT_INT/_BOOL/_ENUM macros
deleted when BAML_LIT became polymorphic. And LitValueOf's int64_t
normalization silently wrapped unsigned values above INT64_MAX, so
BAML_LIT(UINT64_MAX) aliased BAML_LIT(-1); the constexpr-throw guard now
fails constant evaluation with the message in the diagnostic.
@codeshaunted
codeshaunted merged commit 2172572 into avery/cpp-async Jul 17, 2026
47 of 49 checks passed
@codeshaunted
codeshaunted deleted the avery/cpp-literals branch July 17, 2026 22:25
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