You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix VM-style compiler gaps (get_ref dispatch, field assign, method desugaring, match-arm flow) and Option/extern call-site typing so idiomatic programs and all examples build. Add integration tests, bytecode_vm example, refresh showcase/todo/http/text_summary, and update docs.
Copy file name to clipboardExpand all lines: .cursor/skills/writing-ion-code/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -150,7 +150,7 @@ Import with paths like `import "stdlib/io.ion" as io;`:
150
150
151
151
No stdlib stdin/line input. For POSIX `read` on fd 0, see [examples/todo_demo/](../../../examples/todo_demo/).
152
152
153
-
Built-ins: `Vec<T>`, `String`, `Box<T>`, `Option<T>`, `Result<T, E>` (define enums in-file or import). `Vec::get` / `Vec::pop` move elements out; use `Vec::get_ref(&v, i)` for read-only in-function peek (`Option<&T>`, local only). `String` literals assign to `String`; use `String::from("...")` when a owned copy is needed.
153
+
Built-ins: `Vec<T>`, `String`, `Box<T>`, `Option<T>`, `Result<T, E>` (define enums in-file or import). `Vec::get` / `Vec::pop` move elements out; use `Vec::get_ref(&v, i)` for read-only in-function peek (`Option<&T>`, local only). Match on `&Enum` from `get_ref` dispatches variants directly (no `*` deref). Struct field paths support `=` and `+=` on owned and `&mut` receivers. Nested generics such as `Vec<Vec<int>>` parse as consecutive `>` closings. String literals and `&String` coerce to `&str` at call sites.
Copy file name to clipboardExpand all lines: .cursor/skills/writing-ion-code/references/verified-patterns.md
+18-5Lines changed: 18 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -47,7 +47,24 @@ s.push_str("hi");
47
47
let lit: String = "hello";
48
48
```
49
49
50
-
`Vec::get` / `Vec::pop` return `Option<T>` and **move** the element out. For read-only scans use `Vec::get_ref(&v, i)` which returns `Option<&T>` (local temporary only; cannot return or store). In `match Option::Some(x)`, `x` is `&T`: copy types bind by value; structs with owned fields bind as a pointer so nested `Vec` fields are not dropped. `Vec::set(&mut v, index, value)` returns `int` (0 = ok).
50
+
`Vec::get` / `Vec::pop` return `Option<T>` and **move** the element out. For read-only scans use `Vec::get_ref(&v, i)` which returns `Option<&T>` (local temporary only; cannot return or store). In `match Option::Some(x)`, `x` is `&T`: copy types bind by value; structs and enums with non-copy fields bind as a pointer. Inner `match x` on `&Enum` dispatches variants without deref. `Vec::set(&mut v, index, value)` returns `int` (0 = ok). Method syntax (`v.push(x)`, `v.get_ref(i)`) desugars to `Vec::` builtins with correct receiver borrows.
51
+
52
+
## Struct field mutation
53
+
54
+
```ion
55
+
struct VM { ip: int; stack: Vec<int>; }
56
+
57
+
fn step(vm: &mut VM) {
58
+
vm.stack.push(1);
59
+
vm.ip += 1;
60
+
}
61
+
```
62
+
63
+
Field paths are valid assignment targets on owned structs and `&mut` parameters.
64
+
65
+
## VM dispatch loop
66
+
67
+
See [tests/test_vm_execute.ion](../../../../tests/test_vm_execute.ion): `match vm.code.get_ref(vm.ip)` then inner `match op` on `&Op`, field updates, and `break` inside `match` within `loop`.
51
68
52
69
## Box
53
70
@@ -68,10 +85,6 @@ let elem: int = arr[0]; // bounds checked unless unsafe
Copy file name to clipboardExpand all lines: CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,9 @@
1
1
# Changelog
2
2
3
+
## 2026-07
4
+
5
+
-**VM-style idioms**: `match` on `&Enum` from `Vec::get_ref`; struct field assignment and `+=` on owned/`&mut` paths; method desugaring (`vec.push`, `vec.get_ref`) with correct borrows; nested generic types (`Vec<Vec<int>>`); match-arm control-flow unification (`break`/`return` with value arms); `&str` call-site coercion; enum literals in `Vec::push`/`set` without double-wrapped C; `&mut Struct` field access via `->` in codegen. Integration tests and examples `bytecode_vm`, updated `showcase`, `todo_demo`, `http_server`, `text_summary`. Fix extern call typing so `&T` arguments match `&T` parameters (no erroneous copy-type ref stripping). Fix `Option<T>` match codegen to use the scrutinee type instead of the first registered monomorph. Former negative match-arm rvalue tests now pass as positive runs.
6
+
3
7
## 2026-06
4
8
5
9
-**Readiness hardening**: beta compatibility and runtime ABI documents, a lightweight security policy, CLI/`ion-build` multi-error type diagnostics, sanitizer CI smoke (6 tests), and full integration harness `-Wall -Wextra -Werror` on Linux CI. Cgen warning-hygiene improvements (binding usage tracking and `(void)` silences, borrow/defer silences, string literal `.data`/`uint8_t*` casts, string `for...in` length casts), `String` runtime data as `uint8_t*`, and `CFLAGS`/`LDFLAGS` support in the integration harness.
- Assignment: `=`, `+=` (compound assignment desugars to `x = x + e` for supported `+` types)
187
+
- Assignment: `=`, `+=` (compound assignment desugars to `x = x + e` for supported `+` types). Assignment targets may be locals, index expressions, or field paths on owned structs or `&mut Struct` receivers (for example `vm.ip += 1`).
188
188
- Type casting: `as` keyword for explicit type conversions
-`Vec::new()` and `Vec::with_capacity()` infer `T` from a `let` type annotation when present (e.g. `let v: Vec<i32> = Vec::new()`).
1023
1023
-`Vec::get()` and `Vec::pop()` return `Option<T>` to handle out-of-bounds or empty cases. Both **move** the element out of the vector. To preserve vector length after a read-only scan, either use `Vec::get_ref()` (below) or copy fields and `Vec::set()` a rebuilt struct literal to put the value back (nested `Vec` fields still move on put-back).
1024
-
-`Vec::get_ref()` returns `Option<&T>`: a **local, stack-only borrow** of an in-place element. It does not move or hollow the slot. The result is only valid as a short-lived binding within the current function (for example in a `match` arm). Match arms bind the element as `&T`; codegen uses `T*` for types with owned fields and copies by value for copy types, so repeated scans over `Vec<struct-with-nested-Vec>` do not double-free nested fields. It cannot be returned, stored in structs or enums, sent on channels, or cross `spawn`. While an `&T` from `get_ref` is active, the root owner of the vector (the binding behind `&Vec<T>`) is shared-borrowed: `&mut Vec<T>` on that owner, `Vec::set`, `Vec::push`, and `Vec::pop` on the same vector are rejected until the borrow ends. Out-of-range or negative indices yield `Option::None`. Nested inspection (`order.lines` then `get_ref`) follows the same root-owner borrow rules as field paths (Section 5.3).
1024
+
- `Vec::get_ref()` returns `Option<&T>`: a **local, stack-only borrow** of an in-place element. It does not move or hollow the slot. The result is only valid as a short-lived binding within the current function (for example in a `match` arm). Match arms bind the element as `&T`; for enum elements, an inner `match` on that binding dispatches variants directly (no unary `*` deref). Copy fields in struct or enum variant patterns bind as `T`; non-copy fields bind as `&T`. Codegen uses `T*` for types with owned fields and copies by value for copy types, so repeated scans over `Vec<struct-with-nested-Vec>` do not double-free nested fields. It cannot be returned, stored in structs or enums, sent on channels, or cross `spawn`. While an `&T` from `get_ref` is active, the root owner of the vector (the binding behind `&Vec<T>`) is shared-borrowed: `&mut Vec<T>` on that owner, `Vec::set`, `Vec::push`, and `Vec::pop` on the same vector are rejected until the borrow ends. Out-of-range or negative indices yield `Option::None`. Nested inspection (`order.lines` then `get_ref`) follows the same root-owner borrow rules as field paths (Section 5.3). Field paths through `&Struct` that are already references (for example `order.lines` when `order: &Order`) are passed to `Vec` methods without an extra `&`.
1025
1025
-`Vec::set()` requires a mutable reference and returns an error code (0 for success, non-zero for failure). After shared borrows from `get_ref` end, `Vec::set` on the same index is allowed.
1026
1026
1027
1027
For cross-function or long-lived access, Ion still favors an **index/handle style**: helpers return indices or keys and callers re-index within their own function bodies.
@@ -1055,7 +1055,8 @@ Note that:
1055
1055
-`String::push_byte()` appends a single byte to an existing `String`.
1056
1056
-`==` and `!=` compare UTF-8 byte content (value equality), not pointer identity.
1057
1057
1058
-
`&str` is always a **borrowed view** into existing UTF-8 data; it cannot be returned or stored in long-lived structures in ways that would violate the no-escape rule. The standard library intentionally avoids APIs that would expose `&str` values across function boundaries in ways that require complex lifetime reasoning (e.g., `String::as_str` methods that return borrowed views).
1058
+
-`String::from` and stdlib APIs accepting `&str` also accept string literals and `&String` at call sites.
1059
+
-`&str` is always a **borrowed view** into existing UTF-8 data; it cannot be returned or stored in long-lived structures in ways that would violate the no-escape rule. The standard library intentionally avoids APIs that would expose `&str` values across function boundaries in ways that require complex lifetime reasoning (e.g., `String::as_str` methods that return borrowed views).
|[http_server/](examples/http_server/)| Sockets FFI, spawn per client, stdin `quit` to stop; see [http_server/README.md](examples/http_server/README.md)|
0 commit comments