docs: tuple syntax cutover — Tuple(...) type, .(...) value, channel-outside-Tuple failables
Rewrite specs.md tuple/failable/pack/UFCS/grammar sections to the new syntax, update readme.md, and refresh stale tuple references in example header comments. Also fixes two pre-existing doc inaccuracies surfaced in review: drop the value-discarding `;` in the tuple-return examples, and correct the §13 function-type grammar production (optional param list + optional trailing `!` channel). Optional semantics unchanged. current/CHECKPOINT-LANG.md logs the cutover.
This commit is contained in:
@@ -35,7 +35,7 @@ main :: () {
|
||||
print("{}\n", a); // 2
|
||||
print("{}\n", b); // 1
|
||||
|
||||
wrap :: (x: i64) -> Tuple(i64) { .(x) } // 1-tuple needs trailing comma; (i64) groups
|
||||
wrap :: (x: i64) -> Tuple(i64) { .(x) } // 1-tuple type `Tuple(i64)`; bare `(i64)` groups
|
||||
t := wrap(99);
|
||||
print("{}\n", t.0); // 99
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// tuple here). Tuples are POSITIONAL, so `TupleInfo` is just a `[]Type` (no field
|
||||
// names). Two paths:
|
||||
// 1. Programmatic build: `define(declare("Pair"), .tuple(.{ elements = … }))`.
|
||||
// 2. Round-trip: `define(declare("TripleCopy"), type_info((i64, bool, f64)))`
|
||||
// 2. Round-trip: `define(declare("TripleCopy"), type_info(Tuple(i64, bool, f64)))`
|
||||
// reflects a source tuple type INTO a `.tuple(TupleInfo)` value and
|
||||
// reconstructs it — no literal element list.
|
||||
#import "modules/std.sx";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// A tuple literal used in a type position (`(i32, i32)` reinterpreted as a tuple
|
||||
// type at a type-demanding site like `size_of`) must list only types. A non-type
|
||||
// element — here the `1` in `(i32, 1)` — is rejected with a user-facing
|
||||
// A tuple type (`Tuple(i32, i32)` at a type-demanding site like `size_of`) must
|
||||
// list only types. A non-type
|
||||
// element — here the `1` in `Tuple(i32, 1)` — is rejected with a user-facing
|
||||
// diagnostic instead of silently fabricating an `i64` field for that slot.
|
||||
// Regression (issue 0067).
|
||||
// Expected: a clean "tuple type element is not a type" error at the `1`; exit 1.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Feature 1 — materialize a tuple from a pack via `(..xs.method)` (Decision 2:
|
||||
// a pack is stored by materializing a tuple). `(..xs.get)` projects `get` over
|
||||
// Feature 1 — materialize a tuple from a pack via `.(..xs.method)` (Decision 2:
|
||||
// a pack is stored by materializing a tuple). `.(..xs.get)` projects `get` over
|
||||
// the pack and collects the results into a real tuple value, which can then be
|
||||
// stored, indexed, and (for `Box(T)`) is heterogeneous per position.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Feature 1 — TYPE-position pack projection `xs.T`. The per-element protocol
|
||||
// type-arg `T` projects into a Pack of types, usable in type/signature
|
||||
// positions: a tuple type `(..xs.T)` and a closure signature
|
||||
// positions: a tuple type `Tuple(..xs.T)` and a closure signature
|
||||
// `Closure(..xs.T) -> R`. (`T` of each element comes from its
|
||||
// `impl Box(T) for <elem>`.)
|
||||
|
||||
@@ -17,8 +17,8 @@ impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl Box(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
impl Box(i64) for Dbl { get :: (self: *Dbl) -> i64 => self.n * 2; }
|
||||
|
||||
// Tuple type `(..xs.T)` — heterogeneous (i64, string), matched by the
|
||||
// value-projection `(..xs.get)`.
|
||||
// Tuple type `Tuple(..xs.T)` — heterogeneous (i64, string), matched by the
|
||||
// value-projection `.(..xs.get)`.
|
||||
snap :: (..xs: Box) -> void {
|
||||
t : Tuple(..xs.T) = .(..xs.get);
|
||||
print("0={} 1={}\n", t.0, t.1);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Phase 4.2 — the canonical `Combined` struct's storage layer: a generic
|
||||
// struct whose field is a pack of PARAMETERIZED-protocol values,
|
||||
// `sources: (..VL(Ts))` → `(VL(T0), VL(T1), …)`. Each `VL(Ti)` is a real
|
||||
// `sources: Tuple(..VL(Ts))` → `Tuple(VL(T0), VL(T1), …)`. Each `VL(Ti)` is a real
|
||||
// 16-byte protocol value (issue: parameterized-protocol value types), and
|
||||
// `(..VL(Ts))` applies `VL` per pack element. Instantiate + whole-tuple store
|
||||
// `Tuple(..VL(Ts))` applies `VL` per pack element. Instantiate + whole-tuple store
|
||||
// of `xx`-erased values + per-element method dispatch all work.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Phase 6 — `c.sources = (..sources)`: materialize a pack into a
|
||||
// Phase 6 — `c.sources = .(..sources)`: materialize a pack into a
|
||||
// protocol-typed tuple field, erasing each concrete pack element to the field's
|
||||
// protocol slot. The pack `..sources: VL` holds concrete cells; `(..sources)`
|
||||
// into a `(..VL(Ts))` field `xx`-erases each to its `VL(Ti)` value.
|
||||
// protocol slot. The pack `..sources: VL` holds concrete cells; `.(..sources)`
|
||||
// into a `Tuple(..VL(Ts))` field `xx`-erases each to its `VL(Ti)` value.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// - `$R` is inferred at the call site from the lowered mapper's closure ret,
|
||||
// bound into the mono (`-> VL($R)` ⇒ `VL(i64)`, `Combined($R, ..)` ⇒
|
||||
// `Combined(i64, ..)`), and folded into the mangle.
|
||||
// - `(..sources)` materializes the pack into the `(..VL(Ts))` field (per-element
|
||||
// - `.(..sources)` materializes the pack into the `Tuple(..VL(Ts))` field (per-element
|
||||
// erase) and `mapper(..sources.get)` projects+spreads; `xx c` erases the
|
||||
// generic-struct instance to `VL(i64)` via the generic impl's monomorphized
|
||||
// thunk.
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
// arrive in Phase 2 — do NOT expect this to compile/run yet. The authoritative
|
||||
// checks are the parser unit tests in src/parser.zig ("parse pack expansion: …").
|
||||
|
||||
// 1. Tuple value position — `(..pack)` / `(..pack.field)`:
|
||||
// 1. Tuple value position — `.(..pack)` / `.(..pack.field)`:
|
||||
tv1 :: () => .(..xs);
|
||||
tv2 :: () => .(..xs.value);
|
||||
tv3 :: () => .(a, ..xs, b); // mixed positional + spread
|
||||
|
||||
// 2. Tuple type position — `(..F(Ts))` / `(..F(Ts.Arg))`:
|
||||
// 2. Tuple type position — `Tuple(..F(Ts))` / `Tuple(..F(Ts.Arg))`:
|
||||
tt1 :: (x: Tuple(..ValueListenable(Ts))) => x;
|
||||
tt2 :: (x: Tuple(..ValueListenable(Ts.Arg))) => x;
|
||||
|
||||
|
||||
@@ -46,17 +46,17 @@ main :: () -> i32 {
|
||||
// ── GAPS (Feature 1 work — intentionally NOT exercised above) ──────
|
||||
//
|
||||
// G1. Tuple field projection across elements:
|
||||
// t := (Listenable.{value=1}, Listenable.{value=2});
|
||||
// v := t.value; // expected: (1, 2) — Decision 3 "tuple.field"
|
||||
// t := .(Listenable.{value=1}, Listenable.{value=2});
|
||||
// v := t.value; // expected: .(1, 2) — Decision 3 "tuple.field"
|
||||
// Today: `error: field 'value' not found on type 'tuple'`.
|
||||
// Needed by canonical `self.sources.value`.
|
||||
//
|
||||
// G2. Tuple spread into call args:
|
||||
// p := (10, 20);
|
||||
// p := .(10, 20);
|
||||
// add(..p); // expected: add(10, 20) — Decision 3 "..tuple"
|
||||
// Today: lowers to one `undef` arg → LLVM arity verification failure.
|
||||
// Needed by canonical `mapper(..sources.value)` and `(..sources)`.
|
||||
// Needed by canonical `mapper(..sources.value)` and `.(..sources)`.
|
||||
//
|
||||
// Both are already scheduled: parsing in Phase 1.2 (PackExpansion node covers
|
||||
// `(..pack)` / `..pack.field`), sema in Phase 2.3 ("tuple-spread parallels").
|
||||
// `.(..pack)` / `..pack.field`), sema in Phase 2.3 ("tuple-spread parallels").
|
||||
// No separate Feature 1.5 needed — see Step 0.4 triage in CHECKPOINT-LANG.md.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
// - wrapper-alias element `BoxPtr :: *Box` (engine wrapper aliasing)
|
||||
// - union body-builder child `WrapU :: union { b: Box }` (C1, registerUnionDecl)
|
||||
// - enum body-builder child `WrapE :: enum { V: Box }` (C1, registerEnumDecl)
|
||||
// - tuple-literal element `size_of((Box, i32))` (O1/K5)
|
||||
// - tuple-type element `size_of(Tuple(Box, i32))` (O1/K5)
|
||||
// - inline-anonymous body child `x : union { b: Box }` (inline-anon engine arm)
|
||||
//
|
||||
// Fail-before (pre-E6b-R): each of these resolved `Box` through the stateless
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Compound type literals in expression position — `size_of` /
|
||||
// `align_of` accept pointer (`*T`), optional (`?T`), array (`[N]T`),
|
||||
// function (`(A) -> B`), and tuple (`(A, B)`) types directly. Also
|
||||
// function (`(A) -> B`), and tuple (`Tuple(A, B)`) types directly. Also
|
||||
// const-decl RHS aliases through the same forms (`Ptr :: *u8;` etc).
|
||||
// Same shape as the existing `size_of(i32)` baseline path.
|
||||
|
||||
@@ -22,7 +22,7 @@ main :: () -> i32 {
|
||||
// Function-type literal in expression position.
|
||||
print("size_of((i32)->i32) = {}\n", size_of((i32) -> i32));
|
||||
|
||||
// Tuple literal reinterpreted as tuple type at the type-demanding site.
|
||||
// Tuple type at the type-demanding site.
|
||||
print("size_of((i32, i32)) = {}\n", size_of(Tuple(i32, i32)));
|
||||
|
||||
// Aliases.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// - `t.0 = v` writes one element in place (was a known gap: the lvalue path
|
||||
// looked the element up by name via getStructFields and left the pointee
|
||||
// `.unresolved`; now it indexes the tuple positionally like the read path).
|
||||
// - Named tuples `(x: T, y: U)` keep their field names through parsing and
|
||||
// - Named tuples `Tuple(x: T, y: U)` keep their field names through parsing and
|
||||
// type resolution, so `t.x` reads/writes by name (and `.0` by position).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// 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.
|
||||
// Parenthesized type grouping: bare parens `(T)` are GROUPING ONLY (in every
|
||||
// position) and resolve to the inner type. A tuple type is `Tuple(...)`:
|
||||
// `Tuple(T)` is a 1-tuple, `Tuple(A, B)` a 2-tuple. Bare parens never form a
|
||||
// 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.
|
||||
// without ambiguity — grouping is decoupled from the tuple grammar.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
@@ -28,7 +28,7 @@ main :: () {
|
||||
fns : [1](Closure(i64, i64) -> i64) = .[ add ];
|
||||
print("{}\n", fns[0](3, 4)); // 7
|
||||
|
||||
// A 1-tuple type still requires the trailing comma.
|
||||
// A 1-tuple type is `Tuple(i64)`.
|
||||
one : Tuple(i64) = .(9);
|
||||
print("{}\n", one.0); // 9
|
||||
|
||||
|
||||
Reference in New Issue
Block a user