aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/analyzer.zc
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 14:57:42 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 14:57:42 +0330
commit0432ac6aefccbc5a9af25bd4ed2d4451611c4ff4 (patch)
treeba312d92bc223e1a4c500134cf1343f7e1f63180 /src/compiler/analyzer.zc
parentmerge work/borrow: borrow returns before definition, borrows clause, borrow m... (diff)
analyzer: an outer owner moved into a deeper container can take it back (loop-built lists); block-end frees name the owner (why 9) in messages and LSP related info
Diffstat (limited to 'src/compiler/analyzer.zc')
-rw-r--r--src/compiler/analyzer.zc38
1 files changed, 36 insertions, 2 deletions
diff --git a/src/compiler/analyzer.zc b/src/compiler/analyzer.zc
index ff6a6c1..a1588e8 100644
--- a/src/compiler/analyzer.zc
+++ b/src/compiler/analyzer.zc
@@ -122,7 +122,7 @@ int shadow_finish(int from) {
while (k < 24) { if ((e[2] >> k) & 1) flags = flags | effect_get(e[1], k); k++; }
if ((flags & (EF_ALIAS | EF_IDENTITY)) && !(flags & EF_UNKNOWN) && !dry) {
tunpack(e[3]); curinc = e[4]; panic = 0;
- errat(); ended_message(e[6], e[7], e[8], e[9]); rt.put_s("; "); rt.put_s(sname[e[1]]); rt.put_s(", defined after this call, returns a borrow of its argument"); errend();
+ errat(); ended_message(e[6], e[7], e[8], e[9], 0); rt.put_s("; "); rt.put_s(sname[e[1]]); rt.put_s(", defined after this call, returns a borrow of its argument"); errend();
}
e = next;
}
@@ -1147,6 +1147,7 @@ int block_close(int save) {
unused_check(save);
exit_vars(fdepth, 1);
lend_drop(fdepth, save);
+ block_end_owners(save);
alias_end(fdepth, save);
while (i < save) { if (lhome[i] >= fdepth) { lstate[i] = S_DEAD; lhome[i] = fdepth - 1; } i++; }
local_drop(save);
@@ -1155,6 +1156,26 @@ int block_close(int save) {
return 0;
}
+// owners freed at this block's end: an outer alias of one, or an outer owner
+// stored into one, dies with it and remembers where (why 9).
+int block_end_owners(int save) {
+ int i = save, j; word info = 0;
+ if (!fchk || !live) return 0;
+ while (i < nloc) {
+ if (lhome[i] >= fdepth && lstate[i] == S_M && lown[i]) {
+ info = 0; j = lbase;
+ while (j < save) {
+ if (lstate[j] == S_CHILD && lroot(j) == i) {
+ if (!info) { info = talloc(6); info[0] = lname[i]; info[1] = lpos[i]; info[2] = tpack(); info[3] = 9; info[4] = 0; info[5] = info[2]; }
+ local_ended[j] = info[2]; local_end_info[j] = info; lstate[j] = S_DEAD;
+ }
+ j++;
+ }
+ }
+ i++;
+ }
+ return 0;
+}
// an alias in an outer block whose owner is about to disappear dies with it
int alias_end(int dep, int save) {
int i, r;
@@ -1532,6 +1553,19 @@ int assigncheck(int k, int i, int rc) {
else lstate[i] = S_PLAIN;
return C_PLAIN;
}
+ // an outer owner moved into a deeper container takes the container back:
+ // head = item after item.next = head. the container leaves its block.
+ if (st == S_CHILD && lown[i] && j >= 0 && lroot(i) == j && lstate[j] == S_M && lown[j]
+ && lhome[j] >= lhome[i] && !local_captured[i] && !local_captured[j]) {
+ int k = lbase;
+ while (k < nloc) { if (k != i && lstate[k] == S_CHILD && lowner[k] == j) lowner[k] = i; k++; }
+ lstate[i] = S_M; lused[i] = 0;
+ lnsz[i] = lnsz[j]; lleaf[i] = lleaf[j];
+ local_ended[i] = 0; local_end_info[i] = 0;
+ end_why = 3; end_whom = lname[i]; end_owner(j); luse(j); ev_put(j, EV_MOVE, i);
+ if (ltag[i] & 15) lstate[i] = ltag[i] & 15;
+ return C_PLAIN;
+ }
if (!empty(st)) {
cerrn(i, "still owns an object; overwriting it would leak it");
return C_PLAIN;
@@ -1587,7 +1621,7 @@ int assigncheck(int k, int i, int rc) {
}
else { end_why = 4; end_whom = lname[i]; end_owner(j); luse(j); ev_put(j, EV_STORE, i); emitown(i); } // storing it gives it away
} else if (js != st) cerrn(j, "its tag doesn't match its container's (both have to be m, u or d)");
- else if (lhome[j] < lhome[r]) cerrn(j, "lives in an outer block than the container it's stored into");
+ else if (lhome[j] < lhome[r] && (r != i || !lown[j] || (local_captured && (local_captured[i] || local_captured[j])))) cerrn(j, "lives in an outer block than the container it's stored into");
else { lstate[j] = S_CHILD; lowner[j] = i; luse(j); ev_put(j, EV_STORE, i); emitown(i); }
return C_PLAIN;
}