Skip to content

baml-language: implement new PPIR#3264

Merged
sxlijin merged 2 commits intocanaryfrom
push-pqsmnrvrxlxy
Mar 27, 2026
Merged

baml-language: implement new PPIR#3264
sxlijin merged 2 commits intocanaryfrom
push-pqsmnrvrxlxy

Conversation

@sxlijin
Copy link
Copy Markdown
Contributor

@sxlijin sxlijin commented Mar 21, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added stream type expansion functionality with support for type attributes
    • Type expressions now carry attributes for enhanced annotation capabilities
  • Tests

    • Added comprehensive test fixtures for stream type coverage, including basic schemas, complex nested types, and edge case scenarios

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 21, 2026

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

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Mar 27, 2026 9:32pm
promptfiddle Ready Ready Preview, Comment Mar 27, 2026 9:32pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 21, 2026

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

This pull request introduces type-attribute support throughout the BAML compiler by extending the Ty and TypeExpr enums to carry TyAttr metadata, restructuring TypeExpr variants from tuple to struct form, implementing a new PPIR (Post-Parse Intermediate Representation) stream-expansion system, and updating pattern matches and type construction across ~30 codebase files plus helper scripts.

Changes

Cohort / File(s) Summary
Type attribute base infrastructure
baml_language/crates/baml_base/src/attr.rs
Added PartialOrd and Ord derives to TyAttrValue and TyAttr to support total ordering.
AST TypeExpr restructuring
baml_language/crates/baml_compiler2_ast/src/ast.rs
Converted all TypeExpr enum variants from tuple/unit forms (e.g., Path(Vec<Name>), Int, Optional(Box<TypeExpr>)) to struct forms carrying attrs: Vec<RawAttribute> (e.g., Path { segments, attrs }, Int { attrs }, Optional { inner, attrs }). Added public accessor methods attrs() and attrs_mut(). Also added Hash derive to RawAttribute and RawAttributeArg.
AST lowering infrastructure
baml_language/crates/baml_compiler2_ast/src/lower_cst.rs, lower_expr_body.rs, lower_type_expr.rs
Made lower_attribute crate-public. Updated all type construction and pattern matching to use new struct-form TypeExpr variants. Implemented attribute collection from CST and attachment to type expressions via collect_type_attrs helper and attrs_mut() mutations.
AST companion/macro support
baml_language/crates/baml_compiler2_ast/src/companions.rs, lib.rs
Updated companion type expression construction to struct form. Added type_expr! test macro for convenient construction with empty attrs. Updated all test assertions to match new variant shapes.
Ty enum attribute propagation
baml_language/crates/baml_compiler2_tir/src/ty.rs, builder.rs, lower_type_expr.rs, generics.rs, narrowing.rs, normalize.rs, throw_inference.rs, package_interface.rs, signature.rs
Extended all Ty variants to carry TyAttr field (either as tuple element or struct field attr). Updated pattern matches across inference, lowering, narrowing, normalization, and throw logic to destructure new TyAttr fields. Propagated TyAttr::default() through type construction sites.
PPIR stream expansion system
baml_language/crates/baml_compiler2_ppir/src/expand.rs, ty.rs, lib.rs
Introduced new expand.rs module implementing BEP-006 v12 stream type expansion with expand_partial() and stream_expand() entry points, SapAttrs struct for SAP typing restrictions, and SymbolKind classification. Refactored PpirTypeAttrs to use TyAttrValue-based model. Updated PpirTy::from_type_expr to extract attributes from TypeExpr.attrs(). Redesigned canonical query system: file_semantic_index, namespace_items, and package_items now synthesize and aggregate *$stream AST items.
Type inference attribute handling
baml_language/crates/baml_compiler2_tir/src/inference.rs
Updated ResolvedClassFields.fields tuple structure to include SAP attribute names Vec<(Name, Ty, Vec<Name>)>. Extended resolve_class_fields to compute per-field SAP attribute names from field type expressions.
HIR type extraction
baml_language/crates/baml_compiler2_hir/src/builder.rs, signature.rs
Updated pattern matching for restructured TypeExpr variants. Changed unresolved parameter type default to TypeExpr::Unknown { attrs: vec![] }.
MIR lowering
baml_language/crates/baml_compiler2_mir/src/lower.rs
Updated convert_tir2_ty and related MIR construction to match new Tir2Ty variant shapes with additional fields. Modified self-parameter type resolution to detect TypeExpr::Unknown { .. } struct form.
Builtin extraction
baml_language/crates/baml_builtins2_codegen/src/extract.rs
Updated throw-category extraction and type conversion to use struct-form TypeExpr variants (Path { segments, .. }, Union { variants, .. }, etc.). Adjusted union null-filter to test TypeExpr::Null { .. }.
LSP type display utilities
baml_language/crates/baml_lsp2_actions/src/utils.rs, type_info.rs, completions.rs, annotations.rs, tokens.rs
Updated type rendering and pattern matching for new Ty attribute fields and TypeExpr struct variants. Adjusted resolved.fields destructuring to handle (name, ty, sap_attrs) tuple. Updated Ty::Class/Enum/Primitive/etc. pattern matches to ignore new TyAttr fields.
Syntax tree helpers
baml_language/crates/baml_compiler_syntax/src/ast.rs
Added public UnionMemberParts::attributes() iterator method to extract Attribute child nodes.
Test infrastructure & snapshots
baml_language/crates/baml_tests/src/compiler2_tir/{mod.rs, inference.rs, phase3a.rs, phase3a_recursion.rs, phase5.rs}, baml_language/crates/tools_onionskin/src/compiler.rs
Updated type rendering functions (type_expr_to_string, render_tir, hir2_type_expr_to_string) to pattern-match struct-form variants. Extended snapshots to include synthesized *$stream class/type-alias declarations with SAP attributes. Updated field iteration to destructure (name, ty, sap_attrs) tuples.
Test fixture files
baml_language/crates/baml_tests/projects/stream_types/{basic.baml, complex.baml, attrs.baml, edge_cases.baml}
Added BAML schema test files covering stream-directive behavior, type attributes at field/class level, recursive types, unions, literals, and edge cases.
Automated fix scripts
fix_ty.py, fix_ty2.py, fix_ty3.py, fix_ty_final.py
Added four Python helper scripts to automate cargo check error recovery: parsing compiler diagnostics, classifying fixes, applying targeted text replacements for missing TyAttr arguments, struct-pattern conversions, field-count mismatches, and import injection.

Sequence Diagram(s)

Given the nature of this change—primarily type representation refactoring and PPIR infrastructure introduction—generating sequence diagrams is not appropriate. The changes involve:

  • Pattern matching updates that don't alter control flow
  • Addition of metadata fields to existing types
  • Type system restructuring (not new sequential interactions)
  • Static AST synthesis and aggregation (not dynamic interactions)

The PPIR expansion logic, while substantial, operates as a static pre-processing transformation without multi-component interactions that would benefit from sequencing visualization.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Justification: This PR exhibits high complexity and scope: it introduces a new PPIR stream-expansion subsystem (483 lines in expand.rs), restructures core type representations (Ty and TypeExpr) across the entire compiler with heterogeneous pattern-match updates across 20+ files, adds type-attribute propagation machinery, refactors canonical query semantics to synthesize $stream types, and includes substantial test/snapshot updates. While many changes are repetitive pattern matching, the variety of affected compilation phases, the density of logic in PPIR expansion/canonicalization, and the cascading nature of type-representation changes demand careful architectural and logical verification across multiple interdependent compiler stages.

Possibly related PRs

Suggested reviewers

  • imalsogreg
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'implement new PPIR' is directly related to the main changes in this PR, which implement a new PPIR (Partial Parse Intermediate Representation) expansion system. This is the primary purpose of the extensive changes shown in the raw summary.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch push-pqsmnrvrxlxy

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 and usage tips.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 21, 2026

Merging this PR will degrade performance by 41.88%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

❌ 12 regressed benchmarks
✅ 3 untouched benchmarks
⏩ 98 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime bench_incremental_rename_type 15.4 ms 22.1 ms -30.44%
WallTime bench_incremental_close_string 11.1 ms 13.8 ms -19.71%
WallTime bench_scale_100_functions 35.8 ms 61 ms -41.36%
WallTime bench_single_simple_file 8.2 ms 11 ms -25.24%
WallTime bench_incremental_add_new_file 5.9 ms 8.5 ms -30.32%
WallTime bench_incremental_add_string_char 11.1 ms 14 ms -20.46%
WallTime bench_incremental_add_user_field 13.1 ms 18.4 ms -29.13%
WallTime bench_incremental_add_field 4.6 ms 6.3 ms -27.18%
WallTime bench_incremental_add_attribute 11.1 ms 13.9 ms -20.09%
WallTime bench_incremental_modify_function 4.6 ms 6.3 ms -26.92%
WallTime bench_scale_deep_nesting 11.2 ms 19.4 ms -41.88%
WallTime bench_empty_project 7.5 ms 9.3 ms -19.3%

Comparing push-pqsmnrvrxlxy (d2abfb7) with canary (248a49f)

Open in CodSpeed

Footnotes

  1. 98 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eed6a53ca5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from eed6a53 to 127240c Compare March 21, 2026 00:18
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 21, 2026

Binary size checks passed

7 passed

Artifact Platform Gzip Baseline Delta Status
bridge_cffi Linux 4.0 MB 5.7 MB -1.7 MB (-29.2%) OK
bridge_cffi-stripped Linux 2.5 MB 4.3 MB -1.8 MB (-41.5%) OK
bridge_cffi macOS 3.3 MB 4.6 MB -1.3 MB (-29.1%) OK
bridge_cffi-stripped macOS 2.0 MB 3.5 MB -1.5 MB (-42.2%) OK
bridge_cffi Windows 3.2 MB 4.6 MB -1.4 MB (-29.7%) OK
bridge_cffi-stripped Windows 2.1 MB 3.5 MB -1.5 MB (-41.9%) OK
bridge_wasm WASM 2.0 MB 3.0 MB -979.9 KB (-33.1%) OK

Generated by cargo size-gate · workflow run

@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from 127240c to 8471286 Compare March 23, 2026 18:42
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from 8471286 to 10e6ebf Compare March 23, 2026 20:01
@sxlijin sxlijin force-pushed the paulo/rust-functions-2 branch from 8ae3391 to 291af76 Compare March 23, 2026 21:29
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from 10e6ebf to b49f6fb Compare March 23, 2026 21:32
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from b49f6fb to 1adcd79 Compare March 23, 2026 21:48
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from 1adcd79 to a8bd49e Compare March 23, 2026 21:52
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from a8bd49e to c22189e Compare March 23, 2026 21:53
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from c22189e to 69485c1 Compare March 23, 2026 22:20
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from 69485c1 to 74ca579 Compare March 23, 2026 22:38
@sxlijin sxlijin force-pushed the push-pqsmnrvrxlxy branch from 74ca579 to 6271e5b Compare March 24, 2026 00:53
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
baml_language/crates/bex_sap/src/sap_model/convert.rs (1)

15-25: 🧹 Nitpick | 🔵 Trivial

Remove the unused ParseFloat error variant.

The ParseFloat variant (line 18) is unreachable—no code in this module or elsewhere in the codebase produces a std::num::ParseFloatError. The variant can be safely removed.

baml_language/crates/tools_onionskin/src/compiler.rs (1)

2834-2838: ⚠️ Potential issue | 🟡 Minor

Render SAP attrs in the TIR2 column browser too.

The flat run_tir2() view now shows @sap.*, but this branch drops _sap_attrs, so the column/detail pane renders the same field as unannotated. That makes the two TIR2 views disagree on the resolved field shape.

Possible fix
-                            for (fname, fty, _sap_attrs) in &resolved.fields {
-                                detail.push(vec![
-                                    DetailSpan::Code(format!("    {fname}")),
-                                    DetailSpan::TypeAnnotation(format!(": {fty}")),
-                                ]);
+                            for (fname, fty, sap_attrs) in &resolved.fields {
+                                let mut line = vec![
+                                    DetailSpan::Code(format!("    {fname}")),
+                                    DetailSpan::TypeAnnotation(format!(": {fty}")),
+                                ];
+                                if !sap_attrs.is_empty() {
+                                    line.push(DetailSpan::Code(format!(
+                                        " {}",
+                                        sap_attrs
+                                            .iter()
+                                            .map(|a| format!("@{a}"))
+                                            .collect::<Vec<_>>()
+                                            .join(" ")
+                                    )));
+                                }
+                                detail.push(line);
                             }
♻️ Duplicate comments (9)
baml_language/crates/baml_compiler2_tir/src/package_interface.rs (1)

272-275: ⚠️ Potential issue | 🔴 Critical

self type resolution still exports the wrong package for non-baml classes.

Line 272 correctly matches TypeExpr::Unknown { .. }, but this branch still routes through build_self_type_for_class, which hardcodes package "baml" (Line 458). That produces incorrect exported method signatures for dependency classes and inconsistent behavior versus own-package lookup.

baml_language/crates/baml_tests/src/compiler2_tir/mod.rs (1)

895-900: ⚠️ Potential issue | 🟡 Minor

Preserve union precedence in type_expr_to_string_hir.

Without wrapping union inners here, (A | B)? renders as A | B? and (A | B)[] renders as A | B[], which changes the snapshot meaning.

🛠️ Suggested fix
-                baml_compiler2_ast::TypeExpr::Optional { inner, .. } => {
-                    format!("{}?", type_expr_to_string_hir(inner, pkg_prefix))
-                }
-                baml_compiler2_ast::TypeExpr::List { inner, .. } => {
-                    format!("{}[]", type_expr_to_string_hir(inner, pkg_prefix))
-                }
+                baml_compiler2_ast::TypeExpr::Optional { inner, .. } => {
+                    let s = type_expr_to_string_hir(inner, pkg_prefix);
+                    if matches!(**inner, baml_compiler2_ast::TypeExpr::Union { .. }) {
+                        format!("({s})?")
+                    } else {
+                        format!("{s}?")
+                    }
+                }
+                baml_compiler2_ast::TypeExpr::List { inner, .. } => {
+                    let s = type_expr_to_string_hir(inner, pkg_prefix);
+                    if matches!(**inner, baml_compiler2_ast::TypeExpr::Union { .. }) {
+                        format!("({s})[]")
+                    } else {
+                        format!("{s}[]")
+                    }
+                }
baml_language/crates/baml_compiler2_ast/src/lib.rs (1)

990-1036: 🧹 Nitpick | 🔵 Trivial

Test documents current parser limitation but assertion is permissive.

The test at lines 1026-1029 accepts @stream.done as either a type attribute OR a field attribute. Per the learnings, @stream.done should only be a type-level attribute. While the comment documents this as a "current parser limitation," the permissive assertion means this test will pass even if the parser is later fixed, potentially masking regressions in either direction.

Consider splitting into two assertions to explicitly document the expected vs. actual behavior:

Suggested improvement
-        assert!(
-            stream_done_is_type_attr || stream_done_is_field_attr,
-            "expected `@stream.done` somewhere: type_attrs={type_attr_names:?}, field_attrs={field_attr_names:?}",
-        );
+        // Document current behavior: `@stream.done` ends up as field attr when after `@alias`
+        // TODO: When parser is fixed, change this to assert stream_done_is_type_attr
+        assert!(
+            stream_done_is_field_attr,
+            "documenting current parser behavior: `@stream.done` should be field attr here, \
+             type_attrs={type_attr_names:?}, field_attrs={field_attr_names:?}",
+        );

Based on learnings: alias, description, and skip are the only field-level attributes. All other @ attributes including stream.* are type-level attributes.

baml_language/crates/baml_compiler2_tir/src/inference.rs (1)

433-434: ⚠️ Potential issue | 🟠 Major

Keep alias-cycle validation on the pre-expansion package view.

Switching this query to baml_compiler2_ppir::package_items() pulls synthesized *$stream aliases into the cycle graph. The new recursion snapshots already show the regression: every invalid user alias now reports a second A$stream / Loop$stream diagnostic at 0..0.

Possible fix
-    let pkg_items = baml_compiler2_ppir::package_items(db, pkg_id);
+    let pkg_items = baml_compiler2_hir::package::package_items(db, pkg_id);

If you still need PPIR items elsewhere, filter generated *$stream aliases out before calling collect_type_aliases.

baml_language/crates/baml_compiler2_ast/src/lower_type_expr.rs (2)

119-123: ⚠️ Potential issue | 🟠 Major

Preserve attrs on parenthesized types instead of dropping them.

collect_type_attrs() has already captured outer attrs here, but these paths recurse into the inner type and return it unchanged, and apply_modifiers_from_parts() only reattaches attrs when a postfix wrapper exists. (Foo | Bar) @sap.pending_never and `A | (B) `@stream.done therefore lose their type attrs entirely.

Please add a Rust unit regression for an attributed parenthesized type. Based on learnings: alias, description, and skip are the only field-level attributes; all other @ attributes are type-level attributes that apply to type expressions.

Also applies to: 207-220, 291-296


225-230: ⚠️ Potential issue | 🟠 Major

Route union-member attrs to the outer wrapper when [] or ? are present.

These branches still build the base with attrs and then call apply_modifiers_from_parts(..., vec![]). For members like Foo[] @stream.done or `map<string, Foo>? `@sap.pending_never, the attr lands on the inner base instead of the outer List/Optional, so downstream .attrs() readers miss it on the actual member type.

Fix pattern
-        let base = TypeExpr::Literal {
-            value: baml_base::Literal::String(s),
-            attrs,
-        };
-        return apply_modifiers_from_parts(base, parts, vec![]);
+        let base = TypeExpr::Literal {
+            value: baml_base::Literal::String(s),
+            attrs: vec![],
+        };
+        return apply_modifiers_from_parts(base, parts, attrs);

Apply the same pattern to the integer/float/map/named-type branches in this function.

Please add a Rust unit regression for an attributed union member with a postfix modifier. Based on learnings: `alias`, `description`, and `skip` are the only field-level attributes; all other `@` attributes are type-level attributes that apply to type expressions.

Also applies to: 233-238, 241-246, 262-267, 272-283

baml_language/crates/baml_compiler2_ppir/src/lib.rs (2)

202-211: ⚠️ Potential issue | 🟠 Major

Synthetic fields drop field-level attributes (@alias, @description, @skip).

Line 208 uses attributes: vec![], which discards field-level attributes from the source field. This changes the serialized shape and skip semantics of $stream classes relative to the original type.

Suggested fix
                     fields.push(ast::FieldDef {
                         name: raw.name,
                         type_expr: Some(ast::SpannedTypeExpr {
                             expr: type_expr,
                             span: TextRange::default(),
                         }),
-                        attributes: vec![],
+                        attributes: field.attributes.clone(),
                         span: TextRange::default(),
                         name_span: TextRange::default(),
                     });

Based on learnings, alias, description, and skip are the only field-level attributes and should be preserved on stream class fields.


227-235: ⚠️ Potential issue | 🟠 Major

Synthetic $stream classes drop generic type parameters.

Line 229 uses generic_params: Vec::new(), but the generated fields may still reference type parameters like T. For class Box<T> { value T }, the synthetic Box$stream will contain an unbound T that downstream resolution treats as a named type.

Suggested fix
                 synthetic_items.push(ast::Item::Class(ast::ClassDef {
                     name: SmolStr::new(format!("{}$stream", c.name)),
-                    generic_params: Vec::new(),
+                    generic_params: c.generic_params.clone(),
                     fields,
                     methods: Vec::new(),
baml_language/crates/baml_compiler2_ppir/src/expand.rs (1)

302-314: ⚠️ Potential issue | 🟠 Major

Alias body attributes are overwritten rather than merged, losing alias-defined attributes.

At lines 305-306, direct assignment overwrites the alias body's stream_must_exist and stream_done attributes without merging. This means attributes declared on the alias definition itself are lost when the alias is used without explicitly repeating those attributes at the use site.

This is inconsistent with how @@stream.* block attributes are handled at lines 458-459, which use TyAttrValue::or() to preserve existing values. Since alias bodies are populated from type alias definitions via PpirTy::from_type_expr() and include extracted type attributes, use-site values should merge with alias-defined attributes, not replace them.

Recommend using TyAttrValue::or() to merge like the block attribute logic:

Suggested fix
                         if let Some(body) = alias_bodies.get(path) {
                             let mut resolved = body.clone();
-                            resolved.attrs_mut().stream_must_exist = must_exist;
-                            resolved.attrs_mut().stream_done = done;
+                            let alias_must_exist = resolved.attrs().stream_must_exist;
+                            let alias_done = resolved.attrs().stream_done;
+                            resolved.attrs_mut().stream_must_exist = alias_must_exist.or(must_exist);
+                            resolved.attrs_mut().stream_done = alias_done.or(done);

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 77a61edc-46da-4f6d-bc1d-088eee6d68d1

📥 Commits

Reviewing files that changed from the base of the PR and between cd57e2e and a81a307.

⛔ Files ignored due to path filters (53)
  • baml_language/crates/baml_tests/snapshots/attribute_validation/baml_tests__attribute_validation__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/duplicate_class_span/baml_tests__duplicate_class_span__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/error_cases/baml_tests__error_cases__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/function_types/baml_tests__function_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/generator/baml_tests__generator__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/match_exhaustiveness/baml_tests__match_exhaustiveness__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/paren_union_test/baml_tests__paren_union_test__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_error_recovery/baml_tests__parser_error_recovery__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_expressions/baml_tests__parser_expressions__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_stress/baml_tests__parser_stress__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_strings/baml_tests__parser_strings__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/pending_greaters_fix/baml_tests__pending_greaters_fix__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_annotations/baml_tests__stream_annotations__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_crossfile/baml_tests__stream_crossfile__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__03_hir2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_7_mir2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_tir2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__05_diagnostics2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__06_codegen2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_annotation/baml_tests__type_annotation__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_annotation_errors/baml_tests__type_annotation_errors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap is excluded by !**/*.snap
📒 Files selected for processing (41)
  • baml_language/crates/baml_base/src/attr.rs
  • baml_language/crates/baml_builtins2_codegen/src/extract.rs
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_ast/src/companions.rs
  • baml_language/crates/baml_compiler2_ast/src/lib.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler2_emit/src/lib.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/signature.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_ppir/src/expand.rs
  • baml_language/crates/baml_compiler2_ppir/src/lib.rs
  • baml_language/crates/baml_compiler2_ppir/src/ty.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/generics.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_compiler2_tir/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler2_tir/src/package_interface.rs
  • baml_language/crates/baml_compiler2_tir/src/throw_inference.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_lsp2_actions/src/completions.rs
  • baml_language/crates/baml_lsp2_actions/src/type_info.rs
  • baml_language/crates/baml_lsp2_actions/src/utils.rs
  • baml_language/crates/baml_tests/projects/stream_types/attrs.baml
  • baml_language/crates/baml_tests/projects/stream_types/basic.baml
  • baml_language/crates/baml_tests/projects/stream_types/complex.baml
  • baml_language/crates/baml_tests/projects/stream_types/edge_cases.baml
  • baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/mod.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase3a.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase3a_recursion.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase5.rs
  • baml_language/crates/baml_type/src/attr.rs
  • baml_language/crates/baml_type/src/defs.rs
  • baml_language/crates/bex_heap/src/gc.rs
  • baml_language/crates/bex_heap/src/tlab.rs
  • baml_language/crates/bex_sap/src/sap_model/convert.rs
  • baml_language/crates/bex_vm_types/src/types.rs
  • baml_language/crates/tools_onionskin/src/compiler.rs
💤 Files with no reviewable changes (4)
  • baml_language/crates/bex_heap/src/gc.rs
  • baml_language/crates/bex_heap/src/tlab.rs
  • baml_language/crates/baml_compiler2_emit/src/lib.rs
  • baml_language/crates/bex_vm_types/src/types.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs (1)

787-800: ⚠️ Potential issue | 🟠 Major

Don't lower bare builtin type tokens as unresolved paths.

When the parser takes this fallback, string, int, bool, null, etc. are all turned into TypeExpr::Path, so typed match/catch bindings resolve differently depending on whether the CST produced a TYPE_EXPR node or just a WORD token. Reuse the normal token-to-TypeExpr mapping here before defaulting to Path.

baml_language/crates/tools_onionskin/src/compiler.rs (2)

25-71: ⚠️ Potential issue | 🟡 Minor

Render TypeExpr.attrs in Onionskin's type strings.

hir2_type_expr_to_string still makes string and string @stream.done`` render identically, so the AST/HIR/HIR2/TIR views cannot show whether the new type-level attrs survived parsing and lowering. At minimum, append each node's attrs when building the display string.


2834-2838: ⚠️ Potential issue | 🟡 Minor

Keep the class detail pane in sync with the flat TIR2 view.

The flat renderer above now shows @..., but this detail view still binds _sap_attrs and suppresses them. Selecting a class therefore hides the new per-field SAP state even though the same data is already available here.

Diff to keep the detail pane aligned
-                            for (fname, fty, _sap_attrs) in &resolved.fields {
-                                detail.push(vec![
-                                    DetailSpan::Code(format!("    {fname}")),
-                                    DetailSpan::TypeAnnotation(format!(": {fty}")),
-                                ]);
-                            }
+                            for (fname, fty, sap_attrs) in &resolved.fields {
+                                let mut line = vec![
+                                    DetailSpan::Code(format!("    {fname}")),
+                                    DetailSpan::TypeAnnotation(format!(": {fty}")),
+                                ];
+                                if !sap_attrs.is_empty() {
+                                    let attrs = sap_attrs
+                                        .iter()
+                                        .map(|a| format!("@{a}"))
+                                        .collect::<Vec<_>>()
+                                        .join(" ");
+                                    line.push(DetailSpan::Code(format!(" {attrs}")));
+                                }
+                                detail.push(line);
+                            }
♻️ Duplicate comments (13)
baml_language/crates/baml_lsp2_actions/src/utils.rs (1)

194-194: ⚠️ Potential issue | 🟡 Minor

Use Display for media hover strings.

format!("{kind:?}").to_lowercase() is only accidentally correct for the concrete media kinds; MediaKind::Generic still renders as generic, so hover text diverges from the source-syntax renderer. kind.to_string() fixes that without changing the existing concrete cases.

Suggested fix
-        TypeExpr::Media { kind, .. } => format!("{kind:?}").to_lowercase(),
+        TypeExpr::Media { kind, .. } => kind.to_string(),
baml_language/crates/baml_compiler2_tir/src/package_interface.rs (1)

272-275: ⚠️ Potential issue | 🔴 Critical

This now exports dependency self under the wrong package.

Routing untyped self through build_self_type_for_class() exposes the helper's hard-coded Name::new("baml"). A dependency method like pkg.User.foo(self) will now publish self as baml.User, while lookup_own_class_method() still resolves the same parameter against the defining package. Please derive the package from the defining file and reuse that logic in both paths.

baml_language/crates/baml_compiler2_ast/src/lib.rs (1)

991-1035: ⚠️ Potential issue | 🟠 Major

Make this test fail on misplaced @stream.done.

Allowing @stream.done to pass as either a type attr or a field attr makes the regression invisible. The new PPIR path only consumes TypeExpr::attrs(), so this test still passes while stream expansion silently drops the flag.

Suggested tightening
-        assert!(
-            stream_done_is_type_attr || stream_done_is_field_attr,
-            "expected `@stream.done` somewhere: type_attrs={type_attr_names:?}, field_attrs={field_attr_names:?}",
-        );
+        assert!(
+            stream_done_is_type_attr,
+            "expected `@stream.done` as a type attribute: type_attrs={type_attr_names:?}, field_attrs={field_attr_names:?}",
+        );
+        assert!(
+            !stream_done_is_field_attr,
+            "@stream.done should not be accepted as a field attribute: field_attrs={field_attr_names:?}",
+        );
baml_language/crates/baml_compiler2_ppir/src/ty.rs (1)

279-287: ⚠️ Potential issue | 🟠 Major

Don't erase float literal types to Unknown.

TypeExpr::Literal still distinguishes float literals, but this branch collapses them before PPIR/stream expansion. A type like 3.14 | null now takes the Unknown path instead of the literal path, which changes behavior relative to the other literal cases. Please preserve floats here with a lossless PPIR representation.

baml_language/crates/baml_lsp2_actions/src/type_info.rs (1)

221-225: ⚠️ Potential issue | 🟠 Major

Hover still drops the new @sap.* field metadata.

resolve_class_fields() now carries the stream-field SAP attrs in the third tuple element, but this map throws them away. Hover for $stream companion classes will therefore render only null | ..., while render_tir now includes @sap.parse_without_null / @sap.in_progress_never on the same fields.

Suggested fix
 let fields = resolved
     .fields
     .iter()
-    .map(|(field_name, ty, _)| (field_name.as_str().to_string(), utils::display_ty(ty)))
+    .map(|(field_name, ty, sap_attrs)| {
+        let attrs = sap_attrs
+            .iter()
+            .map(|a| format!("@{a}"))
+            .collect::<Vec<_>>()
+            .join(" ");
+        let rendered_ty = if attrs.is_empty() {
+            utils::display_ty(ty)
+        } else {
+            format!("{} {}", utils::display_ty(ty), attrs)
+        };
+        (field_name.as_str().to_string(), rendered_ty)
+    })
     .collect();
baml_language/crates/baml_compiler2_tir/src/builder.rs (1)

1411-1417: ⚠️ Potential issue | 🟠 Major

Bare primitive/media pattern sugar still lowers to unknown.

These branches synthesize TypeExpr::Path for int, string, image, etc., but lower_type_expr_in_ns() only recognizes those spellings through the dedicated primitive/media variants. The lowered type becomes unknown, so match x { int => ... } stops narrowing and catch (e: string) can turn into an accidental catch-all because ty_covers_fact(Unknown, _) is true.

Suggested fix
-                    self.lower_pattern_type_expr(
-                        &TypeExpr::Path {
-                            segments: vec![name.clone()],
-                            attrs: vec![],
-                        },
-                        at_expr,
-                    )
+                    self.lower_bare_type_sugar(name, at_expr)
fn lower_bare_type_sugar(&mut self, name: &Name, at_expr: ExprId) -> Ty {
    match name.as_str() {
        "int" => Ty::Primitive(PrimitiveType::Int),
        "float" => Ty::Primitive(PrimitiveType::Float),
        "string" => Ty::Primitive(PrimitiveType::String),
        "bool" => Ty::Primitive(PrimitiveType::Bool),
        "null" => Ty::Primitive(PrimitiveType::Null),
        "image" => Ty::Primitive(PrimitiveType::Image),
        "audio" => Ty::Primitive(PrimitiveType::Audio),
        "video" => Ty::Primitive(PrimitiveType::Video),
        "pdf" => Ty::Primitive(PrimitiveType::Pdf),
        _ => self.lower_pattern_type_expr(
            &TypeExpr::Path {
                segments: vec![name.clone()],
                attrs: vec![],
            },
            at_expr,
        ),
    }
}

Also applies to: 1543-1549

baml_language/crates/baml_tests/projects/stream_types/attrs.baml (1)

1-15: ⚠️ Potential issue | 🟡 Minor

Broaden this fixture past the easy cases.

This still only exercises @stream.* on bare leaf types plus a pure block-level case. Please add at least one wrapped type (string?, int[], etc.), one class that mixes @@stream.done with a field-level @stream.*, and one real field-level attr (@alias/@description/@skip) next to a @stream.* type so the parser boundary this PR touches is actually covered.

Based on learnings, alias, description, and skip are the only field-level attributes; all other @ attributes including stream.* are type-level attributes that apply to type expressions.

baml_language/crates/baml_tests/src/compiler2_tir/mod.rs (1)

895-900: ⚠️ Potential issue | 🟠 Major

Parenthesize union inners in type_expr_to_string_hir.

The TIR helper above already handles this, but the HIR renderer still prints A | B? / A | B[] for Optional and List over a union, so (A | B)? and (A | B)[] snapshots change meaning.

🛠️ Proposed fix
                 baml_compiler2_ast::TypeExpr::Optional { inner, .. } => {
-                    format!("{}?", type_expr_to_string_hir(inner, pkg_prefix))
+                    let s = type_expr_to_string_hir(inner, pkg_prefix);
+                    if matches!(**inner, baml_compiler2_ast::TypeExpr::Union { .. }) {
+                        format!("({s})?")
+                    } else {
+                        format!("{s}?")
+                    }
                 }
                 baml_compiler2_ast::TypeExpr::List { inner, .. } => {
-                    format!("{}[]", type_expr_to_string_hir(inner, pkg_prefix))
+                    let s = type_expr_to_string_hir(inner, pkg_prefix);
+                    if matches!(**inner, baml_compiler2_ast::TypeExpr::Union { .. }) {
+                        format!("({s})[]")
+                    } else {
+                        format!("{s}[]")
+                    }
                 }
baml_language/crates/baml_compiler2_ppir/src/expand.rs (2)

72-84: ⚠️ Potential issue | 🟠 Major

Resolve aliases before computing a union's pending default.

Every alias returns PendingDefault::Null here. A union like Rows | int where type Rows = string[] will still prepend null, even though Rows already has a non-null pending default from its body. Thread alias_bodies and the same depth guard through pending_default / union_pending_default so this decision is based on the resolved alias body.

Also applies to: 94-106


302-306: ⚠️ Potential issue | 🟠 Major

Don't clobber alias-defined @stream.* attrs during alias resolution.

body already carries the alias body's top-level stream attrs. Replacing them with must_exist / done here clears flags declared on the alias itself, so type Foo = string @stream.done`` behaves as undecorated unless each reference repeats the flag.

🛠️ Proposed fix
                         if let Some(body) = alias_bodies.get(path) {
                             // Set merged attrs on the resolved body and recurse
                             let mut resolved = body.clone();
-                            resolved.attrs_mut().stream_must_exist = must_exist;
-                            resolved.attrs_mut().stream_done = done;
+                            let alias_must_exist = resolved.attrs().stream_must_exist;
+                            let alias_done = resolved.attrs().stream_done;
+                            resolved.attrs_mut().stream_must_exist =
+                                alias_must_exist.or(must_exist);
+                            resolved.attrs_mut().stream_done =
+                                alias_done.or(done);
                             return stream_expand_inner(
                                 &resolved,
                                 package_items,
baml_language/crates/baml_compiler2_ppir/src/lib.rs (3)

50-76: ⚠️ Potential issue | 🟠 Major

Qualify PPIR's block-attr and alias-body maps by package.

These helpers scan project.files(db) but key the results only by namespace_path + name. If two packages both define Foo in the same namespace, stream expansion in one package can pick up the other package's alias body or @@stream.* flags.

Also applies to: 82-106


202-210: ⚠️ Potential issue | 🟠 Major

Preserve field metadata on generated $stream fields.

Clearing attributes here strips @alias, @description, and @skip from the synthetic field, which changes serialized names and skip semantics for the streamed class.

🛠️ Proposed fix
                     fields.push(ast::FieldDef {
                         name: raw.name,
                         type_expr: Some(ast::SpannedTypeExpr {
                             expr: type_expr,
                             span: TextRange::default(),
                         }),
-                        attributes: vec![],
+                        attributes: field.attributes.clone(),
                         span: TextRange::default(),
                         name_span: TextRange::default(),
                     });
Based on learnings: `alias`, `description`, and `skip` are the only field-level attributes (applied to class/enum fields). All other `@` attributes including `check`, `assert`, and `stream.*` are type-level attributes that apply to type expressions.

227-229: ⚠️ Potential issue | 🟠 Major

Keep generic parameters on the synthesized $stream class.

stream_expand can still emit field types containing T / K / V, but this synthetic ClassDef drops generic_params. class Box<T> { value T } will therefore produce Box$stream.value: T with T unresolved, typically at synthetic 0..0 spans.

🛠️ Proposed fix
                 synthetic_items.push(ast::Item::Class(ast::ClassDef {
                     name: SmolStr::new(format!("{}$stream", c.name)),
-                    generic_params: Vec::new(),
+                    generic_params: c.generic_params.clone(),
                     fields,
                     methods: Vec::new(),
                     attributes: class_attrs,

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 332a31c7-4d12-4809-b801-a595d10b8244

📥 Commits

Reviewing files that changed from the base of the PR and between a81a307 and 1de517a.

⛔ Files ignored due to path filters (53)
  • baml_language/crates/baml_tests/snapshots/attribute_validation/baml_tests__attribute_validation__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/duplicate_class_span/baml_tests__duplicate_class_span__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/error_cases/baml_tests__error_cases__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/function_types/baml_tests__function_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/generator/baml_tests__generator__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/match_exhaustiveness/baml_tests__match_exhaustiveness__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/paren_union_test/baml_tests__paren_union_test__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_error_recovery/baml_tests__parser_error_recovery__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_expressions/baml_tests__parser_expressions__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_stress/baml_tests__parser_stress__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_strings/baml_tests__parser_strings__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/pending_greaters_fix/baml_tests__pending_greaters_fix__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_annotations/baml_tests__stream_annotations__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_crossfile/baml_tests__stream_crossfile__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__03_hir2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_7_mir2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_tir2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__05_diagnostics2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__06_codegen2.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_annotation/baml_tests__type_annotation__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_annotation_errors/baml_tests__type_annotation_errors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap is excluded by !**/*.snap
📒 Files selected for processing (41)
  • baml_language/crates/baml_base/src/attr.rs
  • baml_language/crates/baml_builtins2_codegen/src/extract.rs
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_ast/src/companions.rs
  • baml_language/crates/baml_compiler2_ast/src/lib.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler2_emit/src/lib.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/signature.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_ppir/src/expand.rs
  • baml_language/crates/baml_compiler2_ppir/src/lib.rs
  • baml_language/crates/baml_compiler2_ppir/src/ty.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/generics.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_compiler2_tir/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler2_tir/src/package_interface.rs
  • baml_language/crates/baml_compiler2_tir/src/throw_inference.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_lsp2_actions/src/completions.rs
  • baml_language/crates/baml_lsp2_actions/src/type_info.rs
  • baml_language/crates/baml_lsp2_actions/src/utils.rs
  • baml_language/crates/baml_tests/projects/stream_types/attrs.baml
  • baml_language/crates/baml_tests/projects/stream_types/basic.baml
  • baml_language/crates/baml_tests/projects/stream_types/complex.baml
  • baml_language/crates/baml_tests/projects/stream_types/edge_cases.baml
  • baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/mod.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase3a.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase3a_recursion.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase5.rs
  • baml_language/crates/baml_type/src/attr.rs
  • baml_language/crates/baml_type/src/defs.rs
  • baml_language/crates/bex_heap/src/gc.rs
  • baml_language/crates/bex_heap/src/tlab.rs
  • baml_language/crates/bex_sap/src/sap_model/convert.rs
  • baml_language/crates/bex_vm_types/src/types.rs
  • baml_language/crates/tools_onionskin/src/compiler.rs
💤 Files with no reviewable changes (4)
  • baml_language/crates/baml_compiler2_emit/src/lib.rs
  • baml_language/crates/bex_heap/src/gc.rs
  • baml_language/crates/bex_heap/src/tlab.rs
  • baml_language/crates/bex_vm_types/src/types.rs

coderabbitai[bot]
coderabbitai bot previously requested changes Mar 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
baml_language/crates/baml_compiler2_mir/src/lower.rs (1)

105-214: ⚠️ Potential issue | 🟠 Major

Preserve TyAttr when lowering TIR into MIR types.

convert_tir2_ty() initializes a fresh TyAttr::default() and reuses it for every arm, so any attrs attached in TIR disappear before expr_ty(), pat_ty(), and parameter/return lowering feed MIR. That blocks end-to-end type-attribute behavior even if earlier phases populate Tir2Ty correctly. Map the incoming attr through each variant here instead of zeroing it out.

Based on learnings: New language features for BAML require coordinated updates across Parser (parser-database), IR/validation (baml-core), Compiler (baml-compiler), and VM (baml-vm).

baml_language/crates/baml_compiler2_tir/src/lower_type_expr.rs (1)

52-210: ⚠️ Potential issue | 🔴 Critical

Lower the new TypeExpr attrs instead of discarding them.

Every branch here emits TyAttr::default() and never reads the record-style attrs now carried on TypeExpr. That means @check, @assert, @stream.*, etc. are dropped at the AST→TIR boundary, so later phases never even see them. Thread type_expr.attrs() into the emitted TyAttr for both leaf and recursive variants.

Based on learnings: all @ attributes except alias, description, and skip are type-level attributes that apply to type expressions.

baml_language/crates/tools_onionskin/src/compiler.rs (2)

29-70: ⚠️ Potential issue | 🟠 Major

Render type-level attrs in this formatter.

Every arm here drops the new metadata with .., so HIR2/TIR2 signatures collapse attributed types back to plain Foo / string. Onionskin will hide the new PPIR/type-attribute surface instead of showing what was actually parsed.

Based on learnings, check, assert, and stream.* are type-level attributes that apply to type expressions.


2834-2838: ⚠️ Potential issue | 🟡 Minor

Keep sap_attrs in the TIR2 class detail pane.

The flat TIR2 renderer now includes these attrs, but the column-browser detail view throws them away. Selecting a class will therefore hide field type attrs even though the summary view shows them.

Based on learnings, check, assert, and stream.* are type-level attributes that apply to type expressions.

baml_language/crates/baml_compiler2_tir/src/throw_inference.rs (1)

447-468: ⚠️ Potential issue | 🟠 Major

Don't let TyAttr change throw-fact identity.

throw_fact_from_expr() normalizes runtime throws to default attrs and fact_display_name() already ignores attrs, but _ => out.insert(ty.clone()) keeps declared leaf attrs verbatim. The same nominal throw type can then land in the set twice depending only on whether it came from a throw expression or a throws contract. Canonicalize the leaf before inserting it so throw sets stay keyed by the thrown type, not incidental metadata.

baml_language/crates/baml_compiler2_tir/src/builder.rs (1)

704-723: ⚠️ Potential issue | 🟠 Major

Keep the annotation’s TyAttr on annotated let bindings.

This path stores ty from check_expr into bindings/locals, but check_expr usually returns the initializer’s inferred attr, not the annotation’s. For let x: int @stream.done = 1, x is recorded as plain 1/int, so later reads drop the declared streaming metadata.

🛠️ Suggested fix
-                        let ty = self.check_expr(*init, body, &ann_ty);
+                        let ty = self
+                            .check_expr(*init, body, &ann_ty)
+                            .with_attr(ann_ty.attr().clone());

Also applies to: 738-750

♻️ Duplicate comments (10)
baml_language/crates/baml_compiler_syntax/src/ast.rs (1)

262-267: 🛠️ Refactor suggestion | 🟠 Major

Add a focused lib test for attributed union members.

This helper is now the preservation point for union-member @... metadata; please add a unit test for cases like A @x | B, "lit" @x | T, and (A | B) @x``, then run cargo test --lib.

As per coding guidelines "Prefer writing Rust unit tests over integration tests where possible" and "Always run cargo test --lib if you changed any Rust code".

baml_language/crates/baml_lsp2_actions/src/type_info.rs (1)

224-224: ⚠️ Potential issue | 🟠 Major

Hover drops field type-attribute metadata.

At Line 224, destructuring (field_name, ty, _) discards the new field metadata from resolve_class_fields, so TypeInfo::Class hover cannot surface those annotations. Please plumb the third value through TypeInfo and hover rendering.

baml_language/crates/baml_compiler2_tir/src/inference.rs (2)

438-452: ⚠️ Potential issue | 🟠 Major

Run cycle detection on pre-expansion package items.

These helpers now walk baml_compiler2_ppir::package_items, which pulls synthesized *$stream aliases into the structural cycle graph again. That can recreate duplicate/0..0 diagnostics for user-defined cycles. Use the pre-expansion HIR package view here, or filter generated PPIR items before collecting aliases/fields.

Possible fix
-    let pkg_items = baml_compiler2_ppir::package_items(db, pkg_id);
+    let pkg_items = baml_compiler2_hir::package::package_items(db, pkg_id);

Apply the same change in both detect_invalid_alias_cycles() and detect_invalid_class_cycles().


581-586: ⚠️ Potential issue | 🟠 Major

Alias-declared attrs still don't survive ResolvedClassFields.

sap_attrs only read the field's immediate type_expr, so f: MyAlias still loses attrs declared on type MyAlias = ... @.... Downstream behavior now depends on whether the alias was spelled inline or expanded manually. Pull attr names from the resolved alias/TyAttr path too, not just the field syntax.

Based on learnings: all @ attributes except alias, description, and skip are type-level attributes that apply to type expressions.

baml_language/crates/baml_tests/src/compiler2_tir/mod.rs (1)

896-901: ⚠️ Potential issue | 🟠 Major

Keep union inners parenthesized in type_expr_to_string_hir.

The HIR renderer still appends ? / [] directly to the inner string. That turns (A | B)? into A | B? and (A | B)[] into A | B[], so the snapshots describe a different type than the AST.

🛠️ Suggested fix
-                baml_compiler2_ast::TypeExpr::Optional { inner, .. } => {
-                    format!("{}?", type_expr_to_string_hir(inner, pkg_prefix))
-                }
-                baml_compiler2_ast::TypeExpr::List { inner, .. } => {
-                    format!("{}[]", type_expr_to_string_hir(inner, pkg_prefix))
-                }
+                baml_compiler2_ast::TypeExpr::Optional { inner, .. } => {
+                    let s = type_expr_to_string_hir(inner, pkg_prefix);
+                    if matches!(**inner, baml_compiler2_ast::TypeExpr::Union { .. }) {
+                        format!("({s})?")
+                    } else {
+                        format!("{s}?")
+                    }
+                }
+                baml_compiler2_ast::TypeExpr::List { inner, .. } => {
+                    let s = type_expr_to_string_hir(inner, pkg_prefix);
+                    if matches!(**inner, baml_compiler2_ast::TypeExpr::Union { .. }) {
+                        format!("({s})[]")
+                    } else {
+                        format!("{s}[]")
+                    }
+                }
baml_language/crates/baml_compiler2_ppir/src/expand.rs (2)

50-54: ⚠️ Potential issue | 🟠 Major

Resolve aliases before choosing a union's pending default.

pending_default() still hard-codes every TypeAlias to Null. For type Rows = string[]; x: Rows | int, that forces the union down the null-prepend path instead of reusing the alias body's empty-array default, so the generated $stream type is wrong for alias-backed unions. Thread alias_bodies and the depth guard through pending_default() / union_pending_default() so this decision uses the resolved alias body.

Also applies to: 79-84, 94-100


301-306: ⚠️ Potential issue | 🟠 Major

Merge alias-body @stream.* flags instead of overwriting them.

body.clone() already carries the alias body's own top-level stream attrs. Replacing them here discards alias-defined @stream.must_exist / @stream.done, so type Foo = int @stream.must_exist`` behaves as if the alias had no flag unless every use-site repeats it.

Suggested fix
                         if let Some(body) = alias_bodies.get(path) {
                             // Set merged attrs on the resolved body and recurse
                             let mut resolved = body.clone();
-                            resolved.attrs_mut().stream_must_exist = must_exist;
-                            resolved.attrs_mut().stream_done = done;
+                            let alias_must_exist = resolved.attrs().stream_must_exist;
+                            let alias_done = resolved.attrs().stream_done;
+                            resolved.attrs_mut().stream_must_exist =
+                                alias_must_exist.or(must_exist);
+                            resolved.attrs_mut().stream_done =
+                                alias_done.or(done);
                             return stream_expand_inner(
baml_language/crates/baml_compiler2_ppir/src/lib.rs (3)

70-75: ⚠️ Potential issue | 🟠 Major

Use one canonical key shape for block_attrs and alias_bodies.

These helpers key entries as namespace_path + name and omit the package, but PpirTy::from_type_expr() later looks them up with the raw AST path segments. Relative names in non-root namespaces will silently miss, and same namespace/type pairs from different packages will collide. Either qualify both sides to the same package-aware path, or scope these maps per package/file and keep the raw AST spelling on both sides.

Also applies to: 104-106


202-208: ⚠️ Potential issue | 🟠 Major

Preserve field-level metadata on generated $stream fields.

This resets every synthetic field to attributes: vec![], which drops @alias, @description, and @skip from the source field. The generated $stream class then stops matching the original field name/description/skip semantics.

Suggested fix
                     fields.push(ast::FieldDef {
                         name: raw.name,
                         type_expr: Some(ast::SpannedTypeExpr {
                             expr: type_expr,
                             span: TextRange::default(),
                         }),
-                        attributes: vec![],
+                        attributes: field.attributes.clone(),
                         span: TextRange::default(),
                         name_span: TextRange::default(),
                     });

Based on learnings, alias, description, and skip are the only field-level attributes (applied to class/enum fields).


227-230: ⚠️ Potential issue | 🟠 Major

Keep the original generic parameters on the synthesized $stream class.

The generated fields can still mention T/K/V, but generic_params: Vec::new() leaves those names unbound. Downstream resolution will treat them as named types instead of type parameters.

Suggested fix
                 synthetic_items.push(ast::Item::Class(ast::ClassDef {
                     name: SmolStr::new(format!("{}$stream", c.name)),
-                    generic_params: Vec::new(),
+                    generic_params: c.generic_params.clone(),
                     fields,
                     methods: Vec::new(),

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 85e8af45-4af8-45d7-a1d0-2f8b1668245c

📥 Commits

Reviewing files that changed from the base of the PR and between 1de517a and 0ad17d9.

⛔ Files ignored due to path filters (48)
  • baml_language/crates/baml_tests/snapshots/attribute_validation/baml_tests__attribute_validation__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/duplicate_class_span/baml_tests__duplicate_class_span__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/error_cases/baml_tests__error_cases__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/function_types/baml_tests__function_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/generator/baml_tests__generator__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/match_exhaustiveness/baml_tests__match_exhaustiveness__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/paren_union_test/baml_tests__paren_union_test__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_error_recovery/baml_tests__parser_error_recovery__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_expressions/baml_tests__parser_expressions__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_speculative/baml_tests__parser_speculative__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_stress/baml_tests__parser_stress__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/parser_strings/baml_tests__parser_strings__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/pending_greaters_fix/baml_tests__pending_greaters_fix__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/simple_function/baml_tests__simple_function__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_annotations/baml_tests__stream_annotations__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_crossfile/baml_tests__stream_crossfile__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__01_lexer__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__02_parser__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__attrs.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__basic.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__complex.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/stream_types/baml_tests__stream_types__10_formatter__edge_cases.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_annotation/baml_tests__type_annotation__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_annotation_errors/baml_tests__type_annotation_errors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap is excluded by !**/*.snap
📒 Files selected for processing (43)
  • baml_language/crates/baml_base/src/attr.rs
  • baml_language/crates/baml_builtins2_codegen/src/extract.rs
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_ast/src/companions.rs
  • baml_language/crates/baml_compiler2_ast/src/lib.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler2_hir/src/builder.rs
  • baml_language/crates/baml_compiler2_hir/src/signature.rs
  • baml_language/crates/baml_compiler2_mir/src/lower.rs
  • baml_language/crates/baml_compiler2_ppir/src/expand.rs
  • baml_language/crates/baml_compiler2_ppir/src/lib.rs
  • baml_language/crates/baml_compiler2_ppir/src/ty.rs
  • baml_language/crates/baml_compiler2_tir/src/builder.rs
  • baml_language/crates/baml_compiler2_tir/src/generics.rs
  • baml_language/crates/baml_compiler2_tir/src/inference.rs
  • baml_language/crates/baml_compiler2_tir/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler2_tir/src/narrowing.rs
  • baml_language/crates/baml_compiler2_tir/src/normalize.rs
  • baml_language/crates/baml_compiler2_tir/src/package_interface.rs
  • baml_language/crates/baml_compiler2_tir/src/throw_inference.rs
  • baml_language/crates/baml_compiler2_tir/src/ty.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_lsp2_actions/src/annotations.rs
  • baml_language/crates/baml_lsp2_actions/src/completions.rs
  • baml_language/crates/baml_lsp2_actions/src/tokens.rs
  • baml_language/crates/baml_lsp2_actions/src/type_info.rs
  • baml_language/crates/baml_lsp2_actions/src/utils.rs
  • baml_language/crates/baml_tests/projects/stream_types/attrs.baml
  • baml_language/crates/baml_tests/projects/stream_types/basic.baml
  • baml_language/crates/baml_tests/projects/stream_types/complex.baml
  • baml_language/crates/baml_tests/projects/stream_types/edge_cases.baml
  • baml_language/crates/baml_tests/src/compiler2_tir/inference.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/mod.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase3a.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase3a_recursion.rs
  • baml_language/crates/baml_tests/src/compiler2_tir/phase5.rs
  • baml_language/crates/tools_onionskin/src/compiler.rs
  • fix_ty.py
  • fix_ty2.py
  • fix_ty3.py
  • fix_ty_final.py

sxlijin added 2 commits March 27, 2026 14:11
baml-language: ppir fixes

fix pending_default() alias resolution

preserve field/class attributes on stream expansion via clone-and-modify

scope block attrs and alias bodies by package

fix tyassert
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