Repository navigation
B-538: fully-spanned recursive TypeExpr (precise unresolved-type spans) - #3866
Conversation
Rowan keeps whitespace/newlines/comments as child tokens, so a node's
`text_range()` includes leading trivia. Diagnostic and editor spans built
from raw `text_range()` underlined the inter-token gap before the real
token (e.g. the space after `->` in a return type), and multi-line body
spans pulled in the newline + indentation after `{`.
Route node-derived spans through `SyntaxNodeExt::span_range` (= the
existing-but-unused `trimmed_range`), which trims to the first/last
non-trivia token. Parser end-of-input error spans now collapse to a
zero-width caret at the end of the last real token (rustc's
`shrink_to_hi` idiom) instead of reaching into `tokens.last()` and
covering a trailing newline.
Add a byte-level regression check in `test_05_diagnostics` asserting no
diagnostic annotation span begins or ends on whitespace, enforced across
the whole snapshot corpus.
Also line-align the `describe` body slice, which had been relying on the
span bug to preserve the first line's indentation.
…point at the member
…ollapses duplicates
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughType expressions now use ChangesTypeExpr kind migration
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90+ minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
…ap-key/dotted-root span changes)
There was a problem hiding this comment.
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 (3)
baml_language/crates/baml_compiler2_ast/src/lower_cst.rs (1)
176-181: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winDon't merge specialized
implements ... fortargets as plain local classes.This check now treats any one-segment path as mergeable even when it carries associated-type bindings. A target like
Foo<...>is already excluded bygeneric_args.is_empty(), butFoowithassociated_type_bindingswill still get folded into the local class, which strips the specialization and changes later resolution semantics.Suggested fix
let target_name = match &imp.for_target.kind { crate::ast::TypeExprKind::Path { segments, generic_args, + associated_type_bindings, .. - } if segments.len() == 1 && generic_args.is_empty() => segments.first().cloned(), + } if segments.len() == 1 + && generic_args.is_empty() + && associated_type_bindings.is_empty() => + { + segments.first().cloned() + } _ => None, };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_compiler2_ast/src/lower_cst.rs` around lines 176 - 181, The target selection in lower_cst.rs is too permissive: the `match` on `imp.for_target.kind` in the `target_name` logic only rejects `generic_args`, so a one-segment `Path` with `associated_type_bindings` can still be merged as a local class. Tighten the guard in this path-matching branch to only return `segments.first()` when the target is a plain unparameterized path with no associated-type bindings, and otherwise leave it unmerged so specialized `implements ... for` targets preserve their resolution semantics.baml_language/crates/baml_lsp2_actions/src/check.rs (2)
5327-5408: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFinish recursing through the new nested type-expression forms.
collect_type_var_namesandtype_expr_contains_selfskip pathassociated_type_bindingsandAssociatedTypeProjection, so type vars andSelfdisappear when they only occur there. That can misfire the unconstrained-impl check and miss the dedicatedSelf-in-interface-field diagnostic for nested cases.Suggested fix
fn collect_type_var_names( expr: &baml_compiler2_ast::TypeExpr, type_params: &[Name], out: &mut HashSet<Name>, ) { use baml_compiler2_ast::TypeExprKind; match &expr.kind { TypeExprKind::Path { segments, generic_args, + associated_type_bindings, .. } => { if segments.len() == 1 && type_params.contains(&segments[0]) { out.insert(segments[0].clone()); } for a in generic_args { collect_type_var_names(a, type_params, out); } + for binding in associated_type_bindings { + collect_type_var_names(&binding.ty, type_params, out); + } } + TypeExprKind::AssociatedTypeProjection { + base, + interface, + .. + } => { + collect_type_var_names(base, type_params, out); + if let Some(interface) = interface { + collect_type_var_names(interface, type_params, out); + } + } TypeExprKind::List { inner, .. } | TypeExprKind::Optional { inner, .. } => { collect_type_var_names(inner, type_params, out); } @@ fn type_expr_contains_self(expr: &baml_compiler2_ast::TypeExpr) -> bool { use baml_compiler2_ast::TypeExprKind; match &expr.kind { TypeExprKind::Path { segments, generic_args, + associated_type_bindings, .. } => { (segments.len() == 1 && segments[0].as_str() == "Self") || generic_args.iter().any(type_expr_contains_self) + || associated_type_bindings + .iter() + .any(|binding| type_expr_contains_self(&binding.ty)) } + TypeExprKind::AssociatedTypeProjection { + base, + interface, + .. + } => { + type_expr_contains_self(base) + || interface + .as_ref() + .is_some_and(|interface| type_expr_contains_self(interface)) + } TypeExprKind::Optional { inner, .. } | TypeExprKind::List { inner, .. } => { type_expr_contains_self(inner) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_lsp2_actions/src/check.rs` around lines 5327 - 5408, The recursion in collect_type_var_names and type_expr_contains_self is incomplete for the new nested type-expression forms, so type vars and Self can be missed when they appear only inside path associated_type_bindings or AssociatedTypeProjection. Update both helpers to descend into those path-level nested structures in the same way they already walk generic_args, unions, maps, and functions, using the existing symbols collect_type_var_names and type_expr_contains_self as the central traversal points. This will keep the unconstrained-impl check and the Self-in-interface-field diagnostic working for nested associated-type cases.
247-342: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse each
TirTypeError’s precise span when reporting signature type errors.These branches still always anchor on the full return/parameter annotation span, so unresolved names inside compound signature types on non-expression-bodied functions will keep underlining the whole type instead of the offending nested identifier. That leaves this signature-only path outside the B-538 fix even though the precise range is already available on the error object.
Suggested fix
for error in type_errors.drain(..) { diagnostics.push( Diagnostic::error( tir_type_error_to_diagnostic_id(&error), error.to_string(), ) .with_primary_span(Span { file_id, - range: ret_spanned.span, + range: error.precise_span().unwrap_or(ret_spanned.span), }) .with_phase(DiagnosticPhase::Type), ); } @@ for error in type_errors.drain(..) { diagnostics.push( Diagnostic::error( tir_type_error_to_diagnostic_id(&error), error.to_string(), ) .with_primary_span(Span { file_id, - range: type_spanned.span, + range: error.precise_span().unwrap_or(type_spanned.span), }) .with_phase(DiagnosticPhase::Type), ); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_lsp2_actions/src/check.rs` around lines 247 - 342, The signature type-error reporting in check.rs still uses the whole return/parameter TypeExpr span instead of each TirTypeError’s own location. Update the diagnostic creation in the return-type branch and the parameter-type loop so each error uses the precise span carried by the error object, rather than ret_spanned/type_spanned, while keeping the existing lowering flow in lower_sig_te and the self/param handling intact.
🧹 Nitpick comments (3)
baml_language/crates/baml_compiler_syntax/src/ast.rs (1)
217-246: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd unit tests for
UnionMemberParts::span()edge cases.This helper now defines diagnostic precision for dotted names, generic members, literal members, and empty members. A small local test matrix here would lock that behavior down faster than reblessing broad snapshots.
As per coding guidelines, "Prefer writing Rust unit tests over integration tests where possible".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_compiler_syntax/src/ast.rs` around lines 217 - 246, Add focused Rust unit tests for UnionMemberParts::span() to cover the edge cases introduced by this helper: a dotted WORD/DOT type name should return only the leading name span, generic or postfix-modified members should still exclude the trailing modifiers, literal/string-based members should fall back to the full token/child-node extent, and empty members should return None. Place the tests near UnionMemberParts::span() in ast.rs so the behavior is locked down without relying on broader snapshot tests.Source: Coding guidelines
baml_language/crates/baml_compiler2_ast/src/ast.rs (1)
164-175: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a unit test for span-insensitive
TypeExprequality/hash. Two structurally identical values with different spans should still compare equal and dedupe in aHashSet.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_compiler2_ast/src/ast.rs` around lines 164 - 175, Add a unit test around TypeExpr, PartialEq, and Hash that creates two structurally identical TypeExpr values with different spans and verifies they compare equal and only occupy one entry in a HashSet. Use the existing TypeExpr construction path in ast.rs so the test clearly exercises the span-insensitive behavior implemented by TypeExpr::eq and TypeExpr::hash.Sources: Coding guidelines, Learnings
baml_language/crates/baml_lsp2_actions/src/describe.rs (1)
1390-1391: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStale variable name after
SpannedTypeExprremoval.
spanned_tenow binds a plainTypeExpr, not a spanned wrapper. Renaming totekeeps it consistent with the other call sites updated in this PR (e.g. Line 1379, 1383).♻️ Suggested rename
- if let Some(spanned_te) = &alias.type_expr { - collect_type_expr_deps(db, file, spanned_te, &mut deps, &mut seen); + if let Some(te) = &alias.type_expr { + collect_type_expr_deps(db, file, te, &mut deps, &mut seen); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_lsp2_actions/src/describe.rs` around lines 1390 - 1391, The local binding name in the alias.type_expr branch is stale after SpannedTypeExpr was removed; rename the `spanned_te` variable in `collect_type_expr_deps` to match the plain `TypeExpr` it now holds, consistent with nearby call sites such as the other `collect_type_expr_deps` usages in this function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@baml_language/crates/baml_compiler_parser/src/parser.rs`:
- Around line 1575-1582: Update `Parser::last_non_trivia_token` in `parser.rs`
so it skips the same trivia as `current()`, not just whitespace/newlines. Right
now it can still treat `//` and `/* */` comment tokens as the last token, which
makes EOF diagnostics anchor after trailing comments instead of after the last
real token. Adjust the predicate to reuse the parser’s full trivia check (for
example the existing `is_basic_trivia`/`current()`-equivalent logic) so EOF
spans always anchor to the last non-trivia token.
In `@baml_language/crates/baml_compiler2_ast/src/lower_config_item.rs`:
- Line 38: The span passed from lower_config_item::lower_config_value_node is
still using the full config item range, which misanchors diagnostics for scalar
env.* references. Update the call site in lower_config_item to forward the value
node’s span instead of item.syntax().span_range(), so errors for direct env.*
values point at the offending scalar node rather than the entire config entry.
In `@baml_language/crates/baml_compiler2_hir/src/builder.rs`:
- Around line 1908-1921: Phase-1 type validation is missing recursion for nested
Path-related children, so invalid attrs inside generic args or associated type
bindings can slip through. Update collect_unknown_type_attrs and the companion
phase-1 traversal around the TypeExprKind::Path handling to recurse into
generic_args, associated_type_bindings, and AssociatedTypeProjection children,
using the existing recursive pattern seen for Optional/List/Map/Union so nested
cases are validated too.
In `@baml_language/crates/baml_lsp2_actions/src/utils.rs`:
- Around line 298-300: The `matches!` checks in `utils.rs` are moving `te.kind`
out of `&TypeExpr`, which breaks compilation because `TypeExprKind` is not
`Copy`. Update both `matches!` calls in the logic around the
`TypeExprKind::Union` and `TypeExprKind::Function` cases to borrow `te.kind`
instead of moving it, keeping the existing `TypeExprKind` pattern matching
intact.
---
Outside diff comments:
In `@baml_language/crates/baml_compiler2_ast/src/lower_cst.rs`:
- Around line 176-181: The target selection in lower_cst.rs is too permissive:
the `match` on `imp.for_target.kind` in the `target_name` logic only rejects
`generic_args`, so a one-segment `Path` with `associated_type_bindings` can
still be merged as a local class. Tighten the guard in this path-matching branch
to only return `segments.first()` when the target is a plain unparameterized
path with no associated-type bindings, and otherwise leave it unmerged so
specialized `implements ... for` targets preserve their resolution semantics.
In `@baml_language/crates/baml_lsp2_actions/src/check.rs`:
- Around line 5327-5408: The recursion in collect_type_var_names and
type_expr_contains_self is incomplete for the new nested type-expression forms,
so type vars and Self can be missed when they appear only inside path
associated_type_bindings or AssociatedTypeProjection. Update both helpers to
descend into those path-level nested structures in the same way they already
walk generic_args, unions, maps, and functions, using the existing symbols
collect_type_var_names and type_expr_contains_self as the central traversal
points. This will keep the unconstrained-impl check and the
Self-in-interface-field diagnostic working for nested associated-type cases.
- Around line 247-342: The signature type-error reporting in check.rs still uses
the whole return/parameter TypeExpr span instead of each TirTypeError’s own
location. Update the diagnostic creation in the return-type branch and the
parameter-type loop so each error uses the precise span carried by the error
object, rather than ret_spanned/type_spanned, while keeping the existing
lowering flow in lower_sig_te and the self/param handling intact.
---
Nitpick comments:
In `@baml_language/crates/baml_compiler_syntax/src/ast.rs`:
- Around line 217-246: Add focused Rust unit tests for UnionMemberParts::span()
to cover the edge cases introduced by this helper: a dotted WORD/DOT type name
should return only the leading name span, generic or postfix-modified members
should still exclude the trailing modifiers, literal/string-based members should
fall back to the full token/child-node extent, and empty members should return
None. Place the tests near UnionMemberParts::span() in ast.rs so the behavior is
locked down without relying on broader snapshot tests.
In `@baml_language/crates/baml_compiler2_ast/src/ast.rs`:
- Around line 164-175: Add a unit test around TypeExpr, PartialEq, and Hash that
creates two structurally identical TypeExpr values with different spans and
verifies they compare equal and only occupy one entry in a HashSet. Use the
existing TypeExpr construction path in ast.rs so the test clearly exercises the
span-insensitive behavior implemented by TypeExpr::eq and TypeExpr::hash.
In `@baml_language/crates/baml_lsp2_actions/src/describe.rs`:
- Around line 1390-1391: The local binding name in the alias.type_expr branch is
stale after SpannedTypeExpr was removed; rename the `spanned_te` variable in
`collect_type_expr_deps` to match the plain `TypeExpr` it now holds, consistent
with nearby call sites such as the other `collect_type_expr_deps` usages in this
function.
🪄 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: ee5bbd94-bb5b-438c-a741-d8c199dac1e0
⛔ Files ignored due to path filters (79)
baml_language/crates/baml_tests/snapshots/broken_syntax/banned_expressions/baml_tests__broken_syntax__banned_expressions__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/error_cases/baml_tests__broken_syntax__error_cases__02_parser__syntax_errors.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/error_cases/baml_tests__broken_syntax__error_cases__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/header_in_llm_function/baml_tests__broken_syntax__header_in_llm_function__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/is_in_type_position/baml_tests__broken_syntax__is_in_type_position__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/mismatched_brackets/baml_tests__broken_syntax__mismatched_brackets__02_parser__main.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/mismatched_brackets/baml_tests__broken_syntax__mismatched_brackets__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/parser_error_recovery/baml_tests__broken_syntax__parser_error_recovery__02_parser__unclosed_string.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/parser_error_recovery/baml_tests__broken_syntax__parser_error_recovery__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/parser_speculative/baml_tests__broken_syntax__parser_speculative__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/parser_strings/baml_tests__broken_syntax__parser_strings__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/pending_greaters_fix/baml_tests__broken_syntax__pending_greaters_fix__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/postfix_non_null_assertion/baml_tests__broken_syntax__postfix_non_null_assertion__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/test_invalid_contexts/baml_tests__broken_syntax__test_invalid_contexts__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/type_annotation_errors/baml_tests__broken_syntax__type_annotation_errors__02_parser__type_malformed.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/type_annotation_errors/baml_tests__broken_syntax__type_annotation_errors__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/compiles/catch_throw/baml_tests__compiles__catch_throw__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/compiles/catch_throw/baml_tests__compiles__catch_throw__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/assignment_expr_position/baml_tests__diagnostic_errors__assignment_expr_position__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/assignment_expr_position/baml_tests__diagnostic_errors__assignment_expr_position__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/basic_types/baml_tests__diagnostic_errors__basic_types__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/basic_types/baml_tests__diagnostic_errors__basic_types__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/builtin_io/baml_tests__diagnostic_errors__builtin_io__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/builtin_io/baml_tests__diagnostic_errors__builtin_io__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/captured_field_chain/baml_tests__diagnostic_errors__captured_field_chain__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/captured_field_chain/baml_tests__diagnostic_errors__captured_field_chain__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/catch_return_type_mismatch/baml_tests__diagnostic_errors__catch_return_type_mismatch__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/catch_return_type_mismatch/baml_tests__diagnostic_errors__catch_return_type_mismatch__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/catch_throw_regressions/baml_tests__diagnostic_errors__catch_throw_regressions__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/catch_throw_regressions/baml_tests__diagnostic_errors__catch_throw_regressions__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/client_option_types/baml_tests__diagnostic_errors__client_option_types__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/closure_errors/baml_tests__diagnostic_errors__closure_errors__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/closure_errors/baml_tests__diagnostic_errors__closure_errors__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/control_flow/baml_tests__diagnostic_errors__control_flow__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/control_flow/baml_tests__diagnostic_errors__control_flow__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/generics/baml_tests__diagnostic_errors__generics__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/generics/baml_tests__diagnostic_errors__generics__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/is_pattern_negative/baml_tests__diagnostic_errors__is_pattern_negative__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/is_pattern_negative/baml_tests__diagnostic_errors__is_pattern_negative__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/json_static_method_arity/baml_tests__diagnostic_errors__json_static_method_arity__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/json_static_method_arity/baml_tests__diagnostic_errors__json_static_method_arity__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/lambda_errors/baml_tests__diagnostic_errors__lambda_errors__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/lambda_errors/baml_tests__diagnostic_errors__lambda_errors__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/match_exhaustiveness/baml_tests__diagnostic_errors__match_exhaustiveness__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/match_exhaustiveness/baml_tests__diagnostic_errors__match_exhaustiveness__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/namespaces_bare_name_rejected/baml_tests__diagnostic_errors__namespaces_bare_name_rejected__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/namespaces_bare_name_rejected/baml_tests__diagnostic_errors__namespaces_bare_name_rejected__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/namespaces_stream_direct_ref/baml_tests__diagnostic_errors__namespaces_stream_direct_ref__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/namespaces_stream_direct_ref/baml_tests__diagnostic_errors__namespaces_stream_direct_ref__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/null_handling/baml_tests__diagnostic_errors__null_handling__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/null_handling/baml_tests__diagnostic_errors__null_handling__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/patterns_class_destructure/baml_tests__diagnostic_errors__patterns_class_destructure__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/patterns_class_destructure/baml_tests__diagnostic_errors__patterns_class_destructure__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/patterns_class_destructure_namespaces/baml_tests__diagnostic_errors__patterns_class_destructure_namespaces__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/patterns_class_destructure_namespaces/baml_tests__diagnostic_errors__patterns_class_destructure_namespaces__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/patterns_new/baml_tests__diagnostic_errors__patterns_new__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/patterns_new/baml_tests__diagnostic_errors__patterns_new__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/runtime_id_misuse/baml_tests__diagnostic_errors__runtime_id_misuse__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/runtime_id_misuse/baml_tests__diagnostic_errors__runtime_id_misuse__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/simple_function/baml_tests__diagnostic_errors__simple_function__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/simple_function/baml_tests__diagnostic_errors__simple_function__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/test_expr_name_type_error/baml_tests__diagnostic_errors__test_expr_name_type_error__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/test_expr_name_type_error/baml_tests__diagnostic_errors__test_expr_name_type_error__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/type_aliases/baml_tests__diagnostic_errors__type_aliases__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/type_reflection_strict/baml_tests__diagnostic_errors__type_reflection_strict__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/type_reflection_strict/baml_tests__diagnostic_errors__type_reflection_strict__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/unknown_type_error/baml_tests__diagnostic_errors__unknown_type_error__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/unknown_type_error/baml_tests__diagnostic_errors__unknown_type_error__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/void_return_type/baml_tests__diagnostic_errors__void_return_type__04_tir.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/diagnostic_errors/void_return_type/baml_tests__diagnostic_errors__void_return_type__05_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase3a__optional_param_default_declaration_diagnostics.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase3a__optional_param_default_forward_reference_checks_lambda_bodies.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snapis excluded by!**/*.snap
📒 Files selected for processing (142)
baml_language/crates/baml_builtins2_codegen/src/extract.rsbaml_language/crates/baml_compiler2_ast/src/ast.rsbaml_language/crates/baml_compiler2_ast/src/cleanup_guard.rsbaml_language/crates/baml_compiler2_ast/src/companions.rsbaml_language/crates/baml_compiler2_ast/src/disambiguate.rsbaml_language/crates/baml_compiler2_ast/src/lib.rsbaml_language/crates/baml_compiler2_ast/src/lower_config_item.rsbaml_language/crates/baml_compiler2_ast/src/lower_cst.rsbaml_language/crates/baml_compiler2_ast/src/lower_expr_body.rsbaml_language/crates/baml_compiler2_ast/src/lower_type_expr.rsbaml_language/crates/baml_compiler2_emit/src/lib.rsbaml_language/crates/baml_compiler2_hir/src/builder.rsbaml_language/crates/baml_compiler2_hir/src/item_tree.rsbaml_language/crates/baml_compiler2_hir/src/signature.rsbaml_language/crates/baml_compiler2_mir/src/lower.rsbaml_language/crates/baml_compiler2_ppir/src/lib.rsbaml_language/crates/baml_compiler2_ppir/src/ty.rsbaml_language/crates/baml_compiler2_tir/src/associated_projection.rsbaml_language/crates/baml_compiler2_tir/src/builder.rsbaml_language/crates/baml_compiler2_tir/src/generics.rsbaml_language/crates/baml_compiler2_tir/src/infer_context.rsbaml_language/crates/baml_compiler2_tir/src/inference.rsbaml_language/crates/baml_compiler2_tir/src/interfaces.rsbaml_language/crates/baml_compiler2_tir/src/interfaces/impl_rules.rsbaml_language/crates/baml_compiler2_tir/src/lower_type_expr.rsbaml_language/crates/baml_compiler2_tir/src/package_interface.rsbaml_language/crates/baml_compiler2_tir/src/throw_inference.rsbaml_language/crates/baml_compiler2_visualization/src/control_flow/from_ast.rsbaml_language/crates/baml_compiler_diagnostics/src/diagnostic.rsbaml_language/crates/baml_compiler_parser/src/parser.rsbaml_language/crates/baml_compiler_syntax/src/ast.rsbaml_language/crates/baml_compiler_syntax/src/traversal.rsbaml_language/crates/baml_lsp2_actions/src/check.rsbaml_language/crates/baml_lsp2_actions/src/describe.rsbaml_language/crates/baml_lsp2_actions/src/type_info.rsbaml_language/crates/baml_lsp2_actions/src/utils.rsbaml_language/crates/baml_lsp2_actions_tests/test_files/inlay_hints/call_arg_names.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/inlay_hints/for_loops.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/break_continue.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/class.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/for_loops.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/function.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/if_else.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/match_expr.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/multi_segment_path.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/catch/catch_all_exhaustive.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/catch/catch_wildcard_only.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/catch/exhaustiveness_checks.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/catch/invalid_arm_syntax.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/catch/nested_catch.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/map_types2.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/misspeled_boolean_literals.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/secure_types.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/spelling_error.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/unknown_type.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/enum/enum_unquoted_description.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/expr/constructors_invalid.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/expr/instanceof_narrowing.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/expr/missing_semicolons.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/expr/unresolved_builtin_namespace.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/expr/var_keyword_let_await.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/expr/watch_when.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/duplicate_names.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/invalid.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/invalid2.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/match.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/shorthand_clients.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/headers/if_then_only_header.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/hover/catch_rethrow.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/hover/catch_rethrow_caller.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/hover/function_throws.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/if_let/if_let_binding_scope.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/if_let/if_let_chained.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/if_let/if_let_destructure.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/if_let/if_let_irrefutable_warns.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/if_let/if_let_no_else_in_value_position.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/if_let/if_let_throws.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/duplicate_implements.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_ambiguous_interface_field_access.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_ambiguous_method_call.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_default_method_non_exhaustive.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_default_on_required_method.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_default_outside_implements.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_field_declared_in_implements_block.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_field_rule_invariant_union.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_generic_bound_violation.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_generic_requires_cycle_changes_args.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_match_without_wildcard.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_missing_field_in_implements_block.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_missing_required_interface.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_multi_self_call_on_interface_receiver.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_old_qualified_projection.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_out_of_body_field_interface.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/error_self_outside_type.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/field_type_mismatch.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/missing_required_method.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/interface/unknown_interface.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/invalid_assignment/arrays.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/invalid_assignment/class_arrays.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/invalid_assignment/maps.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/invalid_assignment/nested_arrays.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/iterator/stdlib_iterator_errors.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_destructure.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_diverges_loop.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_else_no_bindings.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_irrefutable_warns.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_must_diverge.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_throws.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/let_else/let_else_wildcard_irrefutable.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/loops/break.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/loops/c_for.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/loops/continue.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/match/match_non_exhaustive.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/match/match_with_guards.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/misc/dynamic_types_parser_errors.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/parens.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throw_basic.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throw_expression.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throw_in_catch.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throw_with_catch.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_basic_syntax.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_caller_sees_contract.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_caller_variant_contract.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_contract_violation.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_enum_exact_match.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_enum_extraneous.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_enum_variant_precise.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_enum_variant_violation.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_mixed.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_never_unreachable_rethrow.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_never_violation.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/throw/throws_type_alias_repro.bamlbaml_language/crates/baml_project/src/client_codegen.rsbaml_language/crates/baml_tests/build.rsbaml_language/crates/baml_tests/src/compiler2_tir/explicit_type_args.rsbaml_language/crates/baml_tests/src/compiler2_tir/mod.rsbaml_language/crates/baml_tests/src/compiler2_tir/phase3a.rsbaml_language/crates/baml_tests/src/compiler2_tir/phase3a_recursion.rsbaml_language/crates/baml_tests/src/compiler2_tir/phase5.rsbaml_language/crates/baml_tests/src/compiler2_tir/phase6.rsbaml_language/crates/baml_tests/src/utils/mod.rsbaml_language/crates/tools_onionskin/src/compiler.rs
💤 Files with no reviewable changes (6)
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/function.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/match_expr.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/for_loops.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/if_else.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/multi_segment_path.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/break_continue.baml
…+ map-key/dotted-root diagnostics)
⏭️ Performance benchmarks were skippedPerf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to To run them on this PR, do any of the following, then push a commit (or re-run CI):
|
Binary size checks passed✅ 7 passed
Generated by |
…ion missed in merge rebless)
…lidation), value-node span for env.*, skip comments in EOF anchoring
Fixes B-538 — an unresolved type inside a compound (union/map/tuple) underlined the whole compound instead of the offending identifier.
Root cause
ast::TypeExprwas span-less except for a single outerSpannedTypeExprwrapper, so every diagnostic from a type-expr was reported at the whole annotation's span.Fix — recursive spanning (chosen over a targeted patch)
TypeExpris now a fully-spanned tree:struct TypeExpr { kind: TypeExprKind, span }withDeref/DerefMutto the kind enum and aTypeExprKind::at(span)constructor. The oldenum TypeExprbecameenum TypeExprKind;SpannedTypeExpris deleted (redundant). Every node carries its real CST span (span_range()per node; union members get the offending-identifier range viaUnionMemberParts::span()), so any sub-type diagnostic points exactly at it — no per-diagnostic special-casing.TypeExprare structural (ignore span) to preserve dedup / Salsa early-cutoff.Effect
(was: the whole
map<…>underlined.)Verification
Full
baml_tests(2654) +baml_lsp2_actions_tests(375) green after rebless. Only span-narrowing snapshot changes — verified no message/error-code/diagnostic-count changes (balanced line counts). Workspace compiles--all-targets.Summary by CodeRabbit
requires,implementstargets, and field/type-alias types.