Skip to content

Commit 4209a24

Browse files
committed
fix(vm): self referencing closures were crashing the VM
1 parent 3c2c74c commit 4209a24

5 files changed

Lines changed: 25 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- sys:version, has the version of the ArkScript VM
1313

1414
### Changed
15+
- fix a bug related to recursive closures: once a closure was referenced in its own scope, we couldn't convert it to string or compare it against another closure/itself
1516

1617
### Removed
1718

include/Ark/VM/Value/Value.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ namespace Ark
202202
friend ARK_API bool operator!(const Value& A) noexcept;
203203

204204
friend class Ark::VM;
205+
friend class Ark::internal::Closure;
205206
friend class Ark::BytecodeReader;
206207
friend struct std::hash<Ark::Value>;
207208

lib/std

src/arkreactor/VM/Value/Closure.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@ namespace Ark::internal
2929
std::string out = "(";
3030
for (std::size_t i = 0, end = m_scope->m_data.size(); i < end; ++i)
3131
{
32+
const auto& [id, value] = m_scope->m_data[i];
3233
if (i != 0)
3334
out += ' ';
3435

35-
out += '.' + vm.m_state.m_symbols[m_scope->m_data[i].first] + '=';
36-
out += m_scope->m_data[i].second.toString(vm);
36+
out += '.' + vm.m_state.m_symbols[id] + '=';
37+
if (value.valueType() == ValueType::Closure && value.closure().scopePtr() == scopePtr())
38+
out += "Ref(self)";
39+
else
40+
out += value.toString(vm);
3741
}
3842
return out + ")";
3943
}
@@ -43,6 +47,9 @@ namespace Ark::internal
4347
// they do not come from the same closure builder
4448
if (A.m_page_addr != B.m_page_addr)
4549
return false;
50+
// pointers are identical, we are dealing with the same object
51+
if (A.m_scope.get() == B.m_scope.get())
52+
return true;
4653

4754
return *A.m_scope == *B.m_scope;
4855
}

tests/unittests/resources/LangSuite/weird-tests.ark

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,16 @@
118118
(if (> n 1)
119119
((let F (fun (m) (if m m 1))) n))
120120
(set n (+ n 1)) })
121-
(test:eq n 10) }) })
121+
(test:eq n 10) })
122+
123+
(test:case "recursive structure" {
124+
(let make (fun ((mut x)) {
125+
(let _set (fun (y) (set x y)))
126+
(fun (&x &_set) ()) }))
127+
(let closure (make 1))
128+
(closure._set closure)
129+
(test:eq closure closure.x)
130+
(test:eq closure closure.x.x)
131+
(test:eq closure.x closure.x.x)
132+
(test:eq closure closure.x.x.x.x.x)
133+
(test:eq (toString closure) (+ "(.x=Ref(self) ._set=" (toString closure._set) ")")) }) })

0 commit comments

Comments
 (0)