plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
d03136b
— Peter John
2026-10-27T11:17:47+05:30
docs(plans): Zig error values/sets — error.Name, return, error X = A | B, X!T
docs/plans/2026-10-27-zig-error-sets.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Zig error values and sets: `error.Name`, `return`, `error X = A | B`, `X!T`
|
|
2
|
+
|
|
3
|
+
**Status:** planned. Waiting for the user to verify it before it runs.
|
|
4
|
+
**Builds on:** `2026-10-27-zig-errors.md` (merged). The runtime stays the same: `!T` is `(T leaves…, i32 code)` and error names are global i32 codes.
|
|
5
|
+
|
|
6
|
+
## User decisions
|
|
7
|
+
- `return error.Name`, with `fail` removed. An error is an ordinary value written `error.Name`.
|
|
8
|
+
- Zig-style sets: an optional named declaration `error ParseError = BadNumStr | NegativeNum`; pinned returns `ParseError!Int` or inline `error{BadNumStr}!Int`; sets merge with `||`; `!Int` stays inferred.
|
|
9
|
+
- Bare names in `match e` arms (`BadNumStr => …`).
|
|
10
|
+
|
|
11
|
+
## Design
|
|
12
|
+
1. **Error values.**
|
|
13
|
+
- `error.Name` is an expression whose type is the singleton set `error{Name}`. It needs no declaration, because names are global codes as today.
|
|
14
|
+
- In a `!T` or `T?` slot (return, tail, arg, field, default, list element) an error value is the failure.
|
|
15
|
+
- `return error.X` replaces `fail X`. In a `T?` slot `error.Missing` is simply the absent value anywhere, so the old dual rule for `fail Missing` goes away.
|
|
16
|
+
- `fail` is removed from the grammar, AST, checker, codegen, highlighting and LSP, with no hints.
|
|
17
|
+
2. **Named sets.** `error Name = A | B | C` is a top-level item, and names must be unique, like consts. A set name is usable as a type, the type of a bare error value (`e: ParseError`), and in `X!T`.
|
|
18
|
+
3. **Error-union types.**
|
|
19
|
+
- `!T` is inferred, as today.
|
|
20
|
+
- `ParseError!T` is pinned to a named set.
|
|
21
|
+
- `error{A, B}!T` is pinned to an inline set.
|
|
22
|
+
- `(A || B)!T` merges sets.
|
|
23
|
+
- The old `!T [A, B]` pinned spelling is removed. That also removes E2's "generics must touch the name" whitespace rule: generics go back to normal, because the set now comes before `!`.
|
|
24
|
+
- `T?` = `error{Missing}!T`.
|
|
25
|
+
4. **`catch e`** gives `e` the exact set type. `match e` arms are bare names in the set (`error.X` is also accepted). Exhaustiveness, `e.name()`, `?`, `!`, `?.` and inference are unchanged.
|
|
26
|
+
5. **Std and migration.** Every `-> !T [A, B]` pinned signature becomes `error{A, B}!T`, or a named set where one is reused, e.g. `error IoError = IoFailed | NoSuchPath` in Os.plum. Every `fail X` becomes `return error.X` (or a bare `error.X` value in a value position). The README Error handling section is rewritten; the docs, highlighting (`error` keyword, the `error.` prefix, `||` in types), VS Code grammar and LSP keywords (`error` added, `fail` removed) are updated; the editors are reinstalled.
|
|
27
|
+
|
|
28
|
+
## Tasks
|
|
29
|
+
- **S1 grammar, parser and AST:** the `error` item, `error.Name` expressions, `X!T` / `error{…}!T` / `(A || B)!T` types, removal of `fail` and of the `!T [..]` spelling, and generics back to normal. Corpus, formatter and highlights.
|
|
30
|
+
- **S2 checker and codegen:** singleton-set error values unify into `!T`/`T?` slots; named sets resolve; `||` union; `match e` arms; set types on `catch e`. Codegen reuses the E3 code paths: an error value is just its i32 code.
|
|
31
|
+
- **S3 migration and docs:** std, examples, README, embedded Rust tests, LSP and editor reinstall.
|
|
32
|
+
|
|
33
|
+
Tests:
|
|
34
|
+
- `error_value_returns_failure` and `error_missing_is_absent_anywhere`;
|
|
35
|
+
- `named_set_pins` and `inline_set_pins`;
|
|
36
|
+
- `set_union_merge` and `pinned_rejects_extra`;
|
|
37
|
+
- `fail_removed` (plain parse error);
|
|
38
|
+
- `old_bracket_pin_removed`;
|
|
39
|
+
- `match_bare_names` and `match_error_prefix_accepted`;
|
|
40
|
+
- `generics_whitespace_free_again` (`Box [Int]`-style spacing no longer matters);
|
|
41
|
+
- `duplicate_error_set_name`.
|
|
42
|
+
- Every existing error test, migrated.
|