aboutsummaryrefslogtreecommitdiff
path: root/docs/history/18-aliases/notes.md
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
commitecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch)
tree70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /docs/history/18-aliases/notes.md
a
Diffstat (limited to 'docs/history/18-aliases/notes.md')
-rw-r--r--docs/history/18-aliases/notes.md13
1 files changed, 13 insertions, 0 deletions
diff --git a/docs/history/18-aliases/notes.md b/docs/history/18-aliases/notes.md
new file mode 100644
index 0000000..eb0afc0
--- /dev/null
+++ b/docs/history/18-aliases/notes.md
@@ -0,0 +1,13 @@
+# tracked aliases
+
+the open end was untracked aliases: `let q = p + 0` or `let c = list[1]` became a plain word, and it dangled once the owner was freed.
+
+## what landed
+
+the analyzer reuses the child link. a pointer-typed value computed from a tracked variable is stored as `S_CHILD` with no `lown` bit: `p + k` and `p - k` (not a pointer difference), `p.field` when the field is a pointer, and `p[i]` when the element is a pointer. untyped `p + k` on an owned object counts too, since that variable is a pointer even when its type is still `word`. using the alias after the owner dies is the same error a child already gets, "used after it was given away". an alias is not an owner, so it can be copied, incremented and passed on, and the scope-end free doesn't free it. an alias that outlives the block its owner was declared in is marked dead when that block closes.
+
+`free` no longer returns the block to the buddy lists. it leaves the header marked free and the check word in place, so `isobj` fails and a second free is a no-op, but the bytes stay. the mark treats a word with that check word and a free flag as a quarantined object and traces it. the sweep merges a quarantined block back only when nothing pointed at it. a reachable one stays quarantined, still intact. the compiler zeros a local after the free it inserts, and `start` scrubs the data stack and collects once compilation is done, so the compiler's own garbage doesn't sit on the heap forever.
+
+## tests
+
+`tests/alias.zc` uses an alias while the owner is alive (arithmetic, a pointer field, an index). `tests/errors/alias_plus.zc`, `alias_index.zc`, `alias_field.zc` and `alias_scope.zc` are the uses after the owner dies. `tests/quarantine.zc` is unchecked: after `free`, churn that would have reused the block, the old words are still there, `free` through the alias doesn't smash them, and a collection while an exact pointer is still live keeps the block. an interior pointer (`p + k` with `k` not zero) does not match the check word, so a later collection reclaims that block; exact pointers (`p + 0`, a pointer field, a pointer element) keep it. an untyped index stays a plain word, since the element might be an integer, and quarantine is what covers that case.