diff --git a/CMakeLists.txt b/CMakeLists.txt index 65f97ca..da60b6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,3 +80,4 @@ set_property(TEST invalid_not_bridge.frank PROPERTY WILL_FAIL true) set_property(TEST region_bad_1.frank PROPERTY WILL_FAIL true) set_property(TEST region_bad_2.frank PROPERTY WILL_FAIL true) set_property(TEST fail_cross_region_ref.frank PROPERTY WILL_FAIL true) +set_property(TEST region_close_fail_1.frank PROPERTY WILL_FAIL true) diff --git a/docs/builtin.md b/docs/builtin.md index 92bc90e..ab7830e 100644 --- a/docs/builtin.md +++ b/docs/builtin.md @@ -44,7 +44,7 @@ Forces the given region to close by invalidating all local references into to re This function will also correct all dirty LRCs. -#### `try_close(reg)` +#### `is_closed(reg)` Checks if the given region can be closed. If the LRC is dirty or subreagions are open, it will correct all dirty LRCs. diff --git a/src/rt/core/builtin.cc b/src/rt/core/builtin.cc index 55cac70..edb3670 100644 --- a/src/rt/core/builtin.cc +++ b/src/rt/core/builtin.cc @@ -300,7 +300,7 @@ namespace rt::core close_function_impl(frame, args, true); return std::nullopt; }); - add_builtin("try_close", [](auto frame, auto args) { + add_builtin("is_closed", [](auto frame, auto args) { auto result = close_function_impl(frame, args, false); auto result_obj = rt::get_bool(result); // The return will be linked to the frame by the interpreter, but the RC diff --git a/src/rt/objects/region.cc b/src/rt/objects/region.cc index 574e0e7..fdf84ed 100644 --- a/src/rt/objects/region.cc +++ b/src/rt/objects/region.cc @@ -308,6 +308,11 @@ namespace rt::objects Region::is_ancestor(dst_reg, to_close_reg)); if (invalidate) { + if (e.key == PrototypeField) + { + ui::error("Can't close the region due to this prototype", e); + } + auto old = src->set(e.key, nullptr); assert(old == dst); add_reference(src, nullptr); diff --git a/tests/regions/region_close_1.frank b/tests/regions/region_close_1.frank index 9f1ad80..abae05c 100644 --- a/tests/regions/region_close_1.frank +++ b/tests/regions/region_close_1.frank @@ -14,8 +14,8 @@ lref2 = r2.b.c # r2.LRC is now 3, from: r2, lref1, lref2 -# Fail `try_close()` -if try_close(r2): +# Fail `is_closed()` +if is_closed(r2): unreachable() # Force close diff --git a/tests/regions/region_close_2.frank b/tests/regions/region_close_2.frank index eefc9d1..86a85b3 100644 --- a/tests/regions/region_close_2.frank +++ b/tests/regions/region_close_2.frank @@ -9,8 +9,8 @@ r1.r2.b = {} # r2.LRC is now 0 # r2.LRC will be 1, from the value on the stack -# Succeed `try_close()` -if try_close(r1.r2): +# Succeed `is_closed()` +if is_closed(r1.r2): pass() else: unreachable() diff --git a/tests/regions/region_close_3.frank b/tests/regions/region_close_3.frank index 7ba5348..a1831d9 100644 --- a/tests/regions/region_close_3.frank +++ b/tests/regions/region_close_3.frank @@ -21,8 +21,8 @@ lref2 = r2.b.c freeze(r2.b) r2 = None -# Succeed `try_close()` after LRC cleaning -if try_close(r1.r2): +# Succeed `is_closed()` after LRC cleaning +if is_closed(r1.r2): pass() else: unreachable() diff --git a/tests/regions/region_close_4.frank b/tests/regions/region_close_4.frank index 564709a..966e9c2 100644 --- a/tests/regions/region_close_4.frank +++ b/tests/regions/region_close_4.frank @@ -9,7 +9,7 @@ r0.r1.r2.r3.a = {} lref = r0.r1.r2.r3.a # Fail try close, since r3 is open -if try_close(r0.r1): +if is_closed(r0.r1): unreachable() # Force close diff --git a/tests/regions/region_close_5.frank b/tests/regions/region_close_5.frank index 4559ff1..76fba9f 100644 --- a/tests/regions/region_close_5.frank +++ b/tests/regions/region_close_5.frank @@ -1,9 +1,9 @@ # Helper to close the region while a ref is on the stack def close_and_get(r1): # Check that the region is currently open - if try_close(r1.r2): + if is_closed(r1.r2): unreachable() - + # Force close it close(r1.r2) diff --git a/tests/regions/region_close_fail_1.frank b/tests/regions/region_close_fail_1.frank new file mode 100644 index 0000000..c316afc --- /dev/null +++ b/tests/regions/region_close_fail_1.frank @@ -0,0 +1,11 @@ +# Construct regions +r1 = Region() + +# Create a local string to share the `String` prototype +local_string = "Hello Local" + +# This also moves the `String` prototype +r1.something = "Important string" + +# This should fail, since implicit freezing is disabled +close(r1)