Edva provides records for product types (structs, tuples, SIMD vectors, packed headers, and bitfields) and enums for nominal tagged unions with \(\ge 2\) named variants.
Product types: records, tuples, #packed, and bitfields
Record construction, access, and definite initialization
Positional construction
Point(10, 20) / (10, 20)
Initializes fields in declaration order
E3084: field type/count mismatch
Named construction
Point(y = 20, x = 10)
Initializes by field name; omitted fields with defaults use their declared default value
—
Zero/default value
Point.zero
Initializes all fields to 0 / <-> / "" or their declared = default expression
—
Forward declaration
p: Point
Allocates uninitialized record storage; every field must be written before being read
E3130: reading uninitialized field
Field read / write
p.x, p.0, p.x = 5
Reads or mutates named, positional, or bitfield slot in place
—
Field-accessor section
(.x), (.0), (.a.b)
1-argument projection function r => r.x
E2064: bare (.)
Structural equality
p1 == p2, p1 != p2
Compares all fields recursively
E3084: if record contains fn field
#use io
#type Point (x: Int = 0 , y: Int = 0 )
#type Flags #packed u8 (fin: <> , syn: <> , rest: 6 )
p: Point
p.x = 10
p.y = 20
f' = Flags (fin = <-> , syn = <+> , rest = 7 )
io:: out $ (p.x + p.y, f' .syn, f' .rest, #size Flags )
#type Point (x: Int , y: Int )
p: Point
p.x = 100
bad = p.y
Sum types: nominal Enum (< V1, V2(T) >)
Enums model nominal tagged unions of two or more uppercase variants, represented at runtime as a 16-byte { i64 tag, ptr payload } pair (#size Enum == 16). Because payloads are arena pointers, recursive enums (#type Expr < Lit(Int), Add(Expr, Expr) >) have fixed 16-byte size without explicit box types.
Enum declaration and construction rules
Declaration
#type Shape < Circle(Float), Rect(Float, Float), Dot >
Requires \(\ge 2\) unique uppercase variant labels separated by commas or aligned newlines
E2070: \(< 2\) variantsE2012: lowercase labelE2074: duplicate label
Unit variant construction
Shape(Dot), Dot, Shape::Dot
Bare Dot is bound in scope if unambiguous; use Shape::Dot when two enums share a label
E3105: ambiguous unqualified labelE3098: payload given to unit variant
Payload construction
Shape(Circle, 5.0)Shape(Rect, (3.0, 4.0))
Type name called with variant label first, followed by payload argument(s)
E3096: unknown variantE3097: missing payloadE3099: wrong payload type
Structural equality
a == b, a != b
Compares variant tags first, then payloads recursively (<, > ordering rejected)
E3084 if fn payloadE3127 on < / >
Enum pattern matching and reflection
Unit / ignore-payload guard
[Dot] / [Dot, Circle]
Matches tag(s); ignores any payload ([Circle _] is forbidden; write [Circle])
E2109: redundant _ in [V _]
Payload binder guard
[Circle r]
Matches Circle and binds payload to r (and implicit _ in branch body)
—
Deep nested pattern
[Add (Lit a, Neg (Lit b))]
Recursively destructures nested enum and tuple/record payloads in a single guard
—
Exhaustiveness
All variants covered or trailing |
Required when choice result is used as a value
E3102: uncovered variants
Compile-time count & label
?T, T.(i) (with #! T: Type)
?T yields variant count; T.(i) yields i-th variant name (String)
E3170: non-constant i
#use io
#type Expr < Lit (Int ), Neg (Expr ), Add (Expr , Expr ) >
eval: Expr => Int
eval = e =>
e
[ Lit n] n
[ Neg (Lit n)] 0 - n
[ Neg x] 0 - eval(x)
[ Add (Lit 0 , rhs)] eval(rhs)
[ Add (lhs, rhs)] eval(lhs) + eval(rhs)
| 0
e = Expr (Add , (Expr (Lit , 10 ), Expr (Neg , Expr (Lit , 3 ))))
io:: out $ eval(e) // 7
Audience: Edva developers
Status: current reference
Audited: 51081a6
Evidence: src/parser.dva, src/annotate.dva,
src/codegen/types.dva, src/codegen/match.dva,
GRAMMAR.md