Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. See [conven

## [0.225.0](https://github.com/boundaryml/baml/compare/0.224.0..0.225.0) - 2026-07-31

### Features

- add `get_field<T>` method calls for runtime-shaped `unknown` values

### Docs

- brand legacy releases as BAML v0 (#4297) - ([5dbd250](https://github.com/boundaryml/baml/commit/5dbd25084b39523854a8967da5f5363b7368f3a6)) - Sam Lijin
Expand Down
10 changes: 10 additions & 0 deletions baml_language/crates/baml_builtins2/baml_std/baml/core.baml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,13 @@ class TaggedString {
/// type of its `${expr}` site; tags inspect element types at runtime.
values: unknown[],
}

/// Builtin companion for the source-level `unknown` primitive.
/// Users never construct this class.
class Unknown {
/// Assert-read a named field from a runtime-shaped class instance.
/// This is the method spelling of `reflect.class.get_field<T>(self, name)`.
function get_field<T>(self, name: string) -> T throws baml.reflect.errors.CompilationError {
reflect.class.get_field<T>(self, name)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class PendingType {
}

/// Assert-read a named field from a runtime-shaped class instance.
/// This is the function spelling of `value.get_field<T>(name)`.
//baml:mut_vm
function get_field<T>(value: unknown, name: string) -> T throws baml.reflect.errors.CompilationError {
$rust_function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ unknown:
}
details: |
Narrow an `unknown` value with pattern matching or an `is` test before using type-specific fields or methods.
Runtime-shaped class values support checked field reads with `value.get_field<T>("name")`, equivalent to `reflect.class.get_field<T>(value, "name")`.

types:
summary: "Concept page for BAML type syntax, aliases, generic bounds, and associated type bindings."
Expand Down
7 changes: 7 additions & 0 deletions baml_language/crates/baml_cli/src/describe_command_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,13 @@ fn dispatch_schema_attributes_and_intrinsic_types_resolve_to_topics() {
}
}

#[test]
fn render_unknown_topic_mentions_checked_field_reads() {
let output = capture_keyword("unknown");
assert!(output.contains(r#"value.get_field<T>("name")"#));
assert!(output.contains(r#"reflect.class.get_field<T>(value, "name")"#));
}

#[test]
fn render_schema_attribute_topic() {
let output = capture_keyword("alias");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function baml.deep_copy <builtin>/baml/core.baml:3
interface baml.Concrete <builtin>/baml/core.baml:9
interface baml.AnyFunction <builtin>/baml/core.baml:24
class baml.TaggedString <builtin>/baml/core.baml:36
class baml.Unknown <builtin>/baml/core.baml:46
class baml.Float <builtin>/baml/float.baml:8
function baml._trunc_to_int <builtin>/baml/float.baml:461
class baml.Int <builtin>/baml/int.baml:14
Expand Down Expand Up @@ -268,8 +269,8 @@ function baml.reflect.class._new <builtin>/baml/ns_reflect/ns_c
function baml.reflect.class.builder <builtin>/baml/ns_reflect/ns_class/class.baml:33
class baml.reflect.class.Builder <builtin>/baml/ns_reflect/ns_class/class.baml:39
class baml.reflect.class.PendingType <builtin>/baml/ns_reflect/ns_class/class.baml:81
function baml.reflect.class.get_field <builtin>/baml/ns_reflect/ns_class/class.baml:113
class baml.reflect.class.Type <builtin>/baml/ns_reflect/ns_class/class.baml:118
function baml.reflect.class.get_field <builtin>/baml/ns_reflect/ns_class/class.baml:114
class baml.reflect.class.Type <builtin>/baml/ns_reflect/ns_class/class.baml:119
class baml.reflect.enum.Value <builtin>/baml/ns_reflect/ns_enum/enum.baml:1
function baml.reflect.enum.value <builtin>/baml/ns_reflect/ns_enum/enum.baml:8
function baml.reflect.enum.new <builtin>/baml/ns_reflect/ns_enum/enum.baml:20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ pub(crate) fn external_class_for_type(
TyKind::Bool { .. } | TyKind::Literal(Literal::Bool(_), _, _) => {
builtin(&[], "Bool", Vec::new())
}
// Keep this entry in sync with `receiver_class`.
TyKind::Unknown { .. } => builtin(&[], "Unknown", Vec::new()),
TyKind::Uint8Array { .. } => builtin(&[], "Uint8Array", Vec::new()),
TyKind::Type { .. } => builtin(&[], "TypeValue", Vec::new()),
TyKind::Media(kind, _) => {
Expand Down Expand Up @@ -201,6 +203,8 @@ pub(crate) fn receiver_class<'db>(
TyKind::Bool { .. } | TyKind::Literal(Literal::Bool(_), _, _) => {
builtin(&[], "Bool", Vec::new())
}
// Keep this entry in sync with `external_class_for_type`.
TyKind::Unknown { .. } => builtin(&[], "Unknown", Vec::new()),
TyKind::Uint8Array { .. } => builtin(&[], "Uint8Array", Vec::new()),
// The `type` primitive's members (reflection, BEP-039) live on
// `class baml.TypeValue` - `reflect.type_of<T>().to_string()`.
Expand Down
4 changes: 4 additions & 0 deletions baml_language/crates/baml_lsp2_actions/src/completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,10 @@ fn completions_for_ty_members(db: &dyn Db, file: SourceFile, ty: &Ty) -> Vec<Com
completions_for_builtin_class_methods(db, &["Map"], BuiltinMethodMode::Instance)
}

Ty::BuiltinUnknown { .. } => {
completions_for_builtin_class_methods(db, &["Unknown"], BuiltinMethodMode::Instance)
}

Ty::String { .. }
| Ty::Uint8Array { .. }
| Ty::Media(_, _)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function inspect(value: unknown) -> string {
return value.<[CURSOR]get_field<string>("name")
}

//----
//- diagnostics
// <no-diagnostics-expected>
//
//- completions
// SHOULD_CONTAIN: get_field

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading