From 0c4252daddaff047d4614658b68d38203e88f569 Mon Sep 17 00:00:00 2001 From: leftibot Date: Sat, 11 Apr 2026 14:48:12 -0600 Subject: [PATCH] Fix #405: push_back() on script-created vector has no effect with vector_conversion When both vector_type and vector_conversion are registered, the dispatch scoring treats all parameter mismatches equally. This causes the C++ push_back (for the converted type) to be selected over the built-in one when both have the same number of type differences. The converted function operates on a temporary copy of the vector, silently discarding the mutation. The fix deprioritizes overloads that require type conversion on the first parameter (the object/receiver), ensuring functions matching the receiver type exactly are always tried first. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../dispatchkit/proxy_functions.hpp | 8 ++++ unittests/compiled_tests.cpp | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index fe65ee5a..9830f190 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -798,6 +798,14 @@ namespace chaiscript { ++numdiffs; } } + + // Deprioritize functions whose first parameter (object/receiver) requires + // type conversion: conversions create temporaries, so mutations on the + // converted object are silently lost (issue #405). + if (plist.size() > 1 && !func->get_param_types()[1].bare_equal(plist[0].get_type_info())) { + numdiffs = plist.size(); + } + ordered_funcs.emplace_back(numdiffs, func.get()); } } diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 4c7d96fa..2bcbb587 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -1437,6 +1437,43 @@ TEST_CASE("Issue #421 - Switch with type_conversion does not compare destroyed o })") == 0); } +// Regression test for issue #405: push_back() on script-created vector has +// no effect when vector_conversion is in effect. The bug occurs because +// dispatch selects the C++ push_back for the converted type over the built-in +// one, operating on a temporary copy of the vector. +TEST_CASE("push_back on script vector with vector_conversion (#405)") { + chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser()); + + // Register both vector_type and vector_conversion for std::vector, + // which is the combination that triggers the bug + auto m = std::make_shared(); + chaiscript::bootstrap::standard_library::vector_type>("VectorString", *m); + m->add(chaiscript::vector_conversion>()); + chai.add(m); + + // push_back on an empty script-created vector + CHECK(chai.eval( + "auto x = [];" + "x.push_back(\"Hello\");" + "x.size() == 1" + )); + + // push_back on a script-created vector with initial elements + CHECK(chai.eval( + "auto y = [\"a\", \"b\"];" + "y.push_back(\"c\");" + "y.push_back(\"d\");" + "y.size() == 4" + )); + + // Verify the actual content is preserved + CHECK(chai.eval( + "auto z = [];" + "z.push_back(\"World\");" + "z[0]" + ) == "World"); +} + // Regression test for issue #607: AST_Node_Trace must be a complete type // when used in eval_error's std::vector call_stack member. // This failed to compile with C++20 on clang/libc++ when AST_Node_Trace