feat: nested multi-field enum patterns (bootstrap + selfhost)

Multi-field variants use Enum_Variant_Payload nested types (avoids tag name clash).
Sema resolves data.Variant.Variant_i; enum field types fully resolve tuples.
Selfhost parses full type exprs in enum payloads; emit structs/tuples before enums.
Example: examples/nested_patterns.bux (Pair::Two, Box::Val((a,c)), Shape::Dot).
This commit is contained in:
2026-07-18 01:33:36 +03:00
parent f9185c96b2
commit 66f11d1869
12 changed files with 383 additions and 209 deletions
+25 -25
View File
@@ -180,7 +180,9 @@ proc matchPatternBindings(ctx: var LowerCtx, subject: HirNode, pattern: Pattern,
let multiField = fieldTypes.len > 1
var payloadBase = dataLoad
if multiField:
let variantStructTy = makeNamed(variantName)
# Nested struct type Enum_Variant_Payload (avoids clash with tag Enum_Variant)
let nestedName = enumName & "_" & variantName & "_Payload"
let variantStructTy = makeNamed(nestedName)
let variantPtr = HirNode(kind: hFieldPtr, fieldPtrBase: dataLoad, fieldName: variantName,
typ: makePointer(variantStructTy), loc: loc)
payloadBase = HirNode(kind: hLoad, loadPtr: variantPtr, typ: variantStructTy, loc: loc)
@@ -208,10 +210,12 @@ proc matchPatternBindings(ctx: var LowerCtx, subject: HirNode, pattern: Pattern,
if entry.name == nf.name:
fieldTy = entry.typ
break
# Named payload fields live under data.VariantName.name
# Named payload fields live under data.Variant.name on Enum_Variant_Payload
let nestedName = enumName & "_" & variantName & "_Payload"
let variantStructTy = makeNamed(nestedName)
let variantPtr = HirNode(kind: hFieldPtr, fieldPtrBase: dataLoad, fieldName: variantName,
typ: makePointer(makeNamed(variantName)), loc: loc)
let variantLoad = HirNode(kind: hLoad, loadPtr: variantPtr, typ: makeNamed(variantName), loc: loc)
typ: makePointer(variantStructTy), loc: loc)
let variantLoad = HirNode(kind: hLoad, loadPtr: variantPtr, typ: variantStructTy, loc: loc)
let fieldPtr = HirNode(kind: hFieldPtr, fieldPtrBase: variantLoad, fieldName: nf.name,
typ: makePointer(fieldTy), loc: loc)
let fieldLoad = HirNode(kind: hLoad, loadPtr: fieldPtr, typ: fieldTy, loc: loc)
@@ -2217,33 +2221,29 @@ proc lowerModule*(module: Module, sema: Sema): HirModule =
for v in decl.declEnumVariants:
var fields: seq[Type] = @[]
for f in v.fields:
var fType = makeUnknown()
if f != nil and f.kind == tekNamed:
case f.typeName
of "int", "int32": fType = makeInt()
of "int64": fType = makeInt64()
of "float64": fType = makeFloat64()
of "float32": fType = makeFloat32()
of "bool": fType = makeBool()
of "String", "str": fType = makeStr()
else: fType = makeNamed(f.typeName)
fields.add(fType)
# Full resolve — supports tuples, pointers, named types, etc.
fields.add(if f != nil: ctx.resolveTypeExpr(f) else: makeUnknown())
var namedFields: seq[tuple[name: string, typ: Type]] = @[]
for nf in v.namedFields:
var fType = makeUnknown()
if nf.ftype != nil and nf.ftype.kind == tekNamed:
case nf.ftype.typeName
of "int", "int32": fType = makeInt()
of "int64": fType = makeInt64()
of "float64": fType = makeFloat64()
of "float32": fType = makeFloat32()
of "bool": fType = makeBool()
of "String", "str": fType = makeStr()
else: fType = makeNamed(nf.ftype.typeName)
let fType = if nf.ftype != nil: ctx.resolveTypeExpr(nf.ftype) else: makeUnknown()
namedFields.add((nf.name, fType))
variants.add(HirEnumVariant(name: v.name, fields: fields, namedFields: namedFields))
# Multi-field / named-field variants get a named nested struct type
# Enum_Variant_Payload (suffix avoids clash with tag constant Enum_Variant).
if fields.len > 1:
var nestedFields: seq[tuple[name: string, typ: Type]] = @[]
for i, ft in fields:
nestedFields.add((v.name & "_" & $i, ft))
let nestedName = decl.declEnumName & "_" & v.name & "_Payload"
structs.add((nestedName, nestedFields))
elif namedFields.len > 0:
var nestedFields: seq[tuple[name: string, typ: Type]] = @[]
for nf in namedFields:
nestedFields.add((nf.name, nf.typ))
let nestedName = decl.declEnumName & "_" & v.name & "_Payload"
structs.add((nestedName, nestedFields))
enums.add((decl.declEnumName, variants))
of dkConst:
let value = ctx.lowerExpr(decl.declConstValue)