aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/decl.zc
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 14:58:36 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 14:58:36 +0330
commit2b9e79db9e1f4d1f74c6ca99c794ba4886e9f003 (patch)
treebabe169ad189da172fb9940ab1ec88aa149722ac /src/compiler/decl.zc
parentanalyzer: an outer owner moved into a deeper container can take it back (loop... (diff)
analyzer: infer .u from returns of fresh objects in the body (prescan guess, then checked as .u)
Diffstat (limited to 'src/compiler/decl.zc')
-rw-r--r--src/compiler/decl.zc37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc
index 52d08c7..6bc8245 100644
--- a/src/compiler/decl.zc
+++ b/src/compiler/decl.zc
@@ -81,8 +81,44 @@ int prescan_fn(int ret, int n, int o3) {
sflag[s] = sflag[s] | F_SIG | F_PRE;
}
if (o3) sflag[s] = sflag[s] | F_O3;
+ if (!ret && is_op(s_lb) && prescan_owned(n)) { sflag[s] = sflag[s] | F_GUESS; if (sflag[s] & F_PRE) ssig[s] = ssig[s] | 1; }
return 0;
}
+// true for a token that makes a fresh owned object when called: new or heap.
+// nothing else: a call to the function itself is no evidence.
+int prescan_maker() {
+ return tk == T_ID && (rt.eq_w(tv, "rt.new") || rt.eq_w(tv, "new") || rt.eq_w(tv, "heap"));
+}
+// prescan: at the { of an untagged function's body, guess whether it returns an
+// owned object: a return of a fresh object, or of a local last set from one.
+// the guess only makes the function compile as if declared .u; its body is then
+// checked against that, so a wrong guess is an error, never a silent leak.
+int prescan_owned(int self) {
+ int depth = 0, n, k, found = 0, nown = 0; let owned[16];
+ while (tk != T_EOF) {
+ if (is_op(s_lb)) depth++;
+ else if (is_op(s_rb)) { depth--; if (!depth) { next(); return found; } }
+ else if (tk == T_ID && rt.eq_w(tv, "return")) {
+ next();
+ if (tk == T_ID) {
+ n = tv; peek();
+ if (pk_tk == T_OP && pk_tv == s_lp && prescan_maker()) found = 1;
+ else if (pk_tk == T_OP && pk_tv == s_semi) { k = 0; while (k < nown) { if (owned[k] == n) found = 1; k++; } }
+ }
+ continue;
+ }
+ else if (tk == T_ID) {
+ n = tv; peek();
+ if (pk_tk == T_OP && pk_tv == s_eq) {
+ next(); next();
+ if (prescan_maker()) { peek(); if (pk_tk == T_OP && pk_tv == s_lp && nown < 16) { owned[nown] = n; nown++; } }
+ continue;
+ }
+ }
+ next();
+ }
+ return found;
+}
// scan ahead, without emitting code, to learn what a block of tokens contains.
int prescan(int kind, int obj) {
int depth = 0, sp = panic, sn = nerr, pend = 0, po3 = 0, n, dep; char* oldmodule = module_name; word oldimports = module_imports;
@@ -359,6 +395,7 @@ int fndef(int chk, int rty, int ret, int n) {
if (amb & 1) { t = lookup(pn[i]); if (t >= 0 && skind[t] == K_TYPE) { pty[i] = sval[t]; typed = 1; } }
amb = amb >> 1; i++;
}
+ if (!ret && (sflag[s] & F_GUESS)) ret = 1; // prescan saw it return an owned object: compile it as .u
sig = ret + np + np + tags * 64;
lo = borrows_clause(pn, np, 1);
// a definition after a prototype keeps the prototype's borrows clause