# Go Code Generation

This document defines the Go code generation target.

## Kind

The target kind identifier is `golang`.

## Options

The Go target reads the following options from its `options` mapping in the project configuration:

- `package: STRING` is the Go package name used in every generated file. Required. The value is used verbatim as the package clause and must be a valid Go package identifier.
- `storage: STRING` selects the master-data backend baked into the generated package. Optional; defaults to `memory`. Accepted values are `memory` (the in-memory executor that consumes records supplied through `NewMasterData` or `LoadJSON`) and `sql` (a SQL-backed executor that translates queries into SQL against a host-supplied database connection — see [Master Data](#master-data)).

A missing or empty `package` is a configuration error. A `storage` value other than `memory` or `sql` is a configuration error.

The Go target does not consume any other options at this stage; unknown options are silently ignored to leave room for future extension without breaking existing configurations.

## File Set

For a project whose lowered IR modules are `m1.mst`, `m2.mst`, ..., the Go target produces:

- One generated file per Masterbelt module. The file name is the module name with the `.mst` suffix replaced by `.go`. Each file contains the Go declarations corresponding to that module's constants.
- A `masterbelt_unions.go` file when any constant has a union type. The file declares the sealed interface and member wrapper types for every union encountered across the project. The file is omitted when no union types are used.
- A `masterbelt_masterdata.go` file when the project declares at least one master. The file declares the `MasterData` struct, the `NewMasterData` constructor, and the `With` / `From` context helpers described in [Master Data](#master-data). The file is omitted when the project declares no master.
- A `masterbelt_query.go` file when the project declares at least one master. The file declares the `QueryPlan` value type, the `Predicate` / `Ordering` interfaces, the exported concrete predicate / ordering node structs that back the inspectable AST, the generic field-handle types (`OrderedField[R, V]`, `BoolField[R]`), the combinators (`And`, `Or`, `Not`), and the in-memory executor consumed by every generated relation terminal; see [Master Data](#master-data). The file is omitted when the project declares no master.

All files share the same Go package and live under the configured output root.

The Go target does not emit a separate runtime file at this stage.

## Type Declarations

Each Masterbelt type declaration emits one Go type declaration. Non-product targets use the Go type-alias form so the declared name is a transparent name for the resolved body:

```go
type LocalName[Params] = MappedTargetType
```

Product targets use a defined type so a named, addressable receiver type is available for methods and serializer hooks:

```go
type LocalName[Params] struct { ... }
```

When the declaration carries type parameters, the emitted Go declaration carries the same parameters as a Go type parameter list (`[T any, ...]`). All parameters are emitted with the `any` constraint at this stage. Visibility follows the source program: a `pub`-declared name is emitted under its public Go identifier, while a non-public name keeps the lowercase form per the visibility rule.

At a use site, a generic declaration is rendered with its type arguments: `LocalName[T1, ...]`. A product literal whose declared type is generic is emitted with type arguments on the literal type as well, for example `Container[int]{Value: 1}`.

### Cross-Module References

All modules in a project share one Go package. A reference to a symbol declared in another Masterbelt module emits the bare Go identifier of that symbol; no Go import statement is required and no module qualifier is added to the call site.

Because every module lives in the same Go package, every top-level identifier across the project must be unique under its Go mapping. The target emits no per-module prefix; collisions are reported as a generation diagnostic.

### Re-exports

A `pub { ForeignName as LocalName } from "..."` declaration emits a forwarding `var` in the current module's Go file:

```go
var LocalName = ForeignName
```

The forwarding `var` makes the local name visible alongside the foreign one inside the shared Go package. Go's type inference keeps the declaration's source type identical to the foreign symbol's type.

### Reserved file name prefix

Files invented by the Go target itself, rather than derived from a Masterbelt source file name, use the reserved `masterbelt_` prefix. This keeps generator-managed files in a separate name space from user-named modules so that a Masterbelt file such as `unions.mst` does not collide with the framework's union catalog. New generator-managed files added to this target MUST use the same prefix.

## Package Clause

Each generated file begins with `package <package>` where `<package>` is the configured package option.

## Reachability

The Go target follows the default reachability policy defined in `codegen/model`: only constants reachable from at least one `pub`-declared constant are emitted. Non-public constants that are not referenced by any reachable constant are dropped from the output, including their identifier in any generated file. Identifier references resolve against the surviving set, so a `pub const A = helper` declaration keeps `helper` even though `helper` itself is not public.

## Visibility

A Masterbelt const item carries a public flag from its `pub` modifier. Each Masterbelt identifier is mapped to a Go identifier whose first letter is upper case for public constants and lower case for non-public constants. The remainder of the identifier is preserved as written.

A constant whose Masterbelt identifier starts with a non-letter character (such as `_`) is not currently supported and is a generation error.

## Constants and Variables

Each Masterbelt const item maps to one Go declaration:

- A `const` declaration is used when the constant's type is `bool`, `string`, or any built-in numeric type (`int`, `int8`, ..., `uint64`) and the lowered expression is a corresponding literal.
- A `var` declaration is used for every other case: `null` typed constants, list and map literals, union typed constants, and references to other constants.

The declared Go type follows the type mapping table below. The right-hand side is the lowered expression rendered as a Go expression.

Doc comment lines from the source are emitted as `// <line>` lines immediately before the declaration in source order, with one space inserted between `//` and the original text when the original text has no leading space.

## Type Mapping

| Masterbelt        | Go                                                                 |
|-------------------|--------------------------------------------------------------------|
| `null`            | `any` (the value `null` lowers to the Go untyped `nil`)            |
| `bool`            | `bool`                                                             |
| `int` / `uint`    | `int` / `uint` (Go's natural integer width)                        |
| `int8` / `uint8`  | `int8` / `uint8`                                                   |
| `int16` / `uint16`| `int16` / `uint16`                                                 |
| `int32` / `uint32`| `int32` / `uint32`                                                 |
| `int64` / `uint64`| `int64` / `uint64`                                                 |
| `string`          | `string`                                                           |
| `list<T>`         | `[]T'` where `T'` is the Go mapping of `T`                         |
| `map<K, V>`       | `map[K']V'` where `K'` and `V'` are the Go mappings                |
| `T1 \| T2 \| ...` | Sealed interface generated into `unions.go` (see Unions below)     |
| `{f: T, ...}`     | Defined Go struct type when reached through an alias declaration; see Product Types below |
| `fn(p: T, ...): R`| Go function type `func(p T, ...) R` (see Function Types below)     |
| `enum Name { ... }`| Defined integer type `type Name storage` plus one `const Variant Name = value` per variant; see Enums below |

Type declarations are resolved before mapping; declared types do not appear in generated code.

## Literal Mapping

- `null` lowers to the Go untyped `nil`.
- `true` and `false` lower to the Go literals `true` and `false`.
- An integer literal lowers to its decoded value rendered in base 10.
- A string literal lowers to a Go double-quoted string with Go escape sequences.
- A list literal `[e1, ..., eN]` of type `list<T>` lowers to `[]T'{e1', ..., eN'}`.
- A map literal of type `map<K, V>` lowers to `map[K']V'{k1: v1, ...}` with entries emitted in lowering order after last-wins deduplication.
- An identifier reference lowers to the referent constant's mapped Go identifier.
- A product literal of type `Item` lowers to a Go struct literal `Item{Name: ..., ...}`. Field initializers preserve the source order of the literal; field name keys are upper-cased so they are reachable from any package.

## Master Data

A `master Foo { record { ... } static { ... } }` declaration follows the runtime model defined in [../masterdata/schema.md](../masterdata/schema.md#runtime-model). The Go target emits the following declarations per master:

- `<Master>Record` — the Go struct that backs one row. Field naming, modifiers, and constructor / getter generation follow the regular [Product Types](#product-types) rules; the only difference is the type name suffix.
- `<Master>Relation` — a Go defined struct type that exposes the master's query surface. The relation is a data-less value type carrying only a `QueryPlan[<Master>Record]` field; it does not own records. Records are reached through `MasterData` at terminal time via the per-master accessor `<master>Executor(*MasterData) Executor[<Master>Record]` emitted in the same file. The accessor wraps the records the host supplied to `NewMasterData` (or `LoadJSON`) as a `memoryExecutor` and returns a never-nil `Executor` so terminals can call `Execute` / `FindByPK` unconditionally.
- `<Master>` — a package-level `var` of type `<Master>Relation` initialised with an empty query plan. Authoring a query starts from this value (`Items.Where(...).ToSlice(ctx)`), never from `data.Items`. A `MasterData` accessor for the master is intentionally absent from the public API: the data is reached implicitly through `From(ctx)`.
- Chainable stages and terminals on `<Master>Relation`: copy-on-write `Where`, `OrderBy`, `ThenBy`, `Skip`, `Take`, plus the terminals `ToSlice`, `Iter`, `FindBy`, `FirstOrDefault`, `Count`, `Any`. The full method shapes appear under [Query API](#query-api).

Both types live as siblings at file scope. The Masterbelt source identifier `<Master>` no longer requires a `data.<Master>` accessor: the package-level relation value carries the same name.

Nested masters follow the same naming scheme on the flattened identifier — `master User { master Friendships { ... } }` emits `UserFriendshipsRecord`, `UserFriendshipsRelation`, and a package-level `UserFriendships` value as siblings of the parent. See [Nested Masters](../masterdata/schema.md#nested-masters).

### MasterData Entry

Every project that declares at least one master emits one generator-managed file `masterbelt_masterdata.go` carrying the project-wide dataset entry. The file declares:

- `MasterData` — a struct with one unexported records slice per master in the project (`<master>Records []<Master>Record`). MasterData owns the records, not the relations. The per-master accessor (`<master>Executor(*MasterData) Executor[<Master>Record]`) emitted next to each relation reads this field and wraps it as a `memoryExecutor` so the terminal call site never sees the storage choice; a future `storage: sql` configuration will change the accessor body to return a SQL-backed executor while keeping the call site stable.
- `NewMasterData(<master1> []<Master1>Record, <master2> []<Master2>Record, ...) *MasterData` — a positional constructor that takes one record slice per master in master-declaration order and returns a fully wired `*MasterData`.
- `With(ctx context.Context, data *MasterData) context.Context` — attaches a `*MasterData` to a context so generated terminals reached through that context can resolve the active records.
- `From(ctx context.Context) *MasterData` — retrieves the `*MasterData` previously attached with `With`, returning `nil` when no value was attached.

The Go target never writes `MasterData`, `With`, `From`, or `NewMasterData` in code emitted from a Masterbelt source program: those identifiers exist for the host application to construct and inject the dataset. Generated terminals consult `From(ctx)` to resolve the active records; the public chainable API never names `MasterData` directly.

When `storage: sql` is configured, the layout above changes:

- `MasterData` carries a single `db SQLDB` field shared by every per-master executor; the per-master records slices are not emitted.
- The positional `NewMasterData(...)` constructor is replaced by `NewSQLMasterData(ctx context.Context, db SQLDB) (*MasterData, error)` so the host application supplies a connection rather than record slices. The constructor stores the supplied `SQLDB` and returns; per-master executors fetch rows on demand through the connection.
- `With` and `From` are unchanged.
- `LoadJSON` is not emitted under `storage: sql`. Hosts that want to seed a SQL backend from the JSON exporter should round-trip the data through the SQLite exporter (see [../masterdata/export-sqlite.md](../masterdata/export-sqlite.md)) and open the resulting database.

The `SQLDB` interface, the matching `SQLRows` / `SQLRow` row interfaces, and the `translatePlan` / `translatePKLookup` helpers live in `masterbelt_query.go`. A host built on `database/sql` wraps `*sql.DB` in a small adapter that satisfies `SQLDB`; alternative SQLite bindings can do the same without dragging a particular driver into the generated package.

The adapter is a handful of lines because `*sql.DB.QueryContext` returns a `*sql.Rows` rather than the generated `SQLRows`:

```go
type sqlDBAdapter struct{ db *sql.DB }

func (a sqlDBAdapter) QueryContext(ctx context.Context, query string, args ...any) (masters.SQLRows, error) {
	rows, err := a.db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	return rows, nil // *sql.Rows already satisfies SQLRows
}

func (a sqlDBAdapter) QueryRowContext(ctx context.Context, query string, args ...any) masters.SQLRow {
	return a.db.QueryRowContext(ctx, query, args...) // *sql.Row already satisfies SQLRow
}

// db, _ := sql.Open("sqlite", "masterdata.db") // host registers its own driver
// data, _ := masters.NewSQLMasterData(ctx, sqlDBAdapter{db: db})
```

`*sql.Rows` and `*sql.Row` already satisfy `SQLRows` / `SQLRow` structurally, so the only wrapping needed is the `QueryContext` return type. The host registers a SQLite driver (`modernc.org/sqlite`, `github.com/mattn/go-sqlite3`, ...) and owns the `*sql.DB` open/close lifetime; the generated code never imports a driver.

Under `storage: memory` the same file also declares `LoadJSON(data []byte) (*MasterData, error)`, a helper that unmarshals the JSON document produced by the JSON exporter (see [../masterdata/export-json.md](../masterdata/export-json.md)) into a fresh `*MasterData`. The function uses `encoding/json` only and is independent of any backend library:

```go
func LoadJSON(data []byte) (*MasterData, error) {
    var raw struct {
        Items           []ItemsRecord           `json:"items"`
        UserFriendships []UserFriendshipsRecord `json:"userFriendships"`
        // ... one per master in declaration order
    }
    if err := json.Unmarshal(data, &raw); err != nil {
        return nil, err
    }
    return NewMasterData(raw.Items, raw.UserFriendships /* ... */), nil
}
```

Each generated `<Master>Record` struct carries a `json:"<surfaceName>"` tag on every field so the inner record objects round-trip with the surface field names as JSON keys. The surface name is the master's source-level field identifier verbatim (`id`, `name`, `userId`) without any case transformation. A `ref<T>` field expands to the underlying primary-key fields under the surrounding field's name joined with `_` (`field_pk1`, `field_pk2`, ...); the JSON tag on each expanded leaf carries the joined source name. Other product types not declared inside a `master` block do not receive JSON tags.

### Static Body Rewrites

A user-declared static method's body is rewritten so the planner-side master references resolve against the package-level relation values and the threaded dataset:

- `Master.toList()` inside the owning master's own static body lowers to `r.ToSlice(ctx)` against the receiver of the surrounding relation method. The receiver is the relation value the static method was invoked on, so a caller that chains stages onto `r` before invoking the static observes those stages.
- `Master.X` (any user-declared static constant or method) inside the same owning master's body lowers to `r.X(ctx)` for a constant or `r.X(ctx, ...)` for a method.
- `OtherMaster.toList()` (a cross-master reference) lowers to `<OtherMaster>.ToSlice(ctx)` against the package-level relation value.
- `OtherMaster.X` (any other cross-master reference) lowers to `<OtherMaster>.X(ctx, ...)` against the package-level relation value.

The receiver of the surrounding relation method is named `r` so a chained owner-self reference never collides with the `self` receiver used by record-attached methods.

### Top-Level Dataset Threading

A top-level function or product-type method that transitively reaches any master static member (constant or method, including the built-in `toList()`) implicitly acquires the dataset and threads it through every call that needs it. The Go target piggy-backs on the existing cancellable inheritance machinery: a function that reaches a master is treated as effectively cancellable, so it receives the same `ctx context.Context` first parameter the cancellable transform adds and forwards it through call sites that also became effectively cancellable. Effects already in scope (`failable`, `asyncable`) compose with the synthesized cancellable transform without further interaction.

The Masterbelt source program never declares `cancellable` for the purpose of master access; the codegen-side inference is invisible at the surface.

### Query API

Every master emits the chainable surface directly on `<Master>Relation`. Predicates and orderings are constructed by methods on a package-level field handle; there is no separate `<Master>Query` type in the public API. See [../masterdata/query.md](../masterdata/query.md) for the cross-target contract and [../masterdata/schema.md](../masterdata/schema.md#query-api) for how it ties into the master-data schema.

The per-master declarations are:

- `<Master>Fields` — a package-level variable that holds one typed field handle per supported record field. The variable is exported regardless of the master's visibility because the field handles are the call-site authoring surface. The backing struct type is unexported (`<master>FieldsStruct`); users reach the field handles through the variable (`ItemsFields.Category.Eq("weapon")`) and never name the struct directly. Fields whose Go type is not one of the supported primitives (numeric, string, bool) are omitted from the field builder silently; the user-facing query API still emits for the rest of the surface.
- Stage methods on `<Master>Relation` (value receivers): `Where(predicate Predicate[<Master>Record]) <Master>Relation`, `OrderBy(ordering Ordering[<Master>Record]) <Master>Relation`, `ThenBy(ordering Ordering[<Master>Record]) <Master>Relation`, `Skip(n int) <Master>Relation`, `Take(n int) <Master>Relation`. Each method returns a freshly allocated relation whose plan field extends the receiver's plan; the receiver is never mutated, so a base relation can be shared across independent chains.
- Terminal methods on `<Master>Relation`: `ToSlice(ctx context.Context) ([]<Master>Record, error)`, `Iter(ctx context.Context) iter.Seq2[<Master>Record, error]`, `FindBy(ctx context.Context, k1 T1, ...) (<Master>Record, bool, error)`, `FirstOrDefault(ctx context.Context) (<Master>Record, bool, error)`, `Count(ctx context.Context) (int, error)`, `Any(ctx context.Context) (bool, error)`. Every terminal carries the same three effects as `toList()` / `FindBy`; the Go target renders the `cancellable` slot (`ctx`) and the `failable` slot (trailing `error`) explicitly.

`Iter` returns `iter.Seq2[<Master>Record, error]` from the standard `iter` package so user code consumes the relation with `for record, err := range Items.Where(...).Iter(ctx) { ... }`. The iterator consumes the same plan as `ToSlice`; backends that can stream a particular operation are free to do so, but the public iterator contract is stable.

`FindBy` honours the relation's `Where` predicates: a primary-key match that fails the filter chain returns the zero record with ok=false. `OrderBy`, `ThenBy`, `Skip`, and `Take` do not affect `FindBy`.

The `QueryPlan[R]` value type, the `Predicate[R]` / `Ordering[R]` interfaces, the exported concrete node structs (`EqPredicate`, `LtPredicate`, `BetweenPredicate`, `AndPredicate`, `AscOrdering`, ...), the generic field-handle types `OrderedField[R any, V cmp.Ordered]` and `BoolField[R any]`, the combinators `And(...)`, `Or(...)`, `Not(...)`, the `Executor[R]` seam consumed by every terminal, the `memoryExecutor[R]` in-memory implementation, and the iterator helpers `iterMemoryPlan` / `iterMemoryError` / `iterMaterialised` all live in the generator-managed `masterbelt_query.go` file. Backends can inspect a relation's plan structurally — every concrete node carries its field reference and operand values — without invoking the closures the in-memory evaluator uses.

```go
weapons, err := masterdata.Items.
    Where(masterdata.And(
        masterdata.ItemsFields.Category.Eq("weapon"),
        masterdata.ItemsFields.Level.Ge(10),
    )).
    OrderBy(masterdata.ItemsFields.SortOrder.Asc()).
    Take(10).
    ToSlice(ctx)
```

### Scope Methods

Each `pub` [scope](../masterdata/schema.md#scope-section) on a master emits an exported method on `<Master>Relation`; a non-`pub` scope is internal to Masterbelt source and is not emitted. The method name is the source scope name in PascalCase (`genderedAdult` → `GenderedAdult`). Its parameters are the scope's declared parameters mapped through the regular [Type Mapping](#type-mapping); it takes no `ctx` and no `error` because a scope is effect-free.

```go
func (r <Master>Relation) <Scope>(<params>) <Master>Relation
```

The method returns a `<Master>Relation`: it extends the receiver's plan with the scope body's stages (with chained scopes inlined) and returns a fresh relation, exactly like the built-in stage methods, so a scope composes with `Where` / `OrderBy` and with other scopes (`masterdata.Records.Adult().Gendered(1)`). The method is backend-independent — it builds a plan and is identical under `storage: memory` and `storage: sql`. A call to a non-`pub` sibling scope is inlined into the method body (with its parameters substituted), because only `pub` scopes are emitted as methods; a call to a `pub` sibling scope is a method call. An `indexed` scope adds no Go surface beyond what its `pub` flag implies; it only influences SQLite index generation.

### Select Projections

Each `select Name { ... }` section on a master ([../masterdata/schema.md](../masterdata/schema.md#select-section)) emits a parallel set of declarations alongside the source relation:

- `<Master><Name>Record` — a Go defined struct type carrying the projected fields. Field order matches the order written in the select body; field types are copied from the master's record by name.
- `<Master><Name>Fields` — the package-level field builder for the projected record, with the same shape as `<Master>Fields` but parametrised on the projected record.
- `<Master><Name>Relation` — the projected relation type. It carries the source relation by value plus its own `QueryPlan[<Master><Name>Record]`. Its stage and terminal methods mirror the source relation's surface, parametrised on the projected record type. Stage methods accept `Predicate[<Master><Name>Record]` / `Ordering[<Master><Name>Record]`; terminals carry the same `(ctx context.Context, ...) (..., error)` shape as the source relation's terminals.
- `Select<Name>() <Master><Name>Relation` — a method on `<Master>Relation` that returns a fresh projected relation capturing the receiver's source-side plan.

Terminals on the projected relation first apply the source-side plan against the master's record slice, then project each surviving record into a `<Master><Name>Record` by copying the named fields, and finally apply the projected plan to the projected slice. Predicates and orderings added through the projected relation are typed on the projected record, so authoring `Where(ItemsSummaryFields.Name.Eq("alpha"))` against an `ItemsSummaryRelation` is a compile-time match; passing a source-record predicate to the projected relation is a compile-time error.

Projected relations do not expose `FindBy`: the projected record does not have a primary-key concept.

```go
summaries, err := Items.
    Where(ItemsFields.Count.Ge(10)).
    SelectSummary().
    OrderBy(ItemsSummaryFields.Name.Asc()).
    ToSlice(ctx)
```

### Join Operator

Each `ref<Target>` field on a master's record ([../masterdata/relations.md](../masterdata/relations.md)) emits a parallel set of declarations alongside the source relation:

- `<Master>Join<Field>Pair` — a Go defined struct type with two exported fields, `Left <Master>Record` and `Right <Target>Record`. The pair is the join's record-side aggregate.
- `<Master>Join<Field>Fields` — a package-level field builder for the pair record. The variable's struct exposes nested `Left` and `Right` sub-builders, each carrying one typed field handle per supported primitive on the corresponding side (including the expanded ref-field columns on the left). Each handle's accessor reads `pair.Left.<field>` or `pair.Right.<field>`.
- `<Master>Join<Field>Relation` — the joined relation type. It carries the source relation by value, the right relation supplied at the call site, and its own `QueryPlan[<Master>Join<Field>Pair]`. Its stage and terminal methods mirror the source relation's surface, parametrised on the pair record. Stage methods accept `Predicate[<Master>Join<Field>Pair]` / `Ordering[<Master>Join<Field>Pair]`; terminals carry the same `(ctx context.Context, ...) (..., error)` shape as the source relation's terminals.
- `Join<Field>(right <Target>Relation) <Master>Join<Field>Relation` — a method on `<Master>Relation` that returns a fresh joined relation capturing the receiver as the source side, the supplied relation as the right side, and a fresh pair-level plan.

Terminals on the joined relation first call `ToSlice(ctx)` on the source relation (so source-side state applies first), then iterate the surviving left records and call `right.FindBy(ctx, leftRecord.<field>_<pk1>, ...)` for each, emitting a `<Master>Join<Field>Pair{Left: ..., Right: ...}` on a successful match and dropping the row on a non-match (INNER JOIN; `LEFT` / `RIGHT` / `FULL OUTER` deferred). Pair-level state (predicates, orderings, skip, take) then applies to the pair slice before the terminal returns.

Joined relations do not expose `FindBy`: the pair record does not have a primary-key concept.

```go
pairs, err := B.
    JoinARecord(A).
    Where(BJoinARecordFields.Right.Name.Eq("alpha")).
    OrderBy(BJoinARecordFields.Left.Id.Asc()).
    ToSlice(ctx)
```

## Product Types

A Masterbelt type declaration whose target is a product type emits a defined Go struct type rather than the type-alias form used for other targets:

```go
type Item struct {
    Name string
    Count int
}
```

The field order matches the field order written in source. A defined type is used so methods and serializer hooks can be attached to the struct receiver idiomatically.

Each field's Go visibility follows its Masterbelt modifier. A field with no modifier (or with the explicit `writable` modifier) is emitted as an exported field with a Title-cased name; a `readonly` field is emitted as an unexported field with a lower-cased name. Mutable fields stay directly assignable; readonly fields can only be set at construction.

When any field of a product declaration carries `readonly`, the target also emits:

- A `NewName[P](field1 T1, ...) Name[P]` constructor that takes every field as a positional parameter in source order and assigns it to the corresponding struct field. The constructor is the only way external callers can populate the unexported readonly fields.
- A value-receiver getter method per readonly field. The getter's name is the Title-cased form of the field's Masterbelt identifier and its return type is the field's mapped Go type.

At a use site, a product literal whose declared type carries any readonly field lowers to a `NewName(...)` constructor call with arguments rearranged into source order. Without any readonly field the literal continues to lower to the existing struct literal form `Name{Field: ...}`.

A `readonly` field whose generated getter name would collide with another field's exported Go name (for example, a readonly field `name` whose getter `Name()` would shadow a mutable field `Name`) is a generation error reported with `masterbelt.codegen.golang.field_modifier_collision`.

A product literal `Item { name: ..., count: ... }` lowers to a Go struct literal whose type is the alias name and whose field initializers use the upper-cased field names.

## Function Types

A Masterbelt function type lowers to a Go function type `func(name T, ...) R`. A type declaration whose body is a function type emits a Go type-alias declaration following the rule in [Type Declarations](#type-declarations):

```go
type BinaryOp = func(left int, right int) int
type Mapper[T any, U any] = func(value T) U
type Summer = func(initial int, values ...int) int
```

Parameter names are preserved from source. A variadic parameter prefixed with `*` in source lowers to a Go variadic parameter prefixed with `...`; the element type is the parameter's declared type. A variadic parameter is permitted only as the last parameter (the language rule defined in [language/types.md](../language/types.md) is enforced before generation).

Effects defined in [Effects](#effects) shape the rendered signature:

- `cancellable` inserts a `context.Context` parameter at the beginning of the parameter list, before any declared parameters.
- `failable` appends an `error` result, yielding a `(R, error)` return tuple where `R` is the declared return type.
- `asyncable` does not change the rendered signature; see [Effects](#effects) for the rationale.

A function type that combines multiple effects applies every transformation listed above.

## Enums

A Masterbelt enum lowers to a Go defined integer type plus one `const` declaration per variant. The defined-type form (no `=`) preserves the enum's nominal identity in Go: the enum type is not interchangeable with its storage type without an explicit `Storage(variant)` conversion at the call site.

```go
type Status int8

const Active Status = 0
const Inactive Status = 1
```

Variant identifiers are emitted at package scope under their source names. A variant whose value was explicit in source uses that value; a variant without an explicit value uses 0 for the first variant and the previous variant's value plus one thereafter (the language rule defined in [language/types.md](../language/types.md)).

A member access expression `Enum.Variant` lowers to the bare Go identifier for the variant. The surface-level dot is not preserved because each variant is already accessible as a package-scope identifier; the type system carries the enum type through the call site.

## Functions and Methods

A top-level function declaration emits a Go `func Name(params) Result { ... }` at package scope. The function name is rendered with the C# convention's capitalization rule: public functions become exported PascalCase identifiers; non-public functions stay lowerCamelCase. Effect modifiers reshape the signature per the [Effects](#effects) section.

A method declared inside a product type emits a Go receiver function `func (self Owner) Method(params) Result { ... }` against the owning struct type. The receiver is named `self` in the emitted Go so a Masterbelt method body that references the implicit `self` keyword maps one-to-one onto the Go receiver. Methods that share a name (overloaded methods) are disambiguated by a 1-based numeric suffix: the first overload keeps the original name, the next is `Method1`, then `Method2`, and so on. Call sites carry the same suffix so the dispatch is decided at the call site by the checker's overload resolution.

A call expression `target(args)` emits the Go call form `target(args)`. A method call `value.method(args)` emits `value.Method(args)` (with the overload suffix when applicable).

A function literal `fn(params): R { ... }` emits a Go function literal `func(params) R { ... }` inline at its surrounding expression position.

A return statement emits the Go `return` statement, optionally followed by the value expression.

## For Statements

A Masterbelt for statement lowers to a Go `for` statement. The IR subject shape selects the form:

- `list<T>` subject — `for _, name := range list { ... }`. A skipped value binding (`_` in source) is rendered as Go's `_`.
- `map<K, V>` subject — `for k, v := range m { ... }`. Either binding renders as `_` when skipped.
- `range(start, end)` subject — `for i := start; i < end; i++ { ... }` with `i` named after the source binding. A `_` binding still requires a loop variable; the Go target synthesizes a local named `__mbI` whose only purpose is to advance the counter.

A `break` statement lowers to the Go `break` keyword; a `continue` statement lowers to the Go `continue` keyword. The Go compiler enforces the rule that both must appear inside a `for` body; the Masterbelt checker has already established that, so the generated code passes the check trivially.

The lowered subject expression is evaluated exactly once (Go's `range` and counted-for forms both have a single evaluation point), matching the language's once-only semantics. Iteration over a `Master.toList()` subject lowers through the [Master Data](#master-data) rewrite: `Items.ToSlice(ctx)` against the package-level relation for a cross-master subject and `r.ToSlice(ctx)` when the iteration appears inside the owning master's own static body. Because `toList()` is `failable`, the surrounding callable inherits the same effect (the Go signature gains a trailing `error` result) and the for-loop subject is lifted into a `__mbRecords, __mbErr := <call>` short variable declaration plus the standard failable propagation guard before the `for _, x := range __mbRecords { ... }` loop — same shape the [Failable Handling](#failable-handling) section defines for `let x = <failable call>`.

## Master Static Members

A master's static section ([../masterdata/schema.md](../masterdata/schema.md#static-section)) emits its members on the master's `<Master>Relation` type (see [Master Data](#master-data)):

- A `static const Name: T = value` emits as a value-receiver method `func (r *<Master>Relation) Name() T { return value }`. The constant body has the same dataset-rewriting rules as a method body so a constant initializer that calls another master's static member resolves through `From(ctx).Other.X(ctx)`.
- A `static fn name(params): R { body }` emits as a value-receiver method `func (r *<Master>Relation) Name(ctx context.Context, params) R { body }`. The first parameter is always `ctx context.Context`; the rest of the parameter list and the return type follow the regular function-type mapping including the effect-driven signature transforms (`failable`, `asyncable`) described in [Effects](#effects).

A `pub` static member emits a Title-cased Go method name; a non-public member emits a lower-cased name. Visibility is independent from the master's own `pub` modifier.

The source-level access `Items.X` inside any callable's body lowers per the [Master Data](#master-data) rewrite rules: the owner-self case resolves to `r.X`, and the cross-master case resolves to `From(ctx).<Other>.X` (with `(ctx, args)` when called).

## Match Statements

A Masterbelt match statement lowers to one of three Go forms depending on the subject's resolved type:

- **Union subject** lowers to a Go type switch on the lowered subject. Each arm becomes one `case` whose case type is the Go form of the arm's pattern type (the wrapper type for a non-null union member, or `nil` for the union's null member). Bindings introduced by the pattern are emitted as local variables in the case body; a type pattern binding extracts the wrapper's `Value` field for non-null members, and uses the subject directly for the `nil` case. A product pattern emits field accesses on the matched value to populate its short-form field bindings. The narrowing of the original subject identifier (when the subject is a plain identifier) emits an additional `name := <extracted>` assignment at the top of the case body using the same narrowed expression. When the match is statically exhaustive no `default` case is emitted; a wildcard arm becomes a `default` case.
- **Enum or literal subject** lowers to a Go value switch on the lowered subject. Each arm becomes one `case` whose case expression list is the arm's enum-pattern or literal-pattern alternatives. A wildcard arm becomes the `default` case.
- **Subject with mixed arm kinds** (for example a union of primitives where some arms are literals and some are type patterns) lowers to an `if`/`else if` chain. Each arm's condition combines a type-assertion check (for type and product patterns) with literal equality checks; bindings are introduced inside the `if` body using the same extraction rules described above.

Guards lower as an `if` check wrapping the arm body. When a guarded arm's guard evaluates to `false`, control falls through the type switch (Go's `case` does not fall through by default, so the synthesized fallthrough is achieved by structuring guarded arms as `if`/`else if` chains nested inside the case).

The Go target emits no `panic` or `default` arm to absorb unhandled cases when the checker has proven exhaustiveness. A wildcard arm explicitly written in source lowers to `default:` (for switch forms) or a trailing `else { ... }` (for the if-chain form).

A match statement is otherwise emitted at its source position inside the surrounding Go function body and shares the function's local scope. The lowered subject is evaluated exactly once at the head of the switch (or assigned to a fresh local at the top of the if-chain).

## Operator Expressions

The unary and binary operator expressions defined in [language/syntax.md](../language/syntax.md) reach the Go target as method calls on the operand's type (see [language/builtins.md](../language/builtins.md)). When the receiver is a built-in primitive type (or an alias whose target resolves to a primitive), the Go target emits the call as the corresponding native Go operator instead of a method invocation:

- Numeric operands emit `+ - * / % == != < <= > >= & | ^ << >>` directly.
- `bool` operands emit `&& || == !=`; the bitwise-shaped methods `and`/`or`/`xor` on `bool` lower to `&& || !=` respectively. Unary `not` emits `!`.
- `string` operands emit `+` for `add` and `== != < <= > >=` for the comparisons.
- Unary `plus`, `minus`, and `not` emit `+`, `-`, and `!`.

A user product type that declares one of the operator method names continues to lower through the regular method call path: the call site emits `receiver.Method(args)` (with the overload suffix when applicable). The native-operator rewrite applies only when the receiver's resolved type is a primitive.

### Built-in Field Accesses

The fields defined in [language/builtins.md](../language/builtins.md) on built-in primitive and generic types lower to native Go expressions:

- `string.length` lowers to `utf8.RuneCountInString(receiver)` (with the `unicode/utf8` import added automatically). The result is the number of Unicode codepoints in the string, matching the spec semantics for `string.length`.
- `list<T>.size` and `map<K, V>.size` lower to `len(receiver)`. The Go `len` built-in returns the slice length and the map entry count respectively, both of which agree with the spec's element / entry count semantics.

No runtime helper is emitted for these fields; the lowering inlines the call at the access site.

### Built-in Generic Operator Methods

`list<T>.add(other)` and `map<K, V>.add(other)` defined in [language/builtins.md](../language/builtins.md) lower to a call into a runtime helper that the Go target writes alongside the generated module files. The helper file is named `masterbelt_runtime.go` (the same reserved `masterbelt_` prefix used by the union file) and is emitted only when at least one generated module references a helper from it.

The helper file declares the package functions used at call sites:

- `masterbeltListAdd[T any](a, b []T) []T` returns a fresh slice containing the elements of `a` followed by the elements of `b`.
- `masterbeltMapAdd[K comparable, V any](a, b map[K]V) map[K]V` returns a fresh map containing every entry of `a` and every entry of `b`, with keys present in both taking the value from `b`.

Call sites for `list.add` emit `masterbeltListAdd(a, b)`; call sites for `map.add` emit `masterbeltMapAdd(a, b)`. The helpers live in the same Go package as the rest of the generated code, so the call site uses the bare identifier without any import qualifier.

## Unions

A union type lowers to a Go sealed interface. For a canonical union `T1 | T2 | ... | TN`:

- The interface type is named by concatenating the title-cased member type names with `Or`. For primitive members, the title-cased names are `Null`, `Bool`, `Int`, `String`. The order matches the canonical order recorded in the IR, which is the lexicographic order of each member's textual type spelling.
- The interface declares one unexported method whose name is `is<Interface>` so only generated types satisfy it.
- For each non-null member type, the file declares a Go wrapper type named `<Interface><Member>` with a single exported `Value` field of the Go type for that member, and implements `is<Interface>` on the wrapper.
- The `null` member does not get a wrapper type. The Go untyped `nil` is the zero value of any interface and serves as the null member's representation directly; an interface variable holding `nil` compares equal to `nil`.

A value of a union type lowers as a wrapper struct literal `<Interface><Member>{Value: <expression>}` for non-null members, and as the Go literal `nil` for null.

At this stage, only unions of primitive types are supported. A union containing a generic member is a generation error.

## Effects

Each effect defined in `codegen/model` maps to Go as follows:

- `cancellable` adds a `context.Context` parameter as the first parameter of the callable.
- `failable` adds a trailing `error` return value to the callable.
- `asyncable` has no idiomatic Go signature transform at this stage; a function type carrying `asyncable` is rendered as if the effect were absent. The lack of mapping is a known limitation: Go has no language-level future/promise type, and the target reserves an explicit choice (such as introducing a runtime channel helper) for a later design pass.

Every effect is inferred along the call graph: the Go target computes an effective effect set per callable by walking from the declared effects and propagating through every transitive call site to a fixed point. A function whose effective set differs from its declared set still renders with the inferred shape. A callable that carries multiple effective effects combines all applicable transformations on its signature; the parameter ordering is `context.Context` first, then declared parameters; the return ordering is declared results followed by `error`.

A caller invokes the resulting Go callable with the inherited context and propagates the returned error using ordinary Go control flow. The Go target does not invent helper macros or wrappers around the call site; effect propagation is recorded by the effective-effect inference and applied during signature rendering and call-site lowering.

## Failable Handling

A function whose effective effect set contains `failable` carries an `error` second result in its Go signature (see [Effects](#effects)). The effective set is the union of the declared effects and the effects of every function the body transitively calls; a non-failable declaration whose body calls a `failable` function still renders as `(T, error)` in Go. The surface program never has to acknowledge this transport (see [language/semantics.md](../language/semantics.md#failable-handling)); the Go target plumbs it transparently:

- `fail "message"` emits `return zero, errors.New("message")` where `zero` is the success-typed zero value (`*new(R)`).
- `fail err` where `err` is an `Error` value emits `return zero, errors.New(err.Message)`.
- A call whose callee is effectively failable, inside a body that is also effectively failable, is rewritten to receive both results and to short-circuit on a non-nil error. For a binding `let x = f()` the emission is `x, __mbErr := f(); if __mbErr != nil { return zero, __mbErr }`; for `return f()` it is the analogous tuple form. The user never writes the guard.

A match expression cannot observe the Error path of a `failable` call subject because the surface type of the call is `R`; the synthesized local for the failure value is internal to this lowering.

## Imports

The Go target's emitter is responsible for assembling the file's import block from the symbols referenced during rendering. A symbol carries the Go import path of the package it lives in and the unqualified identifier name. The emitter:

- Aggregates the set of referenced import paths across every declaration written into a file.
- Picks a default alias from the path's last segment (skipping a trailing `/vN` major-version suffix).
- When two distinct paths share the same default alias, the emitter renames later occurrences by appending a numeric suffix until uniqueness is reached.
- Writes a Go `import (...)` block listing every referenced path; unused references produce no import.
- Rewrites identifier renderings as `alias.Name` for every external reference.

The default alias of the local package is empty: symbols declared in the same generated file reference each other without qualification.

Targets MUST express external references through this emitter mechanism. Inlining raw import paths into source bypasses collision handling and is forbidden.

## Determinism

Generated files are deterministic with respect to the input modules and options. Constants appear in source order within each module file. Union and wrapper type declarations appear sorted by interface name in `masterbelt_unions.go`. Map literal entries appear in lowering order (first occurrence position, last-wins value). Import blocks are emitted in lexicographic path order.
