diff --git a/baml_language/crates/baml_builtins2/baml_std/ai/ns_internal/helpers.baml b/baml_language/crates/baml_builtins2/baml_std/ai/ns_internal/helpers.baml index d9a379f5902..a4edffad5aa 100644 --- a/baml_language/crates/baml_builtins2/baml_std/ai/ns_internal/helpers.baml +++ b/baml_language/crates/baml_builtins2/baml_std/ai/ns_internal/helpers.baml @@ -2,7 +2,7 @@ // One JSON Schema object for a function's parameters, derived from the // signature: every parameter typed via baml.json.schema. -function _schema_for_signature(handler: baml.AnyFunction) -> map { +function _schema_for_signature(handler: reflect.AnyFunction) -> map { let sig = reflect.signature(handler); let props: map = {}; let required: string[] = []; diff --git a/baml_language/crates/baml_builtins2/baml_std/ai/ns_tools/tools.baml b/baml_language/crates/baml_builtins2/baml_std/ai/ns_tools/tools.baml index 1fda737069f..977f795e641 100644 --- a/baml_language/crates/baml_builtins2/baml_std/ai/ns_tools/tools.baml +++ b/baml_language/crates/baml_builtins2/baml_std/ai/ns_tools/tools.baml @@ -11,7 +11,7 @@ class Tool { name: string, description: string, input_schema: map, // JSON Schema for the arguments object - handler: baml.AnyFunction?, // signature-derived dispatch; null for raw tools + handler: reflect.AnyFunction?, // signature-derived dispatch; null for raw tools // Dynamic-source dispatch: the handler receives the validated-by-schema // argument map as one value. Set by raw_tool() when the schema does not // derive from a BAML signature (MCP servers, OpenAPI specs). @@ -26,7 +26,7 @@ class Tool { if let rh: (map) -> string throws unknown = self.raw_handler { return rh(args); } - if let h: baml.AnyFunction = self.handler { + if let h: reflect.AnyFunction = self.handler { let value = reflect.call_any(h, args) catch (e) { let bad: reflect.InvalidArgumentError => { throw baml.errors.InvalidArgument { message: `invalid arguments for ${self.name}: ${bad.to_string()}` } @@ -41,7 +41,7 @@ class Tool { // The explicit constructor. `tools: [f]` normalizes through this. function tool( - handler: baml.AnyFunction, + handler: reflect.AnyFunction, name: string? = null, description: string? = null, on_error: ErrorMode? = null, diff --git a/baml_language/crates/baml_builtins2/baml_std/baml/conversions.baml b/baml_language/crates/baml_builtins2/baml_std/baml/conversions.baml index 2657f56143c..bb96be141ed 100644 --- a/baml_language/crates/baml_builtins2/baml_std/baml/conversions.baml +++ b/baml_language/crates/baml_builtins2/baml_std/baml/conversions.baml @@ -28,6 +28,17 @@ interface ToString { } } +/// Renders a reflected type's name. Declared here, beside the interface it +/// implements, rather than in the `reflect` package: `reflect.Type` is the +/// compiler metatype (no package dependency arises from naming it), while +/// `reflect` deliberately references nothing from `baml`, keeping the stdlib +/// dependency graph acyclic by construction. +implement root.ToString for reflect.Type { + function to_string(self) -> string throws never { + self._to_string_impl() + } +} + /// Internal: default structural rendering used by `string.from` for values /// whose runtime type does not implement `baml.ToString`. Primitives render /// naturally (`5`, `true`, `null`); containers and class instances render diff --git a/baml_language/crates/baml_builtins2/baml_std/baml/core.baml b/baml_language/crates/baml_builtins2/baml_std/baml/core.baml index d4783258690..0d92e59b230 100644 --- a/baml_language/crates/baml_builtins2/baml_std/baml/core.baml +++ b/baml_language/crates/baml_builtins2/baml_std/baml/core.baml @@ -14,109 +14,6 @@ implement Concrete for T { } -/// Implemented automatically by every function value, with its parameter -/// list erased. `Returns` pins the held function's return type and `Throws` -/// its error type; both default to `unknown`, so a bare `AnyFunction` -/// accepts any function. A compiler builtin: it cannot be implemented by -/// hand, cannot be used as a generic bound, and declares no methods. Call -/// the held function through `reflect.call_any`; read its signature with -/// `reflect.signature`. -interface AnyFunction { - type Returns = unknown - type Throws = unknown -} - -/// A read-only reflected view implemented automatically by class values. -/// -/// Narrow an opaque value with `let value: baml.AnyClass = opaque else { ... }` -/// before using this surface. Ordinary class instances implement it, including -/// runtime-minted classes. Of the sealed reflection-kind views, only -/// `reflect.class.Type` implements it. -interface AnyClass { - /// Read a field as `T`. A missing field returns `null`; use `has_field` to - /// distinguish that case from a present field whose value is null. - function get(self, name: string) -> T? throws baml.errors.TypeMismatch { - if (!self.has_field(name)) { - return null - } - // NOTE: spelled with `let … else` rather than `self.get_field(name)?.value()` - // because an optional-chained call does not thread `T` to the callee. - let field: reflect.class.Field = self.get_field(name) else { - return null - } - field.value() - } - - /// Return a value-bound field handle, or `null` when no such field exists. - function get_field(self, name: string) -> reflect.class.Field? throws never { - let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { - return null - } - for (let field in class_type.fields()) { - if (field.name == name) { - return reflect.class.Field { - name: field.name, - type: field.type, - meta: field.meta, - _owner: self, - } - } - } - null - } - - function has_field(self, name: string) -> bool throws never { - let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { - return false - } - for (let field in class_type.fields()) { - if (field.name == name) { - return true - } - } - false - } - - /// Reflected fields bound to this value for `Field.value()`. - function list_fields(self) -> reflect.class.Field[] throws never { - let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { - return [] - } - let fields: reflect.class.Field[] = [] - for (let field in class_type.fields()) { - fields.push(reflect.class.Field { - name: field.name, - type: field.type, - meta: field.meta, - _owner: self, - }) - } - fields - } - - function name(self) -> string throws never { - reflect.Type.of_value(self).to_string() - } - - function type(self) -> reflect.Type throws never { - reflect.Type.of_value(self) - } - - function attributes(self) -> reflect.Meta throws never { - let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { - return reflect.Meta { - alias: null, - description: null, - docstring: null, - other: {}, - } - } - class_type.meta() - } -} - -implement AnyClass for T {} - /// The structured value a tagged template literal produces. /// /// BEP-049 §10. A `tag` ` `…` ` call site lowers to `tag(body = () -> TaggedString { … })`; diff --git a/baml_language/crates/baml_builtins2/baml_std/baml/ns_errors/errors.baml b/baml_language/crates/baml_builtins2/baml_std/baml/ns_errors/errors.baml index 014998b10e4..02f4f4588c0 100644 --- a/baml_language/crates/baml_builtins2/baml_std/baml/ns_errors/errors.baml +++ b/baml_language/crates/baml_builtins2/baml_std/baml/ns_errors/errors.baml @@ -86,7 +86,9 @@ class CompilationError { /// could not be inferred and must be specified, or repeat occurrences of a /// `TypeVar` have no consistent binding. Synthesized host-side from /// `EngineError::TypeMismatch`; each host SDK surfaces it as its native -/// type-error (Python `TypeError`). +/// type-error (Python `TypeError`). The stdlib itself never throws this class +/// from BAML source (reflection's typed reads throw +/// `reflect.errors.TypeMismatch` instead); user code remains free to. class TypeMismatch { message: string, } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_array/array.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_array/array.baml index 3c87a3ea6fb..263fec5f397 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_array/array.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_array/array.baml @@ -1,9 +1,16 @@ /// An array-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:mut_vm + //baml:fallible function element_type(self) -> reflect.Type throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_class/class.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_class/class.baml index 6ec89a56648..80811b3c2e3 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_class/class.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_class/class.baml @@ -2,7 +2,7 @@ class Field { name string type reflect.Type? meta reflect.Meta - /// Present only for handles returned from `baml.AnyClass.list_fields` or + /// Present only for handles returned from `reflect.AnyClass.list_fields` or /// `get_field`. Type-side descriptors returned by `Type.fields()` are /// intentionally ownerless. _owner unknown? @@ -13,13 +13,13 @@ class Field { /// Read this field from its bound owner. An ownerless type-side descriptor /// returns `null`. - function value(self) -> T? throws baml.errors.TypeMismatch { - let owner: baml.AnyClass = self._owner else { + function value(self) -> T? throws reflect.errors.TypeMismatch { + let owner: reflect.AnyClass = self._owner else { return null } reflect.class.get_field(owner, self.name) catch (e) { reflect.errors.CompilationError { message } => { - throw baml.errors.TypeMismatch { message: message } + throw reflect.errors.TypeMismatch { message: message } } } } @@ -154,12 +154,20 @@ function get_field(value: unknown, name: string) -> T throws reflect.errors.C /// A class-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:mut_vm + //baml:fallible function fields(self) -> Field[] throws never { $rust_function } //baml:mut_vm + //baml:fallible function meta(self) -> reflect.Meta throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_enum/enum.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_enum/enum.baml index 05d320f658f..2201889e653 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_enum/enum.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_enum/enum.baml @@ -28,12 +28,20 @@ function get_value(value: unknown) -> string throws never { $rust_function } /// An enum-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:mut_vm + //baml:fallible function values(self) -> Value[] throws never { $rust_function } //baml:mut_vm + //baml:fallible function meta(self) -> reflect.Meta throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_errors/errors.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_errors/errors.baml index b53993167d2..adf873b9783 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_errors/errors.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_errors/errors.baml @@ -9,6 +9,16 @@ class EvaluationError { message string } +/// A reflective typed read did not fit the requested type: `Field.value()` +/// or `AnyClass.get()` asked for a `T` the underlying value is not. +/// +/// Distinct from `baml.errors.TypeMismatch`, the host call-boundary error +/// synthesized from `EngineError::TypeMismatch` — that one names the FFI +/// contract; this one names a reflection read. +class TypeMismatch { + message string +} + /// A session rejected concurrent use. class SessionBusy { message string diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_function/function.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_function/function.baml index a00dcb18b29..90743959cfe 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_function/function.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_function/function.baml @@ -7,12 +7,20 @@ class Parameter { /// A function-kind view of a `type` value. Throws are intentionally not part /// of the function reflection surface. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:mut_vm + //baml:fallible function params(self) -> Parameter[] throws never { $rust_function } //baml:mut_vm + //baml:fallible function return_type(self) -> reflect.Type throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_interface/interface.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_interface/interface.baml index c28909747df..833f2ec5ac2 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_interface/interface.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_interface/interface.baml @@ -1,10 +1,17 @@ /// An interface-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:vm + //baml:fallible function implemented_by(self, other: reflect.Type) -> bool throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_literal/literal.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_literal/literal.baml index 3873732c903..a7d5fa607d0 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_literal/literal.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_literal/literal.baml @@ -5,8 +5,14 @@ function new(value: string | int | bool) -> Type throws never { /// A literal-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_map/map.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_map/map.baml index fd64ad7a0ee..024e2f5f16a 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_map/map.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_map/map.baml @@ -5,12 +5,20 @@ function new(key: reflect.Type, value: reflect.Type) -> Type throws never { /// A map-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:mut_vm + //baml:fallible function key_type(self) -> reflect.Type throws never { $rust_function } //baml:mut_vm + //baml:fallible function value_type(self) -> reflect.Type throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_primitive/primitive.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_primitive/primitive.baml index d4b133a08d9..86a2d7ee860 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_primitive/primitive.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_primitive/primitive.baml @@ -1,7 +1,13 @@ /// A primitive-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_union/union.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_union/union.baml index ad2e51f1929..162c201eb01 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/ns_union/union.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/ns_union/union.baml @@ -5,10 +5,17 @@ function new(types: reflect.Type[]) -> Type throws reflect.errors.CompilationErr /// A union-kind view of a `type` value. Users never construct this class. class Type { + /// The wrapped `type` value. Private by invariant: reflection natives are + /// its only readers, and each kind method panics if the held type no longer + /// classifies as this view's kind. + _ty reflect.Type + implements reflect.TypeView { //baml:vm + //baml:fallible function as_type(self) -> reflect.Type throws never { $rust_function } } //baml:mut_vm + //baml:fallible function member_types(self) -> reflect.Type[] throws never { $rust_function } } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/reflect.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/reflect.baml index 3b2edffedcc..de8e2864422 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/reflect.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/reflect.baml @@ -52,6 +52,109 @@ interface TypeView { /// The closed set of reflection views for a runtime `type` value. type TypeKind = reflect.class.Type | reflect.enum.Type | reflect.union.Type | reflect.literal.Type | reflect.array.Type | reflect.map.Type | reflect.interface.Type | reflect.primitive.Type | reflect.function.Type +/// Implemented automatically by every function value, with its parameter +/// list erased. `Returns` pins the held function's return type and `Throws` +/// its error type; both default to `unknown`, so a bare `AnyFunction` +/// accepts any function. A compiler builtin: it cannot be implemented by +/// hand, cannot be used as a generic bound, and declares no methods. Call +/// the held function through `reflect.call_any`; read its signature with +/// `reflect.signature`. +interface AnyFunction { + type Returns = unknown + type Throws = unknown +} + +/// A read-only reflected view implemented automatically by class values. +/// +/// Narrow an opaque value with `let value: reflect.AnyClass = opaque else { ... }` +/// before using this surface. Ordinary class instances implement it, including +/// runtime-minted classes. Of the sealed reflection-kind views, only +/// `reflect.class.Type` implements it. +interface AnyClass { + /// Read a field as `T`. A missing field returns `null`; use `has_field` to + /// distinguish that case from a present field whose value is null. + function get(self, name: string) -> T? throws reflect.errors.TypeMismatch { + if (!self.has_field(name)) { + return null + } + // NOTE: spelled with `let … else` rather than `self.get_field(name)?.value()` + // because an optional-chained call does not thread `T` to the callee. + let field: reflect.class.Field = self.get_field(name) else { + return null + } + field.value() + } + + /// Return a value-bound field handle, or `null` when no such field exists. + function get_field(self, name: string) -> reflect.class.Field? throws never { + let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { + return null + } + for (let field in class_type.fields()) { + if (field.name == name) { + return reflect.class.Field { + name: field.name, + type: field.type, + meta: field.meta, + _owner: self, + } + } + } + null + } + + function has_field(self, name: string) -> bool throws never { + let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { + return false + } + for (let field in class_type.fields()) { + if (field.name == name) { + return true + } + } + false + } + + /// Reflected fields bound to this value for `Field.value()`. + function list_fields(self) -> reflect.class.Field[] throws never { + let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { + return [] + } + let fields: reflect.class.Field[] = [] + for (let field in class_type.fields()) { + fields.push(reflect.class.Field { + name: field.name, + type: field.type, + meta: field.meta, + _owner: self, + }) + } + fields + } + + function name(self) -> string throws never { + reflect.Type.of_value(self).to_string() + } + + function type(self) -> reflect.Type throws never { + reflect.Type.of_value(self) + } + + function attributes(self) -> reflect.Meta throws never { + let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() else { + return reflect.Meta { + alias: null, + description: null, + docstring: null, + other: {}, + } + } + class_type.meta() + } +} + +implement AnyClass for T {} + /// The runtime signature of a function value, reconstructed from the value /// itself (BEP-062). Positional (required) parameters appear in `args` in /// declaration order; named/optional parameters appear in `opts`, keyed by @@ -217,7 +320,7 @@ class Session { /// sig.returns.to_string() //baml:mut_vm //baml:fallible -function signature(f: baml.AnyFunction) -> Signature throws never { +function signature(f: AnyFunction) -> Signature throws never { $rust_function } @@ -233,6 +336,6 @@ function signature(f: baml.AnyFunction) -> Signature throws never { /// `reflect.errors.CompilationError`). //baml:mut_vm //baml:may_yield -function call_any(f: baml.AnyFunction, args: map) -> R throws E | InvalidArgumentError | reflect.errors.CompilationError { +function call_any(f: AnyFunction, args: map) -> R throws E | InvalidArgumentError | reflect.errors.CompilationError { $rust_function } diff --git a/baml_language/crates/baml_builtins2/baml_std/reflect/type.baml b/baml_language/crates/baml_builtins2/baml_std/reflect/type.baml index c61585b2dd9..30f58b1fda8 100644 --- a/baml_language/crates/baml_builtins2/baml_std/reflect/type.baml +++ b/baml_language/crates/baml_builtins2/baml_std/reflect/type.baml @@ -34,30 +34,30 @@ class Type { //baml:vm function to_baml(self) -> string throws never { $rust_function } - /// Returns the precise kind view of this type value. The view preserves - /// the receiver's identity. - //baml:vm + /// Returns the precise kind view of this type value: a freshly + /// allocated view instance wrapping the receiver in its `_ty` field. + //baml:mut_vm function kind(self) -> reflect.TypeKind throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_class(self) -> reflect.class.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_enum(self) -> reflect.enum.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_union(self) -> reflect.union.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_literal(self) -> reflect.literal.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_array(self) -> reflect.array.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_map(self) -> reflect.map.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_interface(self) -> reflect.interface.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_primitive(self) -> reflect.primitive.Type? throws never { $rust_function } - //baml:vm + //baml:mut_vm function as_function(self) -> reflect.function.Type? throws never { $rust_function } /// Internal shared-render-boundary guard for BEP-066 R-1 and R-3. @@ -76,13 +76,10 @@ class Type { other: map? = null, ) -> reflect.WithMeta throws never { $rust_function } - /// Returns the type name as a human-readable string. - implements baml.ToString { - function to_string(self) -> string throws never { - self._to_string_impl() - } - } - + // `baml.ToString` is implemented for `reflect.Type` by an out-of-body + // `implement` block beside the interface (baml/conversions.baml): the + // `reflect` package deliberately references nothing from `baml`, so the + // stdlib dependency graph stays acyclic by construction. //baml:vm function _to_string_impl(self) -> string throws never { $rust_function diff --git a/baml_language/crates/baml_builtins2_codegen/src/extract.rs b/baml_language/crates/baml_builtins2_codegen/src/extract.rs index 8ae5bd64494..5c969e9bb6b 100644 --- a/baml_language/crates/baml_builtins2_codegen/src/extract.rs +++ b/baml_language/crates/baml_builtins2_codegen/src/extract.rs @@ -359,9 +359,11 @@ fn extract_from_class( }; let receiver = Some(Receiver { class_name: class_name.to_string(), + // The prefix's first segment is the PACKAGE (`baml.media`, + // `reflect.array`); the receiver namespace is everything after it. namespace: namespace_prefix - .strip_prefix("baml.") - .unwrap_or("") + .split_once('.') + .map_or("", |(_, namespaces)| namespaces) .to_string(), // Mirrors `extract_class_fields`: dedicated-variant types and // field-less (opaque/marker) classes get no `view::` struct. @@ -655,9 +657,11 @@ fn extract_from_implements_for( let receiver = Some(Receiver { class_name: recv_class.to_string(), + // The prefix's first segment is the PACKAGE (`baml.media`, + // `reflect.array`); the receiver namespace is everything after it. namespace: namespace_prefix - .strip_prefix("baml.") - .unwrap_or("") + .split_once('.') + .map_or("", |(_, namespaces)| namespaces) .to_string(), instance_backed: false, class_generics: impl_generics.clone(), diff --git a/baml_language/crates/baml_cli/src/describe_render.rs b/baml_language/crates/baml_cli/src/describe_render.rs index bdb555aca5f..5c7605e46bf 100644 --- a/baml_language/crates/baml_cli/src/describe_render.rs +++ b/baml_language/crates/baml_cli/src/describe_render.rs @@ -171,7 +171,7 @@ fn push_impls(out: &mut String, db: &ProjectDatabase, impls: &[Impl<'_>], allows allows_any_class || imp .interface(db) - .is_none_or(|iface| !iface.qualified_name(db).is_builtin_root_type("AnyClass")) + .is_none_or(|iface| !iface.qualified_name(db).is_reflect_root_type("AnyClass")) }) .collect(); if !blankets.is_empty() { @@ -241,9 +241,7 @@ fn render_class(db: &ProjectDatabase, class: Class<'_>) -> String { if hidden > 0 { let _ = writeln!(out, " ({hidden} compiler-synthesized method(s) hidden)"); } - let allows_any_class = - baml_type::type_kind::class_inhabits_any_class(&class.qualified_name(db)); - push_impls(&mut out, db, &class.trait_impls(db), allows_any_class); + push_impls(&mut out, db, &class.trait_impls(db), true); out } @@ -570,8 +568,10 @@ mod tests { fn renders_builtin_class_with_impls() { let db = make_db(); insta::assert_snapshot!(render(&db, "baml.time.Duration")); - assert!(render(&db, "reflect.class.Type").contains("baml.AnyClass")); - assert!(!render(&db, "reflect.enum.Type").contains("baml.AnyClass")); + // Every kind view is an ordinary wrapper class, so all nine render + // the `reflect.AnyClass` blanket row. + assert!(render(&db, "reflect.class.Type").contains("reflect.AnyClass")); + assert!(render(&db, "reflect.enum.Type").contains("reflect.AnyClass")); } #[test] diff --git a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap index df1d0ce667a..b50ef5496e8 100644 --- a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap +++ b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap @@ -19,19 +19,17 @@ function baml._sum_float /baml/containers.baml function baml._mean_float /baml/containers.baml:798 function baml._median_float /baml/containers.baml:805 interface baml.ToString /baml/conversions.baml:25 -function baml._to_string_default /baml/conversions.baml:39 -function baml._to_string_shim /baml/conversions.baml:57 -function baml._cleanup_begin /baml/conversions.baml:72 -interface baml.ToJson /baml/conversions.baml:102 -function baml._to_json_default /baml/conversions.baml:117 -function baml._to_json_shim /baml/conversions.baml:135 -interface baml.FromJson /baml/conversions.baml:165 -function baml._from_json_shim /baml/conversions.baml:184 +function baml._to_string_default /baml/conversions.baml:50 +function baml._to_string_shim /baml/conversions.baml:68 +function baml._cleanup_begin /baml/conversions.baml:83 +interface baml.ToJson /baml/conversions.baml:113 +function baml._to_json_default /baml/conversions.baml:128 +function baml._to_json_shim /baml/conversions.baml:146 +interface baml.FromJson /baml/conversions.baml:176 +function baml._from_json_shim /baml/conversions.baml:195 function baml.deep_copy /baml/core.baml:3 interface baml.Concrete /baml/core.baml:9 -interface baml.AnyFunction /baml/core.baml:24 -interface baml.AnyClass /baml/core.baml:35 -class baml.TaggedString /baml/core.baml:127 +class baml.TaggedString /baml/core.baml:24 class baml.Float /baml/float.baml:8 function baml._trunc_to_int /baml/float.baml:468 class baml.Int /baml/int.baml:19 @@ -107,7 +105,7 @@ class baml.errors.DevOther /baml/ns_errors/error class baml.errors.HostCallable /baml/ns_errors/errors.baml:53 class baml.errors.GenericSdkError /baml/ns_errors/errors.baml:74 class baml.errors.CompilationError /baml/ns_errors/errors.baml:80 -class baml.errors.TypeMismatch /baml/ns_errors/errors.baml:90 +class baml.errors.TypeMismatch /baml/ns_errors/errors.baml:92 class baml.errors.StackFrame /baml/ns_errors/stack_trace.baml:2 class baml.errors.StackTrace /baml/ns_errors/stack_trace.baml:9 class baml.errors.UnknownError /baml/ns_errors/unknown_error.baml:2 diff --git a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_reflect_package_listing.snap b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_reflect_package_listing.snap index e23deaa13a4..97b5fa6ff87 100644 --- a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_reflect_package_listing.snap +++ b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_reflect_package_listing.snap @@ -9,12 +9,14 @@ class reflect.Span /reflect/reflect.baml class reflect.Diagnostic /reflect/reflect.baml:41 interface reflect.TypeView /reflect/reflect.baml:48 type reflect.TypeKind /reflect/reflect.baml:53 -class reflect.Signature /reflect/reflect.baml:59 -class reflect.InvalidArgumentError /reflect/reflect.baml:81 -class reflect.Package /reflect/reflect.baml:88 -class reflect.Session /reflect/reflect.baml:178 -function reflect.signature /reflect/reflect.baml:220 -function reflect.call_any /reflect/reflect.baml:236 +interface reflect.AnyFunction /reflect/reflect.baml:62 +interface reflect.AnyClass /reflect/reflect.baml:73 +class reflect.Signature /reflect/reflect.baml:162 +class reflect.InvalidArgumentError /reflect/reflect.baml:184 +class reflect.Package /reflect/reflect.baml:191 +class reflect.Session /reflect/reflect.baml:281 +function reflect.signature /reflect/reflect.baml:323 +function reflect.call_any /reflect/reflect.baml:339 class reflect.Type /reflect/type.baml:8 class reflect.array.Type /reflect/ns_array/array.baml:2 class reflect.class.Field /reflect/ns_class/class.baml:1 @@ -32,12 +34,13 @@ function reflect.enum.get_value /reflect/ns_enum/enum class reflect.enum.Type /reflect/ns_enum/enum.baml:30 class reflect.errors.CompilationError /reflect/ns_errors/errors.baml:2 class reflect.errors.EvaluationError /reflect/ns_errors/errors.baml:8 -class reflect.errors.SessionBusy /reflect/ns_errors/errors.baml:13 +class reflect.errors.TypeMismatch /reflect/ns_errors/errors.baml:18 +class reflect.errors.SessionBusy /reflect/ns_errors/errors.baml:23 class reflect.function.Parameter /reflect/ns_function/function.baml:1 class reflect.function.Type /reflect/ns_function/function.baml:9 class reflect.interface.Type /reflect/ns_interface/interface.baml:2 -class reflect.interface.Implementation /reflect/ns_interface/interface.baml:13 -function reflect.interface.implementation /reflect/ns_interface/interface.baml:28 +class reflect.interface.Implementation /reflect/ns_interface/interface.baml:20 +function reflect.interface.implementation /reflect/ns_interface/interface.baml:35 function reflect.literal.new /reflect/ns_literal/literal.baml:2 class reflect.literal.Type /reflect/ns_literal/literal.baml:7 function reflect.map.new /reflect/ns_map/map.baml:2 diff --git a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_class_with_impls.snap b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_class_with_impls.snap index 3b155b4ac33..1dd63d98486 100644 --- a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_class_with_impls.snap +++ b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_builtin_class_with_impls.snap @@ -75,5 +75,5 @@ implements: function sub(self, other: baml.time.Duration) -> baml.time.Duration blanket implementations: - baml.AnyClass (/baml/core.baml:118) baml.Concrete (/baml/core.baml:13) + reflect.AnyClass (/reflect/reflect.baml:156) diff --git a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_user_items.snap b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_user_items.snap index 794f349ec00..fd12ba76e78 100644 --- a/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_user_items.snap +++ b/baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_render__tests__renders_user_items.snap @@ -12,8 +12,8 @@ fields: _cache string blanket implementations: - baml.AnyClass (/baml/core.baml:118) baml.Concrete (/baml/core.baml:13) + reflect.AnyClass (/reflect/reflect.baml:156) ════ Mode ════ enum Mode app.baml:8 diff --git a/baml_language/crates/baml_compiler2_emit/src/emit.rs b/baml_language/crates/baml_compiler2_emit/src/emit.rs index 5a1b38866ba..26e6a6a76a6 100644 --- a/baml_language/crates/baml_compiler2_emit/src/emit.rs +++ b/baml_language/crates/baml_compiler2_emit/src/emit.rs @@ -3514,15 +3514,6 @@ impl PullSink for StackifyCodegen<'_, '_> { // so the VM compares each arg invariantly; empty args → // class-pointer identity. TyTemplate::Class(tn, type_args_templates, _) => { - // A reflected `type` value is physically `Object::Type` but its - // reconstructed concrete type is one of the nine sealed kind - // classes. Kind tests must therefore use the structural value - // matcher; class-object pointer identity only applies to normal - // user instances. - if baml_type::type_kind::is_type_kind_class(tn) { - emit_structural(self, ty_template); - return Ok(()); - } let class_name_str = tn.display_name(); let Some(class_obj_idx) = self.class_object_index_for_type_name(tn) else { emit_false(self); diff --git a/baml_language/crates/baml_compiler2_emit/src/lib.rs b/baml_language/crates/baml_compiler2_emit/src/lib.rs index ed7a1487f0c..9bd590fd9cf 100644 --- a/baml_language/crates/baml_compiler2_emit/src/lib.rs +++ b/baml_language/crates/baml_compiler2_emit/src/lib.rs @@ -4674,6 +4674,21 @@ fn topological_sort_packages( } } + // Kahn's algorithm cannot order the members of a dependency cycle: they + // never reach in-degree zero, so they would silently VANISH from the + // result — and with it from `package_init_order`, leaving their globals + // uninitialized. The package dependency graph is acyclic by construction; + // enforce it so a future edge cannot rot into that silent failure. + assert_eq!( + result.len(), + pkg_names.len(), + "package dependency cycle: {:?} cannot be topologically ordered", + pkg_names + .iter() + .filter(|name| !result.contains(name)) + .collect::>() + ); + result } diff --git a/baml_language/crates/baml_compiler2_hir/src/package.rs b/baml_language/crates/baml_compiler2_hir/src/package.rs index bf3af83a57d..9045b75456b 100644 --- a/baml_language/crates/baml_compiler2_hir/src/package.rs +++ b/baml_language/crates/baml_compiler2_hir/src/package.rs @@ -526,10 +526,16 @@ pub fn package_dependencies<'db>( "boundary" => vec![], // "baml" depends on "log" so stdlib code can call log.info/debug/etc. "baml" => vec![PackageId::new(db, Name::new("log"))], - // Reflection is a true root package. It uses the core baml interfaces - // and errors, while `reflect.Type` annotations lower directly to the - // compiler metatype and therefore do not create a baml -> reflect edge. - "reflect" => vec![PackageId::new(db, Name::new("baml"))], + // Reflection is a true root package with NO dependencies: it + // deliberately references nothing from `baml` (its typed reads throw + // `reflect.errors.TypeMismatch`, and `AnyFunction`/`AnyClass` live + // here). The one cross-package tie runs the other way — `baml` + // implements its `ToString` for `reflect.Type` beside the interface + // (conversions.baml), which needs no `baml -> reflect` edge because + // `reflect.Type` is the compiler metatype. Keeping both directions + // empty keeps the stdlib dependency graph acyclic by construction; + // emit's topological package sort asserts that invariant. + "reflect" => vec![], // The "testing" and "assert" packages depend on "baml" only. "testing" | "assert" => vec![PackageId::new(db, Name::new("baml"))], // The "ai" package uses BAML primitives and runtime type reflection. diff --git a/baml_language/crates/baml_compiler2_hir_ty/src/diagnostics.rs b/baml_language/crates/baml_compiler2_hir_ty/src/diagnostics.rs index 2a7f1c4b202..3468a25d9c3 100644 --- a/baml_language/crates/baml_compiler2_hir_ty/src/diagnostics.rs +++ b/baml_language/crates/baml_compiler2_hir_ty/src/diagnostics.rs @@ -626,11 +626,11 @@ pub enum TirTypeError { /// concrete non-interface type. Generic bounds must be interfaces. GenericBoundNotInterface { bound: Ty }, /// BEP-062: an `implements` block targets a compiler-builtin interface - /// (`baml.AnyFunction`), whose conformance is derived by the compiler and + /// (`reflect.AnyFunction`), whose conformance is derived by the compiler and /// cannot be written by hand. BuiltinInterfaceNotImplementable { interface: QualifiedTypeName }, /// BEP-062: a generic parameter's bound names a compiler-builtin interface - /// (`baml.AnyFunction`) that is only legal as a value type (an + /// (`reflect.AnyFunction`) that is only legal as a value type (an /// existential), never as a bound. BuiltinInterfaceNotABound { interface: QualifiedTypeName }, /// [`TYPE_SYSTEM.md` § Generics on Functions](TYPE_SYSTEM.md#generics-on-functions): diff --git a/baml_language/crates/baml_compiler2_hir_ty/src/impls.rs b/baml_language/crates/baml_compiler2_hir_ty/src/impls.rs index 024bb38d154..ca7ff14ae83 100644 --- a/baml_language/crates/baml_compiler2_hir_ty/src/impls.rs +++ b/baml_language/crates/baml_compiler2_hir_ty/src/impls.rs @@ -36,7 +36,6 @@ use baml_type::{ Name, ParamTy, TypeName, interned::{InterfaceRef, Ty, TyKind}, normalize::{TypeContext, equivalent_interned}, - type_kind::class_inhabits_any_class, }; use rustc_hash::FxHashMap; @@ -806,7 +805,7 @@ pub fn impls_for_type<'db>( // concrete-member provider. Keep its blanket witness out of the // concrete receiver lookup tier so established fields and methods // named `get`, `name`, `type`, and so on retain their resolution. - // Explicit `baml.AnyClass` receivers dispatch through + // Explicit `reflect.AnyClass` receivers dispatch through // `resolve_impl`, where the witness remains available. provides_concrete_members(&implemented.name) }) @@ -818,7 +817,7 @@ pub fn impls_for_type<'db>( /// narrowing, so its blanket default methods must stay out of both the ground /// registry and the inference-variable method probe. pub(crate) fn provides_concrete_members(interface: &TypeName) -> bool { - !interface.is_builtin_root_type("AnyClass") + !interface.is_reflect_root_type("AnyClass") } /// Compiler-derived interfaces may deliberately narrow a blanket stdlib impl. @@ -831,14 +830,11 @@ fn derived_impl_allows( concrete: &Ty, interface: &TypeName, ) -> bool { - if !interface.is_builtin_root_type("AnyClass") { + if !interface.is_reflect_root_type("AnyClass") { return true; } let normalized = baml_type::normalize::normalize_interned(concrete, &AliasOnlyFacts::new(db)); - matches!( - normalized.kind(), - TyKind::Class(name, _, _) if class_inhabits_any_class(name) - ) + matches!(normalized.kind(), TyKind::Class(..)) } #[salsa::interned] diff --git a/baml_language/crates/baml_compiler2_hir_ty/src/infer.rs b/baml_language/crates/baml_compiler2_hir_ty/src/infer.rs index 460fc41dd8c..c4f31c77501 100644 --- a/baml_language/crates/baml_compiler2_hir_ty/src/infer.rs +++ b/baml_language/crates/baml_compiler2_hir_ty/src/infer.rs @@ -3425,7 +3425,7 @@ impl<'db> InferenceContext<'db> { ok &= self.sub(&throws.0, &throws.1); ok } - // `baml.AnyFunction` is compiler-derived for concrete function + // `reflect.AnyFunction` is compiler-derived for concrete function // values, rather than an ordinary impl obligation. When a // generic consumer such as `reflect.call_any` receives a // function value directly, carry its output channels into the @@ -3440,7 +3440,7 @@ impl<'db> InferenceContext<'db> { .. }, TyKind::Interface(name, _, expected_pins, _), - ) if name.is_builtin_root_type("AnyFunction") => { + ) if name.is_reflect_root_type("AnyFunction") => { let mut ok = true; for (pin, expected_pin) in expected_pins { let Some(actual_pin) = (match pin.as_str() { @@ -3476,7 +3476,7 @@ impl<'db> InferenceContext<'db> { ) = (actual.kind(), expected.kind()) && a_name == b_name && a_args.len() == b_args.len() - && (a_name.is_builtin_root_type("AnyFunction") + && (a_name.is_reflect_root_type("AnyFunction") || b_pins .iter() .all(|(pin, _)| a_pins.iter().any(|(a_pin, _)| a_pin == pin))) @@ -4684,9 +4684,25 @@ impl<'db> InferenceContext<'db> { { return; } - let expected = Ty::intern(TyKind::Type { - attr: TyAttr::default(), - }); + // The operand contract is `reflect.Type | reflect.TypeView`: a kind + // view is accepted and converts to the `type` value it wraps at the + // VM's type-operand boundary — the same explicit-computation-point + // model as `int + float`, never a subtyping edge. + let expected = Ty::intern(TyKind::Union( + vec![ + Ty::intern(TyKind::Type { + attr: TyAttr::default(), + }), + Ty::intern(TyKind::Interface( + baml_type::QualifiedTypeName::from_dotted_path("reflect.TypeView"), + Box::new([]), + Box::new([]), + TyAttr::default(), + )), + ] + .into(), + TyAttr::default(), + )); let saved_anchor = self.obligation_anchor.replace(operand); let fits = self.sub(&got, &expected); self.obligation_anchor = saved_anchor; diff --git a/baml_language/crates/baml_compiler2_hir_ty/src/interfaces/impl_rules.rs b/baml_language/crates/baml_compiler2_hir_ty/src/interfaces/impl_rules.rs index d1b88a7577c..21bca1c4905 100644 --- a/baml_language/crates/baml_compiler2_hir_ty/src/interfaces/impl_rules.rs +++ b/baml_language/crates/baml_compiler2_hir_ty/src/interfaces/impl_rules.rs @@ -183,9 +183,9 @@ pub(crate) fn lower_generic_param_interface_bounds<'db>( diags, ); match ty { - // BEP-062: `baml.AnyFunction` is legal only as a value type; as a + // BEP-062: `reflect.AnyFunction` is legal only as a value type; as a // bound it is rejected and contributes no constraint. - Ty::Interface(qtn, ..) if qtn.is_builtin_root_type("AnyFunction") => { + Ty::Interface(qtn, ..) if qtn.is_reflect_root_type("AnyFunction") => { diags.push(TirTypeError::BuiltinInterfaceNotABound { interface: qtn }); } Ty::Interface(qtn, generics, assoc, _) => { @@ -422,9 +422,9 @@ pub fn impl_data<'db>( // and associated-binding hygiene. (Signature conformance is phase 5.) let mut conformance_diags: Vec<(TirTypeError, ImplDiagnosticLocation)> = Vec::new(); if let Some(iface_qtn) = interface_loc_qtn(db, iface_loc) { - // BEP-062 (E0153): `baml.AnyFunction`'s conformance is compiler-derived; + // BEP-062 (E0153): `reflect.AnyFunction`'s conformance is compiler-derived; // a written impl is rejected outright. - if iface_qtn.is_builtin_root_type("AnyFunction") { + if iface_qtn.is_reflect_root_type("AnyFunction") { conformance_diags.push(( TirTypeError::BuiltinInterfaceNotImplementable { interface: iface_qtn.clone(), @@ -1727,7 +1727,7 @@ pub fn implements_interface( // The blanket stdlib impl supplies AnyClass's default-method dispatch, but // membership is compiler-derived and narrower. Reuse the normalizer's // class-only rule so `requires AnyClass` cannot observe the blanket. - if interface.name.is_builtin_root_type("AnyClass") { + if interface.name.is_reflect_root_type("AnyClass") { return is_subtype(concrete, &interface.to_ty()); } diff --git a/baml_language/crates/baml_compiler2_hir_ty/src/lower.rs b/baml_language/crates/baml_compiler2_hir_ty/src/lower.rs index 31e07076aad..5df7c554a32 100644 --- a/baml_language/crates/baml_compiler2_hir_ty/src/lower.rs +++ b/baml_language/crates/baml_compiler2_hir_ty/src/lower.rs @@ -2273,7 +2273,7 @@ pub fn signature_lowering_diagnostics<'db>( match lowered.kind() { // The compiler-derived builtin interface is a VALUE type, // never a bound (E0154). - TyKind::Interface(qtn, ..) if qtn.is_builtin_root_type("AnyFunction") => { + TyKind::Interface(qtn, ..) if qtn.is_reflect_root_type("AnyFunction") => { out.push(( source_map.type_refs.span(*bound), TirTypeError::BuiltinInterfaceNotABound { @@ -2426,7 +2426,7 @@ pub fn class_lowering_diagnostics<'db>( ); extend_lowering_diagnostics(&mut out, &source_map.type_refs, diagnostics); match lowered.kind() { - TyKind::Interface(qtn, ..) if qtn.is_builtin_root_type("AnyFunction") => { + TyKind::Interface(qtn, ..) if qtn.is_reflect_root_type("AnyFunction") => { out.push(( source_map.type_refs.span(*bound), TirTypeError::BuiltinInterfaceNotABound { @@ -2513,7 +2513,7 @@ pub fn interface_lowering_diagnostics<'db>( let Some(bound) = assoc.bound else { continue }; let lowered = ctx.lower_type_ref_at(&data.type_refs, bound, TypePosition::ConstraintHead); match lowered.kind() { - TyKind::Interface(qtn, ..) if qtn.is_builtin_root_type("AnyFunction") => { + TyKind::Interface(qtn, ..) if qtn.is_reflect_root_type("AnyFunction") => { out.push(( source_map.type_refs.span(bound), TirTypeError::BuiltinInterfaceNotABound { diff --git a/baml_language/crates/baml_compiler2_mir/src/lower.rs b/baml_language/crates/baml_compiler2_mir/src/lower.rs index d8a13ef6b17..ab5922698ab 100644 --- a/baml_language/crates/baml_compiler2_mir/src/lower.rs +++ b/baml_language/crates/baml_compiler2_mir/src/lower.rs @@ -1004,13 +1004,6 @@ fn switch_member_tag_sufficient(member: &RuntimeTy, scrutinee: Option<&RuntimeTy // the shared `ENUM` tag can't express, so always take the precise chain. RuntimeTy::EnumVariant(..) => false, RuntimeTy::Class(name, args, _) => { - // Reflection-kind classes are transparent views over an - // `Object::Type`: their precise `is` test inspects the wrapped - // realized type, while `TypeTag` sees only the outer `TYPE` tag. - // A tag switch would therefore miss every kind arm. - if baml_type::type_kind::is_type_kind_class(name) { - return false; - } if args.is_empty() { return true; } @@ -1188,11 +1181,37 @@ fn resolution_to_item_ref( }) } MemberResolution::InterfaceConcreteMethod { impl_loc, func_loc } => { - // A statically-resolved interface-method call. Route it through the interface's - // method ref — the runtime dispatches on the concrete receiver's registered impl, - // which is correct. (A direct static call to `func_loc` is a valid optimization, - // not required for correctness; it is deferred.) + // A statically-resolved interface-method call. let block = baml_compiler2_ppir::item_data::impl_block_data(db, *impl_loc); + + // When the impl provides its own frame-free override, call it + // directly: the impl block binds no generic params, so the callee + // needs no frame type args and the resolved function IS the body + // this call must run. Routing such a call through the interface's + // method ref instead would (for a defaulted method) name the + // interface's default-body global, which direct-calls the default + // with an empty frame — its `Self`-typed templates then have no + // slot to substitute and the call traps at runtime. + let impl_is_frame_free = match &block.subject { + baml_compiler2_ppir::item_data::ImplSubjectData::Free { generics, .. } => { + generics.is_empty() + } + baml_compiler2_ppir::item_data::ImplSubjectData::InClass { class, .. } => { + baml_compiler2_hir_ty::lower::class_generic_frame(db, *class).is_empty() + } + }; + if impl_is_frame_free && block.methods.contains(func_loc) { + return Some(def_to_item_ref(db, Definition::Function(*func_loc))); + } + + // BUG: the remaining shapes (a generic impl's override, or an + // impl inheriting the interface default) are still routed through + // the interface's method ref. For a defaulted method that global + // IS the default body, so a direct call runs it without the + // `Self`/impl frame it needs — the same trap the branch above + // avoids. These shapes should lower as virtual dispatch on the + // receiver (the rule carries the frame); today they are only + // reached by paths that never executed before this arm existed. let impl_pkg = file_package(db, impl_loc.file(db)); let impl_pkg_items = baml_compiler2_ppir::package_items( db, @@ -1579,7 +1598,7 @@ fn package_lowering_data<'db>( ); } - // `baml.AnyClass` keeps its ratified reflection-backed default methods + // `reflect.AnyClass` keeps its ratified reflection-backed default methods // in the `baml` package, while `reflect` depends on `baml` for the // interface and core error types. Avoiding a dependency cycle is // intentional, but MIR still needs the root reflect package's concrete diff --git a/baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs b/baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs index 8f2f7471ee6..6130caaeacd 100644 --- a/baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs +++ b/baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs @@ -328,11 +328,11 @@ pub enum DiagnosticId { // Builtin interfaces (BEP-062, E0153/E0154) /// An `implements` block targets a compiler-builtin interface - /// (`baml.AnyFunction`), whose conformance is derived by the compiler + /// (`reflect.AnyFunction`), whose conformance is derived by the compiler /// (every function type implements it) and cannot be written by hand. BuiltinInterfaceNotImplementable, /// A generic parameter's bound (`T extends X`) names a compiler-builtin - /// interface (`baml.AnyFunction`) that is only legal as a value type + /// interface (`reflect.AnyFunction`) that is only legal as a value type /// (an existential), never as a bound. BuiltinInterfaceNotABound, diff --git a/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_anyfunction_reflect/main.baml b/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_anyfunction_reflect/main.baml index c8448fd283f..fc7df76e6f1 100644 --- a/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_anyfunction_reflect/main.baml +++ b/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_anyfunction_reflect/main.baml @@ -23,16 +23,16 @@ function current_time() -> string throws never { } function bare_and_pinned() -> int throws never { - let f: baml.AnyFunction = web_search - let g: baml.AnyFunction = web_search + let f: reflect.AnyFunction = web_search + let g: reflect.AnyFunction = web_search // Covariant pins: a narrower existential fits a wider one, and every // existential fits the bare (unknown-pinned) form. - let widened: baml.AnyFunction = g - let bare: baml.AnyFunction = g + let widened: reflect.AnyFunction = g + let bare: reflect.AnyFunction = g return 0 } -function heterogeneous_tool_map() -> map> throws never { +function heterogeneous_tool_map() -> map> throws never { // Each function coerces independently: Doc[] and string both fit the // Returns pin; never and ToolError both fit the Throws pin. return { @@ -41,7 +41,7 @@ function heterogeneous_tool_map() -> map string throws never { +function signature_access(f: reflect.AnyFunction) -> string throws never { let sig = reflect.signature(f) // The error channel field is `errors` (no keyword-named fields), // and `type` is an ordinary member name on `reflect.Arg`. diff --git a/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_reflect_shadowing/main.baml b/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_reflect_shadowing/main.baml index a7cb22e6782..7eb33bd9c89 100644 --- a/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_reflect_shadowing/main.baml +++ b/baml_language/crates/baml_tests/baml_src/ns_fixtures/ns_reflect_shadowing/main.baml @@ -38,7 +38,7 @@ function helper(q: string) -> string throws never { // The class answers for `describe` and nothing else, so a name it does not // declare still reaches the package. function package_still_reachable() -> string { - let f: baml.AnyFunction = helper + let f: reflect.AnyFunction = helper let sig = reflect.signature(f) return sig.returns.to_string() } diff --git a/baml_language/crates/baml_tests/baml_src/ns_optional_chain_type_args/optional_chain_type_args.baml b/baml_language/crates/baml_tests/baml_src/ns_optional_chain_type_args/optional_chain_type_args.baml index c536acb33e8..fa1ea4cfc47 100644 --- a/baml_language/crates/baml_tests/baml_src/ns_optional_chain_type_args/optional_chain_type_args.baml +++ b/baml_language/crates/baml_tests/baml_src/ns_optional_chain_type_args/optional_chain_type_args.baml @@ -395,13 +395,13 @@ test "non_generic_optional_calls_unchanged" { // ─── The reflection shape the bug was found on ──────────────────────────────── -function reflected_field_read_fn() -> int? throws baml.errors.TypeMismatch { - let value: baml.AnyClass = Point { x: 7, label: "a" } else { return null } +function reflected_field_read_fn() -> int? throws reflect.errors.TypeMismatch { + let value: reflect.AnyClass = Point { x: 7, label: "a" } else { return null } value.get_field("x")?.value() } -function reflected_missing_field_fn() -> int? throws baml.errors.TypeMismatch { - let value: baml.AnyClass = Point { x: 7, label: "a" } else { return null } +function reflected_missing_field_fn() -> int? throws reflect.errors.TypeMismatch { + let value: reflect.AnyClass = Point { x: 7, label: "a" } else { return null } value.get_field("absent")?.value() } @@ -411,11 +411,11 @@ test "reflected_field_read_through_optional_chain" { } /// A type arg the value does not fit is still a domain error -/// (`baml.errors.TypeMismatch`), not a frame-layout failure. +/// (`reflect.errors.TypeMismatch`), not a frame-layout failure. function reflected_field_wrong_type_arg_fn() -> string { - let value: baml.AnyClass = Point { x: 7, label: "a" } else { return "no-class" } + let value: reflect.AnyClass = Point { x: 7, label: "a" } else { return "no-class" } let read = value.get_field("x")?.value() catch (e) { - baml.errors.TypeMismatch { message } => { return "type-mismatch" } + reflect.errors.TypeMismatch { message } => { return "type-mismatch" } } read ?? "null" } diff --git a/baml_language/crates/baml_tests/baml_src/ns_reflect_type_of/reflect_type_of.baml b/baml_language/crates/baml_tests/baml_src/ns_reflect_type_of/reflect_type_of.baml index f7b1565ab9e..ad20d993c18 100644 --- a/baml_language/crates/baml_tests/baml_src/ns_reflect_type_of/reflect_type_of.baml +++ b/baml_language/crates/baml_tests/baml_src/ns_reflect_type_of/reflect_type_of.baml @@ -175,9 +175,11 @@ test "of_value_array_reports_element_type" { assert.is_true(reflect.Type.of_value(xs) == reflect.Type.of()) } -test "of_value_of_a_type_value_is_precise_kind" { - // A reflected class type value has the sealed class-kind view as its concrete type. - assert.is_true(reflect.Type.of_value(reflect.Type.of()) == reflect.Type.of()) +test "of_value_of_a_type_value_is_the_carrier" { + // A type value's concrete type is the `reflect.Type` metatype itself; the + // kind views are ordinary wrapper classes reached through `kind()`/`as_*`. + assert.is_true(reflect.Type.of_value(reflect.Type.of()) == reflect.Type.of()) + assert.is_true(reflect.Type.of_value(reflect.Type.of().as_class()) == reflect.Type.of()) } test "of_value_widened_unknown_slot" { @@ -191,7 +193,7 @@ function of_value_helper(q: string) -> string throws never { } test "of_value_function_value_reports_function_type" { - let f: baml.AnyFunction = of_value_helper; + let f: reflect.AnyFunction = of_value_helper; let t = reflect.Type.of_value(f); // The reconstructed signature type mentions the arrow, not `unknown`. assert.is_true(t != reflect.Type.of()) @@ -205,7 +207,7 @@ test "of_value_function_value_reports_function_type" { // reports the declared name, return type, and error type. test "reflect_signature_reports_the_declared_types" { - let f: baml.AnyFunction = of_value_helper; + let f: reflect.AnyFunction = of_value_helper; let sig = reflect.signature(f); // `name` is null for host and compiler-synthesized callables; a declared // function reports the name it was written with. diff --git a/baml_language/crates/baml_tests/baml_src/ns_structured_prompt_requests/structured_prompt_requests.baml b/baml_language/crates/baml_tests/baml_src/ns_structured_prompt_requests/structured_prompt_requests.baml index 99f8aa6d571..3ab858b0a27 100644 --- a/baml_language/crates/baml_tests/baml_src/ns_structured_prompt_requests/structured_prompt_requests.baml +++ b/baml_language/crates/baml_tests/baml_src/ns_structured_prompt_requests/structured_prompt_requests.baml @@ -98,7 +98,7 @@ test "generated companions apply defaulted llm arguments" { } test "generated build_request companion is reflection-visible" { - let f: baml.AnyFunction< + let f: reflect.AnyFunction< Returns = baml.http.Request, Throws = ai.errors.Failure | baml.errors.InvalidArgument diff --git a/baml_language/crates/baml_tests/baml_src/ns_unknown_error/unknown_error.baml b/baml_language/crates/baml_tests/baml_src/ns_unknown_error/unknown_error.baml index 079f7d44b36..75794afa6df 100644 --- a/baml_language/crates/baml_tests/baml_src/ns_unknown_error/unknown_error.baml +++ b/baml_language/crates/baml_tests/baml_src/ns_unknown_error/unknown_error.baml @@ -261,13 +261,13 @@ function ue_reflect_origin() -> bool { } function ue_call_reflect( - target: baml.AnyFunction, + target: reflect.AnyFunction, ) -> bool { reflect.call_any(target, {}) } function ue_reflect_boundary( - target: baml.AnyFunction, + target: reflect.AnyFunction, ) -> bool throws baml.errors.UnknownError { ue_call_reflect(target) catch_all (error) { _ => throw baml.errors.UnknownError.with_message(error, "reflect call failed"), @@ -275,7 +275,7 @@ function ue_reflect_boundary( } function ue_reflect_preserves_context() -> bool { - let target: baml.AnyFunction = ue_reflect_origin; + let target: reflect.AnyFunction = ue_reflect_origin; ue_reflect_boundary(target) catch_all (error, context) { baml.errors.UnknownError => { context.stack_trace.frames.some((frame: baml.errors.StackFrame) -> bool { diff --git a/baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/anyfunction.baml b/baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/anyfunction.baml index 3ef440d5339..3a09cf008dd 100644 --- a/baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/anyfunction.baml +++ b/baml_language/crates/baml_tests/projects/diagnostic_errors/anyfunction/anyfunction.baml @@ -1,4 +1,4 @@ -// BEP-062: baml.AnyFunction is a compiler builtin. It cannot be implemented +// BEP-062: reflect.AnyFunction is a compiler builtin. It cannot be implemented // by hand (E0153) and cannot be used as a generic bound (E0154) on // functions, classes, impl generics, or associated types. @@ -6,19 +6,19 @@ class MyTool { name string } -implements baml.AnyFunction for MyTool { +implements reflect.AnyFunction for MyTool { } -function pick(f: T) -> T throws never { +function pick(f: T) -> T throws never { return f } -class Holder { +class Holder { f T } interface Registry { - type Callee extends baml.AnyFunction + type Callee extends reflect.AnyFunction } // BEP-062: AnyFunction coercion failures. The derived conformance checks the @@ -42,10 +42,10 @@ function web_search(q: string) -> Doc[] throws ToolError { } function main() -> int throws never { - let bad_ret: baml.AnyFunction = web_search - let bad_throws: baml.AnyFunction = web_search - let not_a_fn: baml.AnyFunction = 42 - let narrow: baml.AnyFunction = web_search - let bad_widen: baml.AnyFunction = narrow + let bad_ret: reflect.AnyFunction = web_search + let bad_throws: reflect.AnyFunction = web_search + let not_a_fn: reflect.AnyFunction = 42 + let narrow: reflect.AnyFunction = web_search + let bad_widen: reflect.AnyFunction = narrow return 0 } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_class_type_args_at_runtime/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_class_type_args_at_runtime/bytecode.snap index 9309172e64b..09c4905b3fc 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_class_type_args_at_runtime/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_class_type_args_at_runtime/bytecode.snap @@ -78,7 +78,7 @@ function class_type_args_at_runtime.$init_test_ns_class_type_args_at_runtime_cla function class_type_args_at_runtime.Box.describe(self: class_type_args_at_runtime.Box<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/bytecode.snap index bc69e0eac8c..8e34abb4ce2 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/bytecode.snap @@ -130,13 +130,13 @@ function fixtures.anyfunction_reflect.current_time() -> string { return } -function fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map> { +function fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map> { load_const user.fixtures.anyfunction_reflect.web_search load_const user.fixtures.anyfunction_reflect.current_time load_const "search" load_const "now" load_type string - load_type baml.AnyFunction + load_type reflect.AnyFunction alloc_map 2 return } @@ -171,17 +171,17 @@ function fixtures.anyfunction_reflect.runtime_enum_llm_companions_compile() -> s return } -function fixtures.anyfunction_reflect.signature_access(f: baml.AnyFunction) -> string { +function fixtures.anyfunction_reflect.signature_access(f: reflect.AnyFunction) -> string { load_var f call reflect.signature store_var sig load_var sig load_field .returns - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_var sig load_field .errors - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _7 load_var sig load_field .args @@ -223,7 +223,7 @@ function fixtures.anyfunction_reflect.signature_access(f: baml.AnyFunction + load_type reflect.AnyFunction load_var2 3 1 call baml.Map.get store_var f diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/main.fmt.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/main.fmt.snap index 75224dc7497..5aa938d7a8d 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/main.fmt.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/main.fmt.snap @@ -26,23 +26,23 @@ function current_time() -> string throws never { } function bare_and_pinned() -> int throws never { - let f: baml.AnyFunction = web_search; - let g: baml.AnyFunction = web_search; + let f: reflect.AnyFunction = web_search; + let g: reflect.AnyFunction = web_search; // Covariant pins: a narrower existential fits a wider one, and every // existential fits the bare (unknown-pinned) form. - let widened: baml.AnyFunction = g; - let bare: baml.AnyFunction = g; + let widened: reflect.AnyFunction = g; + let bare: reflect.AnyFunction = g; return 0; } function heterogeneous_tool_map( -) -> map> throws never { +) -> map> throws never { // Each function coerces independently: Doc[] and string both fit the // Returns pin; never and ToolError both fit the Throws pin. return { "search": web_search, "now": current_time }; } -function signature_access(f: baml.AnyFunction) -> string throws never { +function signature_access(f: reflect.AnyFunction) -> string throws never { let sig = reflect.signature(f); // The error channel field is `errors` (no keyword-named fields), // and `type` is an ordinary member name on `reflect.Arg`. diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/mir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/mir.snap index 583f921a214..46c761f2f86 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/mir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/mir.snap @@ -48,7 +48,7 @@ fn user.fixtures.anyfunction_reflect.current_time() -> string { fn user.fixtures.anyfunction_reflect.bare_and_pinned() -> int { // Locals: let _0: int // _0 // return - let _1: baml.AnyFunction // g + let _1: reflect.AnyFunction // g bb0: { _1 = const fn user.fixtures.anyfunction_reflect.web_search; @@ -61,12 +61,12 @@ fn user.fixtures.anyfunction_reflect.bare_and_pinned() -> int { } } -fn user.fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map> { +fn user.fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map> { // Locals: - let _0: map> // _0 // return + let _0: map> // _0 // return bb0: { - _0 = { const "search": const fn user.fixtures.anyfunction_reflect.web_search, const "now": const fn user.fixtures.anyfunction_reflect.current_time }: map>; + _0 = { const "search": const fn user.fixtures.anyfunction_reflect.web_search, const "now": const fn user.fixtures.anyfunction_reflect.current_time }: map>; goto -> bb1; } @@ -75,10 +75,10 @@ fn user.fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map) -> string { +fn user.fixtures.anyfunction_reflect.signature_access(f: reflect.AnyFunction) -> string { // Locals: let _0: string // _0 // return - let _1: baml.AnyFunction // f // param + let _1: reflect.AnyFunction // f // param let _2: reflect.Signature // sig let _3: string // parts let _4: string @@ -130,12 +130,12 @@ fn user.fixtures.anyfunction_reflect.signature_access(f: baml.AnyFunction [bb2]; + _5 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _6) -> [bb2]; } bb2: { _8 = copy _2.4; - _7 = call const fn reflect.Type.baml.ToString.to_string(copy _8) -> [bb3]; + _7 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _8) -> [bb3]; } bb3: { @@ -173,7 +173,7 @@ fn user.fixtures.anyfunction_reflect.signature_access(f: baml.AnyFunction [bb9]; + _22 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _23) -> [bb9]; } bb9: { @@ -227,7 +227,7 @@ fn user.fixtures.anyfunction_reflect.signature_access(f: baml.AnyFunction [bb18]; + _44 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _45) -> [bb18]; } bb18: { @@ -250,14 +250,14 @@ fn user.fixtures.anyfunction_reflect.typed_dispatch(name: string, args: map // args // param - let _3: map> // tools - let _4: null | baml.AnyFunction // f + let _3: map> // tools + let _4: null | reflect.AnyFunction // f let _5: reflect.Type let _6: reflect.Type let _7: bool let _8: bool let _9: fixtures.anyfunction_reflect.ToolError // e - let _10: baml.AnyFunction + let _10: reflect.AnyFunction let _11: reflect.Type let _12: reflect.Type let _13: bool @@ -271,7 +271,7 @@ fn user.fixtures.anyfunction_reflect.typed_dispatch(name: string, args: map); + _6 = load_type(reflect.AnyFunction); _4 = call const fn baml.Map.get(copy _3, copy _1) -> [bb2]; } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/ppir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/ppir.snap index 4360f3a76d5..329c1103ca9 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/ppir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_anyfunction_reflect/ppir.snap @@ -33,18 +33,18 @@ function user.fixtures.anyfunction_reflect.RuntimeClassify$stream(input: string, ai.stream.from_spec(RuntimeClassify$spec(input), client = client) } function user.fixtures.anyfunction_reflect.bare_and_pinned() -> int [expr] { - { let f: baml.AnyFunction = web_search; let g: baml.AnyFunction = web_search; let widened: baml.AnyFunction = g; let bare: baml.AnyFunction = g; return 0 } + { let f: reflect.AnyFunction = web_search; let g: reflect.AnyFunction = web_search; let widened: reflect.AnyFunction = g; let bare: reflect.AnyFunction = g; return 0 } } function user.fixtures.anyfunction_reflect.current_time() -> string [expr] { { return "now" } } -function user.fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map> [expr] { +function user.fixtures.anyfunction_reflect.heterogeneous_tool_map() -> map> [expr] { { return map { "search": web_search, "now": current_time } } } function user.fixtures.anyfunction_reflect.runtime_enum_llm_companions_compile() -> string [expr] { { let category = reflect.enum.new("Category", [reflect.enum.value("RED", alias = "k7", description = "warm"), "BLUE"]); let prompt = RuntimeClassify$render_prompt("sample").text(); let parsed = RuntimeClassify$parse(`...`); return prompt Add reflect.enum.get_value(parsed) } } -function user.fixtures.anyfunction_reflect.signature_access(f: baml.AnyFunction) -> string [expr] { +function user.fixtures.anyfunction_reflect.signature_access(f: reflect.AnyFunction) -> string [expr] { { let sig = reflect.signature(f); let parts = sig.returns.to_string() Add sig.errors.to_string() Add sig.args.length().to_string(); for arg in sig.args { parts = parts Add arg.name Add arg.type.to_string() }; for key in sig.opts.keys() { let opt = sig.opts.get(key) } if (opt Ne null) { parts = parts Add key Add opt.type.to_string() }; return parts } } function user.fixtures.anyfunction_reflect.typed_dispatch(name: string, args: map) -> user.fixtures.anyfunction_reflect.Doc[] | string [expr] { diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/bytecode.snap index 91a30e39497..7d37af33dd2 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/bytecode.snap @@ -52,7 +52,7 @@ function fixtures.reflect_shadowing.package_still_reachable() -> string { load_const user.fixtures.reflect_shadowing.helper call reflect.signature load_field .returns - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/main.fmt.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/main.fmt.snap index 72666ae380a..53cd5694ece 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/main.fmt.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/main.fmt.snap @@ -41,7 +41,7 @@ function helper(q: string) -> string throws never { // The class answers for `describe` and nothing else, so a name it does not // declare still reaches the package. function package_still_reachable() -> string { - let f: baml.AnyFunction = helper; + let f: reflect.AnyFunction = helper; let sig = reflect.signature(f); return sig.returns.to_string(); } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/mir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/mir.snap index 3e3068fe22e..4bf8411c44e 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/mir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/mir.snap @@ -208,9 +208,9 @@ fn user.fixtures.reflect_shadowing.helper(q: string) -> string { fn user.fixtures.reflect_shadowing.package_still_reachable() -> string { // Locals: let _0: string // _0 // return - let _1: baml.AnyFunction // f + let _1: reflect.AnyFunction // f let _2: reflect.Signature // sig - let _3: baml.AnyFunction + let _3: reflect.AnyFunction let _4: (reflect.Type) -> string throws never bb0: { @@ -221,7 +221,7 @@ fn user.fixtures.reflect_shadowing.package_still_reachable() -> string { bb1: { _4 = copy _2.3; - _0 = call const fn reflect.Type.baml.ToString.to_string(copy _4) -> [bb2]; + _0 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _4) -> [bb2]; } bb2: { diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/ppir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/ppir.snap index f463fba9a97..5d3d35e4248 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/ppir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_reflect_shadowing/ppir.snap @@ -21,7 +21,7 @@ function user.fixtures.reflect_shadowing.local_shadows_package() -> int [expr] { let reflect = 1; return reflect Add 1 } } function user.fixtures.reflect_shadowing.package_still_reachable() -> string [expr] { - { let f: baml.AnyFunction = helper; let sig = reflect.signature(f); return sig.returns.to_string() } + { let f: user.fixtures.reflect_shadowing.reflect.AnyFunction = helper; let sig = reflect.signature(f); return sig.returns.to_string() } } function user.fixtures.reflect_shadowing.unbound_user_method() -> string [expr] { { let m = reflect.describe; return m(user.fixtures.reflect_shadowing.reflect { label: "x" }) } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/bytecode.snap index f5070675a69..c7e50ecd2c9 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/bytecode.snap @@ -4,91 +4,50 @@ source: crates/baml_tests/src/corpus.rs function fixtures.type_kinds.classify(t: reflect.Type) -> string { load_var t call reflect.Type.kind - store_var _2 - load_var _2 - is_type reflect.class.Type - pop_jump_if_false L0 - jump L15 + type_tag + dense_tag [Type, Type, Type, Type, Type, Type, Type, Type, Type] + jump_table [L8, L7, L6, L5, L4, L3, L2, L1, L0], default L10 - L0: - load_var _2 - is_type reflect.enum.Type - pop_jump_if_false L1 - jump L14 - - L1: - load_var _2 - is_type reflect.union.Type - pop_jump_if_false L2 - jump L13 - - L2: - load_var _2 - is_type reflect.literal.Type - pop_jump_if_false L3 - jump L12 - - L3: - load_var _2 - is_type reflect.array.Type - pop_jump_if_false L4 - jump L11 - - L4: - load_var _2 - is_type reflect.map.Type - pop_jump_if_false L5 - jump L10 - - L5: - load_var _2 - is_type reflect.interface.Type - pop_jump_if_false L6 - jump L9 - - L6: - load_var _2 - is_type reflect.primitive.Type - pop_jump_if_false L7 - jump L8 - - L7: + L0: Type load_const "function" - jump L16 + jump L9 - L8: + L1: Type load_const "primitive" - jump L16 + jump L9 - L9: + L2: Type load_const "interface" - jump L16 + jump L9 - L10: + L3: Type load_const "map" - jump L16 + jump L9 - L11: + L4: Type load_const "array" - jump L16 + jump L9 - L12: + L5: Type load_const "literal" - jump L16 + jump L9 - L13: + L6: Type load_const "union" - jump L16 + jump L9 - L14: + L7: Type load_const "enum" - jump L16 + jump L9 - L15: + L8: Type load_const "class" - L16: + L9: return + + L10: + unreachable } function fixtures.type_kinds.exercise_all_kinds() -> bool { diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/mir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/mir.snap index 9e3b2614d1d..30f72189bc1 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/mir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_fixtures/ns_type_kinds/mir.snap @@ -7,105 +7,67 @@ fn user.fixtures.type_kinds.classify(t: reflect.Type) -> string { let _0: string // _0 // return let _1: reflect.Type // t // param let _2: reflect.array.Type | reflect.class.Type | reflect.enum.Type | reflect.function.Type | reflect.interface.Type | reflect.literal.Type | reflect.map.Type | reflect.primitive.Type | reflect.union.Type - let _3: bool - let _4: bool - let _5: bool - let _6: bool - let _7: bool - let _8: bool - let _9: bool - let _10: bool + let _3: int bb0: { _2 = call const fn reflect.Type.kind(copy _1) -> [bb1]; } bb1: { - _3 = is_type(copy _2, reflect.class.Type); - branch copy _3 -> [bb17, bb2]; + _3 = type_tag(_2); + switch copy _3 [Type: bb11, Type: bb10, Type: bb9, Type: bb8, Type: bb7, Type: bb6, Type: bb5, Type: bb4, Type: bb3, otherwise: bb2] (exhaustive); } bb2: { - _4 = is_type(copy _2, reflect.enum.Type); - branch copy _4 -> [bb16, bb3]; + unreachable; } bb3: { - _5 = is_type(copy _2, reflect.union.Type); - branch copy _5 -> [bb15, bb4]; - } - - bb4: { - _6 = is_type(copy _2, reflect.literal.Type); - branch copy _6 -> [bb14, bb5]; - } - - bb5: { - _7 = is_type(copy _2, reflect.array.Type); - branch copy _7 -> [bb13, bb6]; - } - - bb6: { - _8 = is_type(copy _2, reflect.map.Type); - branch copy _8 -> [bb12, bb7]; - } - - bb7: { - _9 = is_type(copy _2, reflect.interface.Type); - branch copy _9 -> [bb11, bb8]; - } - - bb8: { - _10 = is_type(copy _2, reflect.primitive.Type); - branch copy _10 -> [bb10, bb9]; - } - - bb9: { _0 = const "function"; - goto -> bb18; + goto -> bb12; } - bb10: { + bb4: { _0 = const "primitive"; - goto -> bb18; + goto -> bb12; } - bb11: { + bb5: { _0 = const "interface"; - goto -> bb18; + goto -> bb12; } - bb12: { + bb6: { _0 = const "map"; - goto -> bb18; + goto -> bb12; } - bb13: { + bb7: { _0 = const "array"; - goto -> bb18; + goto -> bb12; } - bb14: { + bb8: { _0 = const "literal"; - goto -> bb18; + goto -> bb12; } - bb15: { + bb9: { _0 = const "union"; - goto -> bb18; + goto -> bb12; } - bb16: { + bb10: { _0 = const "enum"; - goto -> bb18; + goto -> bb12; } - bb17: { + bb11: { _0 = const "class"; - goto -> bb18; + goto -> bb12; } - bb18: { + bb12: { return; } } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_inferred_generic_type_args/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_inferred_generic_type_args/bytecode.snap index 27a774191be..862e2f47efe 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_inferred_generic_type_args/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_inferred_generic_type_args/bytecode.snap @@ -182,7 +182,7 @@ function inferred_generic_type_args.Cat.Animal.speak(self: inferred_generic_type function inferred_generic_type_args.Counter.element_type(self: inferred_generic_type_args.Counter<#1>) -> string { load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -251,7 +251,7 @@ function inferred_generic_type_args.LoneIter.NextIter.next2(self: infe function inferred_generic_type_args.Named.tname(self: inferred_generic_type_args.Named<#1>) -> string { load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -304,7 +304,7 @@ function inferred_generic_type_args.PlainThing.Describable.describe(self: inferr function inferred_generic_type_args.ProbeA.TypeProbe.seen(self: inferred_generic_type_args.ProbeA, value: #0) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -353,7 +353,7 @@ function inferred_generic_type_args.StrCounter.Counter.describe(self: inferre function inferred_generic_type_args.TypedBox.Describable.describe(self: inferred_generic_type_args.TypedBox<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -407,7 +407,7 @@ function inferred_generic_type_args.default_method_typevar_name() -> string { function inferred_generic_type_args.echo_type(a: #0) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -424,7 +424,7 @@ function inferred_generic_type_args.free_fn_inferred_t() -> string { function inferred_generic_type_args.free_fn_tname(a: #0[]) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/bytecode.snap index c0ee7e88639..9f1c193b4a7 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/bytecode.snap @@ -108,7 +108,7 @@ function instantiation_expr.bound_method_value() -> int { function instantiation_expr.describe() -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/ns_qualified/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/ns_qualified/bytecode.snap index 6cbbc391ca0..3051a303ef4 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/ns_qualified/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_instantiation_expr/ns_qualified/bytecode.snap @@ -3,7 +3,7 @@ source: crates/baml_tests/src/corpus.rs --- function instantiation_expr.qualified.q_describe() -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_interfaces/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_interfaces/bytecode.snap index 5f9116489b6..6db63d0d5a3 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_interfaces/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_interfaces/bytecode.snap @@ -1962,10 +1962,10 @@ function interfaces.GimpEchoer.GimpEcho.echo(self: interfaces.GimpEchoer, v function interfaces.GoopDescriber$for$GoopBox.describe(self: interfaces.GoopBox<#0>, value: #1) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _4 load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _6 load_var _4 load_const ":" @@ -4740,7 +4740,7 @@ function interfaces.ritv_main() -> bool { function interfaces.rtit_main() -> string { load_type interfaces.RtitAnimal - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -5478,10 +5478,10 @@ function interfaces.w306_main() -> string { function interfaces.w306_names() -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var naked load_type interfaces.W306Box<#0> - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var wrapped load_const "naked=" load_var naked diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_item_projections/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_item_projections/bytecode.snap index 09c0e73bc39..3168566a6ad 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_item_projections/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_item_projections/bytecode.snap @@ -224,7 +224,7 @@ function item_projections.Loud.Sayer.say(self: item_projections.Loud) -> string function item_projections.Plate.Embosser.emboss(u: #1) -> string { load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _2 load_const "emboss " load_var _2 @@ -265,7 +265,7 @@ function item_projections.Poly.Convert.conv(self: item_projections.Poly, function item_projections.Press.Stamper.emboss(u: #0) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _2 load_const "emboss " load_var _2 @@ -275,7 +275,7 @@ function item_projections.Press.Stamper.emboss(u: #0) -> string { function item_projections.Press.Stamper.stamp(self: item_projections.Press, u: #0) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _3 load_const "stamp " load_var _3 diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_lambdas/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_lambdas/bytecode.snap index 41821e027b0..39d5cb5bcb3 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_lambdas/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_lambdas/bytecode.snap @@ -484,11 +484,11 @@ function lambdas.lambdas_inferred_signature() -> string { store_var sig load_var sig load_field .returns - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_var sig load_field .errors - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _7 load_var _5 load_const "/" @@ -504,11 +504,11 @@ function lambdas.lambdas_inferred_throwing_signature() -> string { store_var sig load_var sig load_field .returns - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_var sig load_field .errors - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _7 load_var _5 load_const "/" diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_optional_chain_type_args/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_optional_chain_type_args/bytecode.snap index fced84c1591..5b025dfed06 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_optional_chain_type_args/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_optional_chain_type_args/bytecode.snap @@ -106,10 +106,10 @@ function optional_chain_type_args.$init_test_ns_optional_chain_type_args_optiona function optional_chain_type_args.Boxed.both(self: optional_chain_type_args.Boxed<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _3 load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_var _3 load_const "/" @@ -121,7 +121,7 @@ function optional_chain_type_args.Boxed.both(self: optional_chain_type_args.Boxe function optional_chain_type_args.Boxed.describe(self: optional_chain_type_args.Boxed<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -138,7 +138,7 @@ function optional_chain_type_args.Callables.method(self: optional_chain_type_arg function optional_chain_type_args.Cat.Speaker.speak(self: optional_chain_type_args.Cat) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _2 load_const "cat:" load_var _2 @@ -148,13 +148,13 @@ function optional_chain_type_args.Cat.Speaker.speak(self: optional_chain_type_ar function optional_chain_type_args.Dog.Speaker.speak(self: optional_chain_type_args.Dog) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } function optional_chain_type_args.Holder.ident(self: optional_chain_type_args.Holder, v: #0) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -178,16 +178,16 @@ function optional_chain_type_args.Holder.plain(self: optional_chain_type_args.Ho function optional_chain_type_args.Holder.value(self: optional_chain_type_args.Holder) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } function optional_chain_type_args.Pair.Tagged.tag(self: optional_chain_type_args.Pair<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _3 load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_var _3 load_const "/" @@ -901,7 +901,7 @@ function optional_chain_type_args.reflected_field_read_fn() -> int | null { init_instance user.optional_chain_type_args.Point .x, .label store_var _2 load_var _2 - narrow_bind baml.AnyClass, slot=1 + narrow_bind reflect.AnyClass, slot=1 pop_jump_if_false L0 jump L1 @@ -914,7 +914,7 @@ function optional_chain_type_args.reflected_field_read_fn() -> int | null { store_var value load_var value load_const "x" - load_type baml.AnyClass + load_type reflect.AnyClass load_const "get_field" virtual_call nargs=2 ntypeargs=0 store_var _4 @@ -927,7 +927,7 @@ function optional_chain_type_args.reflected_field_read_fn() -> int | null { L2: load_var value load_const "x" - load_type baml.AnyClass + load_type reflect.AnyClass load_const "get_field" virtual_call nargs=2 ntypeargs=0 store_var _6 @@ -949,7 +949,7 @@ function optional_chain_type_args.reflected_field_wrong_type_arg_fn() -> string init_instance user.optional_chain_type_args.Point .x, .label store_var _2 load_var _2 - narrow_bind baml.AnyClass, slot=1 + narrow_bind reflect.AnyClass, slot=1 pop_jump_if_false L0 jump L1 @@ -962,7 +962,7 @@ function optional_chain_type_args.reflected_field_wrong_type_arg_fn() -> string store_var value load_var value load_const "x" - load_type baml.AnyClass + load_type reflect.AnyClass load_const "get_field" virtual_call nargs=2 ntypeargs=0 store_var _6 @@ -975,7 +975,7 @@ function optional_chain_type_args.reflected_field_wrong_type_arg_fn() -> string L2: load_var value load_const "x" - load_type baml.AnyClass + load_type reflect.AnyClass load_const "get_field" virtual_call nargs=2 ntypeargs=0 store_var _8 @@ -984,7 +984,7 @@ function optional_chain_type_args.reflected_field_wrong_type_arg_fn() -> string call reflect.class.Field.value jump L6 load_var e - is_type baml.errors.TypeMismatch + is_type reflect.errors.TypeMismatch pop_jump_if_false L3 jump L4 @@ -1020,7 +1020,7 @@ function optional_chain_type_args.reflected_missing_field_fn() -> int | null { init_instance user.optional_chain_type_args.Point .x, .label store_var _2 load_var _2 - narrow_bind baml.AnyClass, slot=1 + narrow_bind reflect.AnyClass, slot=1 pop_jump_if_false L0 jump L1 @@ -1033,7 +1033,7 @@ function optional_chain_type_args.reflected_missing_field_fn() -> int | null { store_var value load_var value load_const "absent" - load_type baml.AnyClass + load_type reflect.AnyClass load_const "get_field" virtual_call nargs=2 ntypeargs=0 store_var _4 @@ -1046,7 +1046,7 @@ function optional_chain_type_args.reflected_missing_field_fn() -> int | null { L2: load_var value load_const "absent" - load_type baml.AnyClass + load_type reflect.AnyClass load_const "get_field" virtual_call nargs=2 ntypeargs=0 store_var _6 diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_projection_patterns/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_projection_patterns/bytecode.snap index 496648105e4..538267dca34 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_projection_patterns/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_projection_patterns/bytecode.snap @@ -192,7 +192,7 @@ function projection_patterns.Labeled.is_label(self: projection_patterns.Labeled, function projection_patterns.Labeled.label_name(self: projection_patterns.Labeled) -> string { load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of/bytecode.snap index 18fd482b761..1d0363063c9 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of/bytecode.snap @@ -193,7 +193,7 @@ function reflect_type_of.$init_test_ns_reflect_type_of_reflect_type_of(registry: pop 1 load_var registry load_const "root.reflect_type_of" - load_const "of_value_of_a_type_value_is_precise_kind" + load_const "of_value_of_a_type_value_is_the_carrier" make_closure ., 0 load_const null call testing.TestCollector.register_test_at diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of_generic/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of_generic/bytecode.snap index aec14042a64..1d4578d02a3 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of_generic/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_reflect_type_of_generic/bytecode.snap @@ -141,7 +141,7 @@ function reflect_type_of_generic.$init_test_ns_reflect_type_of_generic_reflect_t function reflect_type_of_generic.Box.describe(self: reflect_type_of_generic.Box<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -155,19 +155,19 @@ function reflect_type_of_generic.HolderStr.delegate(self: reflect_type_of_generi function reflect_type_of_generic.Inner.name(self: reflect_type_of_generic.Inner<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } function reflect_type_of_generic.InnerShow.show(self: reflect_type_of_generic.InnerShow<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } function reflect_type_of_generic.Leaf.describe(self: reflect_type_of_generic.Leaf<#0>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -187,14 +187,14 @@ function reflect_type_of_generic.array_of() -> reflect.Type { function reflect_type_of_generic.array_of_int_fn() -> string { load_type int call user.reflect_type_of_generic.array_of - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } function reflect_type_of_generic.array_of_user_to_string_fn() -> string { load_type reflect_type_of_generic.User call user.reflect_type_of_generic.array_of - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -228,7 +228,7 @@ function reflect_type_of_generic.closure_captures_type_arg_user_fn() -> string { function reflect_type_of_generic.describe() -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -300,7 +300,7 @@ function reflect_type_of_generic.level1() -> reflect.Type { function reflect_type_of_generic.level1_str() -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_runtime_leaf_narrowing/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_runtime_leaf_narrowing/bytecode.snap index 6fdc959b311..adda65e38df 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_runtime_leaf_narrowing/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_runtime_leaf_narrowing/bytecode.snap @@ -99,7 +99,7 @@ function runtime_leaf_narrowing.classify_type_runtime_value(value: reflect.Type L1: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string L2: return @@ -119,7 +119,7 @@ function runtime_leaf_narrowing.if_let_binds_type_runtime_value() -> string { L1: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string L2: return diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_self_frame_slot/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_self_frame_slot/bytecode.snap index f3d2cfd556f..62e495c2c0b 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_self_frame_slot/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_self_frame_slot/bytecode.snap @@ -198,7 +198,7 @@ function self_frame_slot.Crate.Marked.mark(self: self_frame_slot.Crate<#0>) -> s function self_frame_slot.Crate.Marked.type_name(self: self_frame_slot.Crate<#0>) -> string { load_type self_frame_slot.Crate<#0> - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -226,7 +226,7 @@ function self_frame_slot.Croc.Marked.mark(self: self_frame_slot.Croc) -> string function self_frame_slot.Croc.Marked.type_name(self: self_frame_slot.Croc) -> string { load_type self_frame_slot.Croc - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -245,7 +245,7 @@ function self_frame_slot.IntShelf.Store.describe(self: self_frame_slot.IntS function self_frame_slot.Kinded.kind_name(self: self_frame_slot.Kinded) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -332,7 +332,7 @@ function self_frame_slot.Marked$for$T[].mark(self: #0[]) -> string { function self_frame_slot.Marked$for$T[].type_name(self: #0[]) -> string { load_type #0[] - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } @@ -360,19 +360,19 @@ function self_frame_slot.Marked$for$int.mark(self: int) -> string { function self_frame_slot.Marked$for$int.type_name(self: int) -> string { load_type int - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string return } function self_frame_slot.Store.describe(self: self_frame_slot.Store<#1>) -> string { load_type #0 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_type #1 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _7 load_type #2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _9 load_var _5 load_const "/" diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_type_value_narrowing/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_type_value_narrowing/bytecode.snap index a6d411f7467..482f79ecdf3 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_type_value_narrowing/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_type_value_narrowing/bytecode.snap @@ -324,7 +324,7 @@ function type_value_narrowing.optional_type_absent() -> string { call baml.String.from store_var _7 load_var t - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _11 load_type string load_var _11 @@ -381,7 +381,7 @@ function type_value_narrowing.optional_type_present() -> string { call baml.String.from store_var _7 load_var t - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _11 load_type string load_var _11 @@ -441,7 +441,7 @@ function type_value_narrowing.render_mixed_list() -> string { L3: load_var _12 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _14 load_type string load_var2 1 6 @@ -653,7 +653,7 @@ function type_value_narrowing.type_to_string_after_narrowing() -> string { L1: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string L2: return @@ -769,7 +769,7 @@ function type_value_narrowing.union_if_let_int() -> string { L1: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_type string load_var _5 @@ -797,7 +797,7 @@ function type_value_narrowing.union_if_let_type() -> string { L1: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_type string load_var _5 @@ -821,7 +821,7 @@ function type_value_narrowing.union_match_int_first(v: reflect.Type | int) -> st L0: load_var v - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _9 load_type string load_var _9 @@ -865,7 +865,7 @@ function type_value_narrowing.union_match_type_first(v: reflect.Type | int) -> s L1: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_type string load_var _5 @@ -917,7 +917,7 @@ function type_value_narrowing.union_three_way(v: reflect.Type | int | string) -> L3: load_var _2 - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _5 load_type string load_var _5 diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/ns_unknown_error/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/ns_unknown_error/bytecode.snap index b76ddab610b..fe2cb12484a 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/ns_unknown_error/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/ns_unknown_error/bytecode.snap @@ -95,7 +95,7 @@ function unknown_error.UeRunnerImpl.UeRunner.run(self: unknown_error.UeRunnerImp return } -function unknown_error.ue_call_reflect(target: baml.AnyFunction) -> bool { +function unknown_error.ue_call_reflect(target: reflect.AnyFunction) -> bool { load_type bool load_type unknown load_var target @@ -502,7 +502,7 @@ function unknown_error.ue_preserves_origin_trace() -> bool { return } -function unknown_error.ue_reflect_boundary(target: baml.AnyFunction) -> bool { +function unknown_error.ue_reflect_boundary(target: reflect.AnyFunction) -> bool { load_var target call user.unknown_error.ue_call_reflect jump L0 diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/bytecode.snap index bb85d184d1f..237ee4cb2a8 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/bytecode.snap @@ -918,7 +918,7 @@ function ai.Agent._media_value(self: ai.Agent<#0>, turn: ai.ModelTurn, provider: call baml.String.from store_var _83 load_var t - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _87 load_type string load_var _87 @@ -1022,7 +1022,7 @@ function ai.Agent._media_value(self: ai.Agent<#0>, turn: ai.ModelTurn, provider: L16: load_var t - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _42 load_type string load_var _42 @@ -1101,7 +1101,7 @@ function ai.Agent._media_value(self: ai.Agent<#0>, turn: ai.ModelTurn, provider: call baml.String.from store_var _111 load_var t - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _115 load_type string load_var _115 @@ -5447,7 +5447,7 @@ function ai.internal._retry_after_ms(headers: map | null) -> int return } -function ai.internal._schema_for_signature(handler: baml.AnyFunction) -> map { +function ai.internal._schema_for_signature(handler: reflect.AnyFunction) -> map { load_var handler call reflect.signature store_var sig @@ -5828,7 +5828,7 @@ function ai.internal.validate_output_type(return_type: reflect.Type) -> void { L4: load_var return_type - call reflect.Type.baml.ToString.to_string + call baml.root.ToString$for$reflect.Type.to_string store_var _11 load_const "empty enum `" load_var _11 @@ -7196,7 +7196,7 @@ function ai.tools.Tool.call(self: ai.tools.Tool, args: map) -> load_field .handler store_var _8 load_var _8 - narrow_bind baml.AnyFunction, slot=4 + narrow_bind reflect.AnyFunction, slot=4 pop_jump_if_false L1 jump L2 @@ -7390,7 +7390,7 @@ function ai.tools.raw_tool(name: string, description: string, input_schema: map< throw } -function ai.tools.tool(handler: baml.AnyFunction, name: string | null, description: string | null, on_error: ai.tools.ErrorMode | null) -> ai.tools.Tool { +function ai.tools.tool(handler: reflect.AnyFunction, name: string | null, description: string | null, on_error: ai.tools.ErrorMode | null) -> ai.tools.Tool { load_var name load_const cmp_op == diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/mir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/mir.snap index 87795023070..10e7539f31b 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/mir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/mir.snap @@ -2966,10 +2966,10 @@ fn ai.internal._from_shorthand(shorthand: string) -> ai.Client { } } -fn ai.internal._schema_for_signature(handler: baml.AnyFunction) -> map { +fn ai.internal._schema_for_signature(handler: reflect.AnyFunction) -> map { // Locals: let _0: map // _0 // return - let _1: baml.AnyFunction // handler // param + let _1: reflect.AnyFunction // handler // param let _2: reflect.Signature // sig let _3: map // props let _4: string[] // required @@ -5238,7 +5238,7 @@ fn ai.internal.validate_output_type(return_type: reflect.Type) -> void { } bb9: { - _11 = call const fn reflect.Type.baml.ToString.to_string(copy _1) -> [bb10]; + _11 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _1) -> [bb10]; } bb10: { @@ -7725,12 +7725,12 @@ fn ai.tools.Tool.call(self: ai.tools.Tool, args: map) -> string let _4: null | ((map) -> string throws unknown) let _5: (map) -> string throws unknown // rh let _6: (map) -> string throws unknown - let _7: null | baml.AnyFunction - let _8: null | baml.AnyFunction - let _9: baml.AnyFunction // h + let _7: null | reflect.AnyFunction + let _8: null | reflect.AnyFunction + let _9: reflect.AnyFunction // h let _10: unknown // value let _11: unknown // e - let _12: baml.AnyFunction + let _12: reflect.AnyFunction let _13: reflect.Type let _14: reflect.Type let _15: unknown @@ -7765,7 +7765,7 @@ fn ai.tools.Tool.call(self: ai.tools.Tool, args: map) -> string bb1: { _7 = copy _1.3; _8 = copy _7; - _8 = narrow_bind copy _8 as Interface(QualifiedTypeName { pkg: Dep("baml"), namespace: [], name: "AnyFunction" }, [], [("Returns", BuiltinUnknown { attr: TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset } }), ("Throws", BuiltinUnknown { attr: TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset } })], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb2]; + _8 = narrow_bind copy _8 as Interface(QualifiedTypeName { pkg: Dep("reflect"), namespace: [], name: "AnyFunction" }, [], [("Returns", BuiltinUnknown { attr: TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset } }), ("Throws", BuiltinUnknown { attr: TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset } })], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb2]; } bb2: { @@ -7844,10 +7844,10 @@ fn ai.tools.Tool.call(self: ai.tools.Tool, args: map) -> string } } -fn ai.tools.tool(handler: baml.AnyFunction, name: string | null, description: string | null, on_error: null | ai.tools.ErrorMode) -> ai.tools.Tool { +fn ai.tools.tool(handler: reflect.AnyFunction, name: string | null, description: string | null, on_error: null | ai.tools.ErrorMode) -> ai.tools.Tool { // Locals: let _0: ai.tools.Tool // _0 // return - let _1: baml.AnyFunction // handler // param + let _1: reflect.AnyFunction // handler // param let _2: string | null // name // param let _3: string | null // description // param let _4: null | ai.tools.ErrorMode // on_error // param @@ -10169,7 +10169,7 @@ fn ai.Agent._media_value(self: ai.Agent, turn: ai.ModelTurn, provider: string) - bb24: { _82 = const "Expected zero or one " + copy _83; _81 = copy _82 + const " output for "; - _87 = call const fn reflect.Type.baml.ToString.to_string(copy _4) -> [bb25]; + _87 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _4) -> [bb25]; } bb25: { @@ -10279,7 +10279,7 @@ fn ai.Agent._media_value(self: ai.Agent, turn: ai.ModelTurn, provider: string) - } bb44: { - _42 = call const fn reflect.Type.baml.ToString.to_string(copy _4) -> [bb45]; + _42 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _4) -> [bb45]; } bb45: { @@ -10371,7 +10371,7 @@ fn ai.Agent._media_value(self: ai.Agent, turn: ai.ModelTurn, provider: string) - bb61: { _110 = const "the " + copy _111; _109 = copy _110 + const " output did not fit "; - _115 = call const fn reflect.Type.baml.ToString.to_string(copy _4) -> [bb62]; + _115 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _4) -> [bb62]; } bb62: { diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/ppir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/ppir.snap index 5e61765846c..d647f4f55a8 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/ppir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/ai/ppir.snap @@ -474,7 +474,7 @@ class ai.internal.SpecCtx { class ai.internal.SpecCtx$stream { output_format: string | null } -function ai.internal._schema_for_signature(handler: baml.AnyFunction) -> map [expr] { +function ai.internal._schema_for_signature(handler: reflect.AnyFunction) -> map [expr] { { let sig = reflect.signature(handler); let props: map = map { }; let required: string[] = []; for a in sig.args { let _ = props.set(a.name, baml.json.schema(a.type)); required.push(a.name) } } map { "type": "object", "properties": props, "required": required, "additionalProperties": false } } function ai.internal.assemble_llm_prompt(parts: string[], values: unknown[]) -> root.Prompt [expr] { @@ -730,7 +730,7 @@ class ai.tools.Tool { name: string description: string input_schema: map - handler: baml.AnyFunction? + handler: reflect.AnyFunction? raw_handler: (map) -> string throws unknown? on_error: ai.tools.ErrorMode? } @@ -738,7 +738,7 @@ class ai.tools.Tool$stream { name: string | null description: string | null input_schema: map - handler: baml.AnyFunction | null + handler: reflect.AnyFunction | null raw_handler: unknown | null on_error: ai.tools.ErrorMode | null } @@ -750,7 +750,7 @@ class ai.tools.Toolbox$stream { } enum ai.tools.ErrorMode {Report, Raise} function ai.tools.call(self: ?, args: map) -> string [expr] { - { if let rh: (map) -> string throws unknown = self.raw_handler { return rh(args) } } if let h: baml.AnyFunction = self.handler { let value = reflect.call_any(h, args) catch (e) { bad: reflect.InvalidArgumentError => { throw baml.errors.InvalidArgument { message: `...` } } } } baml.json.stringify(baml.json.to_json(value)) else { throw baml.errors.InvalidArgument { message: `...` } } + { if let rh: (map) -> string throws unknown = self.raw_handler { return rh(args) } } if let h: reflect.AnyFunction = self.handler { let value = reflect.call_any(h, args) catch (e) { bad: reflect.InvalidArgumentError => { throw baml.errors.InvalidArgument { message: `...` } } } } baml.json.stringify(baml.json.to_json(value)) else { throw baml.errors.InvalidArgument { message: `...` } } } function ai.tools.get(self: ?, name: string) -> ai.tools.Tool? [expr] { { } self.entries.find((t) -> { { } t.name Eq name }) @@ -767,7 +767,7 @@ function ai.tools.new(tools: ai.tools.Tool[]) -> ai.tools.Toolbox [expr] { function ai.tools.raw_tool(name: string, description: string, input_schema: map, handler: (map) -> string throws unknown, on_error: ai.tools.ErrorMode? = null) -> ai.tools.Tool [expr] { { if (name Eq "__baml_return_output") { throw baml.errors.InvalidArgument { message: "the tool name __b..." } } } ai.tools.Tool { name: name, description: description, input_schema: input_schema, handler: null, raw_handler: handler, on_error: on_error } } -function ai.tools.tool(handler: baml.AnyFunction, name: string? = null, description: string? = null, on_error: ai.tools.ErrorMode? = null) -> ai.tools.Tool [expr] { +function ai.tools.tool(handler: reflect.AnyFunction, name: string? = null, description: string? = null, on_error: ai.tools.ErrorMode? = null) -> ai.tools.Tool [expr] { { let sig = reflect.signature(handler); let resolved_name = name NullCoalesce sig.name } if let n: string = resolved_name { if (n Eq "__baml_return_output") { throw baml.errors.InvalidArgument { message: "the tool name __b..." } } } ai.tools.Tool { name: n, description: description NullCoalesce sig.docstring NullCoalesce "", input_schema: root.internal._schema_for_signature(handler), handler: handler, raw_handler: null, on_error: on_error } else { throw baml.errors.InvalidArgument { message: "anonymous tool ne..." } } } diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/bytecode.snap index bfdff5fc845..f881c45d15e 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/bytecode.snap @@ -1,254 +1,6 @@ --- source: crates/baml_tests/src/corpus.rs --- -function baml.AnyClass.attributes(self: baml.AnyClass) -> reflect.Meta { - load_var self - call reflect.Type.of_value - call reflect.Type.as_class - store_var _4 - load_var _4 - narrow_bind reflect.class.Type, slot=2 - pop_jump_if_false L0 - jump L1 - - L0: - load_const null - load_const null - load_const null - load_type string - load_type string - alloc_map 0 - init_instance reflect.Meta .alias, .description, .docstring, .other - jump L2 - - L1: - load_var _4 - call reflect.class.Type.meta - - L2: - return -} - -function baml.AnyClass.get(self: baml.AnyClass, name: string) -> #1 | null { - load_var2 1 2 - load_type baml.AnyClass - load_const "has_field" - virtual_call nargs=2 ntypeargs=0 - store_var _4 - load_var _4 - unary_op ! - pop_jump_if_false L0 - jump L3 - - L0: - load_var2 1 2 - load_type baml.AnyClass - load_const "get_field" - virtual_call nargs=2 ntypeargs=0 - store_var _5 - load_var _5 - store_var _6 - load_var _6 - narrow_bind reflect.class.Field, slot=5 - pop_jump_if_false L1 - jump L2 - - L1: - load_const null - jump L4 - - L2: - load_type #1 - load_var _6 - call reflect.class.Field.value - jump L4 - - L3: - load_const null - - L4: - return -} - -function baml.AnyClass.get_field(self: baml.AnyClass, name: string) -> reflect.class.Field | null { - load_var self - call reflect.Type.of_value - call reflect.Type.as_class - store_var _5 - load_var _5 - narrow_bind reflect.class.Type, slot=3 - pop_jump_if_false L0 - jump L1 - - L0: - load_const null - jump L5 - - L1: - load_var _5 - call reflect.class.Type.fields - load_type baml.iter.Iterable - load_const "iter" - virtual_call nargs=1 ntypeargs=0 - store_var _8 - - L2: - load_var _8 - load_type baml.iter.Iterator - load_const "next" - virtual_call nargs=1 ntypeargs=0 - store_var _9 - load_var _9 - is_type baml.iter.Done - pop_jump_if_false L3 - jump L4 - - L3: - load_var _9 - store_var_load_var field - load_field .name - load_var name - cmp_op == - pop_jump_if_false L2 - load_var field - load_field .name - load_var field - load_field .type - load_var field - load_field .meta - load_var self - init_instance reflect.class.Field .name, .type, .meta, ._owner - jump L5 - - L4: - load_const null - - L5: - return -} - -function baml.AnyClass.has_field(self: baml.AnyClass, name: string) -> bool { - load_var self - call reflect.Type.of_value - call reflect.Type.as_class - store_var _5 - load_var _5 - narrow_bind reflect.class.Type, slot=3 - pop_jump_if_false L0 - jump L1 - - L0: - load_const false - jump L5 - - L1: - load_var _5 - call reflect.class.Type.fields - load_type baml.iter.Iterable - load_const "iter" - virtual_call nargs=1 ntypeargs=0 - store_var _8 - - L2: - load_var _8 - load_type baml.iter.Iterator - load_const "next" - virtual_call nargs=1 ntypeargs=0 - store_var _9 - load_var _9 - is_type baml.iter.Done - pop_jump_if_false L3 - jump L4 - - L3: - load_var _9 - load_field .name - load_var name - cmp_op == - pop_jump_if_false L2 - load_const true - jump L5 - - L4: - load_const false - - L5: - return -} - -function baml.AnyClass.list_fields(self: baml.AnyClass) -> reflect.class.Field[] { - load_var self - call reflect.Type.of_value - call reflect.Type.as_class - store_var _4 - load_var _4 - narrow_bind reflect.class.Type, slot=2 - pop_jump_if_false L0 - jump L1 - - L0: - load_type reflect.class.Field - alloc_array 0 - jump L5 - - L1: - load_type reflect.class.Field - alloc_array 0 - store_var fields - load_var _4 - call reflect.class.Type.fields - load_type baml.iter.Iterable - load_const "iter" - virtual_call nargs=1 ntypeargs=0 - store_var _8 - - L2: - load_var _8 - load_type baml.iter.Iterator - load_const "next" - virtual_call nargs=1 ntypeargs=0 - store_var _9 - load_var _9 - is_type baml.iter.Done - pop_jump_if_false L3 - jump L4 - - L3: - load_var _9 - store_var field - load_type reflect.class.Field - load_var2 3 6 - load_field .name - load_var field - load_field .type - load_var field - load_field .meta - load_var self - init_instance reflect.class.Field .name, .type, .meta, ._owner - call baml.Array.push - pop 1 - jump L2 - - L4: - load_var fields - - L5: - return -} - -function baml.AnyClass.name(self: baml.AnyClass) -> string { - load_var self - call reflect.Type.of_value - call reflect.Type.baml.ToString.to_string - return -} - -function baml.AnyClass.type(self: baml.AnyClass) -> reflect.Type { - load_var self - call reflect.Type.of_value - return -} - function baml.Array.at(self: #0[], index: int) -> #0 | null { } @@ -6014,6 +5766,12 @@ function baml.random.Xoshiro256PlusPlus.new(seed: uint8array) -> baml.random.Xos return } +function baml.root.ToString$for$reflect.Type.to_string(self: reflect.Type) -> string { + load_var self + call reflect.Type._to_string_impl + return +} + function baml.root.ops.Add$for$string.add(self: string, rhs: string) -> string { load_type string load_var self diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/mir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/mir.snap index b3859716a1a..0dcbb3f0533 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/mir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/mir.snap @@ -1136,6 +1136,20 @@ fn baml.ToString.to_string(self: baml.ToString) -> string { } } +fn baml.root.ToString$for$reflect.Type.to_string(self: reflect.Type) -> string { + // Locals: + let _0: string // _0 // return + let _1: reflect.Type // self // param + + bb0: { + _0 = call const fn reflect.Type._to_string_impl(copy _1) -> [bb1]; + } + + bb1: { + return; + } +} + fn baml._to_string_default = builtin(vm) fn baml._to_string_shim = builtin(vm) @@ -1176,372 +1190,6 @@ fn baml._from_json_shim = builtin(vm) fn baml.deep_copy = builtin(vm) -fn baml.AnyClass.get(self: baml.AnyClass, name: string) -> null | T { - // Locals: - let _0: null | T // _0 // return - let _1: baml.AnyClass // self // param - let _2: string // name // param - let _3: bool - let _4: bool - let _5: null | reflect.class.Field - let _6: null | reflect.class.Field - let _7: reflect.class.Field // field - let _8: reflect.Type - - bb0: { - _4 = virtual_call has_field as baml.AnyClass(copy _1, copy _2) -> [bb1]; - } - - bb1: { - _3 = !copy _4; - branch copy _3 -> [bb6, bb2]; - } - - bb2: { - _5 = virtual_call get_field as baml.AnyClass(copy _1, copy _2) -> [bb3]; - } - - bb3: { - _6 = copy _5; - _6 = narrow_bind copy _6 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Field" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb5, bb4]; - } - - bb4: { - _0 = const null; - goto -> bb7; - } - - bb5: { - _7 = copy _6; - _8 = load_type(#1); - _0 = call const fn reflect.class.Field.value(copy _7) -> [bb7]; - } - - bb6: { - _0 = const null; - goto -> bb7; - } - - bb7: { - return; - } -} - -fn baml.AnyClass.get_field(self: baml.AnyClass, name: string) -> null | reflect.class.Field { - // Locals: - let _0: null | reflect.class.Field // _0 // return - let _1: baml.AnyClass // self // param - let _2: string // name // param - let _3: null | reflect.class.Type - let _4: reflect.Type - let _5: null | reflect.class.Type - let _6: reflect.class.Type // class_type - let _7: reflect.class.Field[] - let _8: baml.iter.Iterator - let _9: unknown - let _10: bool - let _11: reflect.class.Field - let _12: reflect.class.Field // field - let _13: bool - let _14: string - let _15: string - let _16: null | reflect.Type - let _17: reflect.Meta - - bb0: { - _4 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; - } - - bb1: { - _3 = call const fn reflect.Type.as_class(copy _4) -> [bb2]; - } - - bb2: { - _5 = copy _3; - _5 = narrow_bind copy _5 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; - } - - bb3: { - _0 = const null; - goto -> bb11; - } - - bb4: { - _6 = copy _5; - _7 = call const fn reflect.class.Type.fields(copy _6) -> [bb5]; - } - - bb5: { - _8 = virtual_call iter as baml.iter.Iterable(copy _7) -> [bb6]; - } - - bb6: { - _9 = virtual_call next as baml.iter.Iterator(copy _8) -> [bb7]; - } - - bb7: { - _10 = is_type(copy _9, baml.iter.Done); - branch copy _10 -> [bb10, bb8]; - } - - bb8: { - _11 = copy _9; - fresh_cell(_12); - _12 = copy _11; - _14 = copy _12.0; - _13 = copy _14 == copy _2; - branch copy _13 -> [bb9, bb6]; - } - - bb9: { - _15 = copy _12.0; - _16 = copy _12.1; - _17 = copy _12.2; - _0 = reflect.class.Field { copy _15, copy _16, copy _17, copy _1 }; - goto -> bb11; - } - - bb10: { - _0 = const null; - goto -> bb11; - } - - bb11: { - return; - } -} - -fn baml.AnyClass.has_field(self: baml.AnyClass, name: string) -> bool { - // Locals: - let _0: bool // _0 // return - let _1: baml.AnyClass // self // param - let _2: string // name // param - let _3: null | reflect.class.Type - let _4: reflect.Type - let _5: null | reflect.class.Type - let _6: reflect.class.Type // class_type - let _7: reflect.class.Field[] - let _8: baml.iter.Iterator - let _9: unknown - let _10: bool - let _11: reflect.class.Field - let _12: reflect.class.Field // field - let _13: bool - let _14: string - - bb0: { - _4 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; - } - - bb1: { - _3 = call const fn reflect.Type.as_class(copy _4) -> [bb2]; - } - - bb2: { - _5 = copy _3; - _5 = narrow_bind copy _5 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; - } - - bb3: { - _0 = const false; - goto -> bb11; - } - - bb4: { - _6 = copy _5; - _7 = call const fn reflect.class.Type.fields(copy _6) -> [bb5]; - } - - bb5: { - _8 = virtual_call iter as baml.iter.Iterable(copy _7) -> [bb6]; - } - - bb6: { - _9 = virtual_call next as baml.iter.Iterator(copy _8) -> [bb7]; - } - - bb7: { - _10 = is_type(copy _9, baml.iter.Done); - branch copy _10 -> [bb10, bb8]; - } - - bb8: { - _11 = copy _9; - fresh_cell(_12); - _12 = copy _11; - _14 = copy _12.0; - _13 = copy _14 == copy _2; - branch copy _13 -> [bb9, bb6]; - } - - bb9: { - _0 = const true; - goto -> bb11; - } - - bb10: { - _0 = const false; - goto -> bb11; - } - - bb11: { - return; - } -} - -fn baml.AnyClass.list_fields(self: baml.AnyClass) -> reflect.class.Field[] { - // Locals: - let _0: reflect.class.Field[] // _0 // return - let _1: baml.AnyClass // self // param - let _2: null | reflect.class.Type - let _3: reflect.Type - let _4: null | reflect.class.Type - let _5: reflect.class.Type // class_type - let _6: reflect.class.Field[] // fields - let _7: reflect.class.Field[] - let _8: baml.iter.Iterator - let _9: unknown - let _10: bool - let _11: reflect.class.Field - let _12: reflect.class.Field // field - let _13: void - let _14: reflect.class.Field - let _15: string - let _16: null | reflect.Type - let _17: reflect.Meta - let _18: reflect.Type - - bb0: { - _3 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; - } - - bb1: { - _2 = call const fn reflect.Type.as_class(copy _3) -> [bb2]; - } - - bb2: { - _4 = copy _2; - _4 = narrow_bind copy _4 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; - } - - bb3: { - _0 = []: reflect.class.Field[]; - goto -> bb10; - } - - bb4: { - _5 = copy _4; - _6 = []: reflect.class.Field[]; - _7 = call const fn reflect.class.Type.fields(copy _5) -> [bb5]; - } - - bb5: { - _8 = virtual_call iter as baml.iter.Iterable(copy _7) -> [bb6]; - } - - bb6: { - _9 = virtual_call next as baml.iter.Iterator(copy _8) -> [bb7]; - } - - bb7: { - _10 = is_type(copy _9, baml.iter.Done); - branch copy _10 -> [bb9, bb8]; - } - - bb8: { - _11 = copy _9; - fresh_cell(_12); - _12 = copy _11; - _15 = copy _12.0; - _16 = copy _12.1; - _17 = copy _12.2; - _14 = reflect.class.Field { copy _15, copy _16, copy _17, copy _1 }; - _18 = load_type(reflect.class.Field); - _13 = call const fn baml.Array.push(copy _6, copy _14) -> [bb6]; - } - - bb9: { - _0 = copy _6; - goto -> bb10; - } - - bb10: { - return; - } -} - -fn baml.AnyClass.name(self: baml.AnyClass) -> string { - // Locals: - let _0: string // _0 // return - let _1: baml.AnyClass // self // param - let _2: reflect.Type - - bb0: { - _2 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; - } - - bb1: { - _0 = call const fn reflect.Type.baml.ToString.to_string(copy _2) -> [bb2]; - } - - bb2: { - return; - } -} - -fn baml.AnyClass.type(self: baml.AnyClass) -> reflect.Type { - // Locals: - let _0: reflect.Type // _0 // return - let _1: baml.AnyClass // self // param - - bb0: { - _0 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; - } - - bb1: { - return; - } -} - -fn baml.AnyClass.attributes(self: baml.AnyClass) -> reflect.Meta { - // Locals: - let _0: reflect.Meta // _0 // return - let _1: baml.AnyClass // self // param - let _2: null | reflect.class.Type - let _3: reflect.Type - let _4: null | reflect.class.Type - let _5: map - let _6: reflect.class.Type // class_type - - bb0: { - _3 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; - } - - bb1: { - _2 = call const fn reflect.Type.as_class(copy _3) -> [bb2]; - } - - bb2: { - _4 = copy _2; - _4 = narrow_bind copy _4 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; - } - - bb3: { - _5 = { }: map; - _0 = reflect.Meta { const null, const null, const null, copy _5 }; - goto -> bb5; - } - - bb4: { - _6 = copy _4; - _0 = call const fn reflect.class.Type.meta(copy _6) -> [bb5]; - } - - bb5: { - return; - } -} - fn baml.Float.is_nan = builtin(vm) fn baml.Float.is_infinite = builtin(vm) diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/ppir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/ppir.snap index 8f69ba87b54..9a9950f9b5a 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/ppir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/baml/ppir.snap @@ -153,6 +153,9 @@ function baml.to_json(self: ?) -> baml.json.json [expr] { function baml.to_string(self: ?) -> string [expr] { { } root._to_string_default(self) } +function baml.to_string(self: ?) -> string [expr] { + { } self._to_string_impl() +} --- /baml/core.baml --- class baml.TaggedString { @@ -163,28 +166,7 @@ class baml.TaggedString$stream { parts: string[] values: unknown[] } -function baml.attributes(self: ?) -> reflect.Meta [expr] { - { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() } class_type.meta() -} function baml.deep_copy(value: T) -> T [builtin] -function baml.get(self: ?, name: string) -> T? [expr] { - { if (Not self.has_field(name)) { return null }; let field: reflect.class.Field = self.get_field(name) } field.value() -} -function baml.get_field(self: ?, name: string) -> reflect.class.Field? [expr] { - { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class(); for field in class_type.fields() { } if (field.name Eq name) { return reflect.class.Field { name: field.name, type: field.type, meta: field.meta, _owner: self } } } null -} -function baml.has_field(self: ?, name: string) -> bool [expr] { - { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class(); for field in class_type.fields() { } if (field.name Eq name) { return true } } false -} -function baml.list_fields(self: ?) -> reflect.class.Field[] [expr] { - { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class(); let fields: reflect.class.Field[] = []; for field in class_type.fields() { } fields.push(reflect.class.Field { name: field.name, type: field.type, meta: field.meta, _owner: self }) } fields -} -function baml.name(self: ?) -> string [expr] { - { } reflect.Type.of_value(self).to_string() -} -function baml.type(self: ?) -> reflect.Type [expr] { - { } reflect.Type.of_value(self) -} --- /baml/float.baml --- class baml.Float { diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/bytecode.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/bytecode.snap index 0ea50f43e7d..144b929d0a0 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/bytecode.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/bytecode.snap @@ -1,6 +1,254 @@ --- source: crates/baml_tests/src/corpus.rs --- +function reflect.AnyClass.attributes(self: reflect.AnyClass) -> reflect.Meta { + load_var self + call reflect.Type.of_value + call reflect.Type.as_class + store_var _4 + load_var _4 + narrow_bind reflect.class.Type, slot=2 + pop_jump_if_false L0 + jump L1 + + L0: + load_const null + load_const null + load_const null + load_type string + load_type string + alloc_map 0 + init_instance reflect.Meta .alias, .description, .docstring, .other + jump L2 + + L1: + load_var _4 + call reflect.class.Type.meta + + L2: + return +} + +function reflect.AnyClass.get(self: reflect.AnyClass, name: string) -> #1 | null { + load_var2 1 2 + load_type reflect.AnyClass + load_const "has_field" + virtual_call nargs=2 ntypeargs=0 + store_var _4 + load_var _4 + unary_op ! + pop_jump_if_false L0 + jump L3 + + L0: + load_var2 1 2 + load_type reflect.AnyClass + load_const "get_field" + virtual_call nargs=2 ntypeargs=0 + store_var _5 + load_var _5 + store_var _6 + load_var _6 + narrow_bind reflect.class.Field, slot=5 + pop_jump_if_false L1 + jump L2 + + L1: + load_const null + jump L4 + + L2: + load_type #1 + load_var _6 + call reflect.class.Field.value + jump L4 + + L3: + load_const null + + L4: + return +} + +function reflect.AnyClass.get_field(self: reflect.AnyClass, name: string) -> reflect.class.Field | null { + load_var self + call reflect.Type.of_value + call reflect.Type.as_class + store_var _5 + load_var _5 + narrow_bind reflect.class.Type, slot=3 + pop_jump_if_false L0 + jump L1 + + L0: + load_const null + jump L5 + + L1: + load_var _5 + call reflect.class.Type.fields + load_type baml.iter.Iterable + load_const "iter" + virtual_call nargs=1 ntypeargs=0 + store_var _8 + + L2: + load_var _8 + load_type baml.iter.Iterator + load_const "next" + virtual_call nargs=1 ntypeargs=0 + store_var _9 + load_var _9 + is_type baml.iter.Done + pop_jump_if_false L3 + jump L4 + + L3: + load_var _9 + store_var_load_var field + load_field .name + load_var name + cmp_op == + pop_jump_if_false L2 + load_var field + load_field .name + load_var field + load_field .type + load_var field + load_field .meta + load_var self + init_instance reflect.class.Field .name, .type, .meta, ._owner + jump L5 + + L4: + load_const null + + L5: + return +} + +function reflect.AnyClass.has_field(self: reflect.AnyClass, name: string) -> bool { + load_var self + call reflect.Type.of_value + call reflect.Type.as_class + store_var _5 + load_var _5 + narrow_bind reflect.class.Type, slot=3 + pop_jump_if_false L0 + jump L1 + + L0: + load_const false + jump L5 + + L1: + load_var _5 + call reflect.class.Type.fields + load_type baml.iter.Iterable + load_const "iter" + virtual_call nargs=1 ntypeargs=0 + store_var _8 + + L2: + load_var _8 + load_type baml.iter.Iterator + load_const "next" + virtual_call nargs=1 ntypeargs=0 + store_var _9 + load_var _9 + is_type baml.iter.Done + pop_jump_if_false L3 + jump L4 + + L3: + load_var _9 + load_field .name + load_var name + cmp_op == + pop_jump_if_false L2 + load_const true + jump L5 + + L4: + load_const false + + L5: + return +} + +function reflect.AnyClass.list_fields(self: reflect.AnyClass) -> reflect.class.Field[] { + load_var self + call reflect.Type.of_value + call reflect.Type.as_class + store_var _4 + load_var _4 + narrow_bind reflect.class.Type, slot=2 + pop_jump_if_false L0 + jump L1 + + L0: + load_type reflect.class.Field + alloc_array 0 + jump L5 + + L1: + load_type reflect.class.Field + alloc_array 0 + store_var fields + load_var _4 + call reflect.class.Type.fields + load_type baml.iter.Iterable + load_const "iter" + virtual_call nargs=1 ntypeargs=0 + store_var _8 + + L2: + load_var _8 + load_type baml.iter.Iterator + load_const "next" + virtual_call nargs=1 ntypeargs=0 + store_var _9 + load_var _9 + is_type baml.iter.Done + pop_jump_if_false L3 + jump L4 + + L3: + load_var _9 + store_var field + load_type reflect.class.Field + load_var2 3 6 + load_field .name + load_var field + load_field .type + load_var field + load_field .meta + load_var self + init_instance reflect.class.Field .name, .type, .meta, ._owner + call baml.Array.push + pop 1 + jump L2 + + L4: + load_var fields + + L5: + return +} + +function reflect.AnyClass.name(self: reflect.AnyClass) -> string { + load_var self + call reflect.Type.of_value + call baml.root.ToString$for$reflect.Type.to_string + return +} + +function reflect.AnyClass.type(self: reflect.AnyClass) -> reflect.Type { + load_var self + call reflect.Type.of_value + return +} + function reflect.Package._compile(files: map, packages: map) -> reflect.Package { } @@ -141,12 +389,6 @@ function reflect.Type.as_primitive(self: reflect.Type) -> reflect.primitive.Type function reflect.Type.as_union(self: reflect.Type) -> reflect.union.Type | null { } -function reflect.Type.baml.ToString.to_string(self: reflect.Type) -> string { - load_var self - call reflect.Type._to_string_impl - return -} - function reflect.Type.implemented_by(self: reflect.Type, other: reflect.Type) -> bool { } @@ -174,7 +416,7 @@ function reflect.array.Type.element_type(self: reflect.array.Type) -> reflect.Ty function reflect.array.Type.reflect.TypeView.as_type(self: reflect.array.Type) -> reflect.Type { } -function reflect.call_any(f: baml.AnyFunction, args: map) -> #0 { +function reflect.call_any(f: reflect.AnyFunction, args: map) -> #0 { } function reflect.class.Builder._build(self: reflect.class.Builder, implementations: reflect.interface.Implementation[]) -> reflect.class.Type { @@ -212,7 +454,7 @@ function reflect.class.Field.value(self: reflect.class.Field) -> #0 | null { load_field ._owner store_var _3 load_var _3 - narrow_bind baml.AnyClass, slot=2 + narrow_bind reflect.AnyClass, slot=2 pop_jump_if_false L0 jump L1 @@ -238,7 +480,7 @@ function reflect.class.Field.value(self: reflect.class.Field) -> #0 | null { L3: load_var e load_field .0 - init_instance baml.errors.TypeMismatch .message + init_instance reflect.errors.TypeMismatch .message throw L4: @@ -354,7 +596,7 @@ function reflect.map.new(key: reflect.Type, value: reflect.Type) -> reflect.map. function reflect.primitive.Type.reflect.TypeView.as_type(self: reflect.primitive.Type) -> reflect.Type { } -function reflect.signature(f: baml.AnyFunction) -> reflect.Signature { +function reflect.signature(f: reflect.AnyFunction) -> reflect.Signature { } function reflect.union.Type.member_types(self: reflect.union.Type) -> reflect.Type[] { diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/mir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/mir.snap index 1638a69eef3..d1a53d53f8c 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/mir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/mir.snap @@ -27,21 +27,21 @@ fn reflect.class.Field.value(self: reflect.class.Field) -> null | T { let _1: reflect.class.Field // self // param let _2: unknown let _3: unknown - let _4: baml.AnyClass // owner + let _4: reflect.AnyClass // owner let _5: unknown // e - let _6: baml.AnyClass + let _6: reflect.AnyClass let _7: string let _8: reflect.Type let _9: bool let _10: string let _11: string // message - let _12: baml.errors.TypeMismatch + let _12: reflect.errors.TypeMismatch let _13: string bb0: { _2 = copy _1.3; _3 = copy _2; - _3 = narrow_bind copy _3 as Interface(QualifiedTypeName { pkg: Dep("baml"), namespace: [], name: "AnyClass" }, [], [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb2, bb1]; + _3 = narrow_bind copy _3 as Interface(QualifiedTypeName { pkg: Dep("reflect"), namespace: [], name: "AnyClass" }, [], [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb2, bb1]; } bb1: { @@ -74,7 +74,7 @@ fn reflect.class.Field.value(self: reflect.class.Field) -> null | T { _10 = copy _5.0; _11 = copy _10; _13 = copy _11; - _12 = baml.errors.TypeMismatch { copy _13 }; + _12 = reflect.errors.TypeMismatch { copy _13 }; throw copy _12; } } @@ -216,6 +216,372 @@ fn reflect.TypeView.as_type(_1: void) -> void { } } +fn reflect.AnyClass.get(self: reflect.AnyClass, name: string) -> null | T { + // Locals: + let _0: null | T // _0 // return + let _1: reflect.AnyClass // self // param + let _2: string // name // param + let _3: bool + let _4: bool + let _5: null | reflect.class.Field + let _6: null | reflect.class.Field + let _7: reflect.class.Field // field + let _8: reflect.Type + + bb0: { + _4 = virtual_call has_field as reflect.AnyClass(copy _1, copy _2) -> [bb1]; + } + + bb1: { + _3 = !copy _4; + branch copy _3 -> [bb6, bb2]; + } + + bb2: { + _5 = virtual_call get_field as reflect.AnyClass(copy _1, copy _2) -> [bb3]; + } + + bb3: { + _6 = copy _5; + _6 = narrow_bind copy _6 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Field" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb5, bb4]; + } + + bb4: { + _0 = const null; + goto -> bb7; + } + + bb5: { + _7 = copy _6; + _8 = load_type(#1); + _0 = call const fn reflect.class.Field.value(copy _7) -> [bb7]; + } + + bb6: { + _0 = const null; + goto -> bb7; + } + + bb7: { + return; + } +} + +fn reflect.AnyClass.get_field(self: reflect.AnyClass, name: string) -> null | reflect.class.Field { + // Locals: + let _0: null | reflect.class.Field // _0 // return + let _1: reflect.AnyClass // self // param + let _2: string // name // param + let _3: null | reflect.class.Type + let _4: reflect.Type + let _5: null | reflect.class.Type + let _6: reflect.class.Type // class_type + let _7: reflect.class.Field[] + let _8: baml.iter.Iterator + let _9: unknown + let _10: bool + let _11: reflect.class.Field + let _12: reflect.class.Field // field + let _13: bool + let _14: string + let _15: string + let _16: null | reflect.Type + let _17: reflect.Meta + + bb0: { + _4 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; + } + + bb1: { + _3 = call const fn reflect.Type.as_class(copy _4) -> [bb2]; + } + + bb2: { + _5 = copy _3; + _5 = narrow_bind copy _5 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; + } + + bb3: { + _0 = const null; + goto -> bb11; + } + + bb4: { + _6 = copy _5; + _7 = call const fn reflect.class.Type.fields(copy _6) -> [bb5]; + } + + bb5: { + _8 = virtual_call iter as baml.iter.Iterable(copy _7) -> [bb6]; + } + + bb6: { + _9 = virtual_call next as baml.iter.Iterator(copy _8) -> [bb7]; + } + + bb7: { + _10 = is_type(copy _9, baml.iter.Done); + branch copy _10 -> [bb10, bb8]; + } + + bb8: { + _11 = copy _9; + fresh_cell(_12); + _12 = copy _11; + _14 = copy _12.0; + _13 = copy _14 == copy _2; + branch copy _13 -> [bb9, bb6]; + } + + bb9: { + _15 = copy _12.0; + _16 = copy _12.1; + _17 = copy _12.2; + _0 = reflect.class.Field { copy _15, copy _16, copy _17, copy _1 }; + goto -> bb11; + } + + bb10: { + _0 = const null; + goto -> bb11; + } + + bb11: { + return; + } +} + +fn reflect.AnyClass.has_field(self: reflect.AnyClass, name: string) -> bool { + // Locals: + let _0: bool // _0 // return + let _1: reflect.AnyClass // self // param + let _2: string // name // param + let _3: null | reflect.class.Type + let _4: reflect.Type + let _5: null | reflect.class.Type + let _6: reflect.class.Type // class_type + let _7: reflect.class.Field[] + let _8: baml.iter.Iterator + let _9: unknown + let _10: bool + let _11: reflect.class.Field + let _12: reflect.class.Field // field + let _13: bool + let _14: string + + bb0: { + _4 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; + } + + bb1: { + _3 = call const fn reflect.Type.as_class(copy _4) -> [bb2]; + } + + bb2: { + _5 = copy _3; + _5 = narrow_bind copy _5 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; + } + + bb3: { + _0 = const false; + goto -> bb11; + } + + bb4: { + _6 = copy _5; + _7 = call const fn reflect.class.Type.fields(copy _6) -> [bb5]; + } + + bb5: { + _8 = virtual_call iter as baml.iter.Iterable(copy _7) -> [bb6]; + } + + bb6: { + _9 = virtual_call next as baml.iter.Iterator(copy _8) -> [bb7]; + } + + bb7: { + _10 = is_type(copy _9, baml.iter.Done); + branch copy _10 -> [bb10, bb8]; + } + + bb8: { + _11 = copy _9; + fresh_cell(_12); + _12 = copy _11; + _14 = copy _12.0; + _13 = copy _14 == copy _2; + branch copy _13 -> [bb9, bb6]; + } + + bb9: { + _0 = const true; + goto -> bb11; + } + + bb10: { + _0 = const false; + goto -> bb11; + } + + bb11: { + return; + } +} + +fn reflect.AnyClass.list_fields(self: reflect.AnyClass) -> reflect.class.Field[] { + // Locals: + let _0: reflect.class.Field[] // _0 // return + let _1: reflect.AnyClass // self // param + let _2: null | reflect.class.Type + let _3: reflect.Type + let _4: null | reflect.class.Type + let _5: reflect.class.Type // class_type + let _6: reflect.class.Field[] // fields + let _7: reflect.class.Field[] + let _8: baml.iter.Iterator + let _9: unknown + let _10: bool + let _11: reflect.class.Field + let _12: reflect.class.Field // field + let _13: void + let _14: reflect.class.Field + let _15: string + let _16: null | reflect.Type + let _17: reflect.Meta + let _18: reflect.Type + + bb0: { + _3 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; + } + + bb1: { + _2 = call const fn reflect.Type.as_class(copy _3) -> [bb2]; + } + + bb2: { + _4 = copy _2; + _4 = narrow_bind copy _4 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; + } + + bb3: { + _0 = []: reflect.class.Field[]; + goto -> bb10; + } + + bb4: { + _5 = copy _4; + _6 = []: reflect.class.Field[]; + _7 = call const fn reflect.class.Type.fields(copy _5) -> [bb5]; + } + + bb5: { + _8 = virtual_call iter as baml.iter.Iterable(copy _7) -> [bb6]; + } + + bb6: { + _9 = virtual_call next as baml.iter.Iterator(copy _8) -> [bb7]; + } + + bb7: { + _10 = is_type(copy _9, baml.iter.Done); + branch copy _10 -> [bb9, bb8]; + } + + bb8: { + _11 = copy _9; + fresh_cell(_12); + _12 = copy _11; + _15 = copy _12.0; + _16 = copy _12.1; + _17 = copy _12.2; + _14 = reflect.class.Field { copy _15, copy _16, copy _17, copy _1 }; + _18 = load_type(reflect.class.Field); + _13 = call const fn baml.Array.push(copy _6, copy _14) -> [bb6]; + } + + bb9: { + _0 = copy _6; + goto -> bb10; + } + + bb10: { + return; + } +} + +fn reflect.AnyClass.name(self: reflect.AnyClass) -> string { + // Locals: + let _0: string // _0 // return + let _1: reflect.AnyClass // self // param + let _2: reflect.Type + + bb0: { + _2 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; + } + + bb1: { + _0 = call const fn baml.root.ToString$for$reflect.Type.to_string(copy _2) -> [bb2]; + } + + bb2: { + return; + } +} + +fn reflect.AnyClass.type(self: reflect.AnyClass) -> reflect.Type { + // Locals: + let _0: reflect.Type // _0 // return + let _1: reflect.AnyClass // self // param + + bb0: { + _0 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; + } + + bb1: { + return; + } +} + +fn reflect.AnyClass.attributes(self: reflect.AnyClass) -> reflect.Meta { + // Locals: + let _0: reflect.Meta // _0 // return + let _1: reflect.AnyClass // self // param + let _2: null | reflect.class.Type + let _3: reflect.Type + let _4: null | reflect.class.Type + let _5: map + let _6: reflect.class.Type // class_type + + bb0: { + _3 = call const fn reflect.Type.of_value(copy _1) -> [bb1]; + } + + bb1: { + _2 = call const fn reflect.Type.as_class(copy _3) -> [bb2]; + } + + bb2: { + _4 = copy _2; + _4 = narrow_bind copy _4 as Class(QualifiedTypeName { pkg: Dep("reflect"), namespace: ["class"], name: "Type" }, [], TyAttr { sap_parse_without_null: Unset, sap_pending_never: Unset, sap_in_progress_never: Unset }) -> [bb4, bb3]; + } + + bb3: { + _5 = { }: map; + _0 = reflect.Meta { const null, const null, const null, copy _5 }; + goto -> bb5; + } + + bb4: { + _6 = copy _4; + _0 = call const fn reflect.class.Type.meta(copy _6) -> [bb5]; + } + + bb5: { + return; + } +} + fn reflect.Package.current = builtin(intrinsic) fn reflect.Package.compile(files: map, packages: map) -> reflect.Package { @@ -385,20 +751,6 @@ fn reflect.Type._validate_renderable = builtin(vm) fn reflect.Type.meta = builtin(vm) -fn reflect.Type.baml.ToString.to_string(self: reflect.Type) -> string { - // Locals: - let _0: string // _0 // return - let _1: reflect.Type // self // param - - bb0: { - _0 = call const fn reflect.Type._to_string_impl(copy _1) -> [bb1]; - } - - bb1: { - return; - } -} - fn reflect.Type._to_string_impl = builtin(vm) fn reflect.Type.implements = builtin(vm) diff --git a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/ppir.snap b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/ppir.snap index 86dcc4229a3..4e9fafcf018 100644 --- a/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/ppir.snap +++ b/baml_language/crates/baml_tests/snapshots/baml_src/stdlib/reflect/ppir.snap @@ -5,8 +5,10 @@ source: crates/baml_tests/src/corpus.rs --- /reflect/ns_array/array.baml --- class reflect.array.Type { + _ty: reflect.Type } class reflect.array.Type$stream { + _ty: unknown } function reflect.array.as_type(self: ?) -> reflect.Type [builtin] function reflect.array.element_type(self: ?) -> reflect.Type [builtin] @@ -47,8 +49,10 @@ class reflect.class.PendingType$stream { _resolved: unknown | null } class reflect.class.Type { + _ty: reflect.Type } class reflect.class.Type$stream { + _ty: unknown } function reflect.class._build(self: ?, implementations: reflect.interface.Implementation[]) -> reflect.class.Type [builtin] function reflect.class._new(name: string, fields: map>, implementations: reflect.interface.Implementation[]) -> reflect.class.Type [builtin] @@ -74,13 +78,15 @@ function reflect.class.resolved(self: ?) -> reflect.Type? [builtin] function reflect.class.type(self: ?) -> reflect.class.PendingType [builtin] function reflect.class.union(self: ?, others: reflect.Type | reflect.class.PendingType[]) -> reflect.class.PendingType [builtin] function reflect.class.value(self: ?) -> T? [expr] { - { let owner: baml.AnyClass = self._owner } reflect.class.get_field(owner, self.name) catch (e) { reflect.errors.CompilationError { message: message } => { throw baml.errors.TypeMismatch { message: message } } } + { let owner: reflect.AnyClass = self._owner } reflect.class.get_field(owner, self.name) catch (e) { reflect.errors.CompilationError { message: message } => { throw reflect.errors.TypeMismatch { message: message } } } } --- /reflect/ns_enum/enum.baml --- class reflect.enum.Type { + _ty: reflect.Type } class reflect.enum.Type$stream { + _ty: unknown } class reflect.enum.Value { name: string @@ -118,6 +124,12 @@ class reflect.errors.SessionBusy { class reflect.errors.SessionBusy$stream { message: string | null } +class reflect.errors.TypeMismatch { + message: string +} +class reflect.errors.TypeMismatch$stream { + message: string | null +} --- /reflect/ns_function/function.baml --- class reflect.function.Parameter { @@ -131,8 +143,10 @@ class reflect.function.Parameter$stream { optional: bool | null } class reflect.function.Type { + _ty: reflect.Type } class reflect.function.Type$stream { + _ty: unknown } function reflect.function.as_type(self: ?) -> reflect.Type [builtin] function reflect.function.params(self: ?) -> reflect.function.Parameter[] [builtin] @@ -146,8 +160,10 @@ class reflect.interface.Implementation$stream { _handle: $rust_type } class reflect.interface.Type { + _ty: reflect.Type } class reflect.interface.Type$stream { + _ty: unknown } function reflect.interface.as_type(self: ?) -> reflect.Type [builtin] function reflect.interface.field(self: ?, interface_field: string, class_field: string? = null) -> reflect.interface.Implementation [builtin] @@ -156,16 +172,20 @@ function reflect.interface.implemented_by(self: ?, other: reflect.Type) -> bool --- /reflect/ns_literal/literal.baml --- class reflect.literal.Type { + _ty: reflect.Type } class reflect.literal.Type$stream { + _ty: unknown } function reflect.literal.as_type(self: ?) -> reflect.Type [builtin] function reflect.literal.new(value: string | int | bool) -> reflect.literal.Type [builtin] --- /reflect/ns_map/map.baml --- class reflect.map.Type { + _ty: reflect.Type } class reflect.map.Type$stream { + _ty: unknown } function reflect.map.as_type(self: ?) -> reflect.Type [builtin] function reflect.map.key_type(self: ?) -> reflect.Type [builtin] @@ -174,15 +194,19 @@ function reflect.map.value_type(self: ?) -> reflect.Type [builtin] --- /reflect/ns_primitive/primitive.baml --- class reflect.primitive.Type { + _ty: reflect.Type } class reflect.primitive.Type$stream { + _ty: unknown } function reflect.primitive.as_type(self: ?) -> reflect.Type [builtin] --- /reflect/ns_union/union.baml --- class reflect.union.Type { + _ty: reflect.Type } class reflect.union.Type$stream { + _ty: unknown } function reflect.union.as_type(self: ?) -> reflect.Type [builtin] function reflect.union.member_types(self: ?) -> reflect.Type[] [builtin] @@ -289,7 +313,10 @@ function reflect._finish(artifact: reflect.Package, packages: map T [builtin] function reflect._new(packages: map) -> reflect.Session [builtin] function reflect.as_type(self: ?) -> reflect.Type [missing] -function reflect.call_any(f: baml.AnyFunction, args: map) -> R [builtin] +function reflect.attributes(self: ?) -> reflect.Meta [expr] { + { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class() } class_type.meta() +} +function reflect.call_any(f: AnyFunction, args: map) -> R [builtin] function reflect.classes(self: ?) -> map [builtin] function reflect.compile(files: map, packages: map = ...) -> reflect.Package [expr] { { let artifact = Package._compile(files, packages) } Package._finish(artifact, packages) @@ -302,16 +329,34 @@ function reflect.eval(self: ?, source: string) -> T [expr] { { let artifact = self._compile(source) } self._finish(artifact) catch (_) { _ => throw reflect.errors.EvaluationError { message: "session evaluatio..." } } } function reflect.functions(self: ?) -> map [builtin] +function reflect.get(self: ?, name: string) -> T? [expr] { + { if (Not self.has_field(name)) { return null }; let field: reflect.class.Field = self.get_field(name) } field.value() +} function reflect.get_class(self: ?, name: string) -> reflect.class.Type? [builtin] function reflect.get_enum(self: ?, name: string) -> reflect.enum.Type? [builtin] +function reflect.get_field(self: ?, name: string) -> reflect.class.Field? [expr] { + { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class(); for field in class_type.fields() { } if (field.name Eq name) { return reflect.class.Field { name: field.name, type: field.type, meta: field.meta, _owner: self } } } null +} function reflect.get_function(self: ?, name: string) -> F? [builtin] function reflect.get_interface(self: ?, name: string) -> reflect.interface.Type? [builtin] +function reflect.has_field(self: ?, name: string) -> bool [expr] { + { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class(); for field in class_type.fields() { } if (field.name Eq name) { return true } } false +} function reflect.interfaces(self: ?) -> map [builtin] +function reflect.list_fields(self: ?) -> reflect.class.Field[] [expr] { + { let class_type: reflect.class.Type = reflect.Type.of_value(self).as_class(); let fields: reflect.class.Field[] = []; for field in class_type.fields() { } fields.push(reflect.class.Field { name: field.name, type: field.type, meta: field.meta, _owner: self }) } fields +} +function reflect.name(self: ?) -> string [expr] { + { } reflect.Type.of_value(self).to_string() +} function reflect.new(packages: map = ...) -> reflect.Session [expr] { { } Session._new(packages) } -function reflect.signature(f: baml.AnyFunction) -> reflect.Signature [builtin] +function reflect.signature(f: AnyFunction) -> reflect.Signature [builtin] function reflect.tests(self: ?) -> map null throws unknown> [builtin] +function reflect.type(self: ?) -> reflect.Type [expr] { + { } reflect.Type.of_value(self) +} function reflect.with_types(self: ?, types: map) -> reflect.Package [builtin] --- /reflect/type.baml --- @@ -339,6 +384,3 @@ function reflect.of() -> reflect.Type [builtin] function reflect.of_value(value: unknown) -> reflect.Type [builtin] function reflect.optional(self: ?) -> reflect.union.Type [builtin] function reflect.to_baml(self: ?) -> string [builtin] -function reflect.to_string(self: ?) -> string [expr] { - { } self._to_string_impl() -} diff --git a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__03_ppir.snap b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__03_ppir.snap index 33819d96b2e..4677d330224 100644 --- a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__03_ppir.snap +++ b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__03_ppir.snap @@ -27,7 +27,7 @@ class user.ToolError$stream { message: string | null } function user.main() -> int [expr] { - { let bad_ret: baml.AnyFunction = web_search; let bad_throws: baml.AnyFunction = web_search; let not_a_fn: baml.AnyFunction = 42; let narrow: baml.AnyFunction = web_search; let bad_widen: baml.AnyFunction = narrow; return 0 } + { let bad_ret: reflect.AnyFunction = web_search; let bad_throws: reflect.AnyFunction = web_search; let not_a_fn: reflect.AnyFunction = 42; let narrow: reflect.AnyFunction = web_search; let bad_widen: reflect.AnyFunction = narrow; return 0 } } function user.pick(f: T) -> T [expr] { { return f } diff --git a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__05_diagnostics.snap b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__05_diagnostics.snap index f7c8018cf35..df84e41d07f 100644 --- a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__05_diagnostics.snap +++ b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__05_diagnostics.snap @@ -4,68 +4,68 @@ source: crates/baml_tests/src/generated_tests.rs === COMPILER2 DIAGNOSTICS === [type] E0153 - × `baml.AnyFunction` is a compiler builtin and cannot be implemented by hand; every function type implements it automatically + × `reflect.AnyFunction` is a compiler builtin and cannot be implemented by hand; every function type implements it automatically ╭─[anyfunction.baml:9:12] - 9 │ implements baml.AnyFunction for MyTool { - · ──────────────── + 9 │ implements reflect.AnyFunction for MyTool { + · ─────────────────── ╰──── [type] E0154 - × `baml.AnyFunction` cannot be used as a generic bound; use it as a value type instead (e.g. `f: baml.AnyFunction`) + × `reflect.AnyFunction` cannot be used as a generic bound; use it as a value type instead (e.g. `f: reflect.AnyFunction`) ╭─[anyfunction.baml:12:25] - 12 │ function pick(f: T) -> T throws never { - · ──────────────── + 12 │ function pick(f: T) -> T throws never { + · ─────────────────── ╰──── [type] E0154 - × `baml.AnyFunction` cannot be used as a generic bound; use it as a value type instead (e.g. `f: baml.AnyFunction`) + × `reflect.AnyFunction` cannot be used as a generic bound; use it as a value type instead (e.g. `f: reflect.AnyFunction`) ╭─[anyfunction.baml:16:24] - 16 │ class Holder { - · ──────────────── + 16 │ class Holder { + · ─────────────────── ╰──── [type] E0154 - × `baml.AnyFunction` cannot be used as a generic bound; use it as a value type instead (e.g. `f: baml.AnyFunction`) + × `reflect.AnyFunction` cannot be used as a generic bound; use it as a value type instead (e.g. `f: reflect.AnyFunction`) ╭─[anyfunction.baml:21:25] - 21 │ type Callee extends baml.AnyFunction - · ──────────────── + 21 │ type Callee extends reflect.AnyFunction + · ─────────────────── ╰──── [type] E0001 × mismatched types - ╭─[anyfunction.baml:45:55] - 45 │ let bad_ret: baml.AnyFunction = web_search - · ─────┬──── - · ╰── expected `baml.AnyFunction`, found `(q: string) -> Doc[] throws ToolError` + ╭─[anyfunction.baml:45:58] + 45 │ let bad_ret: reflect.AnyFunction = web_search + · ─────┬──── + · ╰── expected `reflect.AnyFunction`, found `(q: string) -> Doc[] throws ToolError` ╰──── [type] E0001 × mismatched types - ╭─[anyfunction.baml:46:56] - 46 │ let bad_throws: baml.AnyFunction = web_search - · ─────┬──── - · ╰── expected `baml.AnyFunction`, found `(q: string) -> Doc[] throws ToolError` + ╭─[anyfunction.baml:46:59] + 46 │ let bad_throws: reflect.AnyFunction = web_search + · ─────┬──── + · ╰── expected `reflect.AnyFunction`, found `(q: string) -> Doc[] throws ToolError` ╰──── [type] E0001 × mismatched types - ╭─[anyfunction.baml:47:38] - 47 │ let not_a_fn: baml.AnyFunction = 42 - · ─┬ - · ╰── expected `baml.AnyFunction`, found `42` + ╭─[anyfunction.baml:47:41] + 47 │ let not_a_fn: reflect.AnyFunction = 42 + · ─┬ + · ╰── expected `reflect.AnyFunction`, found `42` ╰──── [type] E0001 × mismatched types - ╭─[anyfunction.baml:49:57] - 49 │ let bad_widen: baml.AnyFunction = narrow - · ───┬── - · ╰── expected `baml.AnyFunction`, found `baml.AnyFunction` + ╭─[anyfunction.baml:49:60] + 49 │ let bad_widen: reflect.AnyFunction = narrow + · ───┬── + · ╰── expected `reflect.AnyFunction`, found `reflect.AnyFunction` ╰──── diff --git a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__10_formatter__anyfunction.snap b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__10_formatter__anyfunction.snap index 874fb8bd5ba..a6eb8e4897d 100644 --- a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__10_formatter__anyfunction.snap +++ b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/anyfunction/baml_tests__diagnostic_errors__anyfunction__10_formatter__anyfunction.snap @@ -1,7 +1,7 @@ --- source: crates/baml_tests/src/generated_tests.rs --- -// BEP-062: baml.AnyFunction is a compiler builtin. It cannot be implemented +// BEP-062: reflect.AnyFunction is a compiler builtin. It cannot be implemented // by hand (E0153) and cannot be used as a generic bound (E0154) on // functions, classes, impl generics, or associated types. @@ -9,19 +9,19 @@ class MyTool { name: string, } -implements baml.AnyFunction for MyTool { +implements reflect.AnyFunction for MyTool { } -function pick(f: T) -> T throws never { +function pick(f: T) -> T throws never { return f; } -class Holder { +class Holder { f: T, } interface Registry { - type Callee extends baml.AnyFunction + type Callee extends reflect.AnyFunction } // BEP-062: AnyFunction coercion failures. The derived conformance checks the @@ -45,10 +45,10 @@ function web_search(q: string) -> Doc[] throws ToolError { } function main() -> int throws never { - let bad_ret: baml.AnyFunction = web_search; - let bad_throws: baml.AnyFunction = web_search; - let not_a_fn: baml.AnyFunction = 42; - let narrow: baml.AnyFunction = web_search; - let bad_widen: baml.AnyFunction = narrow; + let bad_ret: reflect.AnyFunction = web_search; + let bad_throws: reflect.AnyFunction = web_search; + let not_a_fn: reflect.AnyFunction = 42; + let narrow: reflect.AnyFunction = web_search; + let bad_widen: reflect.AnyFunction = narrow; return 0; } diff --git a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/type_kinds/baml_tests__diagnostic_errors__type_kinds__05_diagnostics.snap b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/type_kinds/baml_tests__diagnostic_errors__type_kinds__05_diagnostics.snap index 3044071bc2b..591ab331ed7 100644 --- a/baml_language/crates/baml_tests/snapshots/diagnostic_errors/type_kinds/baml_tests__diagnostic_errors__type_kinds__05_diagnostics.snap +++ b/baml_language/crates/baml_tests/snapshots/diagnostic_errors/type_kinds/baml_tests__diagnostic_errors__type_kinds__05_diagnostics.snap @@ -5,7 +5,7 @@ source: crates/baml_tests/src/generated_tests.rs [type] E0062 × non-exhaustive match on type reflect.array.Type | reflect.class.Type | reflect.enum.Type | reflect.function.Type | reflect.interface.Type | reflect.literal.Type | reflect.map.Type | - │ reflect.primitive.Type | reflect.union.Type; missing: reflect.function.Type {} + │ reflect.primitive.Type | reflect.union.Type; missing: reflect.function.Type { _ty: _ } ╭─[main.baml:2:3] 2 │ ╭─▶ match (t.kind()) { 3 │ │ reflect.class.Type => "class", diff --git a/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap b/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap index b1f6417769e..3a0db7a6cb5 100644 --- a/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap +++ b/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap @@ -3,8 +3,6 @@ source: crates/baml_tests/src/compiler2_tir/phase5.rs expression: output --- namespace baml: - type AnyClass - type AnyFunction class Array { methods: [filled, generate, length, at, push, pop, remove_at, concat, for_each, filter, filter_map, reverse, sort_by, sort_by_key, slice, join, map, some, every, find, find_index, find_last, find_last_index, includes, index_of, last_index_of, reduce, flat_map, clear, shift, unshift, insert, splice] } class Bigint { methods: [abs, min, max, clamp, isqrt, pow, ilog, to_int, parse, random, _random_byte_count, _random_in_range] } class Bool { methods: [random] } diff --git a/baml_language/crates/baml_tests/src/type_spec/snapshots/baml_tests__type_spec__sweep__s15_sweep_baml_src.snap b/baml_language/crates/baml_tests/src/type_spec/snapshots/baml_tests__type_spec__sweep__s15_sweep_baml_src.snap index 63aa99ad922..f542de5aaef 100644 --- a/baml_language/crates/baml_tests/src/type_spec/snapshots/baml_tests__type_spec__sweep__s15_sweep_baml_src.snap +++ b/baml_language/crates/baml_tests/src/type_spec/snapshots/baml_tests__type_spec__sweep__s15_sweep_baml_src.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/type_spec/sweep.rs -assertion_line: 119 expression: report --- hir_ty error-channel entries: 3 diff --git a/baml_language/crates/baml_tests/src/type_spec/tables.rs b/baml_language/crates/baml_tests/src/type_spec/tables.rs index a8284d1726f..a5f4b6f8f6f 100644 --- a/baml_language/crates/baml_tests/src/type_spec/tables.rs +++ b/baml_language/crates/baml_tests/src/type_spec/tables.rs @@ -539,7 +539,7 @@ function sc_companion() -> baml.Map throws never { assert!(errors.iter().any(|error| matches!( error, TirTypeError::TypeMismatch { expected, got } - if expected.render_canonical() == "reflect.Type" && got.render_canonical() == "42" + if expected.render_canonical() == "reflect.Type | reflect.TypeView" && got.render_canonical() == "42" ))); assert_eq!(extraction_throws.as_deref(), Some("unknown")); assert_eq!(session_args, Some(vec!["unknown".to_string()])); @@ -617,7 +617,7 @@ function scope_shape_bad(runtime_t: reflect.Type) -> null throws never { matches!( &diag.error, TirTypeError::TypeMismatch { expected, got } - if expected.render_canonical() == "reflect.Type" && got.render_canonical() == "42" + if expected.render_canonical() == "reflect.Type | reflect.TypeView" && got.render_canonical() == "42" ) }); saw_static_shape_error |= result.diagnostics.iter().any(|diag| { @@ -788,7 +788,7 @@ function pat_lambda() -> ((int) -> bool throws ScopeEffect) throws never { matches!( &diag.error, TirTypeError::TypeMismatch { expected, got } - if expected.render_canonical() == "reflect.Type" && got.render_canonical() == "42" + if expected.render_canonical() == "reflect.Type | reflect.TypeView" && got.render_canonical() == "42" ) }); let inferred_body = baml_compiler2_ppir::body(&db, owner); diff --git a/baml_language/crates/baml_tests/tests/anyclass_reflection.rs b/baml_language/crates/baml_tests/tests/anyclass_reflection.rs index d2e50dce9d5..9afe7ccde8d 100644 --- a/baml_language/crates/baml_tests/tests/anyclass_reflection.rs +++ b/baml_language/crates/baml_tests/tests/anyclass_reflection.rs @@ -1,4 +1,4 @@ -//! End-to-end coverage for the read-only `baml.AnyClass` reflection surface. +//! End-to-end coverage for the read-only `reflect.AnyClass` reflection surface. use baml_compiler_diagnostics::Severity; use baml_tests::{ @@ -20,7 +20,7 @@ fn compile_error_codes(source: &str) -> Vec { fn requires_any_class_rejects_a_primitive_implementor() { let errors = compile_error_codes( r#" - interface Tagged requires baml.AnyClass { + interface Tagged requires reflect.AnyClass { function tag(self) -> string throws never } @@ -45,7 +45,7 @@ fn any_class_blanket_bound_does_not_expose_members_on_nonclasses() { class Box { value T } - implements Wrapped for Box { + implements Wrapped for Box { function tag(self) -> string { "wrapped:" + self.value.type().to_string() } } @@ -67,7 +67,7 @@ async fn requires_and_bounded_impl_membership_agree_for_real_classes() { class Record { label string } class Box { value T } - interface Tagged requires baml.AnyClass { + interface Tagged requires reflect.AnyClass { function tag(self) -> string throws never } @@ -79,7 +79,7 @@ async fn requires_and_bounded_impl_membership_agree_for_real_classes() { function wrapped(self) -> string throws never } - implements Wrapped for Box { + implements Wrapped for Box { function wrapped(self) -> string { "wrapped:" + self.value.name() } } @@ -112,9 +112,9 @@ async fn runtime_minted_class_narrows_and_exercises_the_complete_surface() { prompt: `Extract ${text}.\n${ctx.output_format}` } - function mismatch_is_catchable(value: baml.AnyClass) -> bool throws never { + function mismatch_is_catchable(value: reflect.AnyClass) -> bool throws never { let ignored = value.get("first") catch (e) { - baml.errors.TypeMismatch { message } => { + reflect.errors.TypeMismatch { message } => { return message.includes("field `VetrecLike.first`") } } @@ -133,7 +133,7 @@ async fn runtime_minted_class_narrows_and_exercises_the_complete_surface() { let opaque = Extract$parse( `{"first":"one","second":"two","third":null,"fourth":"four","fifth":"five"}`, ) - let record: baml.AnyClass = opaque else { + let record: reflect.AnyClass = opaque else { throw "Expected class" } @@ -166,7 +166,7 @@ async fn runtime_minted_class_narrows_and_exercises_the_complete_surface() { } #[tokio::test] -async fn membership_is_class_only_with_the_ratified_kind_view_exception() { +async fn membership_is_class_only_and_kind_views_are_ordinary_classes() { let output = baml_test!( r#" class Point { x int } @@ -175,7 +175,7 @@ async fn membership_is_class_only_with_the_ratified_kind_view_exception() { type Callback = (value: int) -> string throws never function narrows(value: unknown) -> bool throws never { - let class_value: baml.AnyClass = value else { + let class_value: reflect.AnyClass = value else { return false } class_value.type() == reflect.Type.of_value(value) @@ -193,16 +193,18 @@ async fn membership_is_class_only_with_the_ratified_kind_view_exception() { let primitive_kind = reflect.Type.of().as_primitive() ?? throw "primitive kind" let function_kind = reflect.Type.of().as_function() ?? throw "function kind" + // The nine kind views are ordinary wrapper classes, so every one + // of them narrows to `AnyClass` like any other class instance. narrows(Point { x: 1 }) && narrows(class_kind) - && !narrows(enum_kind) - && !narrows(union_kind) - && !narrows(literal_kind) - && !narrows(array_kind) - && !narrows(map_kind) - && !narrows(interface_kind) - && !narrows(primitive_kind) - && !narrows(function_kind) + && narrows(enum_kind) + && narrows(union_kind) + && narrows(literal_kind) + && narrows(array_kind) + && narrows(map_kind) + && narrows(interface_kind) + && narrows(primitive_kind) + && narrows(function_kind) && !narrows(1) && !narrows("text") && !narrows(Color.Red) @@ -226,10 +228,10 @@ async fn reflected_membership_and_static_field_handles_agree_with_narrowing() { } function main() -> bool throws unknown { - let any_class_t = reflect.Type.of() + let any_class_t = reflect.Type.of() let any_class_view = any_class_t.as_interface() ?? throw "AnyClass interface" let point = Point { x: 7 } - let narrowed: baml.AnyClass = point else { + let narrowed: reflect.AnyClass = point else { throw "Expected class" } let field: reflect.class.Field = narrowed.get_field("x") else { @@ -243,7 +245,7 @@ async fn reflected_membership_and_static_field_handles_agree_with_narrowing() { reflect.Type.of().implements(any_class_t) && any_class_view.implemented_by(reflect.Type.of()) && reflect.Type.of().implements(any_class_t) - && !reflect.Type.of().implements(any_class_t) + && reflect.Type.of().implements(any_class_t) && !reflect.Type.of().implements(any_class_t) && narrowed.name() == "Point" && narrowed.attributes().alias == "point" @@ -305,7 +307,7 @@ async fn concrete_members_keep_precedence_until_explicitly_narrowed() { let methods = ExistingMethods {} let boxed = OutOfBodyBox.new("out-of-body") let boxed_value = boxed.get() - let reflected: baml.AnyClass = fields else { + let reflected: reflect.AnyClass = fields else { throw "Expected class" } diff --git a/baml_language/crates/baml_tests/tests/reflect_call_any.rs b/baml_language/crates/baml_tests/tests/reflect_call_any.rs index 1ce2fcfa39a..76826199ecd 100644 --- a/baml_language/crates/baml_tests/tests/reflect_call_any.rs +++ b/baml_language/crates/baml_tests/tests/reflect_call_any.rs @@ -1,4 +1,4 @@ -//! Runtime semantics of BEP-062's AnyFunction slice: `baml.AnyFunction` +//! Runtime semantics of BEP-062's AnyFunction slice: `reflect.AnyFunction` //! coercion carried to runtime, `reflect.signature`, and `reflect.call_any` //! (argument checking, callee defaults, error propagation). @@ -35,7 +35,7 @@ async fn call_any_dispatches_named_args() { } function main() -> int throws never { - let f: baml.AnyFunction = add + let f: reflect.AnyFunction = add return reflect.call_any(f, { "x": 20, "y": 22 }) catch (e) { _ => -1 } @@ -54,7 +54,7 @@ async fn call_any_absent_optional_fires_callee_default() { } function main() -> int throws never { - let f: baml.AnyFunction = scale + let f: reflect.AnyFunction = scale // Absent: the callee's own (non-constant) default fires: 5 * 6. let defaulted = reflect.call_any(f, { "x": 5 }) catch (e) { _ => -1 @@ -79,7 +79,7 @@ async fn call_any_rejects_missing_key_and_type_mismatches() { } function main() -> int throws never { - let f: baml.AnyFunction = greet + let f: reflect.AnyFunction = greet let missing = reflect.call_any(f, {}) catch (e) { reflect.InvalidArgumentError => 1, reflect.errors.CompilationError => 100, @@ -133,7 +133,7 @@ async fn call_any_widens_int_for_float_param() { } function main() -> int throws never { - let g: baml.AnyFunction = scale + let g: reflect.AnyFunction = scale // The one boundary conversion: an integral value widens for a // `float` parameter (JSON Schema's `number` admits integers)... let widened = reflect.call_any(g, { "budget": 150 }) catch (e) { @@ -147,7 +147,7 @@ async fn call_any_widens_int_for_float_param() { } // Nothing else converts: a float does not narrow to `int`, and a // numeric string does not parse to `float`. - let h: baml.AnyFunction = takes_int + let h: reflect.AnyFunction = takes_int let narrowed = reflect.call_any(h, { "n": 1.5 }) catch (e) { reflect.InvalidArgumentError => -1, reflect.errors.CompilationError => -100, @@ -202,7 +202,7 @@ async fn call_any_invalid_argument_error_carries_types() { } function main() -> string throws never { - let f: baml.AnyFunction = greet + let f: reflect.AnyFunction = greet let bad_value = reflect.call_any(f, { "name": 42 }) catch (e) { reflect.InvalidArgumentError => e.argument + ":" + e.expected.to_string() + "|" + e.got.to_string(), reflect.errors.CompilationError => "unexpected-compilation-error", @@ -245,7 +245,7 @@ async fn call_any_propagates_callee_typed_throw() { } function main() -> string throws never { - let f: baml.AnyFunction = fail_search + let f: reflect.AnyFunction = fail_search // Exhaustive without a wildcard: all declared channels are named. return reflect.call_any(f, { "q": "cats" }) catch (e) { ToolError => e.message, @@ -277,7 +277,7 @@ async fn call_any_heterogeneous_tool_map_dispatch() { throw ToolError { message: s } } - function dispatch(tools: map>, name: string, args: map) -> string throws never { + function dispatch(tools: map>, name: string, args: map) -> string throws never { let f = tools.get(name) if f is null { return "no-such-tool" @@ -290,7 +290,7 @@ async fn call_any_heterogeneous_tool_map_dispatch() { } function main() -> string throws never { - let tools: map> = { + let tools: map> = { "shout": shout, "fail": fail, } @@ -312,7 +312,7 @@ async fn call_any_lambda_callee() { let double = (x: int) -> int throws never { x * 2 } - let f: baml.AnyFunction = double + let f: reflect.AnyFunction = double return reflect.call_any(f, { "x": 21 }) catch (e) { _ => -1 } @@ -336,7 +336,7 @@ async fn call_any_bound_method_callee() { function main() -> int throws never { let c = Counter { base: 40 } - let m: baml.AnyFunction = c.bump + let m: reflect.AnyFunction = c.bump return reflect.call_any(m, { "amount": 2 }) catch (e) { _ => -1 } @@ -363,7 +363,7 @@ async fn signature_reports_types_and_param_split() { } function main() -> string throws never { - let f: baml.AnyFunction = search + let f: reflect.AnyFunction = search let sig = reflect.signature(f) let limit = sig.opts.get("limit") let limit_str = "absent" @@ -409,7 +409,7 @@ async fn signature_bound_method_drops_receiver() { function main() -> string throws never { let c = Counter { base: 40 } - let m: baml.AnyFunction = c.bump + let m: reflect.AnyFunction = c.bump let sig = reflect.signature(m) let method_name = "unnamed" let n = sig.name @@ -444,7 +444,7 @@ async fn instantiated_generic_function_reflects_precisely_and_dispatches() { function main() -> string throws never { // An instantiated generic callable carries its realized frame, so its // signature reconstructs at that instantiation rather than coarsely. - let f: baml.AnyFunction = ident + let f: reflect.AnyFunction = ident let sig = reflect.signature(f) let r = reflect.call_any(f, { "x": 42 }) catch (e) { _ => -1 @@ -472,7 +472,7 @@ async fn call_any_reports_unspecialized_generic_function() { } function main() -> string throws unknown { - let f: baml.AnyFunction = ident + let f: reflect.AnyFunction = ident let _ = reflect.call_any(f, { "x": 42 }) catch (e) { reflect.errors.CompilationError => { return e.diagnostics[0].code + "|" + e.diagnostics[0].message @@ -500,7 +500,7 @@ async fn pinned_call_any_declares_unspecialized_generic_compilation_error() { } function main() -> string throws never { - let f: baml.AnyFunction = ident + let f: reflect.AnyFunction = ident let _ = reflect.call_any(f, { "x": "value" }) catch (e) { reflect.errors.CompilationError => { return e.diagnostics[0].code + "|" + e.diagnostics[0].message @@ -534,7 +534,7 @@ async fn uninstantiated_generic_function_reference_is_a_compile_error() { } function main() -> string throws never { - let f: baml.AnyFunction = ident + let f: reflect.AnyFunction = ident return "unreachable" } "# @@ -661,10 +661,10 @@ async fn runtime_enum_identity_and_metadata_are_preserved() { } function main() -> string { - // Widen explicitly to select `reflect.Type.meta(...)`, rather than the - // enum-kind view's zero-argument metadata reader. - let left: reflect.Type = reflect.enum.new("Category", ["RED", "BLUE"]) - let right: reflect.Type = reflect.enum.new("Category", ["RED", "BLUE"]) + // Widen explicitly (`as_type`) to select `reflect.Type.meta(...)`, + // rather than the enum-kind view's zero-argument metadata reader. + let left: reflect.Type = reflect.enum.new("Category", ["RED", "BLUE"]).as_type() + let right: reflect.Type = reflect.enum.new("Category", ["RED", "BLUE"]).as_type() let left_prompt = Classify$render_prompt("sample").text() let right_prompt = Classify$render_prompt("sample").text() let tagged = left.meta( @@ -819,7 +819,7 @@ async fn get_function_refuses_an_unspecialized_generic_through_any_function() { base_url = "http://localhost:1234", ); - type AnyCallable = baml.AnyFunction; + type AnyCallable = reflect.AnyFunction; function GenericList(topic: string) -> T[] { client: TestClient @@ -872,7 +872,7 @@ async fn call_any_still_invokes_a_non_generic_companion() { base_url = "http://localhost:1234", ); - type AnyCallable = baml.AnyFunction; + type AnyCallable = reflect.AnyFunction; function Plain(topic: string) -> string { client: TestClient diff --git a/baml_language/crates/baml_tests/tests/type_kinds.rs b/baml_language/crates/baml_tests/tests/type_kinds.rs index 7cc2306b5fb..b6897985b2d 100644 --- a/baml_language/crates/baml_tests/tests/type_kinds.rs +++ b/baml_language/crates/baml_tests/tests/type_kinds.rs @@ -184,7 +184,11 @@ async fn nested_type_walker_and_kind_specific_readback_work_end_to_end() { && params[1].name == "label" && params[1].type == reflect.Type.of() && function_view.return_type() == reflect.Type.of() - && function_schema.fields().length() == 0 + // The kind views are ordinary wrapper classes: their one + // declared field is the wrapped `_ty`, visible to reflection + // like any other field. + && function_schema.fields().length() == 1 + && function_schema.fields()[0].name == "_ty" } function intrinsic_checks() -> bool throws never { @@ -369,7 +373,7 @@ async fn function_views_of_a_runtime_package_keep_its_definitions() { let param_enum = param.type.as_enum() ?? throw "expected a param enum" let param_row = param_enum.values().at(1) ?? throw "no param rows" - let callable = pkg.get_function>( + let callable = pkg.get_function>( "root.pick", ) ?? throw "missing callable" let sig = reflect.signature(callable) diff --git a/baml_language/crates/baml_type/src/names.rs b/baml_language/crates/baml_type/src/names.rs index d1a2ed28bf0..f6c12aeadd1 100644 --- a/baml_language/crates/baml_type/src/names.rs +++ b/baml_language/crates/baml_type/src/names.rs @@ -138,6 +138,14 @@ impl QualifiedTypeName { self.package().as_str() == "baml" && self.namespace.is_empty() && self.name.as_str() == name } + /// [`Self::is_builtin_root_type`] for the `reflect` package's root + /// namespace (`reflect.AnyFunction`, `reflect.AnyClass`, …). + pub fn is_reflect_root_type(&self, name: &str) -> bool { + self.package().as_str() == "reflect" + && self.namespace.is_empty() + && self.name.as_str() == name + } + /// Returns `true` if this type lives in the `baml.panics` namespace /// (i.e. it is a panic class or the `Panic` type alias). pub fn is_panic_type(&self) -> bool { diff --git a/baml_language/crates/baml_type/src/normalize.rs b/baml_language/crates/baml_type/src/normalize.rs index 60e12af71c5..c175847f4eb 100644 --- a/baml_language/crates/baml_type/src/normalize.rs +++ b/baml_language/crates/baml_type/src/normalize.rs @@ -48,7 +48,7 @@ use crate::{ /// still goes through [`TypeContext::head_lookup`] per call, which is cheap for /// a name-based context and a registry hit for a runtime one. static ANY_FUNCTION: std::sync::LazyLock = std::sync::LazyLock::new(|| { - QualifiedTypeName::new(Name::new("baml"), Vec::new(), Name::new("AnyFunction")) + QualifiedTypeName::new(Name::new("reflect"), Vec::new(), Name::new("AnyFunction")) }); /// Whether `head` is the [`ANY_FUNCTION`] declaration, decided by identity @@ -64,7 +64,7 @@ fn is_any_function>(head: &H, ctx: &C) -> bool { /// The compiler-derived interface every class value inhabits. static ANY_CLASS: std::sync::LazyLock = std::sync::LazyLock::new(|| { - QualifiedTypeName::new(Name::new("baml"), Vec::new(), Name::new("AnyClass")) + QualifiedTypeName::new(Name::new("reflect"), Vec::new(), Name::new("AnyClass")) }); /// [`is_any_function`] for [`ANY_CLASS`]. @@ -73,31 +73,6 @@ fn is_any_class>(head: &H, ctx: &C) -> bool { .is_some_and(|any_class| *head == any_class) } -/// Whether a nominal class head inhabits `baml.AnyClass`. Ordinary classes do. -/// Within the sealed reflection-kind family, only the class-kind value view is -/// intentionally admitted. -/// -/// Decided by identity against the heads `ctx` uses for the kind classes, not -/// by inspecting `head` — the head-generic counterpart of -/// [`crate::type_kind::class_inhabits_any_class`]. Only reached when the -/// supertype is `AnyClass` itself, so the walk over the nine is not on any hot -/// path. -fn head_inhabits_any_class>(head: &H, ctx: &C) -> bool { - let mut is_kind_view = false; - for kind in crate::type_kind::TypeKind::ALL { - let Some(kind_head) = ctx.head_lookup(&kind.class_name()) else { - continue; - }; - if *head == kind_head { - is_kind_view = true; - if matches!(kind, crate::type_kind::TypeKind::Class) { - return true; - } - } - } - !is_kind_view -} - // ═══════════════════════════════════════════════════════════════════════════ // CONTEXT // ═══════════════════════════════════════════════════════════════════════════ @@ -145,7 +120,7 @@ pub trait TypeContext { /// its heap and hands back a handle — state only the context has, and the /// reason this cannot live on [`Head`]. /// - /// Used for the algebra's one nominal special case, `baml.AnyFunction`, + /// Used for the algebra's one nominal special case, `reflect.AnyFunction`, /// whose pins are covariant unlike every other interface. /// /// `None` means the declaration could not be resolved *at all*, and fails @@ -426,7 +401,7 @@ pub trait TypeContext { where Self: Sized, { - NormalTy::canonical(a, self).is_disjoint_from(&NormalTy::canonical(b, self), self) + NormalTy::canonical(a, self).is_disjoint_from(&NormalTy::canonical(b, self)) } /// Whether a broad `==` between operands of types `a` and `b` is always `true`. @@ -468,7 +443,7 @@ pub trait TypeContext { { let a = NormalTy::canonical(a, self); let b = NormalTy::canonical(b, self); - if a.is_disjoint_from(&b, self) { + if a.is_disjoint_from(&b) { Some(false) } else if a.is_unoverridable_singleton() && a == b { Some(true) @@ -762,25 +737,7 @@ impl NormalTy { /// Top-level concrete category of this type, or `None` for a non-ground head /// (union, interface, hole, type variable, …) for which no disjointness is /// provable. - /// Whether `head` is one of the reflection type-kind classes - /// (`reflect..Type`). - /// - /// The algebra's second nominal special case, recognized the same way as the - /// first (`baml.AnyFunction`): by asking the context for each known name's - /// head and comparing, never by inspecting the head itself. A head is opaque - /// here — see [`Head`](crate::Head) — so the context is the only thing that - /// can turn a name the algebra knows into a head it can compare. - fn head_is_type_kind_class>(head: &H, ctx: &C) -> bool { - crate::type_kind::TypeKind::ALL.iter().any(|kind| { - // `TypeKind::class_name` is the one source of the kind-view - // spelling; duplicating it here is how a package rename silently - // un-recognizes the whole family. - ctx.head_lookup(&kind.class_name()) - .is_some_and(|known| &known == head) - }) - } - - fn head_category>(&self, ctx: &C) -> Option { + fn head_category(&self) -> Option { Some(match self { NormalTy::Int | NormalTy::Literal(Literal::Int(_)) => Category::Int, NormalTy::Bigint | NormalTy::Literal(Literal::Bigint(_)) => Category::Bigint, @@ -795,7 +752,6 @@ impl NormalTy { NormalTy::Type => Category::Type, NormalTy::Resource => Category::Resource, NormalTy::PromptAst => Category::PromptAst, - NormalTy::Class(name, _) if Self::head_is_type_kind_class(name, ctx) => Category::Type, NormalTy::Class(..) => Category::Class, NormalTy::List(_) => Category::List, NormalTy::Map { .. } => Category::Map, @@ -807,7 +763,7 @@ impl NormalTy { // happens here). A non-constructor body head (e.g. a still-unguarded // union, pending the ε-closure step) answers `None` through the arms // below — conservative. - NormalTy::Mu { body, .. } => return body.head_category(ctx), + NormalTy::Mu { body, .. } => return body.head_category(), // Not a ground concrete head — nothing provable. (A free `RecVar` // only occurs under its binder, which the μ arm above looks through.) NormalTy::Interface(..) @@ -901,7 +857,7 @@ impl NormalTy { /// Whether no value of `self` can ever be `==`-equal to a value of `other` /// (the structural core of [`definitely_disjoint`]). - fn is_disjoint_from>(&self, other: &NormalTy, ctx: &C) -> bool { + fn is_disjoint_from(&self, other: &NormalTy) -> bool { match (self, other) { // A μ is its unfolding — expose the constructor head before the // structural arms. Terminates without an assumption set because @@ -922,12 +878,12 @@ impl NormalTy { { false } - (NormalTy::Mu { .. }, _) => self.unfold().is_disjoint_from(other, ctx), - (_, NormalTy::Mu { .. }) => self.is_disjoint_from(&other.unfold(), ctx), + (NormalTy::Mu { .. }, _) => self.unfold().is_disjoint_from(other), + (_, NormalTy::Mu { .. }) => self.is_disjoint_from(&other.unfold()), // A union is disjoint from `rhs` iff every member is. - (NormalTy::Union(members), rhs) => members.iter().all(|m| m.is_disjoint_from(rhs, ctx)), - (lhs, NormalTy::Union(members)) => members.iter().all(|m| lhs.is_disjoint_from(m, ctx)), + (NormalTy::Union(members), rhs) => members.iter().all(|m| m.is_disjoint_from(rhs)), + (lhs, NormalTy::Union(members)) => members.iter().all(|m| lhs.is_disjoint_from(m)), // Generic constructors are invariant and their type arguments are real // instance data, so two instantiations are disjoint as soon as one @@ -965,7 +921,7 @@ impl NormalTy { !matches!(x, Literal::Float(_)) && !matches!(y, Literal::Float(_)) && x != y } (NormalTy::Literal(lit), rhs) | (rhs, NormalTy::Literal(lit)) => { - match rhs.head_category(ctx) { + match rhs.head_category() { Some(cat) => cat != Category::of_literal(lit), None => false, } @@ -973,7 +929,7 @@ impl NormalTy { // Otherwise: disjoint iff both are ground concrete heads of different // categories (`int` vs `string`, `list` vs `map`, a class vs an enum). - _ => match (self.head_category(ctx), other.head_category(ctx)) { + _ => match (self.head_category(), other.head_category()) { (Some(x), Some(y)) => x != y, _ => false, }, @@ -1983,23 +1939,18 @@ impl NormalTy { }) } - // `baml.AnyClass` is compiler-derived for class values. The stdlib + // `reflect.AnyClass` is compiler-derived for class values. The stdlib // blanket impl supplies default-method dispatch, but cannot define // membership by itself without also admitting primitives and // containers. Keep this before the general impl-registry arm so // static coercion and the VM's shared runtime type matcher agree. - // Of the nine sealed reflection-kind classes, only the class-kind - // view is admitted by the ratified surface. (sub, NormalTy::Interface(qn, _, _)) if is_any_class(qn, ctx) && !matches!(sub, NormalTy::Interface(..)) => { - matches!( - sub, - NormalTy::Class(head, _) if head_inhabits_any_class(head, ctx) - ) + matches!(sub, NormalTy::Class(..)) } - // BEP-062: `baml.AnyFunction` is a compiler builtin implemented by + // BEP-062: `reflect.AnyFunction` is a compiler builtin implemented by // every function type, with the parameter list erased. Conformance // is derived right here rather than from an `implements` block // (function types are not impl subjects): the return type must fit @@ -2076,14 +2027,6 @@ impl NormalTy { .zip(a2.iter()) .all(|(a, b)| a.invariant_compatible(b, ctx, assumptions)) } - // BEP-066: the nine reflection-kind classes form one sealed family - // beneath the `type` carrier. Because membership is hard-coded to - // builtin qualified names, user classes cannot acquire this edge. - (NormalTy::Class(name, _), NormalTy::Type) - if Self::head_is_type_kind_class(name, ctx) => - { - true - } (NormalTy::List(a), NormalTy::List(b)) => a.invariant_compatible(b, ctx, assumptions), (NormalTy::Map { key: k1, value: v1 }, NormalTy::Map { key: k2, value: v2 }) => { k1.invariant_compatible(k2, ctx, assumptions) diff --git a/baml_language/crates/baml_type/src/normalize/tests.rs b/baml_language/crates/baml_type/src/normalize/tests.rs index 1d06ee4d49f..797b515b196 100644 --- a/baml_language/crates/baml_type/src/normalize/tests.rs +++ b/baml_language/crates/baml_type/src/normalize/tests.rs @@ -182,7 +182,10 @@ fn projection_reduces_to_its_binding() { // ── BEP-066 shared runtime-type algebra ────────────────────────────────── #[test] -fn reflection_kind_classes_are_sealed_type_subtypes_in_both_entries() { +fn reflection_kind_classes_are_ordinary_classes_disjoint_from_the_carrier() { + // The nine kind views are wrapper classes holding `_ty: reflect.Type` — + // no subtyping edge relates them to the `type` carrier in either + // direction, and as nominal classes they are head-disjoint from it. let ctx = Ctx::default(); let carrier = Ty::Type { attr: TyAttr::default(), @@ -191,38 +194,26 @@ fn reflection_kind_classes_are_sealed_type_subtypes_in_both_entries() { for kind in crate::type_kind::TypeKind::ALL { let view = Ty::Class(kind.class_name(), Vec::new(), TyAttr::default()); assert!( - is_subtype(&view, &carrier, &ctx), - "plain subtype entry rejected {kind:?}" + !is_subtype(&view, &carrier, &ctx), + "plain subtype entry admitted {kind:?} beneath the carrier" ); assert!( - is_subtype_interned( + !is_subtype_interned( &interned::Ty::from_plain(&view), &interned::Ty::from_plain(&carrier), &ctx, ), - "interned subtype entry rejected {kind:?}" + "interned subtype entry admitted {kind:?} beneath the carrier" ); assert!( - !definitely_disjoint(&view, &carrier, &ctx), - "reflection view and type carrier cannot be head-disjoint" + !is_subtype(&carrier, &view, &ctx), + "the carrier is not a subtype of {kind:?}" + ); + assert!( + definitely_disjoint(&view, &carrier, &ctx), + "a kind view is an ordinary class, head-disjoint from the carrier" ); } - - let user_lookalike = Ty::Class( - QualifiedTypeName::new( - Name::new("user"), - vec![Name::new("reflect"), Name::new("class")], - Name::new("Type"), - ), - Vec::new(), - TyAttr::default(), - ); - assert!(!is_subtype(&user_lookalike, &carrier, &ctx)); - assert!(!is_subtype_interned( - &interned::Ty::from_plain(&user_lookalike), - &interned::Ty::from_plain(&carrier), - &ctx, - )); } #[test] @@ -1386,11 +1377,11 @@ fn equal_requires_singleton_with_unoverridable_eq() { assert!(!definitely_equal(&class("Dog"), &class("Dog"), &ctx)); } -// ── baml.AnyClass ────────────────────────────────────────────────────────── +// ── reflect.AnyClass ────────────────────────────────────────────────────────── fn any_class() -> Ty { Ty::Interface( - QualifiedTypeName::new(Name::new("baml"), vec![], Name::new("AnyClass")), + QualifiedTypeName::new(Name::new("reflect"), vec![], Name::new("AnyClass")), vec![], vec![], TyAttr::default(), @@ -1421,27 +1412,28 @@ fn any_class_membership_is_derived_for_classes_only() { } #[test] -fn any_class_admits_only_the_class_reflection_kind_view() { +fn any_class_admits_every_reflection_kind_view() { + // The kind views are ordinary classes with an ordinary field, so they + // inhabit `AnyClass` like any other class — no carve-out. let ctx = Ctx::default(); let target = any_class(); for kind in crate::type_kind::TypeKind::ALL { let view = Ty::Class(kind.class_name(), vec![], TyAttr::default()); - assert_eq!( + assert!( is_subtype(&view, &target, &ctx), - kind == crate::type_kind::TypeKind::Class, - "unexpected AnyClass membership for {kind:?}" + "AnyClass rejected {kind:?}" ); } } -// ── BEP-062: baml.AnyFunction ────────────────────────────────────────────── +// ── BEP-062: reflect.AnyFunction ────────────────────────────────────────────── -/// `baml.AnyFunction<...pins>` with the given associated-type pins. An empty +/// `reflect.AnyFunction<...pins>` with the given associated-type pins. An empty /// list models a pre-default-fill existential (lowering normally fills /// `Returns`/`Throws` with `unknown`). fn any_function(pins: Vec<(&str, Ty)>) -> Ty { Ty::Interface( - QualifiedTypeName::new(Name::new("baml"), vec![], Name::new("AnyFunction")), + QualifiedTypeName::new(Name::new("reflect"), vec![], Name::new("AnyFunction")), vec![], pins.into_iter().map(|(n, t)| (Name::new(n), t)).collect(), TyAttr::default(), @@ -1903,8 +1895,8 @@ fn unguarded_mu_disjointness_terminates_conservatively() { NormalTy::List(Box::new(NormalTy::RecVar(0))), ])), }; - assert!(!unguarded.is_disjoint_from(&NormalTy::String, &Ctx::default())); - assert!(!NormalTy::String.is_disjoint_from(&unguarded, &Ctx::default())); + assert!(!unguarded.is_disjoint_from(&NormalTy::String)); + assert!(!NormalTy::String.is_disjoint_from(&unguarded)); } #[test] diff --git a/baml_language/crates/baml_type/src/type_kind.rs b/baml_language/crates/baml_type/src/type_kind.rs index 139489b534a..974a94d56e6 100644 --- a/baml_language/crates/baml_type/src/type_kind.rs +++ b/baml_language/crates/baml_type/src/type_kind.rs @@ -1,6 +1,6 @@ //! Closed BEP-066 reflection-kind classification. -use crate::{ConcreteRealizedTy, Name, QualifiedTypeName, RealizedTy, TyAttr}; +use crate::{Name, QualifiedTypeName, RealizedTy}; /// The nine sealed runtime views of a reflected `type` value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -51,10 +51,6 @@ impl TypeKind { Name::new("Type"), ) } - - pub fn concrete_class_ty(self) -> ConcreteRealizedTy { - ConcreteRealizedTy::Class(self.class_name(), Vec::new(), TyAttr::default()) - } } /// Classify every realized runtime type into exactly one reflection kind. @@ -84,28 +80,6 @@ pub fn is_type_kind_class(name: &QualifiedTypeName) -> bool { && name.name().as_str() == "Type" } -/// Whether `tag` identifies one of the sealed reflection kind classes. -/// -/// A compiled declaration's tag is content-addressed from its fully-qualified -/// name, so this is an integer compare against the nine known names — no -/// lookup, and no runtime declaration can collide with one, since counter tags -/// are drawn from a disjoint range. -#[must_use] -pub fn is_type_kind_tag(tag: crate::typetag::TypeTag) -> bool { - TypeKind::ALL.iter().any(|kind| { - tag == crate::typetag::TypeTag::of_head(&kind.class_name().render_dotted(false)) - }) -} - -/// [`class_inhabits_any_class`] for a runtime head, which carries a tag rather -/// than a name. -#[must_use] -pub fn tag_inhabits_any_class(tag: crate::typetag::TypeTag) -> bool { - !is_type_kind_tag(tag) - || tag - == crate::typetag::TypeTag::of_head(&TypeKind::Class.class_name().render_dotted(false)) -} - /// A builtin type and where its values actually come from, for the /// companion carrier class that stands in for it. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -165,13 +139,6 @@ pub fn builtin_companion_of(name: &QualifiedTypeName) -> Option bool { - !is_type_kind_class(name) || name == &TypeKind::Class.class_name() -} - #[cfg(test)] mod tests { use super::*; @@ -227,18 +194,4 @@ mod tests { ); } } - - #[test] - fn any_class_admits_ordinary_classes_and_only_the_class_kind_view() { - assert!(class_inhabits_any_class( - &QualifiedTypeName::from_dotted_path("user.Record") - )); - for kind in TypeKind::ALL { - assert_eq!( - class_inhabits_any_class(&kind.class_name()), - kind == TypeKind::Class, - "unexpected AnyClass membership for {kind:?}" - ); - } - } } diff --git a/baml_language/crates/bex_vm/src/package_baml/resolve.rs b/baml_language/crates/bex_vm/src/package_baml/resolve.rs index 48241062162..9b20f869759 100644 --- a/baml_language/crates/bex_vm/src/package_baml/resolve.rs +++ b/baml_language/crates/bex_vm/src/package_baml/resolve.rs @@ -14,11 +14,7 @@ use std::borrow::Cow; -use baml_type::{ - Literal, Name, - normalize::TypeContext, - type_kind::{is_type_kind_tag, tag_inhabits_any_class}, -}; +use baml_type::{Literal, Name, normalize::TypeContext}; use bex_vm_types::{ RealizedTy, TyTemplate, TypeHead, errors::VmInternalError, types::RuntimeImplRule, }; @@ -336,20 +332,16 @@ impl<'vm> ImplResolver<'vm> { stack: &mut Vec, ) -> bool { // The blanket stdlib impl exists to supply AnyClass's default-method - // dispatch. Membership is narrower: class values only, and among the - // sealed reflection-kind views only `reflect.class.Type`. Keep the - // carve-out at the recursive proof seam so nested bounds cannot observe - // the blanket rule's broader receiver. + // dispatch. Membership is narrower: class values only. Keep the + // narrowing at the recursive proof seam so nested bounds cannot + // observe the blanket rule's broader receiver. let any_class = self .vm .declaration_head(&baml_type::QualifiedTypeName::from_dotted_path( - "baml.AnyClass", + "reflect.AnyClass", )); if any_class.is_some_and(|head| head == iface) { - return matches!( - concrete_ty, - RealizedTy::Class(head, _, _) if tag_inhabits_any_class(head.tag()) - ); + return matches!(concrete_ty, RealizedTy::Class(..)); } // Key on the normalized (literal/enum-variant → base) type so `1` and `int` @@ -482,15 +474,6 @@ impl<'vm> ImplResolver<'vm> { concrete: &RealizedTy, bindings: &mut [Option], ) -> bool { - // Reflection kind classes are the sealed runtime refinements of `type`. - // Keep `implement I for type` rules applicable when the dynamic receiver - // is one of those refinements (notably TypeValue's tostring override). - if matches!(pattern, TyTemplate::Type { .. }) - && matches!(concrete, RealizedTy::Class(head, _, _) if is_type_kind_tag(head.tag())) - { - return true; - } - // A fully-realized pattern carries no frame refs or holes: compare it to the // concrete type semantically (union-order-insensitive, matching the type // checker) through the canonical fact-opaque `StructuralEquivCtx`. The diff --git a/baml_language/crates/bex_vm/src/package_reflect/reflect.rs b/baml_language/crates/bex_vm/src/package_reflect/reflect.rs index 2dd22f98d58..417848b857b 100644 --- a/baml_language/crates/bex_vm/src/package_reflect/reflect.rs +++ b/baml_language/crates/bex_vm/src/package_reflect/reflect.rs @@ -243,7 +243,12 @@ impl TypeContext for PackageSubtypeContext<'_> { fn package_class_type(vm: &mut BexVm, runtime_type: Option, class_ptr: HeapPtr) -> Value { if let Some(runtime_type) = runtime_type { - return Value::object(runtime_type); + let ty_value = Value::object(runtime_type); + return super::type_kinds::alloc_kind_view( + vm, + baml_type::type_kind::TypeKind::Class, + ty_value, + ); } let Object::Class(class) = vm.get_object(class_ptr) else { unreachable!("Package.classes only contains class pointers") @@ -253,12 +258,18 @@ fn package_class_type(vm: &mut BexVm, runtime_type: Option, class_ptr: Vec::new(), class.ty_attr.clone(), ); - Value::object(vm.tlab.alloc_type(TypeValue::new(ty))) + let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty))); + super::type_kinds::alloc_kind_view(vm, baml_type::type_kind::TypeKind::Class, ty_value) } fn package_enum_type(vm: &mut BexVm, runtime_type: Option, enum_ptr: HeapPtr) -> Value { if let Some(runtime_type) = runtime_type { - return Value::object(runtime_type); + let ty_value = Value::object(runtime_type); + return super::type_kinds::alloc_kind_view( + vm, + baml_type::type_kind::TypeKind::Enum, + ty_value, + ); } let Object::Enum(enm) = vm.get_object(enum_ptr) else { unreachable!("Package.enums only contains enum pointers") @@ -267,7 +278,8 @@ fn package_enum_type(vm: &mut BexVm, runtime_type: Option, enum_ptr: He bex_vm_types::TypeHead::new(enum_ptr, enm.type_tag), enm.ty_attr.clone(), ); - Value::object(vm.tlab.alloc_type(TypeValue::new(ty))) + let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty))); + super::type_kinds::alloc_kind_view(vm, baml_type::type_kind::TypeKind::Enum, ty_value) } fn package_interface_type( @@ -276,7 +288,12 @@ fn package_interface_type( interface_ptr: HeapPtr, ) -> Value { if let Some(runtime_type) = runtime_type { - return Value::object(runtime_type); + let ty_value = Value::object(runtime_type); + return super::type_kinds::alloc_kind_view( + vm, + baml_type::type_kind::TypeKind::Interface, + ty_value, + ); } let Object::Interface(interface) = vm.get_object(interface_ptr) else { unreachable!("Package.interfaces only contains interface pointers") @@ -287,7 +304,8 @@ fn package_interface_type( Vec::new(), TyAttr::default(), ); - Value::object(vm.tlab.alloc_type(TypeValue::new(ty))) + let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty))); + super::type_kinds::alloc_kind_view(vm, baml_type::type_kind::TypeKind::Interface, ty_value) } fn allocate_runtime_declaration_types( @@ -406,8 +424,11 @@ fn function_type(vm: &mut BexVm, package: HeapPtr, name: &LocalName) -> Option RealizedTy { } } -/// The two natives' parameters are statically `baml.AnyFunction`, so a +/// The two natives' parameters are statically `reflect.AnyFunction`, so a /// non-callable here means the coercion rule and the runtime disagree — an /// internal invariant break, not a user error. fn non_callable_error(what: &str) -> VmRustFnError { diff --git a/baml_language/crates/bex_vm/src/package_reflect/runtime_class_builder.rs b/baml_language/crates/bex_vm/src/package_reflect/runtime_class_builder.rs index db891e41133..a93ad19ccae 100644 --- a/baml_language/crates/bex_vm/src/package_reflect/runtime_class_builder.rs +++ b/baml_language/crates/bex_vm/src/package_reflect/runtime_class_builder.rs @@ -426,7 +426,12 @@ impl BamlClassClassBuilder for PackageReflectImpl { builder: &Value, implementations: &[Value], ) -> Result { - build_group(vm, *builder, implementations) + let ty_value = build_group(vm, *builder, implementations)?; + Ok(super::type_kinds::alloc_kind_view( + vm, + baml_type::type_kind::TypeKind::Class, + ty_value, + )) } } diff --git a/baml_language/crates/bex_vm/src/package_reflect/type_class.rs b/baml_language/crates/bex_vm/src/package_reflect/type_class.rs index 259bbea0b83..b7c847204bc 100644 --- a/baml_language/crates/bex_vm/src/package_reflect/type_class.rs +++ b/baml_language/crates/bex_vm/src/package_reflect/type_class.rs @@ -36,10 +36,11 @@ impl BamlClassType for PackageReflectImpl { fn array(vm: &mut BexVm, self_value: &Value) -> Value { let type_value = cloned_type_value(vm, *self_value); - alloc_runtime_type( + let array_ty = alloc_runtime_type( vm, bex_vm_types::RealizedTy::List(Box::new(type_value.ty), baml_type::TyAttr::default()), - ) + ); + super::type_kinds::alloc_kind_view(vm, baml_type::type_kind::TypeKind::Array, array_ty) } fn optional(vm: &mut BexVm, self_value: &Value) -> Value { @@ -51,10 +52,11 @@ impl BamlClassType for PackageReflectImpl { if !members.iter().any(bex_vm_types::RealizedTy::is_null) { members.push(bex_vm_types::RealizedTy::null()); } - alloc_runtime_type( + let union_ty = alloc_runtime_type( vm, bex_vm_types::RealizedTy::Union(members, baml_type::TyAttr::default()), - ) + ); + super::type_kinds::alloc_kind_view(vm, baml_type::type_kind::TypeKind::Union, union_ty) } fn to_baml(vm: &BexVm, self_value: &Value) -> bex_str::BexStr { @@ -81,43 +83,46 @@ impl BamlClassType for PackageReflectImpl { ) } - fn kind(_vm: &BexVm, self_value: &Value) -> Value { - *self_value + fn kind(vm: &mut BexVm, self_value: &Value) -> Value { + let ty = type_value_ty(vm, *self_value) + .unwrap_or_else(|| unreachable!("kind receiver must be Object::Type")); + let kind = baml_type::type_kind::classify_type(&ty); + super::type_kinds::alloc_kind_view(vm, kind, *self_value) } - fn as_class(vm: &BexVm, self_value: &Value) -> Option { + fn as_class(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Class) } - fn as_enum(vm: &BexVm, self_value: &Value) -> Option { + fn as_enum(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Enum) } - fn as_union(vm: &BexVm, self_value: &Value) -> Option { + fn as_union(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Union) } - fn as_literal(vm: &BexVm, self_value: &Value) -> Option { + fn as_literal(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Literal) } - fn as_array(vm: &BexVm, self_value: &Value) -> Option { + fn as_array(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Array) } - fn as_map(vm: &BexVm, self_value: &Value) -> Option { + fn as_map(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Map) } - fn as_interface(vm: &BexVm, self_value: &Value) -> Option { + fn as_interface(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Interface) } - fn as_primitive(vm: &BexVm, self_value: &Value) -> Option { + fn as_primitive(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Primitive) } - fn as_function(vm: &BexVm, self_value: &Value) -> Option { + fn as_function(vm: &mut BexVm, self_value: &Value) -> Option { as_kind(vm, *self_value, baml_type::type_kind::TypeKind::Function) } @@ -1251,9 +1256,14 @@ pub(super) fn type_value_ty(vm: &BexVm, value: Value) -> Option Option { +fn as_kind( + vm: &mut BexVm, + value: Value, + expected: baml_type::type_kind::TypeKind, +) -> Option { let ty = type_value_ty(vm, value)?; - (baml_type::type_kind::classify_type(&ty) == expected).then_some(value) + (baml_type::type_kind::classify_type(&ty) == expected) + .then(|| super::type_kinds::alloc_kind_view(vm, expected, value)) } /// A realized interface instantiation as reflected off a `type` value: which diff --git a/baml_language/crates/bex_vm/src/package_reflect/type_kinds.rs b/baml_language/crates/bex_vm/src/package_reflect/type_kinds.rs index 769c85fa95f..e0456c2924a 100644 --- a/baml_language/crates/bex_vm/src/package_reflect/type_kinds.rs +++ b/baml_language/crates/bex_vm/src/package_reflect/type_kinds.rs @@ -499,7 +499,10 @@ impl BamlNamespaceClass for PackageReflectImpl { baml_type::TyAttr::default(), ); register_class_witnesses(vm, class_ptr, &ty, witnesses); - Ok(Value::object(vm.tlab.alloc_type(TypeValue::new(ty)))) + Ok({ + let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty))); + alloc_kind_view(vm, baml_type::type_kind::TypeKind::Class, ty_value) + }) } fn builder(vm: &mut BexVm, name: &bex_str::BexStr) -> Value { @@ -688,7 +691,10 @@ impl BamlNamespaceEnum for PackageReflectImpl { bex_vm_types::TypeHead::new(enum_ptr, type_tag), baml_type::TyAttr::default(), ); - Ok(Value::object(vm.tlab.alloc_type(TypeValue::new(ty)))) + Ok({ + let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty))); + alloc_kind_view(vm, baml_type::type_kind::TypeKind::Enum, ty_value) + }) } fn get_value( @@ -839,6 +845,7 @@ impl BamlNamespaceLiteral for PackageReflectImpl { }; alloc_runtime_composite( vm, + baml_type::type_kind::TypeKind::Literal, bex_vm_types::RealizedTy::Literal( literal, baml_type::Freshness::Regular, @@ -853,6 +860,7 @@ impl BamlNamespaceMap for PackageReflectImpl { let value = reflected_type_value(vm, *value); alloc_runtime_composite( vm, + baml_type::type_kind::TypeKind::Map, bex_vm_types::RealizedTy::Map { key: Box::new(key.ty), value: Box::new(value.ty), @@ -876,14 +884,20 @@ impl BamlNamespaceUnion for PackageReflectImpl { .collect(); Ok(alloc_runtime_composite( vm, + baml_type::type_kind::TypeKind::Union, bex_vm_types::RealizedTy::Union(members, baml_type::TyAttr::default()), )) } } -fn reflected_ty(vm: &BexVm, value: Value) -> bex_vm_types::RealizedTy { - super::type_class::type_value_ty(vm, value) - .unwrap_or_else(|| unreachable!("kind method receiver must be Object::Type")) +fn reflected_ty( + vm: &BexVm, + view: Value, + expected: baml_type::type_kind::TypeKind, +) -> Result { + let ty_value = view_type_value(vm, view, expected)?; + Ok(super::type_class::type_value_ty(vm, ty_value) + .unwrap_or_else(|| unreachable!("view_type_value returns an Object::Type"))) } /// Realize an interface field declaration against the exact interface @@ -1065,8 +1079,16 @@ pub(super) fn reflected_type_value(vm: &BexVm, value: Value) -> TypeValue { (**type_value).clone() } -fn alloc_runtime_composite(vm: &mut BexVm, ty: bex_vm_types::RealizedTy) -> Value { - Value::object(vm.tlab.alloc_type(TypeValue::new(ty))) +/// Allocate a runtime composite type and wrap it in `kind`'s view: the +/// composite constructors (`literal.new`, `map.new`, `union.new`) declare the +/// kind views as their return types. +fn alloc_runtime_composite( + vm: &mut BexVm, + kind: baml_type::type_kind::TypeKind, + ty: bex_vm_types::RealizedTy, +) -> Value { + let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty))); + alloc_kind_view(vm, kind, ty_value) } pub(super) struct ReflectedTypeRow { @@ -1163,41 +1185,126 @@ pub(super) fn reflected_type_row(vm: &BexVm, value: Value) -> Result Value { + debug_assert!(matches!( + type_value.as_object_ptr().map(|ptr| vm.get_object(ptr)), + Some(Object::Type(_)) + )); + let name = kind.class_name(); + let class = vm.declaration_head(&name).unwrap_or_else(|| { + unreachable!("reflection kind class `{name}` is declared by the stdlib") + }); + Value::object(vm.alloc_instance(class.ptr(), vec![type_value])) +} + +/// Enforce a view's kind invariant on its `_ty` value: `_ty` is private by +/// invariant, so a held type that does not classify as `expected` means user +/// code overwrote the field — a BAML panic, never an answer computed from a +/// state the API rules out. Returns `ty_value` (an `Object::Type`) on success. +pub(crate) fn check_kind_invariant( + vm: &BexVm, + ty_value: Value, + expected: baml_type::type_kind::TypeKind, +) -> Result { + let invariant_panic = |actual: &str| { + crate::errors::VmRustFnError::Panic(bex_vm_types::errors::VmPanic::UserPanic { + message: format!( + "reflect.{}.Type `_ty` holds a {actual} type; the field is private to \ + reflection and must keep its view's kind", + expected.namespace(), + ), + }) + }; + let Some(ty_ptr) = ty_value.as_object_ptr() else { + return Err(invariant_panic("non-`reflect.Type`")); + }; + let Object::Type(type_value) = vm.get_object(ty_ptr) else { + return Err(invariant_panic("non-`reflect.Type`")); + }; + let actual = baml_type::type_kind::classify_type(&type_value.ty); + if actual != expected { + return Err(invariant_panic(&format!("{}-kind", actual.namespace()))); + } + Ok(ty_value) +} + +/// If `value` is an instance of one of the nine kind views, its `_ty` value +/// (no kind check — callers that accept `reflect.TypeView` accept any kind). +pub(crate) fn as_view_type_value(vm: &BexVm, value: Value) -> Option { + let ptr = value.as_object_ptr()?; + let Object::Instance(instance) = vm.get_object(ptr) else { + return None; + }; + let is_view = baml_type::type_kind::TypeKind::ALL.iter().any(|kind| { + vm.declaration_head(&kind.class_name()) + .is_some_and(|head| head.ptr() == instance.class) + }); + is_view.then(|| instance.fields[0].load()) +} + +/// The `Object::Type` value a kind-view instance wraps (`_ty`, its sole +/// declared field), after enforcing the kind invariant. +pub(crate) fn view_type_value( + vm: &BexVm, + view: Value, + expected: baml_type::type_kind::TypeKind, +) -> Result { + // The receiver shape is guaranteed by static dispatch on the view class. + let ptr = view + .as_object_ptr() + .unwrap_or_else(|| unreachable!("kind-view receiver must be an instance")); + let Object::Instance(instance) = vm.get_object(ptr) else { + unreachable!("kind-view receiver must be an Object::Instance") + }; + check_kind_invariant(vm, instance.fields[0].load(), expected) +} + fn reflected_class( vm: &BexVm, - value: Value, -) -> (bex_vm_types::Class, Vec) { - let ptr = value + view: Value, +) -> Result<(bex_vm_types::Class, Vec), crate::errors::VmRustFnError> { + let ty_value = view_type_value(vm, view, baml_type::type_kind::TypeKind::Class)?; + let ptr = ty_value .as_object_ptr() - .unwrap_or_else(|| unreachable!("class.Type receiver must be Object::Type")); + .unwrap_or_else(|| unreachable!("view_type_value returns an Object::Type")); let Object::Type(type_value) = vm.get_object(ptr) else { - unreachable!("class.Type receiver must be Object::Type") + unreachable!("view_type_value returns an Object::Type") }; let bex_vm_types::RealizedTy::Class(head, args, _) = &type_value.ty else { - unreachable!("class.Type receiver must wrap a class type") + unreachable!("a Class-classified type is RealizedTy::Class") }; debug_assert!(head.is_resolved()); let Object::Class(class) = vm.get_object(head.ptr()) else { unreachable!("a class type's head points at Object::Class") }; - ((**class).clone(), args.clone()) + Ok(((**class).clone(), args.clone())) } -fn reflected_enum(vm: &BexVm, value: Value) -> bex_vm_types::Enum { - let ptr = value +fn reflected_enum( + vm: &BexVm, + view: Value, +) -> Result { + let ty_value = view_type_value(vm, view, baml_type::type_kind::TypeKind::Enum)?; + let ptr = ty_value .as_object_ptr() - .unwrap_or_else(|| unreachable!("enum.Type receiver must be Object::Type")); + .unwrap_or_else(|| unreachable!("view_type_value returns an Object::Type")); let Object::Type(type_value) = vm.get_object(ptr) else { - unreachable!("enum.Type receiver must be Object::Type") + unreachable!("view_type_value returns an Object::Type") }; let bex_vm_types::RealizedTy::Enum(head, _) = &type_value.ty else { - unreachable!("enum.Type receiver must wrap an enum type") + unreachable!("an Enum-classified type is RealizedTy::Enum") }; debug_assert!(head.is_resolved()); let Object::Enum(enm) = vm.get_object(head.ptr()) else { unreachable!("an enum type's head points at Object::Enum") }; - (**enm).clone() + Ok((**enm).clone()) } fn opt_string(vm: &mut BexVm, value: Option<&str>) -> Value { @@ -1444,19 +1551,26 @@ fn invalid_enum_value(vm: &BexVm, value: Value) -> crate::errors::VmRustFnError } macro_rules! impl_as_type { - ($trait_name:ident) => { - fn as_type(_vm: &BexVm, r#type: &Value) -> Value { - *r#type + ($kind:ident, $view_ns:ident) => { + #[expect( + clippy::used_underscore_items, + reason = "the generated view accessor is named for the `_ty` field it reads" + )] + fn as_type( + vm: &BexVm, + r#type: &super::view::$view_ns::Type<'_>, + ) -> Result { + check_kind_invariant(vm, r#type._ty(), baml_type::type_kind::TypeKind::$kind) } }; } impl BamlClassClassType for PackageReflectImpl { - impl_as_type!(BamlClassClassType); + impl_as_type!(Class, class); - fn fields(vm: &mut BexVm, r#type: &Value) -> Vec { - let (class, args) = reflected_class(vm, *r#type); - class + fn fields(vm: &mut BexVm, r#type: &Value) -> Result, crate::errors::VmRustFnError> { + let (class, args) = reflected_class(vm, *r#type)?; + Ok(class .fields .iter() .map(|field| { @@ -1487,27 +1601,28 @@ impl BamlClassClassType for PackageReflectImpl { } .to_value(vm) }) - .collect() + .collect()) } - fn meta(vm: &mut BexVm, r#type: &Value) -> Value { - let (class, _) = reflected_class(vm, *r#type); - alloc_meta( + fn meta(vm: &mut BexVm, r#type: &Value) -> Result { + let (class, _) = reflected_class(vm, *r#type)?; + Ok(alloc_meta( vm, class.alias.as_deref(), class.description.as_deref(), class.docstring.as_deref(), &class.other, - ) + )) } } impl BamlClassEnumType for PackageReflectImpl { - impl_as_type!(BamlClassEnumType); + impl_as_type!(Enum, r#enum); - fn values(vm: &mut BexVm, r#type: &Value) -> Vec { - let enm = reflected_enum(vm, *r#type); - enm.variants + fn values(vm: &mut BexVm, r#type: &Value) -> Result, crate::errors::VmRustFnError> { + let enm = reflected_enum(vm, *r#type)?; + Ok(enm + .variants .iter() .map(|variant| { let name = Value::object(vm.alloc_string(variant.name.as_str())); @@ -1520,72 +1635,86 @@ impl BamlClassEnumType for PackageReflectImpl { ); copy::r#enum::Value { name, meta }.to_value(vm) }) - .collect() + .collect()) } - fn meta(vm: &mut BexVm, r#type: &Value) -> Value { - let enm = reflected_enum(vm, *r#type); - alloc_meta( + fn meta(vm: &mut BexVm, r#type: &Value) -> Result { + let enm = reflected_enum(vm, *r#type)?; + Ok(alloc_meta( vm, enm.alias.as_deref(), enm.description.as_deref(), enm.docstring.as_deref(), &enm.other, - ) + )) } } impl BamlClassUnionType for PackageReflectImpl { - impl_as_type!(BamlClassUnionType); + impl_as_type!(Union, union); - fn member_types(vm: &mut BexVm, r#type: &Value) -> Vec { - let bex_vm_types::RealizedTy::Union(members, _) = reflected_ty(vm, *r#type) else { - unreachable!("union.Type receiver must wrap a union type") + fn member_types( + vm: &mut BexVm, + r#type: &Value, + ) -> Result, crate::errors::VmRustFnError> { + let ty = reflected_ty(vm, *r#type, baml_type::type_kind::TypeKind::Union)?; + let bex_vm_types::RealizedTy::Union(members, _) = ty else { + unreachable!("a Union-classified type is RealizedTy::Union") }; - members + Ok(members .into_iter() .map(|ty| Value::object(vm.alloc_type(bex_vm_types::types::TypeValue::new(ty)))) - .collect() + .collect()) } } impl BamlClassArrayType for PackageReflectImpl { - impl_as_type!(BamlClassArrayType); + impl_as_type!(Array, array); - fn element_type(vm: &mut BexVm, r#type: &Value) -> Value { - let bex_vm_types::RealizedTy::List(element, _) = reflected_ty(vm, *r#type) else { - unreachable!("array.Type receiver must wrap an array type") + fn element_type(vm: &mut BexVm, r#type: &Value) -> Result { + let ty = reflected_ty(vm, *r#type, baml_type::type_kind::TypeKind::Array)?; + let bex_vm_types::RealizedTy::List(element, _) = ty else { + unreachable!("an Array-classified type is RealizedTy::List") }; - Value::object(vm.alloc_type(bex_vm_types::types::TypeValue::new(*element))) + Ok(Value::object( + vm.alloc_type(bex_vm_types::types::TypeValue::new(*element)), + )) } } impl BamlClassMapType for PackageReflectImpl { - impl_as_type!(BamlClassMapType); + impl_as_type!(Map, map); - fn key_type(vm: &mut BexVm, r#type: &Value) -> Value { - let bex_vm_types::RealizedTy::Map { key, .. } = reflected_ty(vm, *r#type) else { - unreachable!("map.Type receiver must wrap a map type") + fn key_type(vm: &mut BexVm, r#type: &Value) -> Result { + let ty = reflected_ty(vm, *r#type, baml_type::type_kind::TypeKind::Map)?; + let bex_vm_types::RealizedTy::Map { key, .. } = ty else { + unreachable!("a Map-classified type is RealizedTy::Map") }; - Value::object(vm.alloc_type(bex_vm_types::types::TypeValue::new(*key))) + Ok(Value::object( + vm.alloc_type(bex_vm_types::types::TypeValue::new(*key)), + )) } - fn value_type(vm: &mut BexVm, r#type: &Value) -> Value { - let bex_vm_types::RealizedTy::Map { value, .. } = reflected_ty(vm, *r#type) else { - unreachable!("map.Type receiver must wrap a map type") + fn value_type(vm: &mut BexVm, r#type: &Value) -> Result { + let ty = reflected_ty(vm, *r#type, baml_type::type_kind::TypeKind::Map)?; + let bex_vm_types::RealizedTy::Map { value, .. } = ty else { + unreachable!("a Map-classified type is RealizedTy::Map") }; - Value::object(vm.alloc_type(bex_vm_types::types::TypeValue::new(*value))) + Ok(Value::object( + vm.alloc_type(bex_vm_types::types::TypeValue::new(*value)), + )) } } impl BamlClassFunctionType for PackageReflectImpl { - impl_as_type!(BamlClassFunctionType); + impl_as_type!(Function, function); - fn params(vm: &mut BexVm, r#type: &Value) -> Vec { - let bex_vm_types::RealizedTy::Function { params, .. } = reflected_ty(vm, *r#type) else { - unreachable!("function.Type receiver must wrap a function type") + fn params(vm: &mut BexVm, r#type: &Value) -> Result, crate::errors::VmRustFnError> { + let ty = reflected_ty(vm, *r#type, baml_type::type_kind::TypeKind::Function)?; + let bex_vm_types::RealizedTy::Function { params, .. } = ty else { + unreachable!("a Function-classified type is RealizedTy::Function") }; - params + Ok(params .into_iter() .map(|param| { let name = opt_string(vm, param.name.as_ref().map(baml_type::Name::as_str)); @@ -1599,29 +1728,44 @@ impl BamlClassFunctionType for PackageReflectImpl { } .to_value(vm) }) - .collect() + .collect()) } - fn return_type(vm: &mut BexVm, r#type: &Value) -> Value { - let bex_vm_types::RealizedTy::Function { ret, .. } = reflected_ty(vm, *r#type) else { - unreachable!("function.Type receiver must wrap a function type") + fn return_type(vm: &mut BexVm, r#type: &Value) -> Result { + let ty = reflected_ty(vm, *r#type, baml_type::type_kind::TypeKind::Function)?; + let bex_vm_types::RealizedTy::Function { ret, .. } = ty else { + unreachable!("a Function-classified type is RealizedTy::Function") }; - Value::object(vm.alloc_type(bex_vm_types::types::TypeValue::new(*ret))) + Ok(Value::object( + vm.alloc_type(bex_vm_types::types::TypeValue::new(*ret)), + )) } } impl BamlClassInterfaceType for PackageReflectImpl { - impl_as_type!(BamlClassInterfaceType); - - fn implemented_by(vm: &BexVm, r#type: &Value, other: &Value) -> bool { - ::implemented_by(vm, r#type, other) + impl_as_type!(Interface, interface); + + #[expect( + clippy::used_underscore_items, + reason = "the generated view accessor is named for the `_ty` field it reads" + )] + fn implemented_by( + vm: &BexVm, + r#type: &super::view::interface::Type<'_>, + other: &Value, + ) -> Result { + let ty_value = + check_kind_invariant(vm, r#type._ty(), baml_type::type_kind::TypeKind::Interface)?; + Ok(::implemented_by( + vm, &ty_value, other, + )) } } impl BamlClassLiteralType for PackageReflectImpl { - impl_as_type!(BamlClassLiteralType); + impl_as_type!(Literal, literal); } impl BamlClassPrimitiveType for PackageReflectImpl { - impl_as_type!(BamlClassPrimitiveType); + impl_as_type!(Primitive, primitive); } diff --git a/baml_language/crates/bex_vm/src/type_context.rs b/baml_language/crates/bex_vm/src/type_context.rs index 24bf45e7e4e..92e7596342c 100644 --- a/baml_language/crates/bex_vm/src/type_context.rs +++ b/baml_language/crates/bex_vm/src/type_context.rs @@ -43,7 +43,7 @@ impl TypeContext for BexVm { /// pointing at it. /// /// This is one of the few places a name legitimately enters the runtime: - /// the algebra's `baml.AnyFunction` special case is spelled as a name in + /// the algebra's `reflect.AnyFunction` special case is spelled as a name in /// the algebra's own source. It resolves through the package surfaces — /// never by content-addressing a guess — so the head it returns carries the /// declaration's real tag and pointer. diff --git a/baml_language/crates/bex_vm/src/vm.rs b/baml_language/crates/bex_vm/src/vm.rs index 036eb033e74..913cffecc27 100644 --- a/baml_language/crates/bex_vm/src/vm.rs +++ b/baml_language/crates/bex_vm/src/vm.rs @@ -1851,6 +1851,18 @@ impl BexVm { if count == 0 { return Ok(TakenTypeArgs::default()); } + // Every type-operand position's contract is + // `reflect.Type | reflect.TypeView`; a kind view converts at this + // boundary to the `type` value it wraps, so everything downstream + // sees `Object::Type` only. + for slot in start..end { + let value = self.stack[StackIndex::from_raw(slot)]; + if let Some(ty_value) = + crate::package_reflect::type_kinds::as_view_type_value(self, value) + { + self.stack[StackIndex::from_raw(slot)] = ty_value; + } + } // A type built only from compiled declarations needs no per-frame // carrier: every consumer can find those declarations from the program // index, and they never move. Anything naming a runtime declaration @@ -2330,7 +2342,7 @@ impl BexVm { /// read off the declaration itself. /// /// The one name→head channel inside the VM, for the boundaries that - /// genuinely start from a name (the algebra's `baml.AnyFunction` case, host + /// genuinely start from a name (the algebra's `reflect.AnyFunction` case, host /// conversion, codegen FQN constants). Everything interior already holds a /// head and must deref it instead: content-addressing a name into a tag /// would fabricate an identity rather than resolve one, and cannot see a @@ -2615,6 +2627,9 @@ impl BexVm { /// `Spawn`) consume them this way. fn ensure_pop_type(&mut self) -> Result { let value = self.stack.ensure_pop(); + // A kind view converts to the `type` value it wraps at this boundary. + let value = + crate::package_reflect::type_kinds::as_view_type_value(self, value).unwrap_or(value); let ptr = self.as_object_ptr(value, ObjectType::Type)?; match self.get_object(ptr) { Object::Type(type_value) => Ok(type_value.ty.clone()), @@ -3176,16 +3191,13 @@ impl BexVm { ObjectType::of(other) ), }, - // A `type` value reports its precise sealed reflection-kind class. - // Each kind class is a subtype of the `type` carrier. - Object::Type(type_value) => { - let kind = baml_type::type_kind::classify_type(&type_value.ty); - let name = kind.class_name(); - let head = self.declaration_head(&name).unwrap_or_else(|| { - unreachable!("reflection kind class `{name}` is declared by the stdlib") - }); - ConcreteRealizedTy::Class(head, Vec::new(), TyAttr::default()) - } + // A `type` value's concrete type is the `reflect.Type` metatype + // itself. The nine kind views are ordinary wrapper classes whose + // instances take the `Object::Instance` arm above; nothing about a + // type value's membership depends on classifying its payload. + Object::Type(_) => ConcreteRealizedTy::Type { + attr: TyAttr::default(), + }, // Arrays/maps carry their element/key/value types, so the faithful // `list` / `map` is reconstructed from the value itself. Object::Array(arr) => { @@ -9008,6 +9020,12 @@ impl BexVm { OpCode::RuntimeIsType => { let expected_value = self.stack.ensure_pop(); + // A kind view filters as the `type` value it wraps. + let expected_value = crate::package_reflect::type_kinds::as_view_type_value( + self, + expected_value, + ) + .unwrap_or(expected_value); let value = self.stack.ensure_pop(); // `is unreflect(t)` filters on *nominal* identity: the // scrutinee's declaration must be the one `t` denotes, at diff --git a/baml_language/crates/bex_vm_types/src/errors.rs b/baml_language/crates/bex_vm_types/src/errors.rs index 839682eb888..34d2726a9e4 100644 --- a/baml_language/crates/bex_vm_types/src/errors.rs +++ b/baml_language/crates/bex_vm_types/src/errors.rs @@ -54,7 +54,9 @@ pub enum VmPanic { #[error("operation cancelled")] Cancelled, - /// A user-caused panic from `baml.sys.panic`. + /// A user-caused panic from `baml.sys.panic`, and the stdlib's panic of + /// record for a user-violated native invariant (e.g. a reflection kind + /// view's `_ty` field overwritten with a type of a different kind). #[error("baml.sys.panic: {message}")] UserPanic { message: String },