aboutsummaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 10:11:56 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 10:11:56 +0330
commite1e0a265e931637f452ac05bb7d912e07bcee574 (patch)
tree60289bb1fc3d812dfc576f01e0f8a83091a495c1 /src/compiler
parentanalyzer: check borrow returns of forward-called functions at the unit's end;... (diff)
lsp: borrow errors ranged on the use, with related information for where the owner ended and was declared; vscode client passes relatedInformation through
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/analyzer.zc3
-rw-r--r--src/compiler/base.zc25
2 files changed, 24 insertions, 4 deletions
diff --git a/src/compiler/analyzer.zc b/src/compiler/analyzer.zc
index 103f732..ff6a6c1 100644
--- a/src/compiler/analyzer.zc
+++ b/src/compiler/analyzer.zc
@@ -1002,9 +1002,10 @@ int lend_drop(int dep, int from) {
// or untracked memory, 7 freed by reassigning it, 8 pushed into end_whom.
int end_why; char* end_whom;
int end_owner(int i) {
- int j = lbase; word info = talloc(5);
+ int j = lbase; word info = talloc(6);
lend_check(i);
info[0] = lname[i]; info[1] = lpos[i]; info[2] = tpack(); info[3] = end_why; info[4] = end_whom;
+ info[5] = lreadpos[i]; if (!info[5]) info[5] = info[2]; // the owner's own token where it ended, for the editor
end_why = 0; end_whom = 0;
local_ended[i] = info[2]; local_end_info[i] = info; lstate[i] = S_DEAD;
while (j < nloc) {
diff --git a/src/compiler/base.zc b/src/compiler/base.zc
index bfed062..7e4b5bc 100644
--- a/src/compiler/base.zc
+++ b/src/compiler/base.zc
@@ -415,6 +415,11 @@ int s_new_k, s_recycle_leaf;
// server streams diagnostics and drops a check whose source has been replaced
word chk_hook;
int cmode, chkabort, chkfuel; word dgbuf, dggrow; int dgcap, dgpos, dgn, dgopen, dgprev, dgmode;
+// related places of check-mode records, for the editor: DGREL_W words each, [the record's
+// offset in dgbuf, the packed place where the owner ended, the packed place of the owner's
+// declaration, how it ended (end_why), the owner's name]. reset by chk_begin.
+const int DGREL_W = 5;
+word dgrel; int dgreln, dgrelcap;
// expand a diagnostic in progress, keeping its output offset within the buffer.
int dg_expand() {
dgbuf = chk_resize(dgbuf, dgpos + 5 + rt.outn, dgcap * 2);
@@ -433,8 +438,22 @@ int dg_expand() {
int probe_off = -1, probe_has, probe_n, probe_cap, probe_static;
char** probe_name; word probe_kind, probe_state, probe_type, probe_decl, probe_mem;
char* curinc; int incdepth, dgdrop; int incplace; // how many includes deep the compile is; a record to throw away; the place of the outermost include
+// an open record's range becomes the packed place p (the use itself, not the token after it).
+int dg_place(int p) {
+ if (!cmode || !dgopen || incdepth > 0 || !p || (p & 0xFFFFFF) != tline) return 0;
+ dgbuf[dgpos + 1] = p & 0xFFFFFF; dgbuf[dgpos + 2] = ((p >> 40) & 0x1FFFFF) - 1; dgbuf[dgpos + 3] = (p >> 24) & 0xFFFF;
+ return 0;
+}
+int dg_related(int end_place, int decl_place, int why, char* owner) {
+ if (!cmode || !dgopen || dgdrop || incdepth > 0) return 0;
+ if (dgreln == dgrelcap) { int cap = dgrelcap * 2; if (!cap) cap = 16; dgrel = chk_resize(dgrel, dgreln * DGREL_W, cap * DGREL_W); dgrelcap = cap; }
+ word e = dgrel + dgreln * DGREL_W;
+ e[0] = dgpos; e[1] = end_place; e[2] = decl_place; e[3] = why; e[4] = owner; dgreln++;
+ return 0;
+}
int dg_close() {
if (!dgopen) return 0;
+ if (dgdrop && dgreln && dgrel[(dgreln - 1) * DGREL_W] == dgpos) dgreln--; // its record is thrown away
if (!dgdrop) { dgbuf[dgpos + 4] = rt.outn; dgpos = dgpos + 5 + rt.outn; dgn++; }
dgdrop = 0;
dgopen = 0; rt.outmode = dgmode; rt.outgrow = dggrow;
@@ -470,7 +489,7 @@ word[256] dgseen_initial; word dgseen = dgseen_initial; int dgseen_cap = 256, dg
// start and stop a check run. chk_begin points the diagnostics at a buffer
// the caller owns; chk_end flushes any open record and restores output.
int chk_begin(int buf, int cap) {
- cmode = 1; chkabort = 0; chkfuel = 0; dgbuf = buf; dgcap = cap; dgpos = 0; dgn = 0; dgopen = 0;
+ cmode = 1; chkabort = 0; chkfuel = 0; dgbuf = buf; dgcap = cap; dgpos = 0; dgn = 0; dgopen = 0; dgreln = 0;
nerr = 0; panic = 0; dgmode = rt.outmode; rt.fill_w(dgseen, 0, dgseen_cap); dgseen_n = 0;
return 0;
}
@@ -963,7 +982,7 @@ int cerr(char* msg) {
// "r: used after it was given away; r borrows t, and t was freed on line 5 (t declared on line 4)"
int ended_message(char* use, word info, char* root, int cause) {
char* owner = root; int why = 0; char* whom = 0;
- if (info) { owner = info[0]; why = info[3]; whom = info[4]; }
+ if (info) { owner = info[0]; why = info[3]; whom = info[4]; dg_related(info[5], info[1], why, owner); }
rt.put_s(use); rt.put_s(": used after it was given away; ");
if (!rt.eq_w(use, owner)) { rt.put_s(use); rt.put_s(" borrows "); rt.put_s(owner); rt.put_s(", and "); }
rt.put_s(owner);
@@ -989,7 +1008,7 @@ int cerrn(int i, char* msg) {
if (!info && local_end_info) info = local_end_info[root];
if (info) cause = info[2]; else if (local_ended) cause = local_ended[root];
}
- if (cause && !panic && !dry) { errat(); ended_message(lname[i], info, lname[root], cause); errend(); }
+ if (cause && !panic && !dry) { errat(); dg_place(lreadpos[i]); ended_message(lname[i], info, lname[root], cause); errend(); }
else serrn(lname[i], msg);
}
return 0;