feat: multiple return values — bare-paren signatures, named returns, must-set, defaults

A function may return multiple values via a bare-paren return signature:
`-> (A, B)` / `-> (x: A, y: B)` / `-> (A, B, !)` (error always the last slot),
and `-> ()` is `void`. This is DISTINCT from a `Tuple(…)` value — return-position
only (a dedicated `ReturnTypeExpr` AST node resolving to a reused `.tuple`
TypeId); a parameter / field / variable annotation `x: (A, B)` is rejected. A
single-value `-> (T, !)` stays a plain failable (= `-> T !`).

Returns use the bare comma form `return a, b` / `return x = a, y = b` (no `.( … )`
literal). Consume by destructuring (`a, b := f()`) or single-bind + field access
(`c := f(); c.sum`); a failable bound value holds only the value slots (the error
stays on the `!` channel).

Named return slots are in-scope assignable locals; with no explicit `return` the
implicit return is synthesized from them. Path-sensitive definite-assignment
enforces the must-set rule, and a slot may carry a default that exempts it.
Validation rejects arity mismatches, out-of-slot-order named elements, a
slot/parameter name collision, a comma list from a single-value function, and a
multi-return signature used as a value type.

Examples 0202-0213; readme + specs updated. issues/0197 files a pre-existing
annotated-assignment type-check gap (`x: i32 = "hi"` segfaults) surfaced by the
adversarial review.
This commit is contained in:
agra
2026-06-27 12:31:23 +03:00
parent c94f878e7e
commit 76689a1ea6
65 changed files with 1236 additions and 48 deletions

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,3 @@
hi
bye
7

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,2 @@
17 / 5 = 3 rem 2
sum=42 bigger=true

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,3 @@
classify(7): doubled=14 big=false
classify(21): doubled=42 big=true
classify(-3): caught Negative

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,4 @@
combine: sum=42 good=true
bounds: lo=5 hi=15
roots: val=7 sq=49
roots(-1): caught Negative

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,11 @@
error: named return 'good' may be unset (not assigned on every path) and has no default — assign it on every path, give it a default, or end with an explicit `return`
--> examples/types/0206-types-named-return-must-set.sx:7:57
|
7 | combine :: (f1: i32, f2: i32) -> (sum: i32, good: bool) {
| ^
8 | sum = f1 + f2;
| ^^^^^^^^^^^^^^^^^^
9 | // `good` is never assigned — must-set violation.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10 | }
| ^

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,2 @@
classify(5): sum=-1 good=true
combine(3,4): total=7 ok=true

View File

@@ -0,0 +1,11 @@
error: named return 's' may be unset (not assigned on every path) and has no default — assign it on every path, give it a default, or end with an explicit `return`
--> examples/types/0208-types-named-return-conditional-unset.sx:9:39
|
9 | pick :: (c: bool) -> (s: i64, y: i64) {
| ^
10 | if c { s = 10; } // `s` unset on the else path
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 | y = 1;
| ^^^^^^^^^^
12 | }
| ^

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: this function returns 2 values — return them as `return a, b`, not a single value
--> examples/types/0209-types-multi-return-arity.sx:6:12
|
6 | return a / b; // only one value — needs two
| ^^^^^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,11 @@
error: named return element 'b' does not match the slot 'a' at position 0 — name the elements in slot order
--> examples/types/0210-types-multi-return-name-order.sx:6:5
|
6 | return b = n, a = n + 1; // out of slot order
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: named return element 'a' does not match the slot 'b' at position 1 — name the elements in slot order
--> examples/types/0210-types-multi-return-name-order.sx:6:5
|
6 | return b = n, a = n + 1; // out of slot order
| ^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -0,0 +1,5 @@
error: named return 'sum' collides with a parameter of the same name — rename one
--> examples/types/0211-types-named-return-param-collision.sx:4:22
|
4 | inc :: (sum: i32) -> (sum: i32, ok: bool) {
| ^^^^^^^^^^^^^^^^^^^^

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: this function returns a single value, but a list of 2 was given
--> examples/types/0212-types-single-return-comma.sx:5:5
|
5 | return 1, 2; // single-value return, two given
| ^^^^^^^^^^^^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,5 @@
error: a bare-paren `(A, B)` is a multi-return signature, valid only as a return type; a tuple-valued field uses `Tuple(…)`
--> examples/types/0213-types-multi-return-as-value-type.sx:5:27
|
5 | Point :: struct { coords: (i64, i64); } // field value type — rejected
| ^^^^^^^^^^