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:
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
hi
|
||||
bye
|
||||
7
|
||||
1
examples/types/expected/0203-types-multi-return.exit
Normal file
1
examples/types/expected/0203-types-multi-return.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/types/expected/0203-types-multi-return.stderr
Normal file
1
examples/types/expected/0203-types-multi-return.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
examples/types/expected/0203-types-multi-return.stdout
Normal file
2
examples/types/expected/0203-types-multi-return.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
17 / 5 = 3 rem 2
|
||||
sum=42 bigger=true
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
classify(7): doubled=14 big=false
|
||||
classify(21): doubled=42 big=true
|
||||
classify(-3): caught Negative
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
combine: sum=42 good=true
|
||||
bounds: lo=5 hi=15
|
||||
roots: val=7 sq=49
|
||||
roots(-1): caught Negative
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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 | }
|
||||
| ^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
classify(5): sum=-1 good=true
|
||||
combine(3,4): total=7 ok=true
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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 | }
|
||||
| ^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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
|
||||
| ^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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
|
||||
| ^^^^^^^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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
|
||||
| ^^^^^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user