diff options
| author | 2026-10-15 22:28:06 +0330 | |
|---|---|---|
| committer | 2026-10-15 22:28:06 +0330 | |
| commit | 5a4dc62a79af6135c7050e81a82dbfdfb0a7d4e0 (patch) | |
| tree | 805283b2d30b2cf0f53af42e5a3fc119af5e839f /docs/SPEC.md | |
| parent | definite assignment: reading a local before it is initialized is a compile er... (diff) | |
uninit: track aggregate fills per part, sticky computed-index fills, &a[k] and method calls set the aggregate; fix test/example hits; docs
Diffstat (limited to 'docs/SPEC.md')
| -rw-r--r-- | docs/SPEC.md | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/docs/SPEC.md b/docs/SPEC.md index b645742..7ba5ce0 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -553,12 +553,14 @@ let sq = { let t = 3 + 4; t * t }; // 49 4.1.4 `const k = e;` declares a local constant: no type is written, it takes the initializer's type (read-only, 2.10), needs an initializer (error: a const needs an initializer), and cannot be assigned (error: const storage cannot be modified). `const T k = e;` is a typed const. -4.1.5 definite assignment. a local with no initializer is unset until every path that reaches a read has assigned it (or taken its address). reading an unset local is error: X: used before it is initialized. a local is set by an initializer, by `x = e`, by passing `&x` (the out-parameter pattern), or by a full array initializer list `{...}` (structs have no brace initializer; use `&agg` or pass the array). writing some fields or elements does not set the aggregate: the whole value stays unset until a full array initializer, `&agg`, or using the aggregate as an address (an array decaying to a pointer). at a join (if/else, loop exit, switch, `?:`) a local is set only if every reaching path set it. a `while` or `for` that may run zero times does not count an assignment only inside the body; a `do`/`while` always runs once, so an assignment in its body does. parameters and globals are set from the start (a global with no initializer is 0). locals are not zeroed. +4.1.5 definite assignment. a local with no initializer is unset until every path that reaches a read has assigned it (or taken its address). reading an unset local is error: X: used before it is initialized. a local is set by an initializer, by `x = e`, by passing `&x` (the out-parameter pattern), or by a full array initializer list `{...}` (structs have no brace initializer; use `&agg` or pass the array). an array or struct is tracked part by part: writing every field (top-level) or every element by constant index sets the whole value, and reading a field or constant-index element that was written is fine even before the rest is; reading an unwritten part, or the whole value, before it is set is the error. a write through a computed index (`a[i] = e`, a fill loop) counts as setting the whole array, on every path (an approximation: the analyzer does not prove the loop covers it). a full `{...}` initializer, `&agg`, `&a[k]`, using the aggregate as an address (an array decaying to a pointer), or calling a method on it also set it. at a join (if/else, loop exit, switch, `?:`) a local is set only if every reaching path set it. a `while` or `for` that may run zero times does not count an assignment only inside the body; a `do`/`while` always runs once, so an assignment in its body does. parameters and globals are set from the start (a global with no initializer is 0). locals are not zeroed. ``` int b; pn(b); // error: b: used before it is initialized int x; x = 1; pn(x); // ok int y; if (c) y = 1; pn(y); // error unless every branch sets y -point p; p.x = 1; pn(p.y); // error: partial fill does not set p +point p; p.x = 1; pn(p.y); // error: p.y was never written +point r; r.x = 1; pn(r.x); // ok: that part was written +int[2] a; a[0] = 1; a[1] = 2; f(a); // ok: every element written point q; fill(&q); pn(q.x); // ok: &q sets q (structs have no brace initializer) int z; fill(&z); pn(z); // ok: &z sets z ``` |
