Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ Updated October 16, 2026 (America/New_York).
minimal user awareness; Go+Bend+Rust in one program) are met and merged to `main`;
core-language work has started. See the October 9 section below.

**Arrays inside generic type arguments (October 19, CrocSwap/goSVM#8):**
`Pair[uint32, [][32]byte]`, `[]*[4]T`, `map[K][][2]T` and generic struct
fields such as `V [][3]T` were rejected with `array type was not declared
before use`: type arguments were validated before any array was declared, and
arrays reached only through a generic field were never declared. Both fixed
([GO_GENERICS](docs/GO_GENERICS.md)); host differentials and SBF on both
targets; corpus C and example ELFs unchanged.
[Evidence](results/compiler/2026-10-19-generic-array-type-args/README.md).

**First-program tutorial and release walkthrough (October 18):**
[docs/TUTORIAL.md](docs/TUTORIAL.md) builds a PDA counter
([examples/tutorial](examples/tutorial/README.md), in the CI module loop): scaffold,
Expand Down
10 changes: 10 additions & 0 deletions docs/ERROR_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -648,3 +648,13 @@ Handler results propagate unchanged.
Process reaches in package "P", opt in with "trim" in gosvm.json or -trim
(docs/GO_PACKAGES.md#trimming)`. No recorded corpus entry's message
changed (their dependency packages are not module paths).
- 2026-10-19: Check relaxation (generic type arguments), no trap, code or
generated code changed for accepted programs: a type argument holding an
array through a slice, pointer, map or function type
(`Pair[uint32, [][32]byte]`, `[]*[4]T`), and a generic struct field doing
so (`V [][3]T`), compile; they were rejected with `array type was not
declared before use` (CrocSwap/goSVM#8). An array in such a type argument
that exceeds the per-value limit, or a zero-length array in a slice, now
reports that rule's message (`array storage exceeds experimental 1024-byte
per-value limit`, `slice elements must not contain zero-length arrays or
empty structs`) instead. No recorded corpus program's C changed.
14 changes: 13 additions & 1 deletion docs/GO_GENERICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ Every type argument must be a type the subset can store: an integer scalar
named scalar, a value struct (including one with pointer, slice, string or
interface fields), a scalar array of at most 1,024 bytes, a slice of an
admitted element, a pointer to an admitted element, or an interface type
(including `error`). Each instance's body must
(including `error`). Arrays may sit anywhere inside a type argument
(`Pair[uint32, [][32]byte]`, `[]*[4]T`, `map[K][][2]uint16`, `func([][2]byte)`)
and inside fields of a generic struct (`V [][3]T`, `P *[4]T`, `Rows []Row[T]`),
even when the array type is written nowhere else: Check and the emitter
declare such an array where the instance first uses it. Each instance's body must
then satisfy every subset rule with the arguments substituted; for example
`Eq[T comparable]` instantiated with a struct is rejected because struct
comparison is unsupported, while `Eq[[4]byte]` is accepted.
Expand Down Expand Up @@ -190,6 +194,14 @@ counters ([feature report](FEATURES_REPORT.md)).
- `TestGenericMatchesHandwrittenSBF` builds generic helpers instantiated for
two widths and a hand-written per-type copy: their `.text` sections are
byte-identical (800 bytes) on both targets, so size and compute units match.
- [`generic_arrays_test.go`](../internal/compiler/generic_arrays_test.go)
covers arrays nested in type arguments and generic struct fields
(CrocSwap/goSVM#8): `TestGenericArrayTypeArgsDifferential` runs two
programs over 256 inputs each natively and as host C,
`TestGenericArrayTypeArgsSBF` 64 each on fogo-v0 and solana-v3, and
`TestGenericArrayTypeArgsForms` the accepted forms and the storage rules
still applied inside them
([evidence](../results/compiler/2026-10-19-generic-array-type-args/README.md)).
- `TestGenericAcceptedForms`, `TestGenericRejections` (exact messages),
`TestGenericCrossPackage`, `TestCheckedProgramInstances`,
`TestGenericAliasSpellingsShareInstances`, `TestGenericNamesAreDeterministic`
Expand Down
7 changes: 6 additions & 1 deletion internal/compiler/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,18 @@ const builtinRule = "only len, cap, new, make, append, copy, delete, clear and p
// have a nonzero size without zero-length arrays or empty structs, so the Go
// size used for append growth equals the element's C size.
func (f *frontend) sliceRule(n ast.Node, s *types.Slice) {
f.sliceRuleWith(n, s, f.variableRule)
}

// sliceRuleWith is sliceRule, applying elemRule to the element type.
func (f *frontend) sliceRuleWith(n ast.Node, s *types.Slice, elemRule func(ast.Node, types.Type)) {
if isContext(s.Elem()) {
f.fail(n, "slices of Context unsupported")
}
if _, ok := s.Elem().(*types.Tuple); ok {
f.fail(n, "unsupported type %s", s)
}
f.variableRule(n, s.Elem())
elemRule(n, s.Elem())
if zeroSizePart(s.Elem()) {
f.fail(n, "slice elements must not contain zero-length arrays or empty structs")
}
Expand Down
1 change: 1 addition & 0 deletions internal/compiler/arrays.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func (g *generator) emitType(node ast.Node, t types.Type) {
}
for i := 0; i < st.NumFields(); i++ {
f := st.Field(i)
nestedArrays(f.Type(), func(a *types.Array) { g.emitArray(node, a) })
if a, ok := f.Type().Underlying().(*types.Array); ok {
g.emitArray(node, a)
} else if _, ok := f.Type().Underlying().(*types.Struct); ok && !isEmptyStruct(f.Type()) {
Expand Down
Loading