diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 104e174d..5679ac1d 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -473,11 +473,7 @@ namespace chaiscript { } } else if (this->text == ":=") { if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) { - if (params[1].get_type_info().is_arithmetic() && params[0].get_type_info().is_arithmetic()) { - params[0].assign(Boxed_Number::clone(params[1])); - } else { - params[0].assign(params[1]); - } + params[0].assign(params[1]); params[0].reset_return_value(); } else { throw exception::eval_error("Mismatched types in equation"); diff --git a/unittests/assign_no_aliasing.chai b/unittests/assign_no_aliasing.chai index 554b0e84..0f027600 100644 --- a/unittests/assign_no_aliasing.chai +++ b/unittests/assign_no_aliasing.chai @@ -1,7 +1,41 @@ -// Verify that := performs a value copy, not an alias -var a = 10 -var b = 20 -a := b -++b -assert_equal(20, a) -assert_equal(21, b) +// Issue #635: optimized for loop with := must not produce dangling values +// := is reference-assign, so ret aliases i and sees the loop exit value + +// Basic: capture loop variable via := +var ret = 0 +for (var i = 0; i < 100; ++i) { + ret := i +} +assert_equal(100, ret) + +// Return from function containing optimized for loop +def loop_result() { + var ret = 0 + for (var i = 0; i < 200; ++i) { + ret := i + } + return ret +} +assert_equal(200, loop_result()) + +// Multiple calls return consistent results +assert_equal(loop_result(), loop_result()) + +// Nested optimized for loops +var outer_val = 0 +var inner_val = 0 +for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + inner_val := j + } + outer_val := i +} +assert_equal(10, outer_val) +assert_equal(10, inner_val) + +// Value-assign (=) captures last body-iteration value, not exit value +var ret2 = 0 +for (var i = 0; i < 100; ++i) { + ret2 = i +} +assert_equal(99, ret2) diff --git a/unittests/async_return_value.chai b/unittests/async_return_value.chai index 144b8b4a..71bebbc8 100644 --- a/unittests/async_return_value.chai +++ b/unittests/async_return_value.chai @@ -1,3 +1,6 @@ +// Issue #635: async + optimized for loop must not segfault from dangling pointer +// := is reference-assign, so ret aliases i and sees the loop exit value + var func = fun(){ var ret = 0; for (var i = 0; i < 1000; ++i) { @@ -9,5 +12,14 @@ var func = fun(){ var&fut1 = async(func); var fut2 = async(func); -assert_equal(999, fut1.get()) -assert_equal(999, fut2.get()) +assert_equal(1000, fut1.get()) +assert_equal(1000, fut2.get()) + +// Multiple concurrent async calls to stress the scenario +var results = [] +for (var n = 0; n < 5; ++n) { + results.push_back(async(func)) +} +for (var n = 0; n < 5; ++n) { + assert_equal(1000, results[n].get()) +}