linear_type.nx
buildroot/runtime/linear_type.nx
about
linear_type.nx -- runtime tracking for linear/affine resources.
Phase A of the full linear-type system (EFFICIENCY_ROADMAP ยง3.2).
Today's NishiLang has no compile-time borrow checker, so we
approximate the safety benefit at runtime: an owning handle
struct that tracks "has this been used yet?" + panics on
double-use. Callers that adopt this pattern get the benefit
immediately; the compiler-side move/borrow checker can
retrofit without breaking the API later.
The canonical failure this prevents: double-free / use-after-
free / duplicate-consume bugs -- the same class that tonight's
"duplicate main in nxc.s" + "alloca clobbered by callee-saved
reuse" bugs both lived in. Linear types at compile time would
reject both without a test suite.
Usage:
let h: *Linear = linear_new(ptr as i64, LK_FILE_HANDLE)
let taken: i64 = linear_take(h) // consume exactly once
linear_take(h) // -> LINEAR_ERR_REUSE
Also exposes a RefCount type for when true linearity is too
strict and you want shared ownership with explicit counting.
Invariants:
LT1 `linear_take` on a fresh handle returns its payload + 0.
LT2 Subsequent `linear_take` returns LINEAR_ERR_REUSE
deterministically.
LT3 `refcount_clone` always succeeds + bumps count.
LT4 `refcount_drop` decrements; when count hits 0, calls
the user-registered free hook exactly once.
dependencies 1 imports · 0 importers
imports: syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 46 | struct Linear { |
| 90 | struct RefCount { |
consts
| 36 | const LK_GENERIC: i64 = 0 |
| 37 | const LK_FILE_HANDLE: i64 = 1 |
| 38 | const LK_SOCKET: i64 = 2 |
| 39 | const LK_MEMORY_ARENA: i64 = 3 |
| 40 | const LK_MUTEX_GUARD: i64 = 4 |
| 41 | const LK_CAPABILITY: i64 = 5 |
| 43 | const LINEAR_ERR_REUSE: i64 = -1001 |
| 44 | const LINEAR_ERR_NULL: i64 = -1002 |
functions
| 53 | func linear_new(payload: i64, kind: i64) -> *Linear {
called by 1: main |
| 63 | func linear_take(h: *Linear) -> i64 {
called by 1: main |
| 71 | func linear_peek(h: *Linear) -> i64 { |
| 77 | func linear_alive(h: *Linear) -> i64 {
called by 1: main |
| 96 | func refcount_new(payload: i64, free_hook: i64) -> *RefCount {
called by 1: main |
| 106 | func refcount_clone(r: *RefCount) -> i64 {
called by 1: main |
| 116 | func refcount_drop(r: *RefCount) -> i64 {
called by 1: main |
| 122 | func refcount_count(r: *RefCount) -> i64 {
called by 1: main |
| 127 | func main() -> i64 { |