Add tests for #421: switch with type_conversion lifetime bug

Add both a compiled C++ test (with registered type_conversion) and a
pure ChaiScript test (with dynamic objects and custom == operator) to
verify that switch case comparisons properly manage object lifetimes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
leftibot 2026-04-10 18:18:25 -06:00
parent 78d2de0ccf
commit a329be16ad
2 changed files with 144 additions and 0 deletions

View File

@ -1304,3 +1304,97 @@ TEST_CASE("Test if non copyable/movable types can be registered") {
chai.add(chaiscript::user_type<Nothing>(), "Nothing");
chai.add(chaiscript::constructor<Nothing()>(), "Nothing");
}
// Issue #421: Class with type_conversion from int and "==" operator
// causes switch statement to compare destroyed objects.
// The switch case comparison must use Function_Push_Pop to properly
// manage the lifetime of temporaries created by type conversions.
TEST_CASE("Issue #421 - Switch with type_conversion does not compare destroyed objects") {
struct MyType {
int value;
explicit MyType(int v) : value(v) {}
};
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
chai.add(chaiscript::user_type<MyType>(), "MyType");
chai.add(chaiscript::constructor<MyType(int)>(), "MyType");
chai.add(chaiscript::fun(&MyType::value), "value");
chai.add(chaiscript::fun([](const MyType &a, const MyType &b) { return a.value == b.value; }), "==");
chai.add(chaiscript::type_conversion<int, MyType>([](const int &i) { return MyType(i); }));
// Test switch with type conversion - the case integer literals must be
// converted to MyType via the registered conversion before comparison.
// Without Function_Push_Pop, the converted temporaries may be destroyed
// before the == operator can compare them.
CHECK(chai.eval<int>(R"({
var result = 0
var obj = MyType(2)
switch(obj) {
case (1) {
result = 1
break
}
case (2) {
result = 2
break
}
case (3) {
result = 3
break
}
}
result
})") == 2);
// Test fall-through with type conversion
CHECK(chai.eval<int>(R"({
var total = 0
var obj = MyType(2)
switch(obj) {
case (1) {
total += 1
}
case (2) {
total += 2
}
case (3) {
total += 4
}
}
total
})") == 6);
// Test matching the first case
CHECK(chai.eval<int>(R"({
var result = 0
var obj = MyType(1)
switch(obj) {
case (1) {
result = 10
break
}
case (2) {
result = 20
break
}
}
result
})") == 10);
// Test no match
CHECK(chai.eval<int>(R"({
var result = 0
var obj = MyType(5)
switch(obj) {
case (1) {
result = 1
break
}
case (2) {
result = 2
break
}
}
result
})") == 0);
}

View File

@ -0,0 +1,50 @@
// Test for issue #421: switch statement with custom == operator on
// dynamic objects must properly manage object lifetimes during
// case comparisons.
class MyType {
var value
def MyType(v) { this.value = v }
}
def `==`(a, b) : a.is_type("MyType") && b.is_type("MyType") {
return a.value == b.value
}
var result = 0
var obj = MyType(2)
switch(obj) {
case (MyType(1)) {
result = 1
break
}
case (MyType(2)) {
result = 2
break
}
case (MyType(3)) {
result = 3
break
}
}
assert_equal(result, 2)
// Also test fall-through with custom == operator
var total = 0
var obj2 = MyType(2)
switch(obj2) {
case (MyType(1)) {
total += 1
}
case (MyType(2)) {
total += 2
}
case (MyType(3)) {
total += 4
}
}
assert_equal(total, 6)