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