From 7324e28f0f0aa42a6790a7a41c988c5d7409d5bb Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 11 Mar 2026 15:48:47 +0300 Subject: [PATCH] js: Backend / unwraping Javascript Objects / TypeError: e.stack.contains is not a function (fixes #10393) --- vlib/v/gen/js/fn.v | 12 ++++++-- vlib/v/gen/js/js.v | 29 +++++++++++++++++-- .../tests/testdata/js_object_field_string.out | 3 ++ .../tests/testdata/js_object_field_string.v | 15 ++++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 vlib/v/gen/js/tests/testdata/js_object_field_string.out create mode 100644 vlib/v/gen/js/tests/testdata/js_object_field_string.v diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index e857ca341..d6ea52126 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -336,11 +336,16 @@ fn (mut g JsGen) method_call(node ast.CallExpr) { name = g.generic_fn_name(node.concrete_types, name) g.write('${name}(') - g.expr(it.left) + g.expr_with_expected_type(it.left, unwrapped_rec_type) g.gen_deref_ptr(it.left_type) g.write(',') for i, arg in it.args { - g.expr(arg.expr) + expected_arg_type := if i < it.expected_arg_types.len { + it.expected_arg_types[i] + } else { + arg.typ + } + g.expr_with_expected_type(arg.expr, expected_arg_type) if i != it.args.len - 1 { g.write(', ') } @@ -441,7 +446,8 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { g.write('${name}(') for i, arg in it.args { - g.expr(arg.expr) + expected_arg_type := if i < it.expected_arg_types.len { it.expected_arg_types[i] } else { arg.typ } + g.expr_with_expected_type(arg.expr, expected_arg_type) if i != it.args.len - 1 { g.write(', ') } diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 5455e0413..7c796976a 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -1882,7 +1882,7 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) { g.write('${tmp}.state = new u8(0);') g.write('${tmp}.data = ') if it.exprs.len == 1 { - g.expr(it.exprs[0]) + g.expr_with_expected_type(it.exprs[0], node.types[0]) } else { // Multi return g.gen_array_init_values(it.exprs) } @@ -1900,7 +1900,7 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) { g.write('throw new ReturnException(') } if it.exprs.len == 1 { - g.expr(it.exprs[0]) + g.expr_with_expected_type(it.exprs[0], node.types[0]) } else { // Multi return g.gen_array_init_values(it.exprs) } @@ -3032,6 +3032,31 @@ fn (mut g JsGen) expr_string(expr ast.Expr) string { return g.out.cut_to(pos).trim_space() } +fn (mut g JsGen) should_wrap_js_selector_rvalue(expr ast.Expr, expected_type ast.Type) bool { + if expected_type == 0 || expected_type.is_ptr() { + return false + } + match expr { + ast.SelectorExpr {} + else { return false } + } + target_sym := g.table.final_sym(g.unwrap_generic(expected_type)) + if target_sym.language == .js || target_sym.name.starts_with('JS.') { + return false + } + return target_sym.kind in shallow_equatables +} + +fn (mut g JsGen) expr_with_expected_type(expr ast.Expr, expected_type ast.Type) { + if g.should_wrap_js_selector_rvalue(expr, expected_type) { + g.write('new ${g.styp(expected_type)}(') + g.expr(expr) + g.write(')') + return + } + g.expr(expr) +} + fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { l_sym := g.table.final_sym(it.left_type) r_sym := g.table.final_sym(it.right_type) diff --git a/vlib/v/gen/js/tests/testdata/js_object_field_string.out b/vlib/v/gen/js/tests/testdata/js_object_field_string.out new file mode 100644 index 000000000..1dc73f774 --- /dev/null +++ b/vlib/v/gen/js/tests/testdata/js_object_field_string.out @@ -0,0 +1,3 @@ +false +false +false diff --git a/vlib/v/gen/js/tests/testdata/js_object_field_string.v b/vlib/v/gen/js/tests/testdata/js_object_field_string.v new file mode 100644 index 000000000..3731ed36b --- /dev/null +++ b/vlib/v/gen/js/tests/testdata/js_object_field_string.v @@ -0,0 +1,15 @@ +fn contains_hello(s string) bool { + return s.contains('hello.v:') +} + +fn get_stack() string { + e := JS.Error{} + return e.stack +} + +fn main() { + e := JS.Error{} + println(e.stack.contains('hello.v:')) + println(contains_hello(e.stack)) + println(get_stack().contains('hello.v:')) +} -- 2.39.5