aboutsummaryrefslogtreecommitdiff
path: root/tests/conformance/6-ownership
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 00:53:25 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 00:53:25 +0330
commit0e333abab5d684be37043196b4c006b71bdf850e (patch)
treed7e6664befd82268d2681c817542b3592bab379d /tests/conformance/6-ownership
parentbench: sieve.zc and trees.zc take namespace and include rt, so run.py's check... (diff)
parenttodo: destructors item closed with what landed; what is left (reassignment fr... (diff)
merge work/dtor: destructors (drop on any heap value, heap(), struct drop, collector drops once with resurrection, freed blocks forget their drop)
Diffstat (limited to 'tests/conformance/6-ownership')
-rw-r--r--tests/conformance/6-ownership/drop_ends_in_o3_rejected.zc9
-rw-r--r--tests/conformance/6-ownership/drop_forms.zc14
-rw-r--r--tests/conformance/6-ownership/drop_free_in_o3_rejected.zc10
-rw-r--r--tests/conformance/6-ownership/drop_gc_once.zc17
-rw-r--r--tests/conformance/6-ownership/drop_gc_resurrect.zc21
-rw-r--r--tests/conformance/6-ownership/drop_heap_values.zc15
-rw-r--r--tests/conformance/6-ownership/drop_in_o3_rejected.zc9
-rw-r--r--tests/conformance/6-ownership/drop_parent_before_child.zc17
-rw-r--r--tests/conformance/6-ownership/drop_reused_address.zc22
-rw-r--r--tests/conformance/6-ownership/drop_set_late.zc10
-rw-r--r--tests/conformance/6-ownership/drop_set_twice.zc10
-rw-r--r--tests/conformance/6-ownership/drop_temporary_statement.zc13
-rw-r--r--tests/conformance/6-ownership/drop_value_and_type.zc11
13 files changed, 178 insertions, 0 deletions
diff --git a/tests/conformance/6-ownership/drop_ends_in_o3_rejected.zc b/tests/conformance/6-ownership/drop_ends_in_o3_rejected.zc
new file mode 100644
index 0000000..4f29537
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_ends_in_o3_rejected.zc
@@ -0,0 +1,9 @@
+// expect error: r: has drop and can't end inside an o3 region
+// destructors, o3: a droppable value's lifetime can't end inside an o3 scope
+include rt;
+struct res { int fd; void drop() { rt.put_s("closed"); } }
+fn main() {
+ o3 { res* r = rt.new(res); r.fd = 1; }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_forms.zc b/tests/conformance/6-ownership/drop_forms.zc
new file mode 100644
index 0000000..e9e4c07
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_forms.zc
@@ -0,0 +1,14 @@
+// expect: 15i'm free as a bird! 15/body y7 x g
+// destructors 2: drop(v, f) and v.drop(f) return v, v.drop = f; is a statement; this is the value. the spec example drops its temporary at the end of the statement
+include rt;
+fn main() {
+ rt.put_n(*heap(15).drop(fn() { rt.put_s("i'm free as a bird! "); rt.put_n(*this); }));
+ rt.put_c(10);
+ let g = drop(heap(1), fn() { rt.put_s("g "); });
+ let x = rt.new(int).drop(fn() { rt.put_s("x "); });
+ let y = rt.new(int); y.drop = fn() { rt.put_s("y"); rt.put_n(*this); rt.put_s(" "); };
+ *y = 7;
+ rt.put_s("body ");
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_free_in_o3_rejected.zc b/tests/conformance/6-ownership/drop_free_in_o3_rejected.zc
new file mode 100644
index 0000000..b318d1f
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_free_in_o3_rejected.zc
@@ -0,0 +1,10 @@
+// expect error: x: has drop and can't end inside an o3 region
+// destructors, o3: an explicit free of a droppable value inside o3 is an error
+include rt;
+fn main() {
+ int* x = rt.new(int);
+ x.drop = fn() { rt.put_s("a"); };
+ o3 { rt.free(x); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_gc_once.zc b/tests/conformance/6-ownership/drop_gc_once.zc
new file mode 100644
index 0000000..abe1d95
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_gc_once.zc
@@ -0,0 +1,17 @@
+// expect: 0 drop 7 1 1 1 0/
+// destructors 6: the collector runs an unreachable value's drop after the sweep, exactly once; later collections never run it again
+include rt;
+int n;
+word g;
+fn make() { g = drop(heap(7), fn() { n++; rt.put_s("drop "); rt.put_n(*this); rt.put_c(32); }); return 0; }
+fn main() {
+ make();
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ g = 0;
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ rt.gc(); rt.put_n(n); rt.put_c(32);
+ rt.put_n(rt.dcount); rt.put_c(10); // its entry is gone with the block
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_gc_resurrect.zc b/tests/conformance/6-ownership/drop_gc_resurrect.zc
new file mode 100644
index 0000000..d964eba
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_gc_resurrect.zc
@@ -0,0 +1,21 @@
+// expect: drop 8 alive 8 1 gone 1/
+// destructors 6: a drop that stores this somewhere reachable revives the value; it stays usable, its drop never runs again, and a later collection reclaims it
+include rt;
+int n;
+word g, saved;
+unchecked int keep(word p) { saved = p; return 0; }
+fn make() { g = drop(heap(8), fn() { n++; keep(this); rt.put_s("drop "); rt.put_n(*this); rt.put_c(32); }); return 0; }
+fn main() {
+ make();
+ g = 0;
+ rt.gc();
+ rt.gc();
+ unchecked { word p = saved; rt.put_s("alive "); rt.put_n(p[0]); rt.put_c(32); }
+ rt.put_n(n); rt.put_c(32);
+ saved = 0;
+ rt.gc(); rt.gc();
+ rt.put_s("gone "); rt.put_n(n);
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_heap_values.zc b/tests/conformance/6-ownership/drop_heap_values.zc
new file mode 100644
index 0000000..63d07c9
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_heap_values.zc
@@ -0,0 +1,15 @@
+// expect: 10 hi 2 4 9 /
+// destructors 1: heap(v) boxes an int, a string and a struct into a fresh owned block sized to the value
+include rt;
+struct foo { int bar; int baz; }
+fn main() {
+ int* a = heap(10);
+ char* s = heap("hi");
+ foo v; v.bar = 4; v.baz = 9;
+ foo* f = heap(v);
+ rt.put_n(*a); rt.put_c(32); rt.put_s(s); rt.put_c(32); rt.put_n(rt.len_w(s)); rt.put_c(32);
+ rt.put_n(f.bar); rt.put_c(32); rt.put_n(f.baz); rt.put_c(32);
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_in_o3_rejected.zc b/tests/conformance/6-ownership/drop_in_o3_rejected.zc
new file mode 100644
index 0000000..9095269
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_in_o3_rejected.zc
@@ -0,0 +1,9 @@
+// expect error: a drop can't be set inside an o3 region
+// destructors, o3: setting a drop inside o3 is an error
+include rt;
+fn main() {
+ int* x = rt.new(int);
+ o3 { x.drop = fn() { rt.put_s("a"); }; }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_parent_before_child.zc b/tests/conformance/6-ownership/drop_parent_before_child.zc
new file mode 100644
index 0000000..9f68c52
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_parent_before_child.zc
@@ -0,0 +1,17 @@
+// expect: parent sees 5 child /
+// destructors 3: a child owned by a field drops after its parent's drop returns, so the parent still sees it
+include rt;
+struct node { int* kid; }
+int* seen;
+fn main() {
+ {
+ node* p = rt.new(node);
+ p.drop = fn() { rt.put_s("parent sees "); rt.put_n(*this.kid); rt.put_c(32); };
+ int* k = rt.new(int); k.drop = fn() { rt.put_s("child "); };
+ *k = 5;
+ p.kid = k;
+ }
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_reused_address.zc b/tests/conformance/6-ownership/drop_reused_address.zc
new file mode 100644
index 0000000..97ef21d
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_reused_address.zc
@@ -0,0 +1,22 @@
+// expect: drop 1 same 1 1 0/
+// destructors 9: a freed block's drop and its bits are cleared, so a block reused at the same address runs no old drop
+include rt;
+int n, first;
+int addr(int* p) { return p as int; }
+int clean(int* p) { unbounded { return (p[-4] & (rt.F_HASDROP | rt.F_DROPPED)) == 0; } }
+// the drop is set in a helper, so main has no closure and its locals take no cells from the heap
+int* .u armed() { int* p = rt.new(int); p.drop = fn() { n++; rt.put_s("drop "); }; return p; }
+fn main() {
+ { int* p = armed(); *p = 1; first = addr(p); }
+ rt.put_n(n); rt.put_c(32);
+ {
+ int* q = rt.new(int); *q = 2;
+ if (addr(q) == first) rt.put_s("same "); else rt.put_s("moved ");
+ rt.put_n(clean(q)); rt.put_c(32);
+ }
+ rt.put_n(n); rt.put_c(32);
+ rt.put_n(rt.dcount);
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_set_late.zc b/tests/conformance/6-ownership/drop_set_late.zc
new file mode 100644
index 0000000..9bd8310
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_set_late.zc
@@ -0,0 +1,10 @@
+// expect error: x: drop set after the value was used
+// destructors 2: the drop must be set before the value is first read, reassigned or passed
+include rt;
+fn main() {
+ int* x = rt.new(int);
+ *x = 4;
+ x.drop = fn() { rt.put_s("a"); };
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_set_twice.zc b/tests/conformance/6-ownership/drop_set_twice.zc
new file mode 100644
index 0000000..843694a
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_set_twice.zc
@@ -0,0 +1,10 @@
+// expect error: x: drop is already set
+// destructors 2: a value's drop can be set only once
+include rt;
+fn main() {
+ int* x = rt.new(int);
+ x.drop = fn() { rt.put_s("a"); };
+ x.drop = fn() { rt.put_s("b"); };
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_temporary_statement.zc b/tests/conformance/6-ownership/drop_temporary_statement.zc
new file mode 100644
index 0000000..fd27623
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_temporary_statement.zc
@@ -0,0 +1,13 @@
+// expect: unlocked a b unlocked c /
+// destructors 3: a value nothing holds drops at the end of its full statement; a bound guard drops at block end
+include rt;
+void unlock() { rt.put_s("unlocked "); }
+fn main() {
+ heap(0).drop = fn() { unlock(); };
+ rt.put_s("a ");
+ { let guard = drop(heap(0), fn() { unlock(); }); rt.put_s("b "); }
+ rt.put_s("c ");
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/6-ownership/drop_value_and_type.zc b/tests/conformance/6-ownership/drop_value_and_type.zc
new file mode 100644
index 0000000..2979e4f
--- /dev/null
+++ b/tests/conformance/6-ownership/drop_value_and_type.zc
@@ -0,0 +1,11 @@
+// expect: body value type only-type /
+// destructors 2: a struct body's drop is the default for its type; a value's own drop runs first, then the type's
+include rt;
+struct res { int fd; void drop() { if (this.fd) rt.put_s("type "); else rt.put_s("only-type "); } }
+fn main() {
+ { res* r = rt.new(res); r.drop = fn() { rt.put_s("value "); }; r.fd = 1; rt.put_s("body "); }
+ { res* q = rt.new(res); q.fd = 0; }
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip