Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/docs/tuple-design.md

Tuple Representation Boundary

This document defines the cross-crate representation contract for the v0.33.0 tuple milestone. Public tuple behavior belongs exclusively to spec/33-tuples.md. Private algorithms and module layouts remain in each workspace crate's colocated README.md and Rust source.

Design Decision

A source tuple is one structural semantic type. It is not lowered into a synthetic nominal type, encoded as a keyed argument-pack entry, or reconstructed independently by editor and backend code. Ordered element types are the complete identity.

The representation flows in one direction:

tuple syntax
    -> semantic tuple TypeId
    -> checked positional aggregate and tuple places
    -> MIR positional aggregate and projections
    -> closed runtime tuple shape
    -> frozen MachineLayoutStore tuple layout
    -> machine aggregate reads and writes

Every arrow consumes the preceding contract. A later stage may attach target-specific facts, but it must not parse source, invent element types, or repeat semantic selection.

Sole Authorities

FactSole authorityConsumers receive
Parentheses denote grouping, closure syntax, callable syntax, or tuple syntaxsyntax parserimmutable syntax nodes
Tuple identity and structural propertiessemantic TypeStoreone interned TypeId and its ordered elements
Expression type, move/copy state, loans, and element provenancechecked-program constructionchecked values, places, and binding plan
Runtime operations and destruction orderMIR constructionconcrete positional aggregates, projections, and destruction plans
Concrete runtime shapeexecutable-program constructionclosed runtime tuple element identities
Alignment, padding, size, offsets, and ABI classmachine-program construction through MachineLayoutStorefrozen layout facts
Registers, stack slots, addresses, and instructionsmachine loweringmachine operations over frozen offsets
Canonical user-facing spellingsemantic presentationrendered (A, B, C) text and semantic source ranges

The source index records occurrences and semantic identities. It cannot decide whether a value is a tuple, choose an element type, or affect checking.

Semantic Model

The semantic type model gains a dedicated tuple kind containing at least two TypeId values. Type interning derives identity from the complete ordered slice. Structural properties such as concreteness and potential storage are calculated at interning time from those elements and then read by consumers.

PackEntry remains a separate compiler-owned type. It represents keyed pack expansion and is not source tuple syntax. Nominal structs retain declaration identity and named FieldId values. A tuple element uses its position; manufacturing fake fields would incorrectly give a structural type declaration-owned identity.

Checked Product Contract

A checked tuple construction contains its tuple TypeId and checked elements in source order. A tuple projection contains an element position and its already-resolved type. Loan and move paths retain that position, allowing different elements to be proven disjoint without consulting syntax or nominal declarations.

Local destructuring is represented by a recursive checked binding pattern containing local identities, discard leaves, and tuple branches. The checked initializer operation is the sole authority for its already-established move or copy behavior. MIR construction consumes both facts; it does not type-check the source pattern or infer transfer behavior again.

The internal binding-pattern contract is recursive even though v0.33.0 exposes it only for local let and var statements. Name and discard leaves plus tuple branches are sufficient. Future parameter or control-flow patterns may consume the same checked contract only after their public semantics are specified.

Executable and Layout Contract

Executable-program construction rejects symbolic tuple elements just as it rejects every other symbolic runtime type. Its runtime tuple shape contains the exact concrete element identities. It does not create declaration or field representations for a structural tuple.

MachineLayoutStore produces one ordered product layout containing an element layout and offset for each position. MIR projection, aggregate construction, and destruction all consume those positions. Machine lowering may share generic aggregate-copy and ABI machinery with structs after layout has erased the semantic distinction, but it must not recover tuple shape from size or source syntax.

Presentation Contract

The semantic type renderer is the sole tuple-spelling authority. Hover, completion, inlay hints, signature help, and diagnostics consume that renderer or its structured result. Numeric source projections resolve through checked tuple-place evidence; they are not entered into the nominal member index and do not receive synthetic definitions.

Formatter behavior is syntax-owned. It may choose one-line or multiline layout, but it cannot use semantic analysis to decide whether parentheses form a tuple.

Rejected Encodings

  • Synthetic struct per tuple type: adds fake declarations and fields, contaminates visibility, navigation, conformance, and identity, and makes structural equality depend on construction order.
  • Reuse PackEntry: conflates keyed expansion with positional products and exposes an internal type that semantic presentation intentionally cannot render.
  • Backend-only tuple lowering: leaves checking without element-place identity and causes the backend to repeat ownership and shape decisions.
  • LSP tuple parser: creates a second source-language interpretation and diverges under recovery.
  • Whole-tuple-only ownership: prevents disjoint element loans and partial moves, making tuples materially less capable than structs without a semantic reason.

Implementation Order

  1. 1. Add syntax nodes, semantic tuple interning, canonical presentation, and recursive local binding syntax. Checking must own tuple typing and produce checked element places and binding plans.
  2. Carry those checked facts through MIR, destruction, runtime shape, target layout, and machine lowering. Execute tuple returns, calls, projections, partial moves, borrows, and drops natively.
  3. Complete formatter and editor behavior, then add practical standard-library APIs whose result is genuinely positional. Keep named public records named.

Each step must remove temporary exhaustiveness gaps before it is committed. No stage may introduce a compatibility representation that a later step is expected to reinterpret or delete.