feat: parenthesized type grouping — (T) groups, (T,) is a 1-tuple (issue 0177)

In type position, parentheses now mirror value position: (T) (a single
unnamed element, no trailing comma) is a GROUPING that resolves to the
inner type; (T,) is a 1-tuple; (A, B) a 2-tuple; named (x: T) and spread
(..Ts) stay tuples; (...) -> R stays a function type. This lets a
closure/optional/function type be parenthesized for readability without
silently becoming a 1-tuple:
  [1](Closure(i64,i64) -> i64)   // array of closures (issue 0177) -> 7
  ?(?i64)                        // genuine nested optional (issue 0165 intent)

Parser: src/parser.zig returns the inner node for a single unnamed
non-spread no-trailing-comma parenthesized type. formatTypeName (both
generic.zig diagnostics + types.zig reflection) now render a 1-tuple as
(T,) so the spelling is unambiguous and diagnostics are self-consistent.
The 0165 coerce/stmt note reworded accordingly.

specs.md §Type Syntax updated; basic/0036 wrap return -> (i64,); obsolete
diagnostic 1195 removed (?(?i64) now compiles); regression
examples/types/0201-types-parenthesized-type-grouping.sx added; 0414 .ir
golden regenerated for the (T,) rendering. Resolves 0177; updates
0165/0170. Verified by 3 adversarial reviews; suite 792/0.
This commit is contained in:
agra
2026-06-23 10:43:47 +03:00
parent c41f51aed3
commit 555ccdc024
18 changed files with 120 additions and 40 deletions

View File

@@ -0,0 +1,38 @@
// Parenthesized type grouping: in type position `(T)` (single element, no
// trailing comma) is a GROUPING that resolves to the inner type — mirroring
// value position where `(expr)` groups and `(expr,)` is a 1-tuple. A 1-tuple
// type requires the trailing comma `(T,)`; `(A, B)` is a 2-tuple.
//
// This lets a closure/optional type be parenthesized for readability:
// [1](Closure(i64,i64) -> i64) // array of closures (grouped element type)
// ?(?i64) // nested optional
// without the parens silently turning it into a 1-tuple.
#import "modules/std.sx";
add :: (a: i64, b: i64) -> i64 { return a + b; }
main :: () {
// `(i64)` groups to `i64`.
g : (i64) = 7;
print("{}\n", g); // 7
// `((i64))` groups twice.
gg : ((i64)) = 8;
print("{}\n", gg); // 8
// `?(?i64)` is a genuine nested optional (grouping, not a 1-tuple).
no : ?(?i64) = 5;
print("{}\n", no!!); // 5
// Parenthesized closure element type → array of callable closures.
fns : [1](Closure(i64, i64) -> i64) = .[ add ];
print("{}\n", fns[0](3, 4)); // 7
// A 1-tuple type still requires the trailing comma.
one : (i64,) = (9,);
print("{}\n", one.0); // 9
// A 2-tuple is unaffected.
two : (i64, i64) = (40, 2);
print("{}\n", two.0 + two.1); // 42
}

View File

@@ -0,0 +1,6 @@
7
8
5
7
9
42