`toString` missing on `TryIntoJs`
Describe the bug
toString method is missing from value constructed with TryIntoJs
To Reproduce
Minimal example:
use boa_engine::{Context, IntoJsFunctionCopied, Source, js_string, value::TryIntoJs};
fn main() {
let mut context = Context::default();
let get_foo_bar = get_foo_bar.into_js_function_copied(&mut context);
context
.register_global_builtin_callable(js_string!("getFooBar"), 0, get_foo_bar)
.unwrap();
let value = context.eval(Source::from_bytes("getFooBar()")).unwrap();
println!(
"{}",
value
.to_string(&mut context)
.unwrap()
.to_std_string_escaped()
);
}
#[derive(TryIntoJs)]
struct FooBar {
foo: usize,
bar: usize,
}
fn get_foo_bar() -> FooBar {
FooBar { foo: 0, bar: 1 }
}
The error message:
thread 'main' panicked at delight_cli/src/main.rs:47:14:
called `Result::unwrap()` on an `Err` value: JsError { inner: Native(JsNativeError { kind: Type, message: "cannot convert object to primitive value", cause: None, .. }), backtrace: None }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Expected behavior
It works without throwing if using js_object:
fn get_foo_bar(context: &mut Context) -> JsObject {
// FooBar { foo: 0, bar: 1 }
js_object!({"foo": 0, "bar": 1}, context)
}
// [object Object]
Build environment
- OS: NixOS Linux
- Version: 25.05
- Target triple: x86_64-unknown-linux-gnu
- Rustc version: rustc 1.88.0 (6b00bc388 2025-06-23)
Additional context
Using the git version of boa:
[[package]]
name = "boa_engine"
version = "0.20.0"
source = "git+https://github.com/boa-dev/boa#488ef539f70c7e80d86b568f5d60e6822eb8f261"
...
I tried replicating this and got the same result. With some additional print statements I also was able to show this:
sfb: Source { reader: UTF8Input { input: Bytes { inner: [103, 101, 116, 70, 111, 111, 66, 97, 114, 40, 41] } }, path: None } value Ok(JsValue(Object(("boa_engine::object::jsobject::ErasedObjectData") 0x55F1A854D6F8)))
I am not sure what this means but hopefully this info helps the next person to touch this issue.
The prints in question:
fn main() {
let mut context = Context::default();
let get_foo_bar = get_foo_bar.into_js_function_copied(&mut context);
context
.register_global_builtin_callable(js_string!("getFooBar"), 0, get_foo_bar)
.unwrap();
let sfb = Source::from_bytes("getFooBar()");
println!("sfb: {:?}", sfb);
let value = context.eval(sfb).unwrap();
println!(
"{}",
value
.to_string(&mut context)
.unwrap()
.to_std_string_escaped()
);
}