Landin the specification source

The Landin specification

This is the normative document. tour.md explains the language and this says what it is; where the two could be read differently, this one decides. It is deliberately partial and it grows one slice at a time, so it says what is true today rather than what is intended.

Three things are in here and the difference matters.

The grammar of the enabled kernel, [1740] to [1830], covers the constructs the compiler enables today and nothing else, so that what a program may say and what the compiler will accept are the same sentence. A construct tour.md describes and this grammar omits is not enabled yet, and the compiler says so by [1830] rather than guessing.

The rules the tour left unsaid, [1840] to [2000], are not about the kernel and they will not be deleted as it grows: that a comparison yields a bool, that an immutable binding may not be written, that a name must be assigned before it is read. The tour teaches by example and a tutorial omits what a reader supplies for themselves, so each of these was found by an implementation needing a rule and finding none. Each cites the sentence it derives from.

The decisions this document took are the register after them. A rule in either part above is a transcription of something the tour already decided or a decision taken because the tour said nothing, and a reader cannot tell the two apart by reading one; the decisions are named in the register, each with the alternative it was chosen over and the fixture that pins it.

All three are ordered by subject, and the numbers are not. An id is a stable citation anchor and never moves, so [1950] sits beside [1890] because both say what an operator takes, and D1 sits beside D233 because both say what a declaration introduces. What is read first and what was found first stopped being the same thing.

THE GRAMMAR OF THE ENABLED KERNEL

The notation is ordinary: a name in lower case is a rule, a quoted word is itself, '?' is optional, '*' is none or more, '+' is one or more, '...' between two quoted bytes is every byte from one to the other, 'any byte' is exactly that, and parentheses group. 'any Unicode scalar' denotes the shortest-form UTF-8 encoding of one scalar value, subject to its stated exclusions. Nothing here is a parser generator's input. The parser is hand written, and this is the agreement it is written against.

The rules come in two layers, and the difference matters. The lexical layer reads bytes. identifier, keyword and literal each produce one token; space, line_end and comment produce no token at all and are discarded where they are found; the rest of that layer spells out part of one of those and produces nothing of its own. Every other rule reads the tokens that remain, and a quoted word or sign in one of them stands for the single token spelled that way. A quoted word is not thereby reserved: when [1760]'s keyword rule omits it, the token is an identifier whose spelling the enclosing production recognises. Thus 'of', 'lenof', 'variant', 'caller', 'range', 'arena', 'concept', 'is', 'as', 'option', 'compiler', 'assembler', 'linker', 'c', 'layout', 'optimal', 'packed', 'at', 'u8', 'u16', 'u32', 'u64', 'link', 'symbol', 'align', 'section', 'keep', 'vector', 'interrupt', 'naked', 'noreturn', 'distinct' and 'out' remain identifier tokens everywhere their contextual productions do not meet them. D225 reserves control words in every position, including ordinary name positions. The packed_unsigned production names contextual representation widths; it does not expand the ordinary scalar family. D202 separately reserves the three tool names as declaration/import bindings; that semantic reservation does not turn their tokens into keywords. A token is as long as it can be, comments excepted, whose opener decides [1780]: 'inc' followed by 'x' with nothing between them is the one name 'incx', which is why [1750] says what separates two tokens.

1740

A source file is an import prelude and declarations in any order

A source file is a possibly empty import prelude followed by declarations in any order. All reached source files together are the program. Declaration order does not affect name lookup inside a module [0130]: names are collected as a set, and a name may be used above the line that introduces it. Active linker.library directives retain canonical source/declaration order for archive resolution (D202). 'public' rides on a declaration and not on a statement [0090]: what a module exports is decided where the module is written, never inside a body.

program     ::= import_declaration* declaration*
import_declaration ::= "import" import_path
                       ("as" identifier | "(" identifiers ")")?
import_path ::= identifier ("/" identifier)*
declaration ::= "public"? (atom_declaration | binding | function
                            | external_function | machine_function | linked_binding
                            | type_declaration
                            | concept_declaration)
                | conformance_declaration
                | fixed_conditional
                | option_declaration
                | tool_directive
option_declaration ::= "option" identifier ":" type "=" expression
tool_directive ::= tool_namespace "." identifier
                   "(" (expression ("," expression)*)? ")"
tool_namespace ::= "compiler" | "assembler" | "linker"
fixed_conditional ::= "fixed" "if" expression "then" declaration*
                      ("elsif" expression "then" declaration*)*
                      ("else" declaration*)? "end" "if"
atom_declaration ::= identifiers ":" "atom"
identifiers ::= identifier ("," identifier)*
1750

A source file is bytes

A source file is bytes, a line ends three ways, and space separates tokens. A span in a diagnostic names a byte, and every later stage must be able to point at the same one, so the lexical rules are written over bytes. A line ends at LF, at CR followed by LF, or at a CR that is not followed by LF, and a file need not end with one at all. Text inside a literal or a comment may be any UTF-8 [0260]; nothing outside them may be. Space is a space byte, a tab, a line end or a comment [1780], and any run of them may sit between two tokens. Two tokens whose spellings would run together into one longer token need at least one, which is the whole of the rule: 'mut x' is two tokens and 'mutx' is one name. Otherwise space carries no meaning, and no rule below this layer mentions it. A line end therefore never terminates a statement: when the token after it can continue the expression or selection before it, it does. This is [1060]'s one-line rule read from the other direction.

space       ::= " " | "\t" | line_end | comment
line_end    ::= "\n" | "\r\n" | "\r"
1760

Identifiers are lower case, and no identifier is a keyword

Identifiers are lower case, and no identifier is a keyword. Every name in the language has this one shape: types, functions, bindings and fields alike, which is why the tour never needs to say which case a thing is written in. Two rules narrow it. A word the keyword rule spells is that keyword and never a name, so 'if' is not available as a binding; that one is the tokeniser's. The other is in the rule itself: a name that starts with '_' needs something after it, so the lone '_' is the discard of [1020] and nothing may be called it. The kernel reserves fifty words; the reserved set of the whole language is larger, and each word joins it when its construct is enabled in the language. Once reserved, it is a keyword in every program, even one that does not use that construct. Type names are not among them: u32 and bool are ordinary declared names [0120] that the kernel happens to predeclare.

Control words cannot name bindings, types, functions, parameters, results, fields, atoms, import bindings or loop and block labels. In particular, begin = 10 and begin: i32 = 10 are invalid; (begin) is not an identifier escape. A longer spelling such as begin_value remains an ordinary identifier. D225 records the reservation and its compatibility consequence.

identifier  ::= lower (lower | digit | "_")*
              | "_" (lower | digit | "_")+
lower       ::= "a" ... "z"
digit       ::= "0" ... "9"
keyword     ::= "addr" | "alignof" | "and" | "any" | "atom" | "begin"
              | "break" | "complete" | "continue" | "dec" | "defer" | "do"
              | "else" | "elsif" | "end" | "escaping" | "extern" | "fail"
              | "false" | "fixed" | "for" | "from" | "if" | "import" | "in"
              | "inc" | "inout" | "loop" | "match" | "mut" | "none" | "not"
              | "or" | "ptr" | "public" | "return" | "sink" | "sizeof"
              | "struct" | "then" | "true" | "try" | "type" | "unchecked"
              | "undo" | "uninit" | "when" | "while" | "with" | "zeroed"
1770

The kernel's literals include characters, floats and text

The kernel's literals are integers, floats, characters, quoted text, the two booleans, and contextual zeroed and uninit. Integer literals are untyped and take the type of their context [0190], defaulting to i32 with none [0200]; the bases and the separator are [0220]'s. Each integer digit run starts and ends in a digit of its base; any internal run of underscores separates digits. A number ends where its spelling ends: a letter, digit or underscore directly after one belongs to it, so 1u64 or 1.5f32 is one malformed literal rather than a number and a name (D245). uninit is D152's restricted private inline-array field initializer; it reserves storage without assigning an item image. It has no stand-alone value type. zeroed has no type of its own: [0540] gives it the all-bits-zero image of a directly supplied initializer, assignment or field-label context. D27--D30 establish fixed-array contexts, D39--D43 scalar contexts, D49 and D57--D59 whole array-field and ordinary-struct contexts, D62 the depth-one indexed field place, D64--D67 labelled struct fields and static images, D75/D76 variant-bearing struct storage and case payloads, and D87 depth-one nested ordinary storage. It remains refused where no enabled construct supplies that context. D161 admits [0260]'s quoted literal when its direct context is a read-only []u8; the unescaped source content is UTF-8 [1750], and [0270]'s byte escapes are decoded into that view. Raw text [0280] takes the same direct byte-slice context by D164, but interprets no escape and removes a line-leading closing delimiter's indentation. The maximal opening quote run chooses the delimiter width; only a later run can close it. Adjacent quotes therefore cannot encode an empty raw literal. Intervening line endings remain content under D164; empty text uses "". D181 adds utf8, utf16 and cstring contexts and makes utf8 the contextless default. A scalar escape is encoded as UTF-8 or UTF-16 for those views; a byte escape remains exclusive to []u8. D162 admits [0210]'s decimal float with [0220]'s optional exponent. D166 adds [0230]'s hexadecimal fraction and required binary exponent. D167 admits [0240]'s type-qualified infinity and nan values for f32 and f64. D163 admits [0250]'s single-quoted character as exactly one Unicode scalar value of fixed type u32. A raw scalar is shortest-form UTF-8; [0270]'s simple escapes and \u{...} spell scalar values, while byte-only \xNN does not.

literal     ::= integer | float | character | text | raw
              | "true" | "false" | "zeroed" | "uninit"
character   ::= "'" (character_escape | unicode_scalar) "'"
unicode_scalar ::= any Unicode scalar except apostrophe, backslash or line_end
character_escape ::= "\\" ("n" | "r" | "t" | "e" | "\\" | "\"" | "'"
                  | "u" "{" hex_digit+ "}")
text        ::= "\"" (text_escape | text_byte)* "\""
text_byte   ::= any byte except quote, backslash or line_end
text_escape ::= "\\" ("n" | "r" | "t" | "e" | "\\" | "\"" | "'"
                  | "x" hex_digit hex_digit
                  | "u" "{" hex_digit+ "}")
raw         ::= quote_run raw_content quote_run
quote_run   ::= "\"" "\"" "\"" "\""*
raw_content ::= any byte+
integer     ::= decimal | hex | octal | binary
float       ::= decimal_fraction decimal_exponent?
              | hex_fraction binary_exponent
decimal_fraction ::= decimal_digits "." decimal_digits
decimal_exponent ::= ("e" | "E") ("+" | "-")? decimal_digits
hex_fraction ::= "0x" hex_digits "." hex_digits
binary_exponent ::= ("p" | "P") ("+" | "-")? decimal_digits
decimal_digits ::= digit ((digit | "_")* digit)?
hex_digits  ::= hex_digit ((hex_digit | "_")* hex_digit)?
decimal     ::= digit ((digit | "_")* digit)?
hex         ::= "0x" hex_digit ((hex_digit | "_")* hex_digit)?
octal       ::= "0o" octal_digit ((octal_digit | "_")* octal_digit)?
binary      ::= "0b" binary_digit ((binary_digit | "_")* binary_digit)?
hex_digit   ::= digit | "a" ... "f" | "A" ... "F"
octal_digit ::= "0" ... "7"
binary_digit ::= "0" | "1"
1780

A comment ends a token, and its opener says which kind it is

A comment ends a token, and its opener says which kind it is. The three forms are [0010], [0020] and [0030], and their openers share a prefix, so length cannot tell them apart: the longest opener decides. '--(' opens a block comment, '---' a doc comment and '--' a line comment, and the form so chosen decides where the comment ends rather than the rule that a token is as long as it can be. A line or doc comment ends at the line end. A block comment ends at its own ')--', so it may sit between two tokens on one line, and it nests: a ')--' closing an inner one does not close it, which is why commenting out a region that already contains one is not a trap. One never closed runs to the end of the file and is reported there. A comment is space [1750], so it may appear wherever a space may.

comment       ::= block_comment | doc_comment | line_comment
block_comment ::= "--(" block_item* ")--"
block_item    ::= block_comment
                | any byte that begins neither "--(" nor ")--"
doc_comment   ::= "---" (any byte except line_end)*
line_comment  ::= "--" (any byte except line_end)*
1790

A binding names one thing, and says how much it may change

A binding names one thing, and says how much it may change. The full form, the inferred form and the mutable form are [0040], [0050] and [0060]; a binding with no value must be assigned before it is read [0080]. [0100]'s shared form writes several bindings, fields, parameters or named returns as one declaration, each name still one thing (D233). The kernel's types are the thirteen scalar names, atom sets, fixed arrays, pointers, slices, D145's any C, function types with their complete declared error sets, and what [1795] declares from them: aliases, named ordinary structs and D74's named variant-bearing structs. mut in a pointer or slice type records permission to write the pointee or viewed elements [0430] [0570]; it is independent of a binding's mut [0070]. Enabled runtime leaves are scalar, atom set, reference, function, fixed array or D147's erased pair; ordinary and variant-bearing structs compose those leaves recursively. A pointer is one target pointer-width carrier and a slice is its non-null base plus a usize length. Neither has an all-zero value [0540]. A function type is written with [1800]'s signature syntax. Its parameter and return names describe positions and declare nothing; only a function declaration opens [1840]'s signature scope. The other TYPES YOU DECLARE remain deferred. A type position holds a declared name either way, since [1760] makes scalar and text-view type names ordinary declared names. The kernel predeclares the thirteen scalar names and the three text-view names; the grammar spells these out because a program need not declare them itself. An array [0520] is a type position too, and its length is part of it. D136 folds the bound expression from integer literals, fixed formals, unary -, and the target-independent binary arithmetic +, -, *, / and %. The element is a type like any other. A parameterized alias or nominal struct is a type position through its fully applied positional application. D135 substitutes an alias during checking; D137 interns a struct application by its template and normalized actual tuple, then checks the substituted field shape.

binding       ::= "mut"? identifiers ":" type ("=" expression)?
                | "mut"? identifier ":=" expression
type          ::= function_type | array_type | pointer_type | slice_type
                | any_type | type_application | scalar_name | packed_unsigned | text_name
                | declaration_reference
function_type ::= signature | c_convention c_signature
                  | machine_convention c_signature
array_type    ::= "[" expression "]" type
pointer_type  ::= "ptr" "mut"? type
slice_type    ::= "[" "]" "mut"? type
any_type      ::= "any" concept_reference
type_application ::= declaration_reference "(" type_argument
                     ("," type_argument)* ")"
type_argument ::= type | integer
scalar_name   ::= "u8" | "u16" | "u32" | "u64"
                | "i8" | "i16" | "i32" | "i64"
                | "usize" | "isize" | "f32" | "f64" | "bool"
text_name     ::= "utf8" | "utf16" | "cstring"
1795

Type aliases and declared identities

A type declaration without a body or distinct names an existing type. [0120] declares a type like any other value and [0650] writes 'distinct' to make one that is not the type it was written from. D15 reads the second as deciding the first: without that word a declaration gives an existing type another name and the two are one type everywhere. A struct body [0670] has no existing type to alias and introduces the nominal type [0710]. Its parenthesized inline field list and its struct ... end block are the same declaration body. The inline body closes at ) and needs at least one named field; it does not turn arbitrary nested type positions into anonymous structural identities. A following -> instead identifies the ordinary function-signature type. Without formals its identity is this declaration's empty-actual instance. With formals, D137 makes each fully applied normalized actual tuple a distinct instance of this declaration; an alias of either keeps that same identity. Every alias chain has to reach a scalar type, atom set, fixed array, function type or struct body. A chain that comes back to an alias in the chain reaches no type and is refused at that declaration. A type name is an ordinary declared name [1760], so one declaration per name per scope [1850] and a name that names nothing is refused [1860] both hold for it unchanged. D188 admits [0660]'s range subtype at this one position and nowhere else, which is why its base is narrower than type: the base must be a name whose alias chain reaches an enabled integer scalar, both bounds are D136-folded values of that base, and the lower must not be above the upper. range is a contextual word [1760] does not reserve, and only .. is admitted because the tour writes no exclusive bound in a type. The representation, the operands and every operator result are the base type's, so this is [0650]'s complement and not a spelling of it.

type_declaration ::= identifier ":" "type"
                     ("=" (encoded_union | atom_union | range_subtype | distinct_body | type | struct_body)
                     | type_formals "=" (encoded_union | atom_union | distinct_body | type | struct_body))
distinct_body   ::= "distinct" type
range_subtype   ::= (scalar_name | declaration_reference) "range"
                    expression ".." expression
concept_declaration ::= identifier ":" "type" "=" concept_body
concept_body    ::= "concept" type_formals
                    ("is" concept_reference
                     ("," concept_reference)*)?
                    concept_entry* "end" identifier?
concept_entry   ::= identifier ":" signature
conformance_declaration ::= type_formals? conformance_target "is"
                            concept_reference "(" conformance_argument
                            ("," conformance_argument)* ")"
                          | type_formals? conformance_target "is"
                            concept_reference "(" ")"
conformance_target ::= array_type | pointer_type | slice_type | any_type
                     | type_application | declaration_reference
conformance_argument ::= identifier ":" argument_rhs
concept_reference ::= declaration_reference
declaration_reference ::= identifier | qualified_reference
qualified_reference ::= identifier ("." identifier)+
type_formals    ::= "(" type_formal ("," type_formal)* ")"
type_formal     ::= identifier ":" "type" constraint?
                  | "fixed" identifier ":" type
constraint      ::= "is" concept_reference
atom_union      ::= union_member "|" union_member ("|" union_member)*
union_member    ::= declaration_reference | type_application | pointer_type
encoded_union    ::= packed_unsigned? "(" encoded_member
                     ("|" encoded_member)* ")"
encoded_member   ::= declaration_reference "=" exclusion
packed_unsigned  ::= "u1" | "u2" | "u3" | "u4" | "u5" | "u6" | "u7" | "u8"
                   | "u9" | "u10" | "u11" | "u12" | "u13" | "u14" | "u15" | "u16"
                   | "u17" | "u18" | "u19" | "u20" | "u21" | "u22" | "u23" | "u24"
                   | "u25" | "u26" | "u27" | "u28" | "u29" | "u30" | "u31" | "u32"
                   | "u33" | "u34" | "u35" | "u36" | "u37" | "u38" | "u39" | "u40"
                   | "u41" | "u42" | "u43" | "u44" | "u45" | "u46" | "u47" | "u48"
                   | "u49" | "u50" | "u51" | "u52" | "u53" | "u54" | "u55" | "u56"
                   | "u57" | "u58" | "u59" | "u60" | "u61" | "u62" | "u63" | "u64"
struct_body      ::= ("layout" "(" ("c" | "optimal"
                     | "packed" ("," ("u8" | "u16" | "u32" | "u64"))?) ")")?
                     ("struct" member+ "end" identifier?
                     | "(" field ("," field)* ")")
member           ::= field | variant_part
field            ::= identifiers ":" type ("at" expression (".." expression)?)?
variant_part     ::= identifier ":" "variant" variant_case
                   ("|" variant_case)* "end" identifier
variant_case     ::= identifier (":" "(" field ("," field)* ")")?
1800

A function is a value with a body, and its returns are named

A function is a value with a body, and its returns are named. '=' opens the body and 'end' closes it [0870]; a body that is one expression still takes an end, and the expression fills the named return [0880]; every named return must be assigned before the function returns [0930]. The parameter conventions [0900], escaping [0780], from [0790], caller [1040] and generic parameters [1290] have their parser and resolution foundation on a declared routine. Its complete signature scope collects type/fixed formals, runtime parameters and named returns before resolving any type; runtime formals alone make the runtime signature. escaping precedes an explicitly written convention, and both precede the parameter name (D140). An omitted convention and explicit in have the same language meaning but remain distinct syntax facts. Each from name is retained in written order and associated with the correspondingly labelled runtime parameter position. For every returning edge that actually carries a tracked reference, the reference-origin pass checks its source set against exactly that ordered list; [0480]'s provably empty optional arm has no reference or origin to compare. Unknown, duplicate, missing and extra sources are rejected. A generic template has no standalone function value or IR item. D138's first executable increment deduces a direct type formal or exact [n]t shape from context-free runtime argument types, interns the concrete routine instance, and emits that instance rather than the template. An enabled nongeneric signature takes values including function values, hands one or more named values (or none) back, and optionally declares [0940]'s payload-free atom error set. A standalone link(symbol: text) may precede the name of a native function declaration, but does not change this signature or convention and does not make its body optional [1610]. A function type reuses the nongeneric signature production but has no body. Its labels are type description only and do not declare parameters or named returns.

An anonymous function [1010] writes that same signature and body without a module name. It captures no enclosing local, parameter or named return: its signature and body are a separate routine whose outer scope is the module. Forming it produces a static code address and does not execute its body. A body is one block. Its statements run in source order and an optional final expression fills the one named return or the complete anonymous aggregate of a multiple return list. One token past a leading name decides between a first statement and a direct expression: ':' opens a binding and an assignment operator opens an assignment; anything else means the body begins with its value. A function returning none has no expression form, because there is no return for one to fill. An unguarded return has no fallthrough edge, so it can end a statement-only block but cannot be read as the prefix of that block's final expression. This also keeps return 1 the refused payload spelling [1810]. A guarded return may prefix a final expression because its untaken edge continues.

function           ::= (link_attributes "public"?)? identifier ":"
                       declared_signature "=" body "end" identifier?
external_function  ::= (link_attributes "public"?)? c_convention link_symbol?
                       identifier ":" c_declared_signature
                       ("=" body "end" identifier?)?
machine_function   ::= (link_attributes "public"?)? machine_convention
                       link_attributes? identifier ":" declared_signature
                       "=" body "end" identifier?
linked_binding     ::= link_attributes "public"? binding
c_convention       ::= "extern" "(" "c" ")"
machine_convention ::= "extern" "(" ("interrupt" | "naked") ")"
link_symbol        ::= "link" "(" "symbol" ":" text ")"
link_attributes    ::= "link" "(" link_attribute ("," link_attribute)* ")"
link_attribute     ::= ("symbol" | "section") ":" text
                     | ("align" | "vector") ":" integer | "keep"
c_signature        ::= "(" (parameters ("," "...")?)? ")" "->" returns errors?
c_declared_signature ::= "(" (routine_formals ("," "...")?)? ")"
                         "->" returns errors?
anonymous_function ::= signature "=" body "end"
signature          ::= "(" parameters? ")" "->" returns errors?
declared_signature ::= "(" routine_formals? ")" "->" returns errors?
routine_formals    ::= routine_formal ("," routine_formal)*
routine_formal     ::= parameter | type_formal
errors             ::= "!" (declaration_reference
                             ("|" declaration_reference)* | "...")
parameters         ::= parameter ("," parameter)*
parameter          ::= "caller" identifiers ":" type
                     | "escaping"? parameter_convention? identifiers ":" type
parameter_convention ::= "in" | "inout" | "sink"
returns     ::= "(" named_return ("," named_return)* ")" | "none" | "noreturn"
named_return ::= identifiers ":" type
                 ("from" identifier ("," identifier)*)?
body        ::= block
block       ::= statement* | value_statement* expression
value_statement ::= binding | destructuring_binding | assignment
                  | increment | discard | call | labeled_application
                  | defer | undo | try
                  | "return" "when" expression
                  | "fail" expression "when" expression
                  | break | continue | loop | while | for
                  | if | match | bare_block | labeled_block
destructuring_binding ::= "(" destructured_field
                          ("," destructured_field)* ")" ":=" expression
destructured_field ::= identifier (":" (identifier | "_"))? | "_"
1810

Statements do one thing each, and only exits carry 'when'

Statements do one thing each, and only exits carry 'when'. Assignment is a statement and never an expression [0390]; there is no '++', and 'inc' and 'dec' are statements too [0400]; discarding a result is written out [1020]; the one-line form of every construct is [1060]. 'when' rides on an exit and on nothing else, which is what keeps a conditional statement from having two spellings. return carries no value. A named return is assigned like any other place and return leaves [0930], which is why the kernel needs no second way to say what a function hands back. fail is the other early exit [0970]: it carries one payload-free atom on the declared channel and does not read the successful named return. A direct or selected call, with positional or named arguments, is a statement as well as an expression, because a function returning none has nothing to bind. That is the only call the position takes: one that hands a result back is refused there, recovered or not, because [1020] wants a result discarded on purpose rather than by omission, and _ = call is how it is written (D244). A labelled application in this position must resolve to a function call; the shared construction syntax still requires its ordinary value context and does not make constructed values standalone statements. A standalone try call explicitly propagates its failure and discards any successful result, whatever its shape. defer and undo each register one call when their statement is reached and evaluate the callee and arguments only on applicable exits from the lexical block [1100] [1110]. They are statements rather than expressions and so cannot supply a block's final value. A match is D77's exhaustive tag selection or [0640]'s exhaustive atom-set selection. A variant subject is one directly selected variant part and each case arm carries one statement or one expression; a bare begin block makes a multi-statement arm. D78 extends the arm with positional payload bindings. An if, a match, and a bare begin block retain their statement forms and also occupy expression positions under [1820]. A place is [1820]'s indexed selection, so a binding, a field of a struct, or an enabled array element is written and stepped exactly as the binding holding it is. What may be written is [1900]'s and not this rule's: a field is writable when the binding it belongs to is.

D165 enables [0390]'s compound forms. Each reads the selected place, applies the corresponding [1820] binary operator to that value and the right-hand expression, then writes the result back. The place is evaluated once before the right-hand expression [0410], must already be assigned [1910], and needs the same write permission as = [1900]. The operator keeps its ordinary type, known-operand, trapping and wrapping rules.

The kernel admits the statement forms of [1130], [1140], [1170], [1180], and [1190]. An unconditional loop tests nothing; a while condition is evaluated before every iteration and must be bool. break transfers to the point after its target loop and continue transfers to that loop's next condition test (or next unconditional iteration). Without a label they target the nearest loop; with one they target the nearest enclosing loop, or labelled bare block, carrying that ordinary name. A labelled loop or block closes with its label. A block is left only by a plain break: continue naming one and break with targeting one are refused (D234). Their optional when condition is evaluated once and must be bool; its false edge continues with the following statement. Both transfers leave every lexical block between the statement and the loop edge, so [1100]'s defer runs and [1110]'s undo does not. A conditional loop's optional complete block runs only when its condition becomes false; a break skips it. Facts established only in a loop body or completion block do not establish definite assignment after the loop. break with and value-producing loops are D158's extension. D159 enables the integer-range form of for: both bounds are evaluated once, from left to right, and have one integer type. a..<b visits the ascending values for which the element is less than b; a..b also visits b. Either form is empty when its first value is already beyond its last. The element binding is an immutable copy with the range's type; an optional index is an immutable usize beginning at zero. continue advances both before the next test, and the inclusive form completes at its maximum integer endpoint without first overflowing it. D160 enables collection traversal over a slice or a fixed array: the source is evaluated once, the element binding is a place in that storage rather than a copy, and the optional index is an immutable usize beginning at zero. The element is writable over []mut T and over a fixed array held in a place the body could assign; over []T and over any other array it is read-only [1160]. A body that writes the storage by index observes the write through the element, and the reverse. Elements that are themselves fixed arrays or slices retain their complete shape under D178, including when copied out through a loop value. An any C element retains its erased identity and evidence under D179. A source that would need [1320]'s iterable evidence is enabled by D180 when its type is a struct or any C and exactly one conformance to the unambiguous concept named iterable supplies Cur, Item, and [1320]'s four exact, infallible signatures. The source expression is evaluated once and copied into private traversal state. first is called once. Each test calls at_end; a false result calls item before entering the body. Fallthrough and continue run applicable cleanup and then call next; a break runs applicable cleanup and skips next. The optional immutable usize index begins at zero and advances with each next call. try for additionally admits the exact fallible_iterable concept with associated Cur, Item, and atom error set. Its four providers declare that same error set. A failed provider runs active failure cleanup and propagates its atom; it neither enters complete nor calls a later provider. When both conformances exist, try for selects fallible_iterable; ordinary for continues to select only iterable.

The cursor keeps its complete type identity between calls. The element is an immutable copy of the exact Item result, not an alias into the source, and therefore carries only the origin allowed by [1320]'s source-free result. An any C source and an any C item each retain their own erased concept and evidence identities; neither two-cell value is ever interpreted as a slice. Missing or ambiguous concept identity, or missing, ambiguous, or non-exact iterable evidence, is L0348. Integer ranges and fixed-array or slice storage traversal retain D159--D160 and D178--D179 unchanged.

D184 admits the exact utf8, utf16, and cstring identities through three intrinsic conformances to [1320]'s four-operation traversal contract. These do not search, add, reorder, or expose a source-declared evidence table, and an ordinary slice or pointer does not acquire them from its representation. Each uses exact usize Cur and u32 Item identities. Cur is a private physical code-unit offset: bytes for utf8 and cstring, UTF-16 code units for utf16. Item is an immutable copied Unicode scalar with no reference origin. It is not an encoded subview and is never an alias into the retained read-only source.

The source expression is evaluated once and its complete carrier and origin are retained before conceptual first produces offset zero. Every test calls at_end; a false result calls item, which decodes exactly one validated scalar before the body. Fallthrough and continue run applicable cleanup and then next, which advances Cur by that scalar's physical width and advances the optional immutable usize loop index by one. break skips next. For utf8 and utf16, at_end is Cur equal to the retained code-unit length. For cstring, it is the first zero byte; that terminator is not an Item, so an embedded U+0000 ends the C string in the same way as its trailing terminator.

D187 enables [1120]'s statement form. unchecked begin opens a region and end unchecked closes it. D225 reserves both opener words under [1760]; neither can name a binding or label. The region is a lexical block with its own scope and it is not an expression: the block forms that also occupy expression positions are the if, the match and the bare begin named above, and this is not one of them. Nesting is idempotent and there is no counter-word. A [1100] defer or [1110] undo call is checked as its registration is written and not as the exit that runs it, so a return, break or fail inside a region keeps every edge of a cleanup registered outside one. Which check edges the region removes, which it never removes, and what a removed one leaves behind are D187's.

These intrinsic providers declare no atom error. D181 validates utf8 and utf16 views, and D183 preserves that validity across text slices, so a well-formed view of either identity does not trap during traversal. A literal cstring is also valid UTF-8. D199's foreign cstring boundary promises only accessible backing through the first NUL: D184 validates each scalar before decoding and traps on malformed encoding, including inside unchecked. A NUL continuation is rejected before any later byte is read. Missing terminators or stale storage remain [0430]'s pointer validity non-guarantee rather than a recoverable text outcome. D181--D183's validation, pooling, single trailing terminator, identities, indexing, slicing, permissions, origins, traps and errors remain unchanged, as do D159--D160 and D178--D180 range, array, slice and declared-evidence traversal.

statement   ::= binding | destructuring_binding | assignment | increment
              | discard | call | labeled_application | defer | undo | try
              | return | fail
              | break | continue | loop | while | for | if | match
              | unchecked | bare_block | labeled_block
assignment  ::= place assignment_operator expression
assignment_operator ::= "=" | "+=" | "-=" | "*=" | "/=" | "%="
                      | "&=" | "|=" | "^=" | "<<=" | ">>="
                      | "+%=" | "-%=" | "*%="
increment   ::= ("inc" | "dec") place
discard     ::= "_" "=" expression
defer       ::= "defer" call
undo        ::= "undo" call
return      ::= "return" ("when" expression)?
fail        ::= "fail" expression ("when" expression)?
break       ::= "break" identifier? ("with" expression)?
                ("when" expression)?
continue    ::= "continue" identifier? ("when" expression)?
loop        ::= "loop" "do" block "end" "loop"
              | identifier ":" "loop" "do" block "end" identifier
condition   ::= expression | condition_declaration
condition_declaration ::= "mut"? identifier ":=" expression
                        | "mut"? identifier ":" type "=" expression
while       ::= "while" condition "do" block
                ("complete" block)? "end" "while"
              | identifier ":" "while" condition "do" block
                ("complete" block)? "end" identifier
for         ::= "try"? "for" identifier ("," identifier)? "in" expression
                ((".." | "..<") expression)? "do" block
                ("complete" block)? "end" "for"
              | identifier ":" "try"? "for" identifier ("," identifier)?
                "in" expression ((".." | "..<") expression)? "do" block
                ("complete" block)? "end" identifier
try         ::= "try" (call | labeled_application)
if          ::= "if" condition "then" block
                ("elsif" condition "then" block)*
                ("else" block)?
                "end" "if"
match       ::= "match" expression match_arm+ "end" "match"
match_arm   ::= (declaration_reference | "ptr" | "_")
                ("(" match_binding ("," match_binding)* ")")?
                ":" (statement | expression)
match_binding ::= "inout"? identifier
unchecked   ::= "unchecked" "begin" block "end" "unchecked"
bare_block  ::= "begin" block "end"
labeled_block ::= identifier ":" "begin" block "end" identifier
place       ::= indexed
1820

Precedence, tightest first, and comparison does not chain

Precedence, tightest first, and comparison does not chain. The operators are the ones OPERATORS already decided: [0290] for arithmetic, [0300] for the wrapping forms, [0330] for the bitwise set, [0320] for shifts, [0350] for comparison and [0340] for the logical words. Every binary level below is left associative, which the repetition in each rule is what says. Comparison takes at most one operator, so 'a < b < c' is not a sentence in this grammar rather than a fold: a chain that read left to right would compare a bool with a number, and [0310] refuses that anyway. A selection is [0420]'s ordinary member-selection syntax. The enabled representation retains every selected name without deciding whether it denotes a struct field or [0430]'s val pointee; that classification belongs to later checking. It binds tighter than every operator because it is part of naming a thing rather than an operation on one, and it is left to right, so 'a.b.c' selects from what 'a.b' named. Module resolution uses that same retained selection for a qualified declaration reference. When its first name is this file's imported namespace, the first selected name is public module lookup and the namespace produces no runtime value. Otherwise the selection is the ordinary runtime form above. Later selections from a module binding are ordinary fields of the selected value. An index or slice selection [0570] binds the same way and for the same reason, and takes what a selection named: a[i], a.b[i] and a[lower..<upper] are all written there. The two range spellings are retained separately so inclusive and half-open upper bounds are checked before an address is formed. Neither form derives from a call, because nothing selects from one and nothing indexes one either. A call may consume that complete selection as its callee, which is how a function-valued field is called; the call itself still cannot be selected or indexed. D183 extends range selection to the exact utf8 and utf16 identities. Both bounds are exact usize code-unit offsets. They must name scalar boundaries; the half-open upper bound may equal the code-unit length, while the inclusive upper bound names and includes a complete scalar. The result retains the source's immutable text identity and origin. cstring has no corresponding operation. Source, lower and upper are evaluated once in that order, and an invalid ordinary bound or encoded boundary traps. An ordinary-struct literal is [0710]'s nonempty run of labelled field values, optionally followed by [0720]'s contextual fill. D64--D71 state the contexts that admit it. D72's construction and [0980]'s direct named call have one labeled_application syntax: the parser retains each argument's label and neutral RHS, and resolution classifies the callee before selecting type or expression projections. A construction may then use the optional trailing fill; the all-fill spelling remains refused by name. A call-site else binds to the call except where that same token directly closes an enclosing then or elsif arm; parentheses around the recovered call make the inner use explicit. An if, exhaustive match, bare begin block, loop, while, or for is also a primary. A loop is value-producing when its targeted break edges carry with values. Every break edge then carries one value of the joined type; a finite conditional loop also needs complete to leave through such an edge. Scalar values use the join's ordinary slot. Fixed arrays, structs, slices and any fill the caller-owned destination directly before cleanup runs. For the other controls, their conditions or subject run first, then exactly the selected block runs in source order. In a value context the final expression of every edge that can fall through supplies the answer; an edge that returns supplies none. D124 gives the complete edge and type rule, and D125 gives its storage representation. D158 extends the same caller-owned representation to loop values. Evaluation order is left to right and fixed [0410], so the table decides what binds, never what runs first.

primary     ::= literal | array_literal | array_repetition | struct_literal
              | empty_slice | labeled_application | anonymous_function
              | indexed | call | address | pointer_conversion
              | any_construction | measurement | try
              | if | match | bare_block | loop | while | for
              | "(" expression ")"
array_literal ::= "[" expression ("," expression)* "]"
array_repetition ::= "[" integer "of" expression "]"
                   | "[" "of" expression "]"
                   | "[" expression ("," expression)* "," "of" expression "]"
struct_literal ::= "(" field_value ("," field_value)*
                   ("," "of" expression)? ")"
field_value ::= identifier ":" expression
labeled_application ::= indexed "(" labeled_arguments ")" recovery?
labeled_arguments ::= (expression ",")* labeled_argument
                      ("," labeled_argument)* ("," "of" expression)?
labeled_argument ::= identifier ":" argument_rhs
argument_rhs ::= expression | type
indexed     ::= selection (index | slice_selection | ("." identifier))*
index       ::= "[" expression "]"
slice_selection ::= "[" expression (".." | "..<") expression "]"
selection   ::= identifier ("." identifier)*
call        ::= indexed "(" arguments? ")" recovery?
recovery    ::= "else" expression
              | "else" "(" identifier ")" block "end"
address     ::= "addr" place
pointer_conversion ::= "ptr" "(" expression ")"
any_construction ::= "any" "(" expression ")"
empty_slice ::= "[" "]"
measurement ::= ("sizeof" | "alignof") type | "lenof" identifier
              | "lenof" "(" array_literal ")"
arguments   ::= expression ("," expression)* ("," assembly_operand)*
assembly_operand ::= ("in" | "inout") identifier ":" type
                     "at" identifier "=" expression
                   | "out" identifier ":" type "at" identifier
                   | "out" "_" "at" identifier
unary       ::= ("-" | "~" | "not")* primary
product     ::= unary (("*" | "/" | "%" | "*%") unary)*
sum         ::= product (("+" | "-" | "+%" | "-%") product)*
shift       ::= sum (("<<" | ">>") sum)*
conjunction ::= shift ("&" shift)*
exclusion   ::= conjunction ("^" conjunction)*
alternation ::= exclusion ("|" exclusion)*
comparison  ::= alternation (("==" | "<>" | "<" | "<=" | ">" | ">=")
                             alternation)?
logical_and ::= comparison ("and" comparison)*
expression  ::= logical_and ("or" logical_and)*
1830

What is not enabled is refused, and named

What is not enabled is refused, and named. A construct this tour describes and this grammar omits is not a guess the compiler gets to make. Meeting one is a diagnostic that names the construct's paragraph and says what the refused form is, so a program written against the whole tour fails with a list rather than with a parse error. This grammar owns what is already true. The note says one of three things, and never names the work that decided it (D246).

  • A source-form boundary is a disallowed shape within an implemented construct, and the note says it is a recorded boundary; it must not claim that the complete construct remains unimplemented. For example, indexing requires a named place, inline structs require a named type declaration, and a labelled construction starts with a labelled field. D236's constrained compositions and the shapes D233 and D241 leave outside their constructs are of this kind.
  • A withdrawn form is one the language no longer has, and the note says it is withdrawn and names what replaces it. D212 withdraws [0820]'s formerly promised lexical arena block and builtin arena type, and both notes name the ordinary allocator replacement. arena is not a keyword: a declared type, parameter, local, call or label with that spelling remains ordinary. Only the statement shape arena name do and an otherwise-unresolved builtin type spelling receive the migration diagnostic. No compiler rule recognizes the module core/mem. D238's volatile ptr names its withdrawal and the explicit operations that replace it.
  • A transferred form is one a successor roadmap owns, and the note names the successor. D237's u128, i128 and f16 name their transfer to Language evolution.

[1430]'s import alias and [1440]'s selected import forms are enabled; D201 states their binding and visibility rules.

THE RULES THE TOUR LEFT UNSAID

These are the rules an implementation needed and tour.md does not state. They are grouped by subject: names, scopes and what a doc comment is about, then the types and the context a literal takes its type from, then what an operator takes and what it refuses, then places, assignment and what may be discarded, then calls and the declared-error channel, then module values, and last the three boundaries the compiler owns — the hosted entry, the C boundary, and the firmware and machine directives.

1840

The kernel's scopes, outermost first

The kernel's scopes, outermost first. [0130] and [0140] are two sentences about scopes and this grammar has to say which scopes it has, because a rule about an inner scope means nothing until the inner ones are named.

scopewhat it holds
programevery module reachable from the entry directory after [1420]'s ordered-root selection. This is the outer identity and the one whole-program conformance register; it is not a source namespace.
configurationD202's global options and implicit tool namespaces, used by the closed configuration fold before ordinary resolution. It has no runtime declarations or storage.
moduleevery direct .ldn file in one directory [1410]. Its named declarations are shared by those files regardless of order, module-internal by default and public only when written so. Active linker.library directives retain source order (D202).
file importsthe final segment of a plain import, the written alias, or the public declarations named by a selected import in this file's prelude [1420]-[1450]. A namespace binding is not a declaration or value; a selected binding retains the imported declaration's identity. This scope encloses the module scope for lookups performed from that file.
type declarationD135's complete ordered formal list. The scope encloses the declaring file's imports and is visible in every fixed formal's declared type, direct concept constraint and in the alias or struct body, regardless of formal order. It closes with that declaration: its names do not enter the module or another type declaration. A type declaration without formals opens no scope.
concept declarationD142's complete ordered type-formal list. It encloses the declaring file's imports and is visible in every direct constraint, parent name and entry signature. Entry parameter and result labels describe signature positions and declare nothing in this scope.
conformance declarationD142's optional complete type/fixed binder. It encloses the declaring file's imports and is visible in every binder constraint, the target type and every labelled input or function RHS. The conformance itself declares no module name.
signaturea declared routine's type/fixed formals, runtime parameters and named returns [1800]. Every binder is collected before any signature type or direct concept constraint is resolved, so its source order has no visibility meaning. Named returns are places the body assigns [0930]; all three binder kinds share one namespace, but type/fixed formals are compile-time-only and have no storage. A declared function's signature encloses its file-import scope; a no-capture anonymous signature does the same rather than enclosing the expression's local scope. A written function type opens no scope and its labels declare nothing.
bodywhat a function runs; one for each arm of an if and its else; one for each loop body and complete; one for each match arm; one for every bare begin block; and one for a call-site recovery [1810] [1030]. A statement run plus its optional final expression is a block and a block is what scopes [1090], so a name declared in one is not visible in a sibling or after the block closes. D185's initialized condition binding shares the scope of the one if, elsif, or while body it guards; its initializer is resolved in the enclosing scope, and it is absent from later conditions, sibling arms, else, complete, and following statements. Match payload bindings and a recovery error name live only in their block.

[1800]'s direct final expression opens no additional scope inside its function body, because an expression declares nothing. Order matters in a body; module declaration order does not affect lookup. [0130]'s set is a set of named declarations, so a module name may be used above the line that introduces it; [1800]'s block is a sequence, so a local is visible to the statements and final expression after it. Both its written type and initializer resolve before its name exists [0110] (D218), including names inside pointer, slice, array and applied-type syntax. Lookup proceeds through body and signature scopes, then this source file's imports, then its module. An import may therefore shadow a same-named module declaration for qualified lookup, and a parameter or local may shadow the import. A namespace import leaves an unqualified same-named module value visible; a selected declaration shadows the module declaration for ordinary unqualified lookup too. Imports do not enter sibling files and are not re-exported.

1850

One scope gives one name to one thing

One scope gives one name to one thing. Two declarations of one name in one scope leave nothing to choose between them: [0130] makes module name lookup independent of declaration order, so neither is first, and [0140] licenses shadowing between an inner scope and an outer one and not within one. So it is refused, and the report names both places. Shadowing is not this. An inner scope may shadow an outer name [0140] and nothing is said about it, because a rule that permits something does not also warn about it. The file-import scope follows the same rule: two imports with one final segment, including a repeated identical import, are refused and both import sites are reported.

1860

A name that names nothing is refused

A name that names nothing is refused. There is no implicit declaration in this language: a name that is not in scope is a misspelling and not a new binding [1250]. The report names the use, because the use is where the mistake is and the declaration that was meant is not there to point at. An imported namespace whose selected member exists but is not public is a different error: the use is refused as inaccessible and the private declaration is related evidence. A namespace used without selecting a member names no runtime or type value and is likewise refused. A name a selected import [1440] wrote and the import refused is not a misspelling either: the import is where the mistake is and where the one report goes, and a later use of that name adds none (D242). The program is refused by the import.

2000

What a doc comment is about

A doc comment [0030] is about the declaration that follows it, and the language gives it no other meaning: a program means the same with every doc comment removed. The doc comment of a declaration is the run of doc comment lines directly above the line it begins on, read top to bottom. Each line of the run holds nothing but blanks and one doc comment, and the run ends at the first line above it that holds anything else, a blank line among them, so a line comment or an empty line between a doc comment and a declaration keeps the doc comment for nothing. A doc comment on the same line as code, or below a declaration, is about nothing. A doc comment's text is what follows its ---, without one blank after it if there is one.

--- The larger of two counts.
--- Equal counts give the first.
larger: (a: u32, b: u32) -> (c: u32) =
    c = if a < b then b else a end if
end larger

--- About nothing: a blank line follows it.

total: u32 = 0
1870

The kernel's types, and what each of them holds

The kernel's types, and what each of them holds. [1790] gives the kernel scalar and text spellings and nothing that says what one of them holds, so nothing yet says whether a u8 may be given 300. [0150] puts the width in the name, [0160] takes usize and isize from the machine and [0180] gives bool its two values; written out, that is:

typewhat it holds
u8 u16 u32 u64every unsigned value of that many bits
i8 i16 i32 i64every signed one, two's complement
usize isizethe same pair, at the target's pointer width [0160]
f32 f64IEEE 754 binary32 and binary64 values, including signed zero, infinities and NaNs [0170] [0240]
boolfalse and true [0180]
ptr T, ptr mut Tone non-null target address, with tracked origin unless constructed from an integer [0430] [0470]
[]T, []mut Tone non-null aligned base and a usize length [0570] [0580]
utf8a distinct immutable []u8 view of validated shortest-form UTF-8; its length counts bytes [0600]
utf16a distinct immutable []u16 view of valid UTF-16; its length counts code units [0600]
cstringa distinct immutable ptr u8 view of NUL-terminated bytes with no length; a literal's bytes are validated UTF-8, a foreign boundary's promise only accessible backing through the first NUL [0600]
an atom unionexactly the declaration identities in its flattened set [0630] [0640]

Two's complement is not a new decision. [0300]'s wrapping forms have to wrap somewhere and [0320]'s '>>' keeps a sign, and neither means anything without it. Each of the thirteen is its own type. usize is not u64 on a machine whose pointer is eight bytes wide, because if it were, [0310] would refuse a program on one target and accept it on another for a reason no paragraph here could state. [1510]'s 'sizeof usize == 8' asks what a machine does; it does not say two names are one type. D162 enables f32 and f64 without making either an integer or one another. u128 and i128 [0150] and f16 [0170] are not in this version: D237 transfers them to the Language evolution successor, and the checker refuses the three spellings by name. The packed widths are enabled only in D228's packed-field positions [0730]. They are representations within an image, not new ordinary scalar or ABI types. An atom declaration introduces one value and its singleton type. An atom union is structural: aliases are flattened, order and repeated members do not change identity, and assignment or argument passing may widen a singleton or smaller set into a set that contains it. No integer is an atom and no zero or default atom exists. With one atom, atom | ptr T uses zero for the atom and every nonzero pattern for the pointer, occupying one target pointer carrier [0480] (D189). With two or more atoms, D235 places the atom-set carrier and then one pointer carrier by ordinary natural alignment: the first holds the atom's own code, and zero, which no atom has, marks the present case whose pointer the second holds. [1795]'s union_member admits one written pointer type beside the atom names, and a second pointer member is L0338. The source spelling never assumes either representation.

The union is not a pointer. .val, addr of a .val reached through one, an integer conversion of one, any construction from one, a comparison of one, and an argument or result position wanting ptr T are each L0335, because each would read an atom case as an address; ptr(n) cannot produce one for the same reason, and zeroed does not name an atom case because no zero or default atom exists. A plain ptr T widens into a union whose pointer member it relaxes to, and an atom singleton or a contained atom set widens into it, in the direction this paragraph already gives atom sets; a smaller union widens into a larger one with the same pointer member, and neither direction reverses (D235). match [1210] is the only way through: its cases are the union's atom names and the reserved word ptr with an optional read-only binding of the plain pointer type, an inout binding on that arm is L0333 [1220], a case named twice is L0311, and a case named by neither an arm nor _ is L0312 exactly as for an atom set. The bound pointer carries the subject's own origin [0770] [0780], and an atom case carries none, so a union built from a frame address still refuses an escaping use of the bound pointer. An origin names a kind of storage, not a lifetime: "allocated" says a reference came from an allocator, and nothing about whether that allocator has since released or reset it [0770] [0860]. Two arenas are one origin, and a pointer stored in a field and read back carries the field's origin. The checks here are the local ones [0770] promises, and freeing storage under a live reference remains outside them. Fixed arrays hold their declaration-order elements [0520], and ordinary or variant-bearing structs hold the fields their nominal declaration gives them [0710] [0750]. A function type holds a target code address with the complete parameter and result signature [0870] [1000]. The signature, not the address, decides which values may be stored together and how a call is checked.

1880

Where a literal's type comes from, and what a context is

Where a literal's type comes from, and what a context is. [0190] says an integer literal is untyped, takes the type of its context and is checked at that point, and [0200] says it is i32 with none. Neither says what a context is, and a checker cannot ask for one until they are listed. In the kernel these positions give a literal a type:

  • a binding's declared type [1790]
  • the type of the place an assignment writes [1810]
  • the type of the parameter an argument fills [1800]
  • the named return's type, or the complete anonymous result aggregate for a multiple-return expression body [0880] [0990]
  • the result expected from an if, match, bare begin, or call-site else expression; that same complete context reaches every fallthrough answer
  • the element type of a contextual array literal or repetition
  • the field type of a contextual labelled struct literal
  • the complete pointer type of ptr(integer) and the complete slice type of []; the address integer itself takes usize
  • the other operand's type, for a binary operator
  • the other endpoint's integer type, for a range traversal (D219)
  • a unary operator's own context, handed on [1820]
  • a branch's or while loop's condition and an exit's 'when', all of which want a bool [1050] [1070] [1140] [0970] and so give an integer literal a context it cannot take

A call with two or more results has [0990]'s anonymous structural aggregate: its declaration-order field names and complete field types are its value shape. That shape supplies an inferred whole binding and every arm of a control value.

And two give none: the inferred form [0050] and a discard [1020], where [0200]'s i32 is what is left for an integer and D162's f32 for a float. [0250]'s character literal is different: it already has type u32, so a surrounding context must agree and an inferred binding keeps u32. For [0260]'s text literal, those same direct positions may instead supply a complete text view. D161 and D164 admit quoted and raw literals as []u8; D181 admits utf8, utf16 and cstring, and with no supplied context either literal defaults to utf8. These identities remain distinct in a generic actual and in every reference-bearing signature or aggregate field. For [0210]'s float literal, the same positions supply f32 or f64. There is no implicit conversion from an integer literal or integer value; with no context the float defaults to f32. The decimal spelling rounds once to the contextual IEEE format. A finite spelling that would round to infinity is L0300 rather than silently becoming [0240]'s named special value. The named values f32.infinity, f64.infinity, f32.nan and f64.nan have the type written before the dot rather than taking one from context. D167 chooses one canonical quiet NaN pattern for each width; unary minus changes only its sign bit, as it does for infinity. With no surrounding context, the first written answer of a control expression supplies its scalar type, fixed-array element and extent, or nominal aggregate body; every other answer must have that same complete shape. An edge that returns without an answer is not a second answer and does not participate in inference. A context reaches inward through [1820]'s arithmetic, bitwise, shift and unary levels and stops at a comparison and at the logical words. What those give back is a bool [1890] and a bool says nothing about what was compared, so 'r: bool = 1 | 2 == 3' compares two i32 by [0200] and not two bools. Reference agreement includes the complete referred type and shallow permission. [0440] is the sole relaxation: ptr mut T satisfies ptr T, and []mut T satisfies []T; neither direction changes bits, and the reverse is refused. It relaxes a value that flows in: an inout place of reference type also flows back out, so it agrees exactly, as D243 records. Function signature agreement also includes parameter conventions, escaping, and each result's ordered from positions; omitted and explicit in have the same semantic convention. [1975] additionally includes C versus Landin convention and variadicness recursively, including function-valued fields and nested signature parts. A literal whose value the type does not hold is refused [0190], and the report names the literal. A unary minus over a literal is part of the value that check reads, which is what makes 'i8 = -128' the smallest i8 rather than 128 refused and then negated. Nothing else is folded: 'u8 = 200 + 100' is two literals a u8 holds and a sum it does not, and [0300] says that traps rather than that it is refused here. This literal-range rule does not suppress [1975]'s separate refusal of a known null pointer construction, whose closed expression is folded before testing its target-width value.

1890

What each operator takes and what it gives

What each operator takes and what it gives. [1820] settled what binds; this settles what agrees. Every binary operator takes two operands of one type, because [0310] converts nothing. D209 additionally lifts the numeric arithmetic rows over equal-shape fixed arrays or an array and its exact scalar element type; that scalar is evaluated once and broadcast, not implicitly converted.

operatortakes, and gives back
+ - * /one integer or float type, and that type back [0290]
%, and [0300]'s +% -% *%one integer type, and that type back [0290]
& ^ |, and the unary ~one integer type, and that type back [0330]
<< >>an integer shifted by an integer of that same type, and that type back [0320]. The amount is not bounded by the width: [0320] fills with zeros beyond it for any amount.
== <> < <= > >=one type on both sides, and a bool back [0350]; atom sets have identity equality and inequality only, including between disjoint or overlapping sets. D200: the type is a scalar, an atom set, a pointer or a function value; two pointers must point at one type, permission aside, and a slice, an erased value, an array or a struct has no comparison
and or notbool, and a bool back [0340]
unary -one integer or float type, and that type back

So an integer has no logical words and a bool has no arithmetic and no bitwise set: 'and' is what [0340] gave a bool and '&' is what [0330] gave an integer, and neither reaches across. [1820] already read the comparison rule this way when it said a chain would compare a bool with a number and that [0310] refuses it. The positions that want a bool and are not operators are a branch's or while loop's condition [1050] [1070] [1140], and an exit's when [0970]. For D185's condition declaration the required initializer first establishes the binding's declared or inferred type, and that stored value is the bool being tested.

1950

An operand an operation cannot take

An operand an operation cannot take. [1890] says every binary operator takes two operands of one type and gives that type back, and for three of them a value of the right type is still not one the operation can use. No paragraph of the tour says what any of the three does.

the operationthe operand it cannot take
integer / %a divisor of zero [0290]
<< >>a negative amount [0320]
[ ]an index outside the length [0520]

The third is not a binary operator and belongs here anyway, because it is the same question with the same answer. [1720] says this language checks bounds and [0580] says indexing checks the length before it computes an address, so what was left unsaid is only which of refusing and trapping applies where — and that is what the rest of this paragraph already decides for the other two. Float division follows IEEE 754: division by signed zero produces an infinity or NaN and does not use this refusal or trap rule. D18 makes an array index usize, so a negative expression is refused by its type before this row applies. The row asks only whether a well-typed index is below the array's length.

This is not [0300]'s question, and the difference decides both answers. An overflow is a good operation whose result the type does not hold, which is why [1880] leaves it to the trap inside a body. Here the operand is what is wrong and there is no operation to perform at all, which is the case [0310] already answered for 'u8(300)': known when the compiler reads it, it is refused; otherwise it traps. Known is [1880]'s and [1940]'s and nothing besides — inside a body a literal, or a unary minus over one; at module level the whole of [1940]'s fold. So 'x / 0' is refused and 'x / y' traps, and which of the two a program gets does not move when an implementation gets better at folding, which is the objection D7 raised against believing a condition. 'a[4]' on a '[4]u8' is refused for the same reason 'x / 0' is, and 'a[i]' checks its length at run time. A negative amount is writable only where the left operand is signed, because [1890] gives the amount that type. No unsigned shift carries this check, on any target. At module level a trap is not available at all. [1460] says nothing runs before the entry point, so a module value whose divisor is zero has no moment in which to trap and no value to stand for it, exactly as [1940] found for a sum no type holds. Both are refused there. The lowest value of a signed type over -1 is not in the table, and is not a third rule. Its quotient is the case [0300] already covers: that type does not hold it, and [1890] gives '/' no wrapping form to opt out with. Its remainder is 0, which the type does hold, so nothing traps and the machines that fault on it anyway are the x86-64 and arm64 backends' to know about. The report names the operand and not the operator, because the zero and the negative amount are what a reader changes.

1960

A trap stops at the operation

A trap is synchronous with the operation that causes it and happens at that operation's point in [0410]'s order. It does not return. The operation produces no value, and no later action of the failed computation occurs; actions before it are not undone. D232 permits the selected panic handler's terminal computation, without resuming that failed computation or unwinding its cleanup. How the surrounding system reports the trap is not Landin program behaviour. An operating system's signal, exception, status or other encoding is not stable across targets or compiler releases and a program may not depend on it. The same no-continuation rule applies to a return nested in an expression. For example, an index expression runs before the selected element is read and, on the left of an assignment, before its right-hand expression [0410]. If that index returns, neither later action occurs; facts from that edge do not reach a join. The default Linux x86-64 handler deliberately emits ud2; D232 defines selected-handler dispatch. It does not inherit the accidental fault or value of the machine instruction used for the operation.

1900

What may be written, and what may not

What may be written, and what may not. [1810]'s place is a name, and of the four kinds of name the kernel has, two may be written and two may not.

namewritten?
a mutable binding [0060]may be
a named returnmay be: [0930] says it must be, and [1840] declares it as a place for that reason
an immutable bindingmay not: [0040] makes it immutable and [0450] says it protects the value it holds
an in, sink, or caller parametermay not be replaced
an inout parametermay be replaced, through the caller-owned place

An atom declaration and a recovery clause's error name are immutable values, not places. A function declaration is not a place. Nor is a range selection [0570]: it is a new view over its source, as a returned slice is, so an assignment, inc or dec naming one is refused with L0303 as inout already refused it, while an element indexed through it is an ordinary place (D250). A local or module binding holding a function value is an ordinary place: an immutable one may be called but not replaced, and a mutable one may be replaced only by a value with the same complete signature. A named function-valued return is a writable place; an unmarked function-valued parameter is not. A function-valued struct field is an ordinary subobject place: the root binding decides mutability, and replacement requires that field's complete recursive signature. A place reached through .val or slice indexing instead takes writability from the shallow mut in that reference type, independently of the binding that holds it [0430] [0450]. addr retains that place's writability: its result is ptr mut T for a writable place and ptr T for a read-only place. Taking an address does not grant permission to modify immutable storage. The value's type is the place's type [0310], and the report names the place as well as the value, because which of the two is wrong is the reader's to decide. 'inc' and 'dec' say what 'x += 1' says [0400], so each wants a place that may be written and an integer type.

1910

Assigned before it is read

Assigned before it is read. [0080] says a binding declared with no value must be assigned before use and [0930] says every named return must be assigned before the function returns. In a body those are one question and this is its shape: at every read of a name, at every return, and where a body ends, each applicable name has to have been assigned by every path that arrives there. For multiple results the question is asked independently of every named return. Aggregate fields retain independent facts, including a function field read as the callee of a call; the callee expression is checked before any argument expression. A written Boolean literal fixes its if edge: true takes the arm and false skips it. No other condition is believed. A name assigned in one reachable arm of if c and not another is not assigned after it, even if c was initialized with true. Only the written literal is used here; interpreting expressions to decide their value would make legality depend on constant folding. 'return when' is a return [1810], so what the function hands back is assigned above it and not below. A control-flow edge has independent fallthrough, successful-return, and failure consequences. A fail edge never needs the successful named return; its untaken guarded edge continues. A tried call may fail after its arguments and before any later action; a recovered call joins its success edge only with recovery edges that fall through. A return-compatible control-flow edge has two facts: whether it can fall through and whether it can return. Only fallthrough states meet at an if or match join; a returned arm neither lends nor removes assignment facts on a surviving arm. Every reachable fallthrough edge of a control expression must reach its block's final expression, and every such expression has the one complete type and shape from [1880]. An early-return edge needs no joined value, but it still requires the named return to be assigned at that edge. A guarded return has both facts: its taken edge returns and its untaken edge continues with the incoming assignment state. The unevaluated side of and or or is likewise a fallthrough edge: a return from the right operand cannot erase that skip edge, and assignments made only on the right do not survive their join. A sink argument follows one binding-rooted path of ordinary fields and literal fixed-array indexes. Pointer dereferences and slice indexes cross a reference boundary and are refused, including a literal slice index. A slice binding, field or fixed-array element still names its own descriptor storage and may be consumed as a whole. D220 makes this place-form boundary explicit. Callee and arguments evaluate left to right before any place is consumed by that call. Each by-value argument captures its value when evaluated, including an aggregate passed by sink; a later argument may read or assign its original place. If evaluation transfers control before call entry, that call consumes no places. Effects of calls actually entered while evaluating its arguments still hold. On entry, the pending sink places must still be live and become unassigned at their exact binding-rooted paths, in written argument order. Repeated or provably overlapping sink places are refused. Every inout place must remain live after these consumptions, so a provable sink/inout overlap is refused in either argument order. A nested argument call that consumes a pending place requires a subsequent assignment before the outer call can enter. D223 pins this timing independently of argument-value capture and D149's inout rules. A consumed place may be read only after it has been assigned again on every arriving path where it was consumed. A part sunk out of an inout parameter must be assigned again on every return edge [0910]. Reading an enclosing aggregate reads its consumed parts too; assigning that aggregate restores those parts. Other fields and other known array elements remain independent. The inout obligation includes failure propagation: applicable defer and undo actions run before the exit check. Unlike a successful named result, the caller's inout storage remains observable after a recovered failure. This is definite assignment of one consumed place, not ownership; copies made before the sink remain live.

The reference-origin walk is a second local flow fact. addr of local storage and a slice of a by-value array parameter have frame origin. An address reached through a pointer dereference or slice index instead retains that reference's origin, including when ordinary fields or fixed-array indices follow it. Taking the address of the local pointer or slice descriptor itself still has frame origin; copying a descriptor locally does not move its backing storage into the frame. A returned value with frame origin is refused. A retained escaping argument must be independent or derive only from parameters themselves declared escaping. A store checks its destination's backing storage, including inout parameters, pointer pointees, slice elements and reference-bearing fields or variant payloads. Caller storage cannot retain a frame reference or a non-escaping reference from another parameter origin. Updating storage with a reference from that same origin is permitted; retaining another parameter requires escaping. A known address alias to a local joins its writes into the local's value origins, while a pointee write does not change the pointer descriptor's origin. Integer-created pointers are explicitly untracked [0470]; joining one with a tracked frame or parameter reference does not erase the tracked restriction. On each return edge, [0790]'s exact from comparison applies to an actual tracked reference in the returned value. A provably empty arm of [0480]'s optional pointer carries no reference and therefore no origin to compare; it is not an Untracked reference. For every edge that does return a tracked reference, the set of parameter origins is exactly the signature's from set. In addition, D222 forbids a known independent storage origin in a result with a nonempty from clause when its type carries a reachable writable reference. The permission walk includes pointer and slice referents, array elements, struct fields and variant payloads; a read-only outer view does not remove a nested view's permission. An erased value conservatively qualifies, while a function value's signature does not describe storage carried by that code value. Aggregate value origins remain a conservative union, including origins from read-only sibling fields. A separately known independent alternative is retained across control joins, local copies, calls and selection of anonymous result positions. An optional empty atom and an empty slice literal contribute no storage destination; a constructor containing only such empty references preserves that fact. Only the optional atom has D189's exemption from exact source agreement. Explicit untracked conversion alone supplies no origin proof, and does not erase another alternative's known independent origin. A helper which needs parameter and module alternatives passes both as explicit arguments and names both in its from clause. Calls reconstruct those written sources; no body inference is introduced. A live local view records the binding it derives from; an inout or sink use of that binding is refused when the view is read before being replaced. Volatile reference paths remain exempt [0850].

A match payload alias keeps its selected storage live even when the payload is scalar and carries no reference. Both reads and writes use that storage; a derived address or range, pending cleanup argument, or reachable inner-loop use also extends its lifetime. A direct retag, replacement of a containing object, or an inout/sink call that can replace it is refused until the last use. D76 selects a directly written case before evaluating its payload initializers, so reading an old alias in those initializers is still a live use. A whole containing construction also requires those aliases' last use before construction starts; copy a needed scalar first. A computed value destination keeps D134's temporary-and-copy-back order. Known address aliases participate in this local check. Different fields and known array elements remain independent, and a fresh match arm on a later outer-loop iteration creates fresh aliases. D134's copied computed-value subject instead aliases its own temporary; a copied scalar payload value keeps no borrow of the original. Rebinding a pointer descriptor does not replace the payload storage its earlier match selected.

A reference-free scalar operator result carries no reference origin [0840]. This includes a saved lenof result: using that number after an inout use of its source does not keep a view of the source alive. Operand checks and effects still follow each operator's evaluation rules, including short-circuit joins; D14's fixed-array measurement and D31's literal-length measurement remain unevaluated. This value rule does not erase storage provenance: an address or range formed from a selected place still derives from that place's backing reference, even when reading the selected scalar would copy no reference.

A caller position is part of the complete structural function signature. It has D192's ordinary nominal struct type: exactly three fields, in order, file_id: u32, line: u32, column: u32. Aliases retain that identity; other struct identities remain distinct even when their shapes qualify. There is no parameter convention or escaping modifier. It remains an ordinary runtime ABI position after the compiler has filled it; source calls omit it, except for D192's named forwarding from another caller parameter. caller is a contextual word [1760] does not reserve, exactly as range is, and it is the modifier only where a second name follows it: a parameter of that name writes : next, so caller: utf8, in caller: u8 and escaping caller: ptr u8 all declare an ordinary parameter spelled caller.

A module binding is not ordinary pre-use definite assignment. [1460] says its value is known when the compiler reads it; reference-containing module images must likewise supply a valid non-null static image.

1930

What may be discarded

What may be discarded. [1020] says a result is discarded on purpose or not at all, and [1810] writes that '_' '=' expression. Anything with a type may be thrown away, including a value nobody computed for the purpose: '_ = 1 + 2' is a discard of an i32 by [0200], because a rule about wasted work is a rule about people and this one is about types. A break with must target a loop used as an expression [1190]. A statement loop has no result consumer; write _ = loop ... to discard its result, or use a plain break when no result is intended. What may not is a call of a function returning none [1920]. Discarding is for a result, and that call has none. The converse holds as well: a call that does hand a result back is not a statement on its own, so the only discard is the written one (D244). A call with a declared error is also refused when a discard would ignore that outcome; try propagates it and call-site else handles it explicitly. D241 makes the rest mechanical: a discard takes every place and call, and every expression an inferred binding x := e takes; a whole aggregate place is discarded where it stands, after its indexes are evaluated and checked.

1920

What a call means

What a call means. A static T.entry selection requires one declaration of that entry name across T's direct concept, represented-formal constraint and parent closure. Each concept is visited once: a shared ancestor reached along two paths contributes one declaration, while different declaring concepts remain ambiguous even when their providers agree. Parent order and a direct child declaration grant no precedence. D221 records this selection rule; an unused colliding closure may still be declared and conformed to. [0980] gives no source-written parameter a default value, so a call names every non-caller runtime parameter exactly once. A caller position is instead filled by the compiler with D192's three source coordinates, unless a named argument forwards another caller parameter into that position. A positional prefix skips caller positions and fills the other runtime parameters in order; a named suffix may write the remaining parameters in any order, but may not repeat one or name one the callable signature does not have. Matching uses the labels of the static callable signature for a stored or selected function value. Those labels are retained call-shape facts but remain excluded from [1000]'s structural function-type identity. Each runtime argument is synthesized and checked in written order, then its checked value is placed at the matched formal position for the ABI. A static-role label is not a runtime argument of a nongeneric or indirect callable. Each argument has its parameter's type [0310], and the call has the type of the named return. [1975]'s C variadic call is the explicit exception to fixed arity and named matching: all actuals are positional, every fixed parameter is supplied, and the additional tail uses that rule's restricted carriers and default promotions. A call of a function returning none has no successful-result type. It is a statement [1810] and nothing else: nothing binds it, no argument is one, and [1930] cannot discard it, because there is no result there to discard. A call with one named return has that return's type. A call with two or more has [0990]'s anonymous structural aggregate; its fields are selected and destructured by the return names. The orthogonal declared error outcome is unchanged at every result count: a failing call is still tried or recovered. A callee is a function. It may be a declared function; a local, module, parameter or named-return binding; or a selected ordinary or variant-payload struct field whose value has a function type. The complete callee expression is evaluated before the arguments, and every stored form calls the runtime code address. A function's own name and an anonymous function away from a call are values of their function types [1000] [1010]. All positions retain one complete structural signature, recursively when a parameter or result is itself a function. Labels are not part of function signature agreement: parameter order and type, plus the ordered result types, are. The labels do remain the field names of a multiple-result value at its static call site. A binding of any other type is not a function.

A whole multiple result may initialize an inferred local, be selected by field, be assigned to a mutable inferred local of the same named structural shape, or cross a control-expression join. A destructuring binding evaluates its source once and selects fields by return name in any written order. A bare name binds a local of the same name; field: local renames it; field: _ ignores that field; and one bare _ explicitly ignores every unbound field. Unmentioned fields are also ignored, as [0990]'s one-field example requires. An unknown or repeated field and two locals with one name are refused by the ordinary field and scope rules. The anonymous shape is not a nominal struct type and has no type spelling of its own. A scalar type name in front of ( remains [0700]'s explicit conversion. The enabled reference slice admits the two directions [0470] requires: an integer type applied to a pointer checks that the address fits, and ptr(integer) takes its complete pointer type from context and produces an untracked non-null pointer under [1975]'s known-zero refusal and always-on converted-zero check. D168 also admits an enabled integer type applied to an integer value. D169 admits f32 or f64 applied to a float value. Conversion from an enabled integer to f32 or f64 is admitted by D170. D171 admits an enabled integer type applied to a float value, and D172 admits an enabled integer type applied to bool. D173 admits bool applied to an integer value. D174 admits bool applied to a float value, and D176 admits f32 or f64 applied to bool. The deferred integer widths remain refused by [1830].

1980

Declared errors are an orthogonal payload-free atom outcome

A function is infallible when its signature has no !. A concrete ! names a nonempty atom set; that set is part of complete structural function-type identity, recursively when a function value occurs in another signature. A public declaration, anonymous function, and written function type must be concrete. A private declared routine may write ! ...; whole-module checking then takes the least fixed point containing every atom it fails with and every concrete or inferred set propagated by try. Mutually recursive private routines are solved together. An inferred empty set makes the routine infallible. Generic deduction from a recovered error waits for its complete finalized set, including through local aliases. D215 refuses only a circular key/effect dependency in which choosing a generic instance requires the inferred effects of that same unresolved instance; ordinary and mutual error recursion remain least-fixed-point inference.

fail atom leaves by the error outcome and carries no successful result. The atom's possible set must be a subset of the routine's finalized declared set. A fail path need not assign the named successful returns. when evaluates its condition first; only the taken edge evaluates the atom and fails. try call evaluates the call once and propagates its error unchanged; its success value, including a function, fixed array, nominal aggregate or anonymous multiple-result aggregate, has the ordinary call shape. A failing call written without try or call-site else is refused.

Call-site else handles only a nonempty declared error set. Its optional name is an immutable atom value scoped to the recovery block and typed as that complete set. The successful call edge and every recovery edge that falls through must supply the same complete scalar, atom, function, array, nominal aggregate or anonymous multiple-result aggregate shape. A recovery edge may instead return or fail; it then supplies no placeholder and does not participate in the value join. Atom match is exhaustive over the subject's structural set; one final _ arm may cover all members not named explicitly, and atom arms bind no payload.

Neutral IR keeps successful results and errors separate. Atom constants carry source declaration identity and atom-set metadata; slots, datums, signature parts and values retain that structural set. A call with errors names a separate error slot, Failure_Test branches on the abstract outcome, and Fail is its own terminator. No inferred marker reaches IR. Verification checks set runs, identity membership, widening stores and arguments, complete signature equality, call failure slots, and failure subsets before a backend sees the unit.

For the documented Linux x86-64 internal convention, ordinary atom values use a 32-bit carrier. The backend assigns dense nonzero codes in declaration- identity order. They use the ordinary integer argument positions and %eax for a successful atom result. %r10d is the dedicated failure carrier for both direct and indirect Landin calls: zero means success and a nonzero dense atom code means failure. A successful callee clears %r10d; fail writes it. The ordinary scalar or function result remains in %rax, and an aggregate success still uses caller-owned storage, so the error carrier consumes no source parameter, result position, or stack argument. No source atom has code zero.

1940

A module value is known when the compiler reads it

A module value is known when the compiler reads it. [1460] says values at module level must be known at compile time and that nothing runs before the entry point, and the kernel's version of known is short: a literal, 'true', 'false', an operator of [1820] applied to those, and a name bound to a module binding whose value is known. Not a call. There is no compile-time execution in this language, so a call is not a value the compiler holds, and [1830] refuses it as the construct it is rather than as a type error. Ordinary integer +, -, *, / and % in a module image fold in the signed range from -(264 - 1) through 264 - 1, independently of the host and destination width. Every intermediate must fit that fold range; the final image must fit its declared or inferred integer type. Thus a module binding value: u8 = 200 + 100 - 100 holds 200 even though its intermediate 300 does not fit u8. Its individually written literals still need their ordinary type context. A fold beyond the kernel range or a final image outside its destination range is refused: [0300]'s trap has no runtime moment before entry [1460]. Inside a body ordinary arithmetic retains the operand type's width and traps on overflow, so the same u8 addition traps before its subtraction is reached. Wrapping arithmetic, bitwise operations, shifts and explicit conversions keep their own type-dependent rules. D224 records this existing module-fold boundary; D136's fixed expressions and D202's options retain their separate contracts. D162's first float increment admitted a decimal float literal, its unary minus, zeroed, or D167's named infinity and NaN as a module scalar or aggregate-field image. D175 admits +, -, *, / and comparisons over module-known f32 and f64 values, including scalar and aggregate images. The target-neutral folder evaluates IEEE carrier bits with bounded integer work; it does not use the compiler host's floating-point operations as language semantics. [0130] makes a module a set, so one module value may name another written below it. A chain of them that comes back to where it began names nothing at all: no member of it is first, exactly as [1850] found with two declarations of one name. So it is refused, and the report names the declaration the chain came back to, because that is the one place in it the reader is standing. A declared or anonymous function is a compile-time-known code address. A module function binding may name either directly, or another module function binding whose static chain reaches one; a chain that returns to itself is refused like any other module-value cycle. Function code addresses have no all-zero value, so a function-valued module binding must write an initializer. A function field in a static struct or selected variant image is a target-neutral relocation to such a declared or anonymous routine, not an integer fold. Copying a complete module struct image copies that relocation while retaining distinct storage. A module aggregate whose active all-zero shape contains a function field must therefore write an explicit static image too.

A contextual text literal is also known. A []u8, utf8 or utf16 module image is the base of its read-only datum and its decoded code-unit length; a cstring image is the base relocation alone. Each datum has exactly one trailing zero element excluded from a slice length. It is an address relocation rather than an integer fold or code run before the entry point.

An atom-valued module binding must name an initializer. There is no zero atom, and the zero carrier pattern reserved by [1980] is not a source value.

A scalar binding with no value is known too, and what it holds is zero — false, for a bool. [0080] lets a binding carry no value and says it must be assigned before use, and that sentence has nothing to bite on here: [1460] says nothing runs before the entry point, so there is no moment at module level in which to assign one, and [1910]'s walk is over the paths through a body and there is no body. Zero is a value the compiler knows, which is the whole of what [1460] asks. So 'mut counter: u32' is module state a function updates without an initialiser that says nothing, and reading one before anything writes it reads zero rather than being refused, because there is nothing left to refuse.

1970

The first hosted path has one entry shape

The minimal Linux x86-64 path accepts one hosted entry shape: a public function named main, with no arguments and the one named return code of type i32. Its declaration therefore starts public main: () -> (code: i32) =. The returned code is passed to the host as the program's status through the system C ABI [1650]. This is the first native slice's boundary, not a restriction on every hosted executable: [1650]'s C argc and argv form stays available. A freestanding program does not use this rule; its build description names the entry [1650]. The first hosted entry is infallible: this boundary has no host mapping for a declared Landin error. In a rooted program, only a declaration in the designated entry module can satisfy this shape. A reachable imported module's public main is an ordinary public function and is never selected as the executable entry.

1975

The selected hosted C boundaries

extern(c) selects a function convention, not an import or a visibility. Without a body the declaration imports a linked C routine; with = body end it defines a C-convention routine in Landin. A definition may be private (for example a callback) or public. A link(symbol: "foreign_name") annotation may follow extern(c) before the declared name, or stand alone before a native function's declared name [1610]. It selects the linker identity, not the Landin lookup name, signature, convention or visibility. In particular, the standalone form keeps the native Landin convention and still requires the ordinary = body end; link never implies C. The decoded link name has the precise safe ASCII shape [A-Za-z_.$][A-Za-z0-9_.$]*: its first byte is a letter, underscore, dot or dollar, and only a later byte may additionally be a digit. Whitespace, @ suffixes and arbitrary assembler expressions are outside this form. The name is a logical external identity, before the platform's symbol prefix: ELF uses it unchanged; Darwin prepends one underscore, including when the logical name already begins with an underscore. Thus foreign_name maps to _foreign_name and _foreign_name maps to __foreign_name on Darwin. This applies equally to explicit native and C link names and default external names. It does not select a calling convention or enable a backend. Assembly quoting follows that mapping and does not change the resulting object symbol. Compatible bodyless C declarations may share a symbol with each other or with one definition; incompatible signatures and multiple definitions are refused. C imports and public C definitions default to their declared spelling. A private C definition without an override uses collision-safe internal naming. A C function type is extern(c) (parameters) -> returns. Convention and variadic status are part of recursive function identity wherever a function is carried, including nested fields, parameters, results, generic actuals, static images and indirect calls. Neither matching machine widths nor layout(c) makes a Landin function a C callback. Function values are code addresses; ptr handler instead addresses a stored function value.

The selected hosted ABIs are Linux and FreeBSD x86-64 SysV AMD64 LP64, Darwin arm64 AAPCS64 with Apple's platform differences, both conventions with signed plain C char, and Linux and FreeBSD arm64's standard AAPCS64 LP64, whose plain char is unsigned. compiler.c_sysv_lp64, compiler.c_darwin_lp64 and compiler.c_aapcs64_lp64 are their respective fixed bool configuration facts, each true for its own ABI alone, not guesses from pointer width or architecture spelling. The ordinary core/c aliases assert one supported fact before exposing c_char, c_schar, c_uchar, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_size, c_ptrdiff, c_float, c_double and c_bool. These name existing scalar identities: signed/unsigned 8, 16, 32 and 64-bit integers as appropriate, usize/isize, f32/f64 and bool; long and long long are both 64-bit. C char is the selected ABI's plain char, a numeric byte and not a Unicode scalar: i8 under SysV and Darwin, u8 under the standard AAPCS64; c_schar and c_uchar keep their signedness everywhere. A described target's ABI identity and widths do not imply that its C boundary is implemented. C signature, record-layout and variadic-call capabilities are selected explicitly; neither core/c nor generated bindings may infer them from LP64 alone.

A C signature is nongeneric and infallible, takes only in runtime parameters, and returns at most one value. Its admitted values are the enabled integer scalars, bool, pointers, D189's named one-atom pointer unions, f32, f64, fixed C function values and recursively compatible nonempty layout(c) structs. D213 distinct identities over an admitted scalar, pointer, callback or C record have their base's layout and transport, while retaining their own Landin signature identity. A distinct identity does not make an excluded base admissible. Such structs contain those leaves, nested C structs and nonempty fixed arrays of compatible fields, with the selected C field offsets, alignment and trailing padding. Ordinary Landin structs, variants, slices, text and any do not become C records by having a similar byte count. Arrays are fields or pointees, not by-value C array parameters or results. Pointer permission, escaping and written from contracts remain Landin checks; a header alone establishes none of their ownership or retention promises.

The SysV C transport classifies actual target-byte eightbytes as INTEGER or SSE, recursively merging fields at their offsets. In this non-vector subset an aggregate above sixteen bytes uses MEMORY. Integer/pointer and SSE argument register banks are independent. A register aggregate is assigned wholly or rolled back wholly to inline stack storage when either bank is exhausted; it is not passed as the internal Landin pointer carrier. Results use the corresponding integer/SSE return banks, or caller storage through the hidden C result pointer, returned again by the callee. Copies and partial eightbyte loads/stores stay inside the actual object extent. None of this changes Landin's internal convention or [1980]'s separate failure carrier.

Darwin uses independent x0–x7 integer/pointer and v0–v7 floating argument banks. A homogeneous aggregate of one through four f32 or one through four f64 leaves (including nested C records and arrays) uses consecutive floating registers. Other aggregates through sixteen bytes use integer chunks; larger aggregates use a pointer to a caller-owned copy. A register aggregate that cannot fit its bank goes wholly to the stack, exhausting that bank. Fixed scalar and homogeneous floating aggregate stack arguments have their natural size and alignment rather than a mandatory eight-byte slot; any other aggregate on the stack occupies whole eight-byte slots aligned to at least eight, as AAPCS64's B.5 and C.14 require. The caller extends narrow integer arguments to at least 32 bits. Results use x0–x1 or v0–v3; an indirect result uses caller storage addressed by x8 without consuming an ordinary argument register. Copies stay within the object extent. Every Landin routine preserves a frame record through x29; x18 is reserved. These physical rules do not enter target-neutral IR or change source cleanup.

The standard AAPCS64 shares Darwin's banks, homogeneous floating aggregates, sixteen-byte indirect bound, narrow-integer extension, results and x8. It differs in two places. Every stack argument, scalar or aggregate, occupies its size rounded up to whole eight-byte slots and is aligned to at least eight, as C.16 requires. An unnamed variadic argument is assigned exactly as a named one of its promoted type would be, to the next register of its bank and to the stack only when that bank is exhausted. x18 stays reserved there too, so one register rule holds wherever compiler.arch == arm64.

A final , ... after at least one fixed parameter marks a variadic C signature. It is not [0960]'s ! .... Variadic calls use only positional arguments, including their fixed prefix, evaluated in written order. Their unnamed tail admits scalars, pointers (including named optional unions) and fixed C callbacks, not aggregates, arrays, slices, atoms or erased values. Outgoing direct and indirect calls promote unnamed f32 to f64 and bool/narrow integers to C int; untyped integer and floating literals take i32 and f64 respectively. Other admitted tail identities remain unchanged. SysV calls supply the ABI's SSE-register count; Darwin places every promoted unnamed argument in an eight-byte stack slot; the standard AAPCS64 assigns them as named arguments. Fixed arguments retain their declared types. Variadic C function values may be stored and called in Landin, but a C callback parameter, result or record field must have a fixed signature. A native Landin definition that receives varargs is refused: incoming entries require a generated C adapter with an explicit extraction schema rather than an untyped Landin va_list. No declared or inferred Landin error set, exception unwinding, or longjmp across Landin frames is part of this boundary.

Header processing belongs to the separate deterministic clang-AST binding generator, never to refine. The generator contract covers declarations and C adapters for integer-backed enums, untagged unions, bitfields, globals, thread-local access, nullable callbacks and schema-defined incoming varargs. It does not introduce native C union, bitfield or TLS grammar. Policy supplies missing nullability, origin, retention and adapter choices, not handwritten replacement signatures. Nullable callbacks require a genuine code-pointer adapter representation, never a pointer to a function-value cell. Selected extended/x87 or 128-bit scalars, complex, vector, atomic or volatile types, old-style or non-C-calling-convention functions, packed, overaligned, flexible or zero-size by-value records, anonymous unaliased declarations, unsupported arrays, unsafe, stale or missing policies, and unsupported va_list forwarding receive explicit generator refusals rather than guessed layout or a fallback ABI. Enums, unions, bitfields, globals and TLS, nullable callbacks and bounded incoming-varargs schemas cannot be refused wholesale as a completion shortcut. This rule states the generator's contract; it is not a claim that its implementation or differential evidence is complete.

A known integer-to-pointer construction whose value is zero after target usize conversion is refused, including a closed folded expression. A dynamic construction tests the converted address for zero and traps before producing a pointer; this check remains in unchecked. Integer construction still loses origin, not non-nullness. Foreign nullable data pointers use a named one-atom pointer union and exhaustive match. Absent allocator backing uses that same ordinary union discipline, never a forged ptr(0) or ptr(1) allocation. core/mem.dispose reports raw_not_empty for a nonempty prefix and raw_empty for already absent backing; a successful release clears backing to its atom.

Foreign failure detail is ordinary explicit state. After a documented libc failure indication, core/io/hosted captures errno before any other host call and retains the exact terminal value in its system provider, exposed by hosted.last_errno. Safe interrupted open/read/write attempts may retry; completed read/write progress is never replayed. Close consumes the handle even on failure and is never blindly retried, including EINTR. These facts neither add payloads to error atoms nor make errno a process-global Landin variable.

On both hosted paths, the compiler-owned bridge emits the hidden external entry void _landin_host_initialize_arguments(int argc, char **argv); (with the platform symbol prefix) whenever hosted bridge support is retained. An executable's selected no-argument Landin entry calls it with the actual incoming C carriers before its source body runs. A C-owned startup that drives public C-convention Landin routines calls it explicitly before hosted.host() can mint an argument-table capability and before starting any thread that may do so. Merely importing core/io does not perform initialization, and startup-independent bridge services may run without it. Ordinary exports and callbacks never initialize, replace or reset this state.

The host I/O and heap constructors are public, zero-argument library routines. Any ordinary hosted routine can call them; hosted argument services still require the startup described here. Constructor use is not restricted to the entry point or to a routine that received a capability argument. A routine's parameter list therefore records supplied capabilities, not an enforced upper bound on host I/O or allocation in its call tree [1660] [1680]. For a call tree that uses only its supplied providers, a caller can substitute an in-memory world or bounded allocator without changing that code. Establishing that premise requires inspecting the called code; a signature alone cannot establish it, including for code offered as untrusted.

The first call requires a nonnegative argc and non-null argv and retains that exact pair as the one argument root. It allocates and copies nothing: the C owner must keep the argv table and every argument it names readable for the whole lifetime of every Landin world, view and callback derived from them. A later call with the identical count and pointer is harmless; a negative count, null table or attempt to replace either part of the established root traps. The retained-state count, table and indexed services trap before initialization. The published user table begins at argv + 1, its count is max(argc - 1, 0), and the retained-state indexed compatibility lookup traps on an out-of-range index or null entry.

The remaining repository-owned runtime bridge exposes fixed wrappers for strlen, read-only and write-create-truncate open, read, write, close, errno, and hosted heap allocation and release; those wrappers call libc. This is a compiler/runtime ABI used by core/io/hosted and core/heap, not a set of privileged language operations. core/io/hosted turns descriptors and pointer-and-length argument views into ordinary values, maps foreseeable host failures onto declared atoms, and threads its world(provider) concept as the authority for opening files and touching streams [1660] [1680]. Direct Linux syscalls are not part of this route. The required world.write_some reports counted progress for one attempt, with no transfer on failure and no host call for an empty slice. world.same_file follows path aliases and compares file identity before any destructive output open; a missing output returns false, while failed input lookup or other output lookup failures refuse. It assumes stable names, rather than providing race-safe output opening. D153 states these ordinary library contracts and their provider obligations.

1990

Firmware and machine directives have explicit target contracts

D229 enables the constrained Cortex-M0 firmware path. The request selects --target=cortex-m0 --firmware-entry=NAME and an assembly or executable output. NAME is a source declaration in the entry module, not a linker symbol or a hosted main convention. It must identify one defined, nongeneric ordinary () -> none or () -> noreturn routine, or a naked () -> none routine, with no declared error outcome. Source duplicate names, missing entries, invalid signatures and duplicate request options are errors. Entry selection does not require public. A different explicit link(symbol: text) does not change which source declaration is selected. Hosted entry and linkage rules remain [1970]/[1975].

The selected image has 32 KiB flash at zero and 16 KiB RAM at 0x20000000. The initial SP is 0x20004000, aligned to eight bytes. The upper 4 KiB of RAM is reserved for stacks; static RAM ends no later than 0x20003000. This is a constrained test profile, not permission to use the board's larger flash. The firmware request refuses a compiler-framed routine when its known frame alone, including saved registers and reserved homes, exceeds the selected 4 KiB stack reservation. This does not bound total stack use across calls or interrupts; those paths remain programmer obligations. The compiler creates a 48-word, 256-byte-aligned vector image at address zero. Its first two words are the initial SP and compiler reset function. Core slots 4–10 and 12–13 and selected-device slots 21 and 42–47 are zero. Other unspecified handlers enter the compiler's terminal unhandled-exception loop. There is no VTOR relocation, FPU frame, exclusive-access primitive, priority grouping or later-Thumb instruction contract.

Reset masks configurable interrupts, initializes reserved r9 and the root r11 to zero, copies initialized RAM data and RAM code from their flash load addresses, and clears BSS. DSB and ISB precede unmasking and transfer to the selected entry. It does not call user module initializers [1460]/[1940], construct a hosted environment, allocate memory or run a scheduler. This reset contract assumes execution through the hardware reset vector, with no NMI or fault during initialization; a custom NMI/HardFault handler cannot assume initialized storage before reset has completed it. D232 routes ordinary entry return and failed language checks to the selected panic handler, or the terminal default. Naked fallthrough retains its undefined-instruction guard. Hardware faults retain hardware fault dispatch; no failure is returned to a nonexistent hosted caller. none remains absence of a result, not the distinct noreturn return form (D231).

extern(interrupt) and extern(naked) are distinct structural function conventions, separate from ordinary and C functions. Definitions are nongeneric, have exactly () -> none, and declare no error set. Machine conventions are also available in function types. Values retain that exact convention through assignment, parameters, aggregates and generic matching. Taking their function value is allowed; converting to ordinary/C convention or calling it with ordinary source call syntax is refused. A vector reference is a machine entry, not such a call. Interrupt bodies may call ordinary functions and must handle any declared failure locally. Traps still trap. There is no implicit keep attached to either convention.

On exception entry ARMv6-M saves r0–r3, r12, incoming LR, return PC and xPSR on the interrupted stack, adding the architectural alignment word when needed. Handler mode uses MSP; thread mode may use MSP or programmer-established PSP. Ordinary and interrupt routines preserve each r4–r7 register their emitted instructions use. An ordinary routine with no calls, no inline assembly, and no transient stack changes may use SP-relative homes, leave r11 and LR untouched, and save only the low registers it uses. Other routines construct a previous-r11/incoming-LR eight-byte record before publishing r11; they also save the low register used to carry r11 and round the low save area for eight-byte call alignment. r8 and r10 are untouched, r9 remains reserved, and a published r11 is restored. Incoming LR in an interrupt record is EXC_RETURN, not a code address. The epilogue uses BX LR; the hardware restores volatile state, flags and the interrupted stack. 0xfffffff1, 0xfffffff9 and 0xfffffffd are respectively supported returns to a handler, a thread using MSP, and a thread using PSP. The NVIC implements four programmable priority levels (the upper two priority bits), with fixed NMI/HardFault priorities and no priority grouping. Higher-priority interrupts may nest; same/lower priority ones remain pending. PRIMASK masks configurable exceptions, not NMI/HardFault or DMA. The compiler adds no interrupt masking around source memory events. Eight-byte alignment at ordinary calls, callee saves, no red zone and the private r12 zero-success/nonzero-failure outcome are unchanged. Zero is not added to any ordinary source atom domain.

A naked body consists of one assembler.block statement. It has no compiler frame, saved registers, local bindings, ordinary source calls, source branches, cleanup or implicit return. Its text may contain labels, explicit branches and machine return instructions; an appended trap handles fallthrough. The programmer owns stack selection, alignment, callee saves, r9/r11 obligations, LR/EXC_RETURN and any calls written in the assembly. A naked selected entry runs after compiler reset initialization; it does not replace the reset loader. This is the explicit exception to [1550]'s frame guarantee. It does not permit an ordinary routine to omit its frame.

assembler.block takes a quoted or raw fixed text literal in a routine body, optionally followed by operands [1630]. The fixed text is not a runtime argument. D248 records the operand form and D230 the positional shorthand. [1820]'s arguments derive operands after any call's positional arguments, because which callee a name denotes is not the grammar's to say; the checker refuses them on every call but assembler.block. A module tool directive takes expressions only.

An operand is in name: type at register = expression, inout name: type at register = expression, out name: type at register or out _ at register. Its name is its {name} template slot and, for an output, its result field; it declares nothing any scope can see, and two operands of one block cannot share a name. Its type is an exact enabled integer scalar no wider than one register of the target: not bool, a pointer, a distinct type, a range subtype or a type formal. A float operand is transferred to Language evolution by name (D248). An input is evaluated once, in written order, before the block, in the declared type's context; a narrower value is zero- or sign-extended to the full register as its type says. An output takes the low bits of its register. inout passes its input in and its output out of one register, and its output has its input's type. A block with no named output is none; with one, it is that output's scalar; with more, it is the anonymous aggregate of [0990] whose fields are the named outputs in written order. Binding, assignment, destructuring, discard [1020] and D244 treat that value as they treat a call's.

A register is a name the selected target's table answers for, never text:

Cortex-M0Linux x86-64Darwin arm64
instruction textARMv6-M unifiedAT&TApple arm64
operand registersr0–r7rax rbx rcx rdx rsi rdi r8–r15x0–x17, x19–x28
general chooses fromr0–r7rax rcx rdx rsi rdi r8–r11x0–x17
every ordinary block overwritesr0–r7, flagsthose, xmm0–xmm15, flagsthose, v0–v7, v16–v31, flags
saved by the routine when a block names onenonerbx, r12–r15x19–x28
never namedr8–r15 and their aliases, sp, lr, pc, msp, psp, controlrsp, rbp, ripsp, fp, lr, x18, x29, x30, and v8–v15 at every width

A fixed register is its full-width name; general is the one class and asks the compiler to choose a register it does not otherwise name in the block. Every register an operand names is distinct from every other, and a block cannot ask general for more registers than the class has left once its fixed registers and every register its text names are set aside. Every ordinary block may overwrite the overwritten row; a register the routine saves must be declared, as an operand or as out _ at register, which is what makes the routine save and restore it. A discarded output names one fixed register. The text writes {name} where an operand's register belongs, spelled at the width its type selects (%eax or %rax, w9 or x9, r3); {{ and }} are literal braces. Every {name} must name an operand, every general operand must be written in the text, and every register the text names at any width must be declared or overwritten and never be one no block names. Frame pointers, stack pointers, link registers, the platform register and Cortex-M0's reserved r9 are therefore never named, and no register is reserved by the language beyond them. arm64's v8–v15 are callee-saved and no operand can declare a float register, so an ordinary block cannot name them until float operands exist. The private failure registers are overwritten: a failure outcome is copied out as its call returns and is never live across a block.

Every block is a conservative read/write, call and trap boundary in IR, on every target: memory knowledge is invalidated and memory operations cannot be moved across it, and it runs exactly once each time it is reached, never removed, duplicated or merged, in order with other blocks, volatile accesses, atomics, barriers and calls. The memory effect is fixed; no block declares a narrower one (D248). This compiler boundary alone issues no hardware barrier and establishes neither device completion nor cache coherence. D227's external-writer obligations remain.

The text is at most 4096 decoded ASCII bytes, using LF, horizontal tabs and printable characters. Directives, comments, statement separators and labels are refused in an ordinary block, which is straight-line: it cannot branch, call, return or change control mode, except that Cortex-M0 svc enters the SVC exception handler at vector 11. That handler decides whether execution resumes after svc; this exception does not admit other control transfers in an ordinary block. At the default armv6-m level the accepted spelling is a bounded subset of ARMv6-M unified assembly; its instruction allowlist is an implementation limit, pinned by the machine checks. At armv7-m and armv7e-m, the checker retains the text and straight-line restrictions, and the assembler enforces the selected architecture's instruction set. UDF and BKPT are refused in ordinary blocks at every level because they enter exception handling. Naked blocks additionally admit labels, branches, BL/BLX/BX, PUSH/POP, UDF and the MSP/PSP/CONTROL system registers, and take no operands. CPS changes PRIMASK at every level and may change FAULTMASK at armv7-m or armv7e-m; barrier operands are sy or omitted. BASEPRI and FAULTMASK system registers are available at those higher levels. Unsupported system registers remain refused. On x86-64 and arm64 the checker refuses control transfer by mnemonic and leaves which instructions exist to the platform assembler. Unencodable operands and instructions remain explicit assembler failures under the pinned flags, never a target upgrade. Assembly must not overwrite compiler spill or frame storage, saved registers or immutable source storage through an indirect address, leave the stack pointer changed, or on x86-64 leave the direction flag set; an instruction's implicit register effects are the programmer's to declare, as cpuid's write of rbx is. Arbitrary machine text cannot prove those obligations.

This compiler lowers every form of assembly on all three targets. The synthetic target has no registers and refuses assembly outright.

Placement is a declaration annotation: link(section: text, align: integer, vector: integer, keep, symbol: text). Only supplied attributes apply, and duplicate attributes/annotations are errors. Section names are at most 80 ASCII letters, digits, underscores or dots, with a nonempty suffix. Functions select .text.* (flash) or .ramtext.* (RAM execution with a flash load image); immutable data selects .rodata.*, mutable data .data.* or .bss.*. An explicit BSS initializer must be zeroed or the integer literal 0. Compiler .landin_ section names are reserved. Alignment is a decimal power of two from 1 through 256 and is a minimum placement alignment; type layout and alignof do not change. Alignment and vector indexes use decimal integer literals, with the ordinary digit separators allowed; nondecimal prefixes and computed expressions refuse. Without a section annotation every datum/routine has its own input section; mutable zero images use BSS and immutable images use flash.

keep marks the containing input section as a retention root. Naming the same section deliberately coalesces its objects, and keep on any of them retains that section. Relocations from retained sections retain their targets. Unreferenced sections are garbage-collected. Symbol linkage does not itself retain a section. Cortex module data may give one explicit ASCII identifier as its symbol; symbols cannot collide with other explicit declarations or compiler startup/private Arm helpers. Function symbol spelling retains [1975]'s existing rules. Ordinary, C and optimal aggregate layout do not change.

vector: N associates a defined interrupt/naked routine with one unique implemented exception slot: 2, 3, 11, 14, 15, 16–20 or 22–41. Slots are absolute vector indexes, not IRQ numbers. Zero, reset, reserved slots, duplicates and ordinary/C routines are refused. Emitting such an annotation requires an explicit firmware-entry request. The compiler-owned kept vector image carries a relocation to the handler; an unreferenced interrupt routine without keep can still disappear. Thumb function relocations retain bit zero; data addresses are not tagged as code. Linker-defined startup addresses distinguish load from execution locations. Existing static function/text-address images remain relocations, not calls or user-code initialization. The compiler does not enable an arbitrary source initializer referring to a linker symbol; fixed assembly can name the documented _landin_firmware_* startup symbols.

Executable emission retains assembly, object, compiler-generated linker script, ELF and map as explicit outputs. The driver passes each host effect through Landin.Platform, checks output/source aliases before writes, uses ARMv6-M Thumb/AAPCS soft-float assembler flags with fatal warnings, and links with no hosted startup, default libraries or libc. Only the selected private thumb/v6-m/nofp/libgcc.a helper closure is admitted. This does not enable the general C source surface. The linker checks flash bounds, static RAM/stack overlap and the vector address/size; unresolved symbols and relocation or encoding failures remain reported tool failures. An 8 MiB static-image materialization guard applies before firmware emission, including unreachable images, independently of the much smaller physical map and section GC. Hosted placement annotations, arbitrary section addresses/linker scripts, weak symbols, inline hints and general tool directives remain explicit refusals. No request is silently ignored.

THE DECISIONS THIS DOCUMENT TOOK

A rule above is one of two things, and a reader cannot tell them apart by reading it: a transcription of something tour.md already decided, or a decision taken because the tour said nothing and an implementation could not proceed without one. The decisions are listed here with what the tour said before, what was chosen, and what a competent reader could have chosen instead — because a decision written in the same voice as a transcription looks like it was always there, and [1050] was missed twice by a reader who assumed exactly that.

A decision leaves this register only when new evidence closes it: a program that cannot be written, a target that cannot be reached, or a paragraph of the tour that turns out to have settled it after all. Completed implementation does not remove a decision, because its alternative and fixture remain useful review evidence. The history records the delivered vertical slice; this register does not repeat its implementation diary.

The register is the fourteen sections that follow, and they are the subjects tour.md teaches, in the order it teaches them, so a question about arrays is answered in one place whichever document it is asked of. It was chronological until the documents were reorganised by subject, which is why the numbers now run out of order: D1 and D2 are scope decisions and sit beside D233, which was taken far later. Inside a section the numbers do ascend, so a run of decisions that built one subject together is still read in the order it was built. A heading is a stable citation target, and nothing that cites one has to know where it sits.

DECISIONS: DECLARATIONS, NAMES AND SCOPES

What a declaration introduces, which scope holds it, and which words no declaration may use.

D1 — A named return lives in the signature scope

The tour said that a named return is assigned like any other place and that return leaves [1810], and that every named return must be assigned before the function returns [0930]. Neither says which scope declares it.

Chosen: the signature's, beside the parameters [1840]. So f: (r: u32) -> (r: u32) is one name declared twice in one scope, and the body can assign the return from inside any arm.

The alternative: the body's scope. Then a parameter and a return could share a name, and the body would shadow the return rather than assign it.

Pinned by negative/return-shares-a-parameter-name.

D2 — Each arm of an if is its own scope

The tour said nothing. [0140] permits an inner scope to shadow an outer name and [1090] says a bare block is for scoping, but a bare block is not in the kernel and no paragraph says an arm opens a scope. The sentence that now says so is in [1840] and was written here.

Chosen: every arm and the else is a scope, and they are siblings. A name declared in one arm is not visible in another, nor after the branch closes.

The alternative: one scope for the whole body, so a binding in an arm outlives it. Defensible, and it is what a language without block scoping would do — but then two arms could not use the same local name, which is the commonest thing a branch does.

Pinned by positive/arm-scopes-are-siblings, negative/name-from-another-arm, negative/name-after-the-branch-closes.

D10 — A module binding with no value holds zero

The tour said that a binding may carry no value and must be assigned before use [0080], and that values at module level must be known at compile time [1460]. Neither says what one with no value holds, and the two do not combine: [0080]'s "before use" is a rule about paths through a body, and [1460] says nothing runs before the entry point, so at module level there is no path and no moment in which an assignment could happen.

Chosen: zero, and false for a bool [1940]. Reading one before anything writes it reads zero. positive/binding-declared-only stays a positive fixture, and mut counter: u32 is module state a function updates.

The alternative: two, and both were defensible. Refuse a module binding with no value, on the strict reading that no value is not a known value — which is tidy, and costs mut counter: u32 = 0 at every declaration of module state, where the = 0 says nothing a reader did not know. Or keep the declaration and refuse the read, which is [0080] taken literally — but at module level "before use" is a question about which function runs first, and that is a whole-program analysis this specification does not have and the kernel is not equipped to answer.

Pinned by positive/binding-declared-only, positive/module-binding-with-no-value-reads-zero.

D218 — A local's written type precedes its own name

The tour said that the left of : introduces the name and the right supplies its type or value [0110]. [1840] explicitly put the initializer before the new binding. It did not settle the written type's lookup scope; the ordinary-local implementation installed the name first, unlike D185's condition-binding implementation.

Chosen: an ordinary local's written type and initializer both resolve in the incoming lexical scope, before that local is introduced. This includes names nested inside reference types, fixed-array bounds and generic actuals, and applies with or without an initializer. A local may therefore shadow an enclosing type or fixed formal while using it in its own declared type. mut t: t = value uses the enclosing t for the type; following statements see the new runtime binding. An absent enclosing name is still unknown, and an already declared local in the same block still makes a duplicate.

This agrees with D185's condition bindings. It does not change collected module or signature scopes, enable local type declarations, or make a name visible in its own initializer. A generic body resolves the outer type/fixed formal's identity before concrete substitution, just like its other uses.

The alternatives: introducing the local before resolving its type makes its spelling hide the very type or fixed bound being declared. Retaining that rule only for ordinary statements makes the equivalent condition binding behave differently. Resolving all names against the enclosing block would instead lose earlier locals from the incoming scope. All are declined.

Pinned by positive/r491-local-type-scope, including a generic list-element copy derived from prototype 3, negative/r491-local-self-reference, negative/r491-local-self-initializer, negative/r491-local-shadowed-type, positive/condition-declarations and negative/condition-declaration-body-shadowing.

D225 — Control words are reserved everywhere

The discrepancy: [1760] reserved if, then and end, while other already enabled control forms still used identifier tokens. An earlier review repair first fixed declarations and assignments under that contextual contract, but ordinary expression reads remained ambiguous. The intended language rule is that a control word cannot also be an identifier.

Chosen: add begin, break, complete, continue, defer, do, for, loop, match, unchecked, undo, while and with to [1760]'s keyword production. Each is reserved in every name position, regardless of whether its control form appears in the program. Parentheses provide no escape. begin = 10 is illegal; an ordinary binding must use another name, such as begin_value. Existing block, match, loop, transfer, completion and cleanup semantics are unchanged. Other contextual words, including of, caller, range and arena, retain their existing rules.

The alternatives: contextual control-word priority plus a parenthesized name escape preserves dual meanings, while broader contextual lookahead must resolve genuinely ambiguous expressions. Reserving the words removes both problems at the lexical boundary. Existing declarations using these words must be renamed; this compatibility change is explicit and supersedes the earlier contextual-name repair and the matching part of D187.

Pinned by negative/r491-reserved-control-assignment, positive/r491-contextual-statements, positive/r491-bare-block-examples, and the parser case control words are reserved. The bounded case covers all thirteen tokens, longer identifiers and forbidden declaration, parameter, result, field, label, member and parenthesized-name positions. The derived parser, container and hosted prototype controls retain their control-flow and cleanup contracts; reservation adds no execution or aliasing rule.

D233 — A shared declaration is one declaration per name, with one initializer evaluation

The tour said that several names may share one declaration, the same form field lists already use [0100], and showed public red, green, blue: u8 beside an atom list. Atom lists were enabled; shared bindings, fields, parameters and returns were refused by name until the initializer and convention questions their implementation needs were decided.

Chosen: binding, field, parameter and named_return take [1740]'s identifiers list where they took one name. A shared declaration means the declarations written one per name, in written order, each carrying the complete written prefix — public, mut, link(...), caller, escaping, in, inout or sink — the same type and the same suffix, at or from. A prefix applies only when written before the first name, so (a, inout b: T) is not a shared parameter. An initializer is evaluated once, as the first name's; each later name is initialized with a copy of the first name's value, so mut low, high: u32 = next_seed() calls once and leaves two independent places. A module declaration without a value holds zero for every name (D10); with one, the later names copy the first name's static image. The type, at bounds and from sources are written once and checked once: a type that names nothing is one report and two packed fields at one position are one overlap. Debug information lists every name as the ordinary variable, field or parameter it is.

Two parsing rules follow from the list. A comma followed by names that reach : starts the next named return rather than extending a from list, because [0110] makes the name left of : the one being introduced. A run of names ending at : or := begins a binding where [1800]'s one-token lookahead decides between a statement and a value.

The shared form needs a written type. a, b := e stays L0010 citing [0100], because it reads as a destructuring [1810] and nothing written once could be shared. A condition binding (D185), a type declaration, a type or fixed formal, a function and a variant part keep one name each and meet the same L0010. These are recorded boundaries, and the second note says "this is a recorded source-form boundary".

The alternatives: evaluating the initializer once per name, as though the declaration were retyped, was declined: an expression written once runs once, as [0560]'s repeated expression already does, and duplicated side effects would be invisible at the one place they are written. Refusing initializers on shared declarations was declined as less useful for no less work. Applying a convention only to the name it precedes was declined because (a, inout b: T) would then hold two conventions in one list, while [0100]'s field-list reading gives every name the whole prefix. Admitting a, b := e with a copied inferred type was declined for the destructuring reading.

Pinned by positive/shared-declarations-every-position, runtime/shared-declarations-evaluate-once, negative/r491-shared-declaration, negative/shared-type-names-nothing, negative/shared-packed-fields-overlap and negative/shared-link-symbol-duplicates.

D246 — A refusal by name says what the form is, not which work decided it

The discrepancy: [1830] required a named refusal's second note to say "which work enables it", and every note printed ROADMAP.md and a work item of the first roadmap, followed by what the item did: recorded the boundary, withdrew the form or transferred it. By the time the first roadmap closed no note was a promise any more. Each named a finished item that had recorded a boundary, withdrawn a form or transferred one to a successor, so the item told a reader nothing the rest of the sentence did not. Pointing at ROADMAP.md for it pointed at a file that no longer holds that item's text. D190 had already had to move one refusal's item by editing a string, and D196 another, because an item finishes long before the diagnostic that names it stops being printed.

Chosen: the second note states what the refused form is: "this is a recorded source-form boundary", "this form is withdrawn; " followed by what replaces it, or "this is transferred to Language evolution". The compiler records that as a standing in each refusal table, a recorded boundary, a withdrawal or a transfer, in place of the item it named, and the Report body writes the note from the standing alone. The first note, the paragraph, the codes L0010 and L0304 and every primary message are unchanged. The construct inventory holds each row with a refusal to explaining it in the row's own disposition, and a transferred refusal's row to naming the successor.

The alternatives: keeping a pointer that outlives its item was declined for the reason above. Naming the decision, D212 or D236, in place of the item was declined: a decision is stable, but it is the reason for the refusal and not what the refusal is, and a reader who wants the reason reaches it from the paragraph the first note names. A fourth standing, "pending", for a construct the kernel will enable was left out because no refusal is one. If one is added, its note says the construct is not enabled yet, and which work enables it stays ROADMAP.md's to say.

Pinned by negative/r491-shared-declaration, negative/arena-block-names-owner, negative/arena-type-names-owner, negative/r491-volatile-pointer, negative/refused-widths-name-their-owner, negative/r740-parameterized-application-boundary, negative/r720-range-subtype-array-element and negative/cortex-refused-type-named, whose recorded reports carry the notes, and the parser case shared declarations have a named refusal.

D251 — A warning is the compiler's, never the language's

The discrepancy: [1850] says a rule that permits something does not also warn about it, and nothing in the language defines a warning. The catalogue has had a warning severity since the first slice and no code used it. A lint is a judgement the language does not make; the risk of one is a second opinion that disagrees with the rules, or a verdict that depends on it.

Chosen: a warning is a catalogued code at warning level, raised by the compiler and never by a rule of the language. It never refuses a program: the exit status stays 0, and an accepted program is emitted exactly as it would be without it. A warning is admitted only where the compiler can say, from facts a rule already decided, that something written was not needed, and only with the exact fix that removes it and leaves the program's meaning unchanged; the catalogue requires every occurrence to carry that fix. Shadowing is never warned about, as [1850] says. There is no way to silence a warning, because the answer to one is its fix; the first warning that needs silencing brings the mechanism and records here where it lives.

The first warning is L0326: a local binding declared mut [0060] that no assignment, step, inout argument or mutable view needed, found where the checker's own [1900] check answers from that mut. Its fix removes mut and the blanks after it, never a comment or a line end, and is offered only where those bytes are all that separate the word from the name. A shared declaration [0100] is warned about only when none of its names needed mut, because one word serves them all. A module binding is never warned about, because a linked routine or a debugger may write it. The warning runs only on a program the checker accepted and only in a routine body it checked, so an uninstantiated generic says nothing.

L0349 warns about an unused immutable local whose initializer is a direct integer, float, character or boolean literal. The checker finds no resolved reference to the binding and offers deletion of its whole line as an exact fix. It warns only when the binding is alone on that line, has no attached doc comment, is not part of a shared declaration, and belongs to a checked routine body. Calls, names, aggregate construction and other expressions are excluded: deleting those could remove work. A module binding is excluded for the same external-use reason as L0326.

The alternatives: no lints at all, which [1850] reads as. That leaves the compiler unable to say what it knows about a program it accepts, and pushes the judgement into a second tool whose rules drift from the checker's. Unused imports were declined as a first lint: an import adds its module to the program and its conformances to the one register [1280], so removing one can change what the program means. Unused immutable locals with an initializer that may do work are still declined: quieting one by adding a discard [1930] would judge that work as wasted. A direct scalar literal has no such work, and deleting its unused declaration is an exact repair.

Pinned by negative/mut-never-written and negative/unused-pure-local, which apply the fixes and compile the results clean, and the codes: of every accepted fixture whose program warns.

D254 — A doc comment is the run of lines directly above a declaration

From [0030] and [1780].

The tour said that a doc comment attaches to the declaration that follows it, and nothing about what "follows" means when a blank line, another comment or code comes between, or when two doc comments are stacked. Nothing read a doc comment until an editor asked what a name was.

Chosen: [2000]. The run of doc comment lines directly above the line a declaration begins on, read top to bottom; anything else on a line, a blank line among them, ends the run, and a doc comment beside code or below a declaration is about nothing. A declaration that does not begin its line, such as a parameter, has none. The language gives a doc comment no other meaning, so this decides only what a tool shows.

The alternatives: the nearest doc comment above, however far, which hands a file's opening comment to whatever is declared first; a blank line allowed between, which makes a section heading the documentation of the first declaration under it; and a doc comment after the declaration on the same line, which [1780]'s line comment already serves and which would make every trailing remark documentation.

Pinned by server/doc comments are the run above and the hover session under compiler/tests/server/.

DECISIONS: NUMBERS AND LITERALS

How a literal is written, what it means, and which scalar types the kernel has.

D3 — Signed integers are two's complement

The tour said nothing: the word complement appears nowhere in it. [0300] gives wrapping operators and [0320] gives a sign-keeping >>, and neither means anything without a representation.

Chosen: two's complement, stated in [1870]. So i8 holds -128 and not -127, and -128 is writable.

The alternative: leaving it to the target. Then i8 = -128 would be a program whose legality depended on the machine, which [0310]'s refusal of implicit conversion exists to prevent.

Pinned by positive/literal-at-the-widest-value, negative/literal-below-its-type.

D4 — usize is a distinct type from u64

The tour said only that usize and isize are pointer-width integers [0160]. It does not say whether that makes usize a name for u64 on a machine whose pointer is eight bytes wide.

Chosen: distinct, on every target [1870]. Adding a usize to a u64 is refused everywhere.

The alternative: the same type where the widths agree. That is what a C programmer expects, and it costs this: a program would compile on linux-x86-64 and be refused on a 32-bit target for a reason no paragraph of the specification could state.

Pinned by negative/usize-is-not-u64.

D5 — A typed sibling gives an untyped literal its type

The tour said that an integer literal takes the type of its context and is checked at that point [0190], and that with no context it is i32 [0200]. It never says what a context is. That list is in [1880] and was written here.

Chosen: eight positions give a literal a type, and one of them is the other operand of a binary operator. So in x + 1 with x: u8, the 1 is a u8.

The alternative: only a declared type is a context. Then x + 1 would make the 1 an i32 by [0200] and immediately refuse it against x, so every literal in an expression would need a conversion the kernel does not have. This is the decision with the least room in it, and it is still a decision.

Pinned by positive/literal-takes-a-sibling-type.

D162 — Decimal f32 and f64 values keep IEEE bits through runtime operations

The tour said that f16, f32 and f64 exist [0170], that a float literal is recognisably distinct from an integer [0210], that decimal exponents and separators are accepted [0220], and that signed zero and arithmetic-produced IEEE special values are observable [0240]. It did not state the type of a contextless float, whether one width could arrive before the others, how a finite decimal overflow is treated, or whether module folding may inherit the compiler host's arithmetic.

Chosen: f32 and f64 are enabled. A decimal literal has digits on both sides of its dot and may have e or E, an optional sign, and a nonempty decimal exponent; underscores follow the integer digit-run rule. It takes f32 or f64 from context and otherwise defaults to f32. Integer and float literals remain separate classes with no implicit conversion. The literal rounds once to IEEE binary32 or binary64; a finite spelling that would become infinity is L0300. Unary minus flips the IEEE sign bit, preserving negative zero and a NaN payload.

At runtime +, -, *, /, unary minus and all six comparisons use the value's IEEE width. Division by signed zero yields infinity or NaN rather than [1950]'s integer refusal or trap. Equality is false for an unordered NaN, inequality true, and every ordered comparison false. Values retain their raw bits through local and module scalar storage, fixed arrays, ordinary structs, internal parameters and returns. Representation-class routine sharing treats a float as distinct from a same-width integer. The first external C boundary continued to refuse float signatures until its float register classes were supplied. D204 and the current [1975] subsequently define that separate C float path; the limit in this decision does not override them.

A module float at this decision may use a literal, its unary minus or zeroed, also inside a static aggregate image. Float arithmetic in a module image remained a named refusal: the target-neutral folder does not borrow the compiler host's rounding mode or NaN behavior. D166 subsequently enables hexadecimal floats [0230], D167 enables the named infinity and nan members [0240], and D175 enables module float arithmetic and comparison. f16 and explicit integer/float conversions [0310] remain separate hosted increments.

The alternatives: default to f64, admit decimal literals only with an explicit type, treat a float's same-width integer carrier as interchangeable, lower float operations through integer arithmetic, or evaluate module values with the Ada host's float types. Those choices contradict the tour's inferred f32 examples, lose IEEE behavior, make routine sharing change operations, or make cross-compilation depend on the host.

Pinned by runtime/float-decimal-runtime, negative/float-literal-not-enabled, negative/float-literal-overflows-context, negative/float-remainder-is-integer-only, negative/float-type-not-enabled, negative/integer-literal-not-a-float, negative/malformed-float-exponent, positive/r440-external-float for the later f64 C-boundary admission, negative/external-aggregate-boundary and negative/r440-c-slice-parameter for the boundary's continuing carrier refusals, the lexer cases, and the float.ieee guarantee row.

D163 — A character is one decoded Unicode scalar with fixed type u32

The tour said that [0250]'s character literal is a codepoint typed u32 and [0270] gives literals one closed escape set. It did not say whether the byte escape denotes a character, whether raw source may contain more than one scalar, or which stage rejects a nonscalar \u{...} value.

Chosen: the kernel admits a single-quoted literal only when its content decodes to exactly one Unicode scalar value. Raw content is one shortest-form UTF-8 scalar. The simple escapes \n, \r, \t, \e, \\, \" and \' denote their codepoints, and \u{...} denotes one scalar written in hexadecimal. The byte-only \xNN form is not a character spelling. Empty, multiple, malformed UTF-8, unknown-escape, surrogate and above-10FFFF contents are lexical L0322; an unclosed quote remains L0014.

The literal's type is always u32, including in an inferred binding. A different scalar context is L0301 rather than an implicit conversion. Its decoded value uses the existing integer constant carrier, arithmetic, comparison, module folding and aggregate images; the IR and backend need no character-specific operation or representation. Lexing, checking and lowering call one decoder so they cannot disagree about the scalar.

The alternatives: treat \xNN as a codepoint, infer an integer type from context, retain UTF-8 bytes as the value, or permit a quoted grapheme cluster. Those choices erase [0270]'s byte/codepoint boundary, contradict [0250]'s fixed type, or turn a scalar literal into the text representation work [0600] owns. All were declined.

Pinned by runtime/character-literal-codepoints, negative/character-literal-byte-escape, negative/character-literal-empty, negative/character-literal-invalid-codepoint, negative/character-literal-multiple, negative/character-literal-needs-u32, the decoder and lexer cases, and the source.lexical and types.values guarantee rows.

D164 — Raw byte text uses matching quote runs and exact indentation

The tour said that [0280]'s raw literal has the same number N of quotes on each side, with N at least three, interprets no escape, and strips the closing delimiter's indentation from every line. It did not define whether a longer quote run closes a literal, how indentation mismatches are handled, or which currently enabled text carrier receives the bytes.

Chosen: the kernel admits raw literals in D161's direct read-only []u8 context. The maximal opening quote run chooses N; the first later run of at least N quotes closes the token, consumes exactly N, and leaves any additional quotes for following tokens. Runs shorter than N are content. Backslashes and [0270]'s apparent escapes are ordinary bytes. Raw source content must remain shortest-form UTF-8, and the view carries the same uncounted trailing NUL as quoted text. At this decision a literal without a direct byte-slice context defaults to the then-deferred utf8; D181 later enables that default.

A closer is line-leading when an earlier line ending is followed only by spaces or tabs before it. That exact byte prefix is removed at the start of every nonblank content line that begins after a line ending; content on the opener's own line is unchanged. A nonblank line with a shorter or different prefix is lexical L0323; horizontal bytes on a blank line are discarded. Line endings, including the one immediately after an opener or before the closer, remain content. An inline closer has no indentation to remove. A mismatched or absent closing run remains the existing unterminated-literal L0014.

After indentation is removed, raw and quoted literals with equal byte content share D161's one pooled read-only datum. Checking, module images, aggregate fields, calls and lowering otherwise use the same slice path; neither IR nor the backend learns a raw-literal operation.

The alternatives: fix the delimiter at three quotes, close on a shorter run, silently leave under-indented lines unchanged, count visual columns rather than exact source bytes, interpret escapes, or allocate raw and quoted content separately. Those choices contradict [0280], make tabs target/editor dependent, or duplicate representation that is observably identical after decoding. All were declined.

Pinned by runtime/raw-literal-bytes, negative/raw-literal-inconsistent-indentation, negative/raw-literal-needs-read-only-slice, negative/raw-literal-write, negative/unterminated-raw-literal, the raw decoder and lexer cases, and the source.lexical and text.literal-storage guarantee rows.

D166 — Hexadecimal floats are converted from source bits, not host floats

The tour said that [0230]'s hexadecimal float literals express every representable value exactly, including subnormals. It did not define the required exponent syntax, the result of a spelling between two representable values, or whether the compiler may ask its own floating-point implementation to read the value.

Chosen: a hexadecimal float is 0x, a nonempty hexadecimal digit run, a dot, another nonempty hexadecimal digit run, and a required p or P binary exponent. The exponent has an optional sign and a nonempty decimal digit run. Each digit run admits [0220]'s separators but neither begins nor ends with one. Like D162's decimal form, the literal takes f32 or f64 from context and otherwise defaults to f32; it remains a float rather than sliding into the integer class.

Conversion reads the hexadecimal significand as bits and combines it with the written binary exponent. An exactly representable normal or subnormal value therefore reaches its target with the exact bits [0230] promises. A value between target values rounds to nearest with ties to even, including at zero, the subnormal/normal boundary and an exponent carry. Underflow may produce zero. A finite spelling that rounds to infinity is L0300, as for D162's decimal form; a zero significand remains zero even with an arbitrarily large exponent.

The conversion uses only bounded integer accumulation of the significant, round and sticky bits. It does not parse through an Ada floating-point type, so cross-compilation does not inherit the host's width, rounding mode or handling of subnormals. The resulting IEEE pattern follows every D162 storage, aggregate, internal-call, arithmetic and comparison path without new IR or backend operations. An absent or incomplete binary exponent is lexical L0321. Enabling this form removes the scanner's final deferred token family; L0010 continues to name parser-level constructs that [1830] leaves disabled.

The alternatives: use the compiler host's hexadecimal conversion, accept only spellings already exact in the contextual width, or retain an arbitrary precision significand. The first makes a target value host-dependent, the second contradicts ordinary literal rounding, and the third retains far more source state than the precision, round bit and sticky bit require. All were declined.

Pinned by runtime/float-hexadecimal-runtime, negative/hex-float-overflows-context, negative/malformed-hex-float-exponent, the lexer cases, and the float.ieee and source.lexical guarantee rows.

D167 — IEEE special values are inherent type-qualified constants

The tour said that [0240] writes infinity and NaN as members of a float type, that unary minus supplies their negative forms, and that NaN comparison is unordered. It did not say whether the qualifier or the surrounding context chooses the width, which NaN payload a source name denotes, whether a signed NaN retains that sign, or whether the names are valid module images.

Chosen: the kernel enables exactly f32.infinity, f64.infinity, f32.nan and f64.nan. The type before the dot is an inherent part of the value: it does not convert to another contextual float width, so a width mismatch is L0301. No other scalar type has these members, and no other member of f32 or f64 is a named value. An unknown type-qualified member is also L0301 rather than an unresolved module or runtime field selection.

Infinity has the ordinary positive IEEE pattern. nan denotes one canonical quiet NaN: 0x7FC00000 for f32 and 0x7FF8000000000000 for f64. Unary minus flips only the sign bit of either named value, preserving the quiet NaN's payload. These bits use the existing float IR carrier, storage, internal-call, arithmetic and comparison paths; no new runtime operation or backend opcode is introduced.

A named special and its unary minus are compile-time scalar leaves, not member reads from storage. They are therefore valid in module scalar images and in the scalar leaves of module arrays and structs wherever a float literal is valid. General module float arithmetic remains D162's L0304 boundary at this increment and is subsequently enabled by D175. f16 and explicit integer/float conversions remain separate hosted increments.

The alternatives: infer the width from context despite the written type, spell the values as unqualified lexical literals, preserve an unspecified or host-chosen NaN payload, or reject them from static images as field reads. Those choices respectively make the qualifier misleading, add another token family for values the tour writes as members, make generated target bits depend on the compiler host, or deny a constant spelling where an equivalent literal image is already accepted. All were declined.

Pinned by runtime/float-named-specials, negative/float-special-name-unknown, negative/float-special-on-integer-type, negative/float-special-width-mismatch, the direct checking case, and the float.ieee guarantee row.

D190 — u128, i128 and f16 are refused by name

D228 subsequently enables packed unsigned field representations; the historical quotation below records the earlier kernel boundary. D237 later transfers u128, i128 and f16 to the Language evolution successor with new consumer, target and compiler evidence; the refusal below keeps its code, now says "u128 is not in this version of the language", and its note now names that transfer.

The tour said that the integers are u8, u16, u32, u64, u128, i8, i16, i32, i64 and i128 [0150], and that the floating-point types are f16, f32 and f64 [0170]. It teaches the language and does not schedule work, so it said nothing about which of those widths the kernel enables or about what would have to be built for the rest. [1870] answers the first half — "u128 and i128 [0150], the packed widths [0730] and f16 [0170] are described in this tour and are not enabled yet" — and answered the second half nowhere.

Chosen: the refusal of u128, i128 and f16 is the specification's, and the work that would enable them is not the text, literal and loop work that enabled f32 and f64. The refusal itself was unchanged in every respect a program can observe: the checker still matched the resolved spelling, still reported L0304 with "u128 is not enabled yet", and still attached [1830]'s two notes naming the paragraph and the enabling work. Only the second note changed, to name work that would decide the widths rather than the work that had deferred them; D237 later made that note "this is transferred to Language evolution" and D246 made it state the form's standing.

This is an ownership correction and not a language change, and the reason it can be one is that the refusal was already normative. [1790]'s scalar_name production spells thirteen names and has never spelled these three, so the enabled kernel grammar does not admit them and never has; a program writing one is refused by the specification and not by a schedule. What was wrong was a single entry in the compiler's own table, which named the hosted construct work because D162 happened to belong to it when it enabled f32 and f64 and deferred f16 — not because that work's scope, "text, literals, patterns, loops, unchecked, modules, builtin directives and hosted entry behavior", ever included widening the scalar set. [0150] is already a paragraph split across owners: the packed widths u4, u12 and u23 that the same paragraph names belong to the freestanding register work [0730], and nobody reads that as the hosted construct work owing a bit-field allocator.

The construct-applicability register keeps [0150] and [0170] accounted for by the hosted construct work, because that work accounted for those paragraphs as far as the kernel enables them — D162 gave [0170] its two enabled widths and D168 through D176 gave [0150]'s enabled ones the complete conversion matrix. Only the residual refusal moves, which is exactly what D188 did for [0660]'s composite positions and D189 for [0480]'s multi-atom form. A row whose construct one piece of work accounts for and whose remaining refusal another decides is the register's ordinary shape, not an exception made here.

What enabling them would inherit is written down so that the refusal is scoped rather than vague, and it is five things and not one.

  • Landin.Types.Magnitude is range 0 .. 2 64 - 1 and Landin.Types.Folded is range -(2 64 - 1) .. 2 64 - 1. At 128 bits neither is an Ada range type on any host: Folded's symmetric form needs 129 bits and Magnitude's upper bound needs an unsigned 128. Both become software carriers, and so does the single type Pattern is mod 2 64 that Landin.Stages.Checking, Landin.Stages.Lowering and Landin.Backend.X86_64 each fold with.
  • A 128-bit scalar is the first one the backend's one-accumulator memory model cannot hold in a register: Held_Size is Byte_1 .. Byte_8 by declaration, and the SysV classification is two INTEGER eightbytes at 16-byte alignment.
  • Its arithmetic is add/adc, sub/sbb and a three-multiply mul, and a division and remainder x86-64 has no instruction for — divq divides a 128-bit dividend by a 64-bit divisor for a 64-bit quotient and faults when that quotient does not fit. Either an emitted software sequence or a dependency on a support library, and the second contradicts D166, D169 and D175's standing refusal to borrow arithmetic this compiler does not own.
  • f16 is the whole D162--D176 float programme re-run at binary16: decimal and hexadecimal literal conversion at p=11 and emax=15 with subnormals, D167's canonical quiet NaN at that width, D169's rounding across a three-by-three width matrix, D175's module fold, and runtime arithmetic that baseline x86-64 cannot do at all, since F16C is Ivy Bridge and later. That is an ISA baseline change affecting every emitted binary and the Linux gate, or a software encode and decode around every operation.
  • Enabling f16 reopens a settled decision rather than extending one. D170 records that "the enabled integer range cannot overflow either float width", which is true only while f16 is absent: binary16's largest finite value is 65504, so a u32 of 65520 or more rounds to infinity, and the conversion.integer-to-float guarantee row would move from class static to class trap and would owe trapping runtime evidence.

One design answer is recorded here so it is not rediscovered: f16 arithmetic should promote through f32 and round once. binary32 carries 24 significand bits and 24 >= 2 * 11 + 2, so a single rounding of the f32 result to binary16 is the correctly rounded binary16 result for +, -, * and /, and the double rounding is innocuous. Whether the promotion is emitted or the operations are done in software is a target question and stays open.

The alternatives: implementing them inside the hosted construct work was weighed and declined as out of proportion to what that work is for. It is four to six increments — the two carriers above, the backend pair, the float programme at a third width, and the reopened conversion guarantee — and none of the hosted path's evidence needs any of it. Giving the two widths dedicated hosted work so they land before the macOS arm64 and Cortex-M slices was the closest alternative; it was declined because f16 must exist on every target once it is enabled and the baseline Linux x86-64 ISA cannot do binary16 arithmetic at all, which makes it target work and not hosted work. Splitting the two owners — f16 to the freestanding float slice, u128 and i128 to the deferred-behaviour decisions — was declined for the same reason. Amending [0150] or [0170] to delete the three names was declined because they are language the tour teaches and no evidence says the language should lose them. Leaving the compiler's table naming the hosted construct work while the widths were decided elsewhere was declined because [1830]'s note was then a promise to a user about where to look, and a note naming finished work is a wrong answer to that question.

No document exercises any of the three. Nothing in tour.md, spec.md, examples.md or the four prototypes writes u128, i128 or f16 in an example, which is the honest measure of how much design pressure exists for them today: none that has been recorded.

Pinned by negative/wide-integer-not-enabled, negative/float-type-not-enabled, negative/refused-widths-name-their-owner, whose recorded report is where "this is transferred to Language evolution" is executable text rather than a comment and which is the only fixture in the corpus that reaches i128 at all, and the types.values guarantee row.

D219 — Either integer range endpoint supplies literal context

The tour said that an integer literal takes its context [0190], defaults to i32 without one [0200], and may appear at either end of a traversal [1150]. D159 required one integer type for the two bounds but did not specify which endpoint supplies context. The implementation previously defaulted an untyped lower bound before considering a typed upper bound, although an upper literal already took a typed lower bound's type.

Chosen: either typed integer endpoint supplies the type of an untyped integer peer. With two untyped integer bounds, both take i32. Literal values and untyped integer arithmetic must fit that chosen type under [1880]; this includes refusing a negative lower literal when the upper bound is unsigned. Two bounds that already have different integer types still disagree. A float, character or other already typed value does not silently become another integer type. The iteration element keeps the selected integer type.

This makes the prototypes' 0..<count and the tour's 1..<lenof data use usize when their upper bounds do. It changes type selection only: D159's bound evaluation remains once each, lower then upper, and its inclusive terminal check, immutable element, usize index and completion rules are unchanged.

The alternatives: always taking the lower bound's type requires an explicit conversion for the same literal that already works at the other endpoint. Widening two typed bounds would introduce an implicit conversion forbidden by [0310]. Taking an outer result or loop-body use as context would turn the header's type into a later dataflow inference. All are declined.

Pinned by positive/r491-range-endpoint-context, derived from the counted prefix loops in all four prototypes and the tour's sort header, negative/r491-range-context-overflow, negative/for-range-endpoints-disagree and negative/for-range-needs-integer. D159's existing runtime traversal fixture retains the independent evaluation and terminal-bound evidence.

D237 — u128, i128 and f16 leave this slice for Language evolution

The tour said that the integers include u128 and i128 [0150] and the floats include f16 [0170]. D190 kept all three refused by name, recorded the x86-64 cost enabling them would inherit, and declined deleting them because they are language the tour teaches and no evidence said the language should lose them.

Chosen: the language does not lose them; this slice does. [0150] and [0170] now say that u128, i128 and f16 are not in this version and that the Language evolution successor roadmap owns them, with a program that needs 128-bit arithmetic or binary16 values as the trigger. The checker keeps its named L0304 for the three spellings; its message says the type is not in this version of the language and its second note says "this is transferred to Language evolution". [1790]'s thirteen scalar names, Landin.Types, the parser's scalar table and the highlighters are unchanged.

New evidence answers D190's reason, and it is of three kinds.

  • Consumers. D190 counted documents; this decision counts programs. The four complete derived prototypes, the repository core library, examples.md and the 1849 fixture directories write none of the three types outside the refusal fixtures below.
  • Targets, measured with the pinned tools on 2026-09-19. The Cortex-M0 lane's arm-none-eabi-gcc 14.2.1 refuses both __int128 and _Float16 as not supported on this target, and its pinned thumb/v6-m/nofp/libgcc.a (SHA-256 137aa204587d2cefcc3eea90685a29d1e2f058a0a9cbdc29329e6f27c6249903) has binary16 conversions (__gnu_h2f_ieee, __gnu_f2h_ieee, __gnu_d2h_ieee) but no 128-bit multiply, divide or shift helper. A u128 there is four words whose multiplication and division this compiler would emit itself. At the Linux x86-64 baseline ISA, GCC 16.1 compiles a binary16 addition to two __extendhfsf2 calls and one __truncsfhf2, and a 128-bit division to __udivti3; neither is an instruction. arm64 alone converts binary16 in hardware.
  • Compiler. The checker's folding domain is the two Ada range types Magnitude and Folded, with 848 occurrences in 21 source files, and a signed 128-bit fold needs 129 bits. Every backend's Held_Size is Byte_1 .. Byte_8, so u128 would be the first scalar no backend holds in its accumulator model, with an ABI position of its own on each of three targets. f16 reruns the D162--D176 float programme at binary16 and turns D170's statically safe integer-to-float conversion into a trapping one.

Against no consumer, that cost is what [1710] asks a feature to earn, and nothing has earned it. A transfer rather than a deletion keeps D190's point: the types remain a designed direction with a stated trigger.

The alternatives: implementing all three on every target was declined on the evidence above; the plan it would follow is software 128-bit fold carriers, register pairs on the hosts and four words at eight-byte alignment on Cortex-M0, compiler-emitted multiplication and division on all three, f16 promoted through f32 with one rounding as D190 recorded, and a trapping conversion.integer-to-float row. u128 and i128 on the two hosts only was declined, because narrowing an integer to hosted targets is a language decision the 32 KiB target argues against, and 128-bit arithmetic matters least where it costs most. f16 as a storage-only type with conversions was declined, because a float without arithmetic contradicts [0170]'s reading and still reopens D170. Deleting the names was declined, because nothing shows the language should lose them, only that nothing yet needs them.

Pinned by negative/wide-integer-not-enabled, negative/float-type-not-enabled, negative/refused-widths-name-their-owner, whose recorded report carries the transfer note, negative/refused-width-conversion, which records the same refusal where a width is written as a conversion, and the types.values guarantee row.

D245 — A number ends where its spelling ends

The tour said that a token is as long as it can be [1750], and that an integer starts and ends its digit run with a digit of its base [0220]. It writes no literal with a suffix, and nothing in it says what a letter directly after a number does. Before this decision the scanner answered three ways: 12abc was one malformed integer, 1e5 one malformed float, and 1u64, 0xffg or 1.5f32 a number followed by a name, which was then refused as undeclared. check.py's tokeniser refused all of them as one lexeme, so the two implementations of the lexical rules disagreed.

Chosen: a letter, digit or underscore directly after a number belongs to it, and the whole run is one malformed literal: L0011 for an integer, L0321 for a float. 1u64 is one refusal pointing at four bytes, not a valid 1 and an unknown u64, and the same holds for a hexadecimal run with a letter past f, an octal or binary run with a digit past its base, and every float form. [1770] states the rule. A width belongs on the binding, as in mask: u64 = 1, since an integer literal takes the type of its context [0190].

A competent reader could have stopped the number at the last byte its base spells and let the rest begin a name, which is what most of the scanner did. That reading turns a C or Rust suffix into a confusing undeclared-name report about u64 — a type name, not a value — and it makes 0xffg a hexadecimal number and a variable g. The other alternative, admitting width suffixes, was declined because [0190] already gives a literal its type from its context and a suffix would be a second way to say the same thing.

Pinned by negative/integer-runs-into-a-name, negative/float-runs-into-a-name, the existing negative/float-literal-without-fraction, and the lexer case "numbers run to the end of their spelling".

DECISIONS: OPERATORS, CONVERSIONS AND TRAPS

What an operator takes, what a conversion checks, and where a program stops.

D6 — A shift's right operand takes the left operand's type

The tour said that shifts fill with zeros beyond the width for any amount, and that a signed >> keeps its sign [0320]. It says nothing about the amount's type.

Chosen: the same type as the value being shifted [1890]. So shifting a u8 by 300 is refused, because 300 is not a u8, while shifting it by 40 is accepted and yields zero.

The alternative: any integer type for the amount, or one fixed type such as usize for every shift. Either would accept x << 300 and produce zero, which is what [0320] says an over-wide amount does — so this decision makes the specification's own example the boundary case rather than the rule.

Pinned by negative/shift-amount-takes-the-left-type.

D8 — A zero divisor is refused when it is known, and traps when it is not

The tour said that integer division truncates toward zero and that the remainder takes the sign of the dividend [0290], and nothing else. It does not say what a zero divisor does, and [0300] does not reach it: a quotient that does not exist is not a result that overflowed.

Chosen: [0310]'s shape, in [1950]. Refused where the compiler knows the divisor, trapped where it does not, and refused at module level always. % goes with /, because the divisor is the same operand.

The alternative: a defined value, which is the only other thing on offer. AArch64's SDIV answers 0 and x86-64's IDIV raises a hardware fault, both measured — so the Linux x86-64 and Darwin arm64 targets already disagree, and adopting either would make one program mean two things or make the other target pay for a value nobody asked for. Leaving it to the machine is the same alternative D4 refused, in the same words.

Pinned by negative/divisor-is-zero, negative/remainder-by-zero, negative/divisor-is-zero-in-a-body, positive/divisor-is-not-known, and for the trap runtime/a-zero-divisor-traps and runtime/a-zero-remainder-divisor-traps.

D9 — A negative shift amount is refused when it is known, and traps when it is not

The tour said that shifts fill with zeros beyond the width for any amount and that a signed >> keeps its sign, and that there is one form only [0320]. It says nothing about a negative amount, and D6 is what makes one writable: the amount takes the left operand's type, so a signed left operand admits a negative one.

Chosen: the same shape as D8, in [1950], so that the two operands no operation can take are one rule and not two.

The alternative: three, and each is some language's answer. Read the amount as unsigned, so -1 is beyond the width and [0320] already says the answer is zero — which is exactly what Cortex-M0 does, measured, and it turns a likely bug into a silent zero. Reverse the direction, which is Swift's answer, and which [0320]'s "One form only" is the sentence against. Or mask the amount to the width, which is what x86-64, AArch64, Java and C# all do, measured on the first two — but [0320] has already declined masking for over-wide amounts, since it says they fill with zeros rather than wrap around, so masking here would make one operator answer two ways.

Pinned by negative/shift-amount-is-negative, negative/shift-amount-is-negative-in-a-body, positive/shift-amount-is-not-known, and for the trap runtime/negative-left-shift-traps and runtime/negative-right-shift-traps.

D11 — A trap is a deliberate synchronous stop

The tour said that overflow traps [0300] and a runtime conversion whose value does not fit traps [0310]; [1950] adds two operands that trap when their value is not known. None says where a trap happens, whether it returns, what follows it, or whether the host's report is program behaviour.

Chosen: [1960]. A trap happens at the operation's point in evaluation order, never returns, and permits no later Landin action. Its operating-system encoding is not stable. The default Linux x86-64 handler uses a deliberate ud2, so the language does not inherit whichever fault or value an arithmetic instruction happens to provide.

The alternative: leave each operation to its machine instruction, or call a runtime routine. The first has already been ruled out by D8's measured x86-64 and AArch64 disagreement, and would wrongly trap the defined remainder of the lowest signed value by -1 on x86-64. The second can give a stable report, but makes that report an interface the language must preserve and a runtime every freestanding target must supply.

The deferred obligation: [1670] promised the fixed two-scalar, never-returning handler when the original kernel could not express its atom set or return form. D231 supplies noreturn; D232 now supplies source handler selection, check dispatch and optional site mapping on all three emitting targets. The original default trap remains the constrained default. The alternative declined above was a mandatory reporting runtime instead of that contract, not [1670] itself.

Evidence: runtime/checked-overflow-traps and runtime/a-zero-divisor-traps run on Linux x86-64 and are held to having ended without returning a status, which is the whole of what this decision makes observable. The first is the one that tells a trap edge from no edge: without it the addition keeps its low byte and the program returns normally. Neither says which signal ended it, because this decision is what says that question has no stable answer.

Pinned by runtime/checked-overflow-traps, runtime/a-zero-divisor-traps, and the conversion traps the paragraph above asked for: runtime/float-to-integer-out-of-range-traps, runtime/float-to-integer-nan-traps and runtime/range-subtype-store-traps.

D13 — An amount at or past the width gives zero on every shift

The tour said two things about a shift that do not agree at the boundary: that shifts "fill with zeros beyond the width, for any amount", and that "Signed >> keeps the sign" [0320]. Its example is a <<, so it settles nothing for the one operator where the two sentences meet. D6 makes the question reachable, since the amount takes the left operand's type and a signed left operand admits an amount of any size.

Chosen: the zeros sentence governs every shift, so an amount at or past the width gives zero and a signed >> is not an exception. With minus_one: i32 = -1, minus_one >> 31 is -1 and minus_one >> 32 is 0. A backend therefore tests the amount against the type's own width rather than letting the processor mask the count — x86-64 masks to five bits at 32-bit and six at 64, which is the masking [0320] already declined for over-wide amounts.

The alternative: let "keeps the sign" govern at every amount, so a signed >> saturates to all sign bits and minus_one >> 32 is -1. It is continuous where this rule has a step, and it is what x86-64's sar gives for free once the count is clamped. It was declined because it makes one operator answer two ways — zeros for << and for unsigned >>, sign bits for signed >> — where the tour states the zero-fill rule for shifts as a class and states the sign rule about which bits >> brings in, not about what an exhausted shift leaves behind.

Pinned by runtime/shifts-fill-with-zeros-beyond-the-width, whose i32 and i8 bindings of -1 >> 32 and -1 >> 8 and whose u64 binding of 1 << 64 are each zero on the hardware.

D14 — A measurement is a usize, and only the target knows it

The tour said that sizeof, alignof and lenof measure, and that on an array or a literal the length is a compile-time value [0370]. It writes w1 := sizeof u32 with the inferred form, so nothing in it says what type a measurement has, and [0200]'s default is about an integer _literal_ rather than about this.

Chosen: usize. A size and an alignment are counts of bytes on the machine being compiled for, which is what [0160] says usize is for, and a measurement that defaulted to i32 would need a conversion at every use where a width is wanted. lenof has the same result type. It takes a direct identifier naming a fixed array or slice; [0370]'s slice length is a runtime value. D31 also admits a parenthesized nonempty array literal. Other general expression operands remain outside [1820]'s measurement grammar. The spelling stays contextual rather than joining [1760]'s reserved words.

Where the answer comes from is the other half of this decision and the half with teeth. A scalar sizeof or alignof is not folded by the checker or the lowering: Landin.IR carries Measure_Size or Measure_Align with the type asked about, and the backend answers, because a byte size needs a target. That is the seam [0320]'s zero-fill already sits on, and it keeps the IR target-neutral — the same source emits 8 for sizeof usize against the Linux x86-64 description and 4 against the synthetic 32-bit one.

A fixed array is measured from its resolved structural type, whether [1790] writes it inline or D15 reaches it through aliases. Its size is its element count multiplied by the target's size for the scalar element, and a nonempty array's alignment is that element's target alignment. Lowering preserves those questions as the existing scalar measurement, usize Number and Multiply IR; it adds no array-measurement opcode and asks no host question. The internal zero-element shape keeps size zero and alignment one; this says what a shape already representable inside the checker means and does not decide whether source may spell one.

A fixed array's element count is already part of its type (D17), so lenof name lowers to the existing usize Number IR with that count. It does not read the named storage and does not require the binding to be definitely assigned.

The alternative: i32, which is what an untyped literal would default to and so the least surprising answer for a reader who has only read [0200]; declined because it makes the common use — comparing against or multiplying by a width — start with a conversion. Or folding in the checker, which would put a target fact in a stage this repository has kept target-neutral on purpose, and which Landin.IR's own header already argues against for the shifts.

Pinned by positive/measurement-of-a-type, positive/measurement-of-fixed-arrays, positive/lenof-uninitialized-fixed-array, negative/measuring-refused-types, negative/lenof-scalar, negative/lenof-unresolved-name, runtime/lenof-named-fixed-arrays, runtime/measurements-answer-for-the-target, and the backend case that emits one source against two target descriptions.

D165 — Compound assignment retains one destination and one operator

The tour said that assignment is a statement, listed thirteen compound spellings [0390], fixed destination-before-value evaluation [0410], and said that inc x means what x += 1 means [0400]. It did not say whether the destination was re-evaluated for its implicit read, whether it had to be assigned already, or whether a compound form inherited every failure boundary of its binary operator.

Chosen: place op= value evaluates place once, reads its existing scalar value, evaluates value, applies the corresponding [1820] binary operator and writes the result through that retained place. The thirteen forms are +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, +%=, -%= and *%=. Destination evaluation and its implicit read both precede the right-hand expression. A computed index or pointer path is retained as an internal address, not reconstructed after the expression.

The destination must be assigned on every arriving path because the operation reads its old value; success leaves it assigned. It needs the same binding or reference write permission as plain assignment. Both operands have the destination scalar type under [1890]: ordinary arithmetic admits integers and floats, while remainder, wrapping, shifts and bitwise forms admit integers only. Known zero integer divisors and negative shifts retain [1950]'s L0306. Runtime checked overflow and impossible integer operands retain [1960]'s trap; the three wrapping forms and admitted shifts remain total. Float division by signed zero retains D162's IEEE result.

This is one read-modify-write language operation but makes no atomicity or concurrency claim. Aggregates, slices, any, functions, pointers and atoms have no applicable binary operator and are L0301 rather than acquiring a copy-update meaning.

The alternatives: desugar by copying the place syntax into both sides of plain assignment, evaluate the right-hand side before reading the old value, let an unassigned destination become initialized, or define separate compound operator rules. Those choices duplicate observable calls in indexes, reverse [0410], permit a read of indeterminate storage, or let two spellings of one operation drift. All were declined.

Pinned by runtime/compound-assignment, runtime/compound-assignment-overflow-traps, negative/compound-assignment-as-expression, negative/compound-assignment-float-remainder, negative/compound-assignment-immutable, negative/compound-assignment-unassigned, negative/compound-assignment-zero-divisor, and the arithmetic.known, arithmetic.runtime, arithmetic.total and assignment.flow guarantee rows.

D168 — Integer conversion checks a mathematical value, not its bits

The tour said that [0310] writes conversion as a type applied to a value, rejects an impossible compile-time conversion, and traps when a runtime value does not fit. It did not say whether signedness changes reinterpret a pattern, whether every enabled integer width participates, or how a module conversion is folded without compile-time execution.

Chosen: the kernel enables an application of any enabled integer type to one integer value. The source keeps its own integer type and the destination is the applied type; no contextual or implicit conversion is introduced. The mathematical source value must lie between the destination's inclusive minimum and maximum. Widening a signed value therefore preserves its sign, a negative value never converts to unsigned, and crossing to a signed type rejects an unsigned value above that signed maximum. There is no truncation, wrapping or same-width bit reinterpretation.

An integer literal operand is checked immediately in the destination context. A conversion of a module-known integer expression is folded through the same target-aware integer fold as its source; an impossible known result is L0300. At runtime the neutral IR retains the source and destination integer types, and the Linux backend sign- or zero-extends the source before comparing it with the destination bounds. An out-of-range value reaches [1950]'s existing ud2 trap; an in-range value stores the destination-width pattern. The same conversion opcode continues to carry [0470]'s pointer-to-integer address check.

Conversion from a float to an integer and conversions involving bool remain L0304 at this increment. D169 subsequently admits conversion between the two enabled float widths, D170 admits conversion from an enabled integer to either float width, D171 admits the remaining float-to-integer direction, and D172 admits bool as an integer source, and D173 admits integer-to-bool conversion. Float-to-bool conversion and the deferred u128, i128 and packed integer widths gain no spelling through this increment.

The alternatives: reinterpret the low bits, make narrowing wrap, allow a negative signed value to cross to same-width unsigned, or give module conversions a runtime initializer. Those choices contradict [0310]'s fit and trap rule, make signedness a representation cast, or contradict [1460]'s rule that nothing runs before the entry point. All were declined.

Pinned by runtime/integer-conversions, runtime/integer-conversion-out-of-range-traps, runtime/integer-conversion-signed-overflow-traps, runtime/integer-conversion-unsigned-overflow-traps, negative/integer-conversion-known-binding-out-of-range, negative/integer-conversion-known-out-of-range, and the conversion.integer guarantee row.

D169 — Float-width conversion rounds an IEEE value, not its carrier

The tour said that [0310] writes conversion as a type applied to a value, rejects an impossible compile-time conversion, and traps when a runtime value cannot convert. It did not say how f64 narrows to f32, whether underflow or loss of precision is impossible, or what happens to signed zero, infinity and NaN.

Chosen: the kernel enables f32 or f64 applied to one float value. An untyped float literal is checked directly in the destination context, as every contextual literal is under [1880]. A typed f32-to-f64 conversion is exact. A typed f64-to-f32 conversion rounds to nearest with ties to even, including at the subnormal boundary; loss of precision and underflow to signed zero are ordinary IEEE rounding rather than failures.

Signed zero and infinity retain their sign and class. A NaN remains a quiet NaN with its sign; its payload after a width change is not a language-visible identity. A finite f64 which would round beyond f32's greatest finite value is the one impossible width conversion: L0300 rejects it when the source is known under [1880] or [1940], and an otherwise identical runtime conversion traps. Converting infinity is not overflow because infinity is a value of both float types.

Module-known conversions fold their IEEE carrier bits with bounded integer work, including the narrowing round bit and sticky bits, so cross-compilation does not borrow the compiler host's float conversion. Runtime Linux x86-64 uses the corresponding SSE width conversion and explicitly distinguishes a finite result overflow from an infinity or NaN source. The existing target-neutral conversion operation now admits every numeric result. D170 subsequently admits its integer-to-float direction, D171 admits its float-to-integer direction, D172 admits bool as an integer source, D173 admits integer-to-bool conversion, D174 admits float-to-bool conversion, and D176 admits bool as a float source.

The alternatives: require exact representability, silently produce infinity on finite overflow, trap on gradual underflow, expose a NaN payload mapping, or fold module conversions through a host float. Those choices make ordinary IEEE narrowing impractical, contradict [0310]'s impossible-conversion rule, discard gradual underflow, turn an unspecified IEEE payload into source identity, or make cross-target output depend on the compiler host. All were declined.

Pinned by runtime/float-width-conversions, runtime/float-width-conversion-overflow-traps, negative/float-width-conversion-known-out-of-range, and the conversion.float-width guarantee row.

D170 — Integer-to-float conversion rounds the mathematical integer

The tour said that [0310] makes conversion explicit and distinguishes an impossible known conversion from one which traps at runtime. It did not say whether integer-to-float conversion requires exact representation, how it rounds, or whether the upper half of u64 participates.

Chosen: the kernel enables f32 or f64 applied to a value of any enabled integer type. The source is the integer's mathematical value, not its carrier bits. An untyped integer operand first takes [0200]'s default i32 source type; a wider literal therefore writes an explicit integer conversion before the float conversion. There is still no implicit conversion between numeric classes.

An exactly representable integer is preserved. Every other value rounds to nearest with ties to even. Every enabled integer, including u64's maximum and i64's minimum, lies inside the finite range of both f32 and f64, so precision loss is ordinary rounding and no integer-to-float conversion can report L0300 or trap. The result of converting integer zero is positive zero.

The module folder derives the IEEE exponent and retained, round and sticky bits with bounded integer work. The Linux backend sign- or zero-extends narrower sources before SSE conversion. Because SSE's qword conversion is signed, a u64 above i64's maximum is halved with its low bit retained as sticky information, converted, and doubled; this produces the same nearest-even result without reinterpreting the source as negative. The neutral conversion verifier admits this one mixed-class direction. D171 subsequently admits the other direction; D172 admits bool as an integer source, D173 admits integer-to-bool conversion, D174 admits float-to-bool conversion, and D176 admits bool-to-float conversion.

The alternatives: require exact representation, saturate at a float boundary, reinterpret an unsigned carrier as signed, use a compiler-host float for module images, or make the conversion implicit. Those choices discard the ordinary IEEE conversion rule, invent a failure despite the float range, lose the upper half of u64, make cross-target output host-dependent, or contradict [0310]. All were declined.

Pinned by runtime/integer-to-float-conversions, negative/float-to-bool-known-invalid, and the conversion.integer-to-float guarantee row.

D171 — Float-to-integer conversion truncates before checking range

The tour said that [0310] makes conversion explicit, rejects an impossible compile-time conversion, and traps when a runtime value cannot convert. It did not say how a fractional float becomes an integer, whether the fractional part participates in the range check, or what infinity and NaN mean as integers.

Chosen: the kernel enables every enabled integer type applied to an f32 or f64 value. A typed source retains its float width. An untyped float operand first takes [0210]'s default f32 type, so the source is rounded to f32 before conversion; there is still no implicit conversion between numeric classes.

The finite source is truncated toward zero, then that mathematical integer is checked against the destination's inclusive range. The ordering matters: u8(-0.75) is zero and succeeds, while u8(-1.0) fails; i8(-128.9) is -128 and succeeds, while i8(-129.0) fails. Infinity and NaN have no integer result and always fail. A known failure is L0300 under [1880] or [1940], and an otherwise identical runtime failure traps under [1950].

The module folder decodes the IEEE sign, exponent and significand with bounded integer work and checks the truncated magnitude without using the compiler host's floating-point conversion. The Linux backend performs the same carrier decode directly rather than using SSE's indefinite overflow result, which cannot distinguish every valid u64 value from failure. The neutral conversion operation consequently admits either numeric class in either direction; D172 subsequently admits bool as an integer source and D173 admits integer as a bool source; D174 subsequently admits float as a bool source.

The alternatives: round to nearest, floor negative values, saturate at the destination boundary, reinterpret the carrier bits, use a compiler-host float for module images, or assign an integer sentinel to infinity or NaN. Those choices either invent a different ordinary conversion rule, hide [0310]'s required failure, make cross-target output host-dependent, or give nonfinite values a mathematical integer they do not have. All were declined.

Pinned by runtime/float-to-integer-conversions, runtime/float-to-integer-out-of-range-traps, runtime/float-to-integer-nan-traps, negative/float-to-integer-known-out-of-range, negative/float-to-integer-known-nan, negative/float-to-bool-known-invalid, and the conversion.float-to-integer guarantee row.

D172 — A bool has the integer image zero or one

The tour said that bool is a scalar type [0180] and that conversion is an explicit type application [0310]. It did not assign a numeric image to false or true, or say whether every numeric value has a truth value.

Chosen: the kernel enables any enabled integer type applied to a bool value. False converts to zero and true converts to one. Both values lie in every enabled signed and unsigned integer range, so this direction is total: it cannot report L0300 or trap. Typed and inferred module values fold to the same image, and runtime conversion zero-extends the bool's one-byte carrier before storing the destination width.

This increment does not define truthiness. Applying bool to an integer or float remains L0304, as does applying a float type to bool. D173 subsequently admits only zero and one from the integer direction, and D174 settles the float-to-bool direction including negative zero, infinity and NaN. D176 later maps bool's already-fixed images into the two enabled float widths.

The alternatives: use all-bits-one for true, preserve an unspecified bool carrier, or simultaneously admit numeric-to-bool truthiness. Those choices make the result depend on representation or settle a distinct semantic question without program evidence. All were declined.

Pinned by runtime/bool-to-integer-conversions, negative/float-to-bool-known-invalid, and the conversion.bool-to-integer guarantee row.

D173 — Only the canonical integer images convert to bool

The tour said that conversion is explicit and an impossible conversion is refused when known or traps at runtime [0310]. D172 fixed bool's integer images at zero and one, but did not say whether conversion back accepts only those images or assigns truth to every nonzero integer.

Chosen: the kernel enables bool applied to any enabled integer value. Integer zero converts to false and integer one converts to true; every other value is impossible. An untyped integer first takes [0200]'s default i32 type, preserving the rule that conversions retain a typed source rather than giving the literal a bool context.

A direct literal or module-known chain outside zero and one is L0300. A runtime source is zero-extended from its own width, compared with one, and traps before storing the one-byte bool result when it is larger; a signed negative carrier therefore fails the same comparison without being mistaken for true. Module images fold the source integer before reserving data. The neutral conversion operation now admits bool on either side of the integer boundary.

Float-to-bool remains L0304 at this increment. D174 subsequently settles signed zero, fractional values, infinity and NaN rather than inferring them from the integer image rule.

The alternatives: make every nonzero integer true, accept any value whose low bit is one, saturate into the bool domain, or reinterpret the low byte. Those choices make conversion hide a noncanonical value or become a bit cast, where [0310] instead provides a checked boundary. All were declined.

Pinned by runtime/integer-to-bool-conversions, runtime/integer-to-bool-out-of-range-traps, negative/integer-to-bool-known-out-of-range, negative/float-to-bool-known-invalid, and the conversion.integer-to-bool guarantee row.

D174 — Float converts to bool only at its canonical images

The tour said that conversion is explicit and impossible conversions are refused when known or trap at runtime [0310]. D172 fixed false and true at the mathematical integer images zero and one, while D173 accepted only those integer images on conversion back. Neither decided how the IEEE values around those images behave.

Chosen: the kernel enables bool applied to f32 or f64. Positive and negative zero both convert to false because they compare equal as IEEE numbers. Exactly positive 1.0 converts to true. Every other value, including negative one, fractions, infinity and NaN, is impossible. An untyped float first takes [0210]'s default f32 type, preserving its source width before conversion.

A direct or module-known impossible source is L0300; the equivalent runtime case traps. Static folding decodes the IEEE carrier with bounded integer work. The Linux backend ignores the sign bit only while recognizing zero, then requires the complete positive-one carrier, so negative zero succeeds but negative one does not. This was recorded as completing explicit conversion among the enabled scalar types, but D172's bool-to-float refusal still remained in the checker; D176 closes that omitted direction without introducing implicit truthiness.

The alternatives: make every nonzero float true, accept any value that truncates to zero or one, reject negative zero, or make NaN true because it is not equal to zero. Those choices import truthiness, make conversion silently discard a fraction, or distinguish IEEE zeros where ordinary comparison does not. All were declined.

Pinned by runtime/float-to-bool-conversions, runtime/float-to-bool-invalid-traps, negative/float-to-bool-known-invalid, and the conversion.float-to-bool guarantee row.

D175 — Module float arithmetic is an IEEE carrier fold

The tour said that module values are known before execution [1460], that the known subset contains operators over known values [1940], and that f32 and f64 arithmetic and comparisons have IEEE behavior [0290], [0350]. D162 left module float operators deferred because using the compiler host's float operations would make cross-compilation inherit that host's rounding mode and NaN behavior.

Chosen: the kernel enables module-level f32 and f64 +, -, *, / and all six comparisons. Operands may be any [1940]-known float expression, including forward or chained module names, conversions, named infinities and NaNs. Their results may initialize scalar bindings or scalar leaves of module arrays, repetitions, structs and variant images.

The shared target-neutral evaluator decodes IEEE carrier bits and uses bounded integer significands for addition and division and a double-width integer for the exact product. Every finite result rounds once to nearest with ties to even and retains gradual underflow. Exact cancellation produces positive zero; otherwise the IEEE sign rules preserve signed zero. Arithmetic overflow and finite division by signed zero produce signed infinity rather than L0300 or a trap. Invalid operations and arithmetic with a NaN produce the width's D167 canonical positive quiet NaN; NaN payload propagation is not a source-visible identity. Comparisons equate the two zeros, order finite values and infinities, and leave NaN unordered, so only <> is true for an unordered pair.

Checking, static aggregate-image lowering and Linux datum emission call the same evaluator. No module initializer runs, no float operation is added to a datum at runtime, and no compiler-host floating-point operation decides an image. The ordinary runtime path remains the SSE implementation D162 already enabled.

The alternatives: fold through Ada float operations, reject overflow or division by zero because integer module folds do, preserve a host-selected NaN payload, flush subnormals to zero, or keep float comparisons out of module bool images. Those choices respectively make cross-compilation host-dependent, contradict IEEE arithmetic, expose an unspecified carrier detail, lose gradual underflow, or leave [1940]'s operator subset inconsistent by operand class. All were declined.

Pinned by runtime/module-float-arithmetic, the direct checking vectors, and the float.ieee guarantee row.

D176 — Bool converts to exact positive float images

The tour said that conversion is explicit [0310], that bool has only false and true [0180], and that f32 and f64 carry IEEE binary32 and binary64 [0170]. D172 fixed bool's mathematical images at zero and one but deliberately left a float type applied to bool refused. D174 was then recorded as completing the enabled scalar conversion matrix even though that refusal remained.

Chosen: the kernel enables f32 or f64 applied to a bool value. False converts to exactly positive floating zero and true converts to exactly positive floating one. Both images are exact in binary32 and binary64, so this direction is total: it cannot report L0300 or trap, and it does not introduce truthiness or an implicit conversion.

The target-neutral fold writes the destination width's exact IEEE carrier for literal, named and computed module-known bool values, including scalar leaves of array and struct images. Runtime Linux code zero-extends the canonical one-byte bool and converts that zero or one into the selected SSE width. The neutral conversion verifier admits bool as a source for either numeric class. At this decision, f16 and [1975]'s external floating-point ABI remained deferred; the internal scalar conversion changed neither boundary. D204 subsequently enabled f32 and f64 in the selected C ABI. f16 remains refused.

The alternatives: reinterpret bool's byte as float bits, produce negative zero for false, route through a contextual integer conversion, or keep the direction refused. Those choices contradict D172's mathematical images, make the result representation-dependent, add a conversion not written by the program, or leave the claimed scalar matrix incomplete. All were declined.

Pinned by runtime/bool-to-float-conversions and the conversion.bool-to-float guarantee row.

D177 — A module bool is a static image, not routine control flow

The tour said that bool has only false and true [0180], that its logical words return bool [0340], and that and and or short-circuit from left to right [0410]. [1460] says nothing runs before the entry point, while [1940] admits every [1820] operator over module-known values. D24 already applies those rules to scalar leaves of module aggregate images. The remaining scalar path nevertheless lowered and and or through routine-style CFG, and the backend's datum fold correctly rejected its Branch instruction.

Chosen: the kernel makes every scalar module bool a target-neutral static image. The one shared lowering-time folder evaluates literal, named, forward and chained module-known operands, comparisons, not, and and or; its existing logical cases visit the left operand first and visit the right operand only when the result still depends on it. The same folder continues to write bool leaves in fixed arrays, repetitions, structs and variants. A bool datum's neutral block carries no computed value, and datum emission reads its canonical zero-or-one image directly, so no initializer is executed and no CFG Branch reaches data emission. Routine expressions keep their existing CFG and observable short-circuit behavior.

This is an implementation conformance repair, not a new source rule. Checking still validates every written subtree before folding: short-circuiting does not hide an ill-typed operand, a call, an impossible integer operand, or another initializer that [1940] refuses. Module value lookup remains independent of declaration order [0130], and a cycle remains refused even if another declaration could skip a reference to it.

The alternatives: teach the backend datum fold to interpret CFG, add a non-short-circuit logical opcode, or retain a second scalar-only syntax folder. Those choices respectively turn static data into executable control, contradict [0410], or let scalar and aggregate images disagree. All were declined.

Pinned by the lowering case module bools become static images, runtime/module-known-short-circuit-bools, negative/module-bool-from-itself for the cycle, the generated IR, and the module.images guarantee row.

D200 — A comparison takes one register-sized value with one equality

The tour said at [0350] which six comparison operators exist and at [1890] that they want one type on both sides and give a bool back. It did not say which types may stand on those sides. The compiler compared type kinds alone, so ptr u8 == ptr u32 was accepted and lowered as an address compare, and []u8 == []u8 or any C == any C passed the checker and was an internal defect in lowering.

Chosen: a comparison operand is a scalar of [1790], an atom set (identity only, as [1890] already said), a pointer, or a function value. Atom equality and inequality compare declaration identities across any two structural sets; neither set must include the other. This changes no store or call-argument subset rule. Two pointers compare by address and must point at one type; permission does not enter, because [0440] lets a mut pointer stand where a plain one does and an address comparison writes through neither. Two function values must agree in signature, as before. A slice, an erased any value, a fixed array and a struct are refused at the operator with L0301, naming the operand.

The alternatives: elementwise equality for slices and arrays, fieldwise equality for structs, and base-and-length identity for slices were each considered. Elementwise equality needs a defined equality for the element, which reopens the question one level down and silently costs a loop; base identity for slices answers a question nobody asks. All were declined for the pre-v1 slice; a later version can add an operator or a core routine without changing what the compiler accepts today.

Pinned by negative/slice-comparison-refused, negative/any-comparison-refused, negative/pointer-comparison-referent-mismatch and positive/pointer-comparison-same-referent, runtime/r490-generic-atom-identity, runtime/r490-lexical-module-observation and the verifier case atom comparisons keep identity.

D224 — Ordinary module arithmetic has a wider folding range

The tour said that a module value is known before entry [1460] and ordinary runtime arithmetic traps on overflow [0300]. The bootstrap IR's decision explicitly admitted x: u8 = 200 + 100 - 100: the intermediate 300 exists only in the folder. [1940]'s phrase about a fold that no type holds left the final image and its intermediates insufficiently distinguished.

Chosen in the bootstrap and retained: ordinary module integer arithmetic uses the signed, symmetric folding range derived from the widest enabled integer magnitude, -(264 - 1) through 264 - 1. Every intermediate stays within it, and the final image must fit its source type. Neither the host word size nor a 32-bit target narrows that folding range. Literal typing, explicit conversions and the type-dependent wrapping, bitwise and shift rules remain separate. Runtime arithmetic keeps its source width and overflow checks. This records existing behavior; it adds no compile-time execution or unbounded integer type.

The alternatives: checking every intermediate at the destination width would reject the already adopted u8 example. Unbounded mathematical folding would remove the kernel's explicit limit, and silently wrapping a module fold would replace an error with a different image. None describes the existing contract.

Pinned by the extended positive/module-fold-that-fits, the existing negative/module-scalar-fold-overflow, and module folds use their own integer range. The bounded IR control checks exact images and retained runtime u8 operations on both target widths, plus final-image and positive/negative fold-range overflow refusals. Container capacity arithmetic inside a function remains subject to the runtime rule.

DECISIONS: POINTERS AND RAW STORAGE

Addresses, the absent pointer, and the operations that read storage the language does not otherwise describe.

D189 — A one-atom pointer union is a pointer whose empty case is zero

D235 later gives two or more atoms beside a pointer a two-cell union and retires Reference_Union_Extent's two-atom arm; the one-atom representation below is unchanged.

The tour said that there is no null, that "maybe a pointer" is an ordinary union of an atom and a pointer type, that with one atom the compiler represents it as a plain pointer with 0 for the empty case, and that the spelling does not decide how a union of several atoms and a pointer is laid out [0480]. It did not say how such a union is written past the one shown example, how the empty case is constructed, how the present case is named in a match, what the union may not do that a pointer may, or which origin the empty case carries.

Chosen: [1795]'s atom_union admits one pointer_type member beside its atom names, and a union that flattens to exactly one atom identity and exactly one pointer type is the type ptr [mut] T carrying that atom as its empty case. It occupies one target pointer carrier with zero reserved for the atom, which is what Landin.Checking.Reference_Union_Extent's one-atom arm has measured since local lifetime checks were built and now has a caller for. Order does not matter: ptr mut u32 | none_found and none_found | ptr mut u32 are the same type, because [1870] already says a union is structural. The atom's singleton widens into the union and so does the bare pointer, in the direction [1870] gives atom sets; neither direction reverses, so a plain pointer fills a union parameter and a union does not fill a ptr T one.

The union is not a pointer, and the six positions that would read its carrier as an address are refused by name because each is a path to a dereference of the reserved zero: .val in a read or an assignment target, addr of a .val reached through one, an integer conversion, any construction, a comparison, and an argument or result position wanting ptr T. The first five are L0335 here; the last is [0440]'s existing reference-agreement refusal. ptr(n) into a union position is L0335 for the same reason, and zeroed stays the aggregate-value L0304 because [1870] states that no zero or default atom exists — an all-zero image is not the atom even though the atom's representation is zero.

match [1210] is the only way through. Its two cases are the atom name and the reserved word ptr, which needs no new keyword because [1760] already reserves it, and which is a syntax node of its own rather than a name, so resolution has nothing to look up. A ptr arm may carry one binding of the plain pointer type; it is optional, definitely assigned on entry to the arm, and read-only, and inout on it is L0333 citing [1220] because writing through it would write the union's own carrier and not a payload. A case named twice is L0311, a case named by neither an arm nor _ is L0312, and _ must be last, which are the same three rules an atom set already has. A ptr arm on an atom-set or variant subject is L0333.

The empty case contributes no origin at all, and in particular never the Untracked fact [0470]'s integer-to-pointer conversion sets, because that fact *suppresses* the frame-escape refusal. On a return edge provably carrying this empty case, [0790]'s exact from contract has no actual reference origin to compare; it does not reinterpret absence as an untracked reference. The bound pointer takes the subject's own origin, so a union built from addr local still refuses an escaping use of the binding with L0314. Lowering is one comparison against zero and the CFG branch a match already emits; the empty case lowers to a usize zero rather than the atom's dense nonzero code, which is the one place a wrong carrier could be produced.

Two or more atoms beside a pointer is refused by name with L0304 citing [0480] until its layout is decided (D235). The tagged carrier [1870] describes needs an IR pair, storage, an ABI position and a backend of its own, which is a representation increment and not this one; [1870]'s sentence about that placement is kept and qualified rather than deleted, and Reference_Union_Extent's two-atom arm stays as the recorded measurement. A union of two pointer types is L0338: there is one carrier and nothing to tell two pointers apart with.

The alternatives: giving the union its own Landin.Types.Type_Kind would have named every site the checker must guard, at the cost of a much larger diff and a disturbed Settled band; the flag on the pointer descriptor was chosen instead because the representation genuinely is a pointer, and the six positions above are the audit that flag owes, which is why each is pinned by a negative fixture of its own rather than by the guard alone. Making the ptr arm's binding required rather than optional would be easier to explain and less useful for a discard-shaped arm. Spelling the present case _ with narrowing would need flow-sensitive typing, which the kernel has none of, and a type-named arm is not in the grammar. Admitting the union inline in a type position rather than only through [1795]'s named declaration would be a change no atom union has today. Laying the multi-atom case out now would have made this increment a representation increment. All were declined.

D206 supersedes the null-construction gap recorded below: [1975] now requires known-zero refusal and an always-on dynamic check, and allocator absence uses the union. The following is the state D189 handed to that work, not a present permission to construct a null pointer.

ptr(0) remains accepted [0470] and runtime/core-mem-allocators uses it as a failure sentinel five times, so null is still mintable on the pointer side even though [1580] states that it is refused. That contradiction is real, it is not resolved here, and it belongs to [1580] and the C boundary with the rest of the foreign-boundary work, which records it rather than leaving [0480] looking closed while its headline sentence is evadable.

Pinned by positive/pointer-unions, runtime/pointer-unions, positive/pointer-union-several-atoms, negative/pointer-union-two-pointers, negative/pointer-union-dereference, negative/pointer-union-assignment-target, negative/pointer-union-address-of-referent, negative/pointer-union-any-construction, negative/pointer-union-case-named-twice, negative/pointer-union-present-arm-named-twice, negative/pointer-union-is-not-a-pointer, negative/pointer-union-match-not-exhaustive, negative/pointer-union-frame-escape, negative/r440-parser-frame-arena, negative/pointer-union-comparison, negative/pointer-union-integer-conversion, negative/pointer-union-from-an-integer, negative/pointer-union-inout-binding, negative/pointer-union-zeroed, negative/pointer-case-arm-is-not-an-atom, the generated lexical and IR records, and the pointer.optional guarantee row.

D206 — Null construction cannot evade the pointer union

The tour said at [0470] that integer construction loses origin, at [0480] that pointers are non-null, and at [1580] that ptr(0) is refused. D189 left the compiler's contrary integer-conversion path for this boundary to close.

Chosen: [1975] refuses known zero after target-width conversion, including closed folds, and checks dynamic converted zero even inside unchecked. Pointer-union transport remains one target carrier, with no origin in the atom arm and the original origin in the narrowed pointer arm. [0790]'s exact from comparison applies only on an edge that actually returns the reference; a provably empty arm has no origin and is not Untracked. A call-site else still handles failure, not absence: a successful union is matched normally. Allocator and disposed backing use named atom/pointer unions; a successful dispose clears to the atom and a repeat reports raw_empty.

The alternatives: keeping zero as an untracked pointer contradicts the niche. Testing before narrowing misses target-width zero; removing the check in unchecked reopens the contradiction. Replacing null with ptr(1) hides absence in a false allocation. A second tagged wrapper wastes a word where the existing one-atom union already expresses the state. All are declined.

Pinned by runtime/null-pointer-dynamic-traps, runtime/null-pointer-unchecked-traps, runtime/null-pointer-union-call-else, negative/null-pointer-union-call-else-frame-escape, negative/r440-parser-frame-arena and runtime/core-mem-dispose-empty, with negative/r440-null-pointer-folded-zero and negative/r440-null-pointer-unchecked-zero for the static refusals of a folded zero and of unchecked construction.

D235 — Several atoms beside a pointer store the atom's own code beside the pointer

The tour said that "maybe a pointer" is an ordinary union of an atom and a pointer type, and that the spelling does not decide how a union of several atoms and a pointer is laid out [0480]; [1870] placed that form as a tag beside the pointer. D189 enabled the one-atom form as a pointer reserving zero and refused two or more atoms beside a pointer by name until its layout was decided, recording that the tagged form needs an IR pair, storage, an ABI position and a backend of its own.

Chosen: a union that flattens — through aliases, parameterized aliases and member unions, ignoring order and repetition — to two or more atom identities and exactly one pointer type is one structural type: its atom set plus the pointer type, whose mut is part of the identity. It is a two-cell aggregate with no source declaration. The first cell is the atom-set carrier, holding the atom's own dense nonzero code exactly as a value of that set would; the second is one target pointer carrier. Code zero, which no atom has, marks the present case, whose non-null pointer the second cell holds. The cells take ordinary natural placement: 16 bytes aligned 8 on Linux x86-64 and Darwin arm64, 8 bytes aligned 4 on Cortex-M0. Every case is built in a cleared temporary and copied whole, so an atom case leaves its pointer cell zero, and a module image does the same. The union is passed, returned and copied as an ordinary aggregate, by address in the internal convention on all three targets.

Widening never reverses. An atom singleton or an atom set contained in the union's set widens by copying its code. A pointer of the member type, or one that relaxes to it by [0440], widens as code zero and the pointer. A one-atom union whose atom is in the set and whose pointer relaxes to the member widens with its zero carrier becoming that atom's code; a smaller several-atom union copies both cells. An inout or sink parameter takes only a place of exactly the same union. Match is D189's: arms name the set's atoms or ptr with an optional read-only binding, exhaustiveness covers every atom and ptr, and an atom outside the set, a duplicate or a missing case, an inout ptr binding and a ptr arm on another subject keep their reports. Lowering loads the code; zero selects the ptr arm and binds the pointer, and any other code dispatches exactly as an atom-set match. The positions D189 refuses for the one-atom form are refused identically: .val, addr of a .val, an integer conversion, any construction, a comparison, a ptr T argument or result, ptr(n) into one, and zeroed. The one-atom form retains L0301 for its invalid context; the many-atom form reports L0328 because it has no zero image. The pointer case carries the stored pointer's origin and an atom case none, so a union built from addr local still refuses an escaping use of its bound pointer. A module union takes an atom or another module union as its static image; an address initializer is the one-atom form's L0305. A call returning a plain pointer cannot fill a union through an atom else: that recovery would need a new lowering, and remains L0301.

No IR instruction, ABI position or instruction selection is added. The code cell is typed with the union's atom set, and every backend already traps an atom-typed load that finds a non-member; the call-failure status channel was the one load allowed to find the zero sentinel. Landin.IR.Admits_Reserved_Zero now names both — that channel and a union's code cell in a frame slot — and the three backends ask it instead, reaching the zero-skipping selection they already had. The verifier holds a union nominal to exactly its code and pointer cells. DWARF describes the union as a structure named by its canonical spelling — atoms by spelling, ties by declaration identity, then the pointer type, for example denied | none_found | ptr mut u32 — with an atom member at offset zero and a ptr member at the pointer's offset. GDB and LLDB show both members in an atom case and in the pointer case.

The alternatives: a tag holding a case index, as a variant part does, was declined because widening from an atom set or a smaller union would then renumber rather than copy, while the code costs nothing more: pointer alignment already rounds a one-byte tag up to the pointer's width. Storing atoms in the pointer's low bits was declined because it depends on the pointee's alignment exceeding the case count, which a byte pointer never does. Reserving small addresses for the atoms, as the one-atom form reserves zero, was declined because Cortex-M0 flash begins at address zero with the vector table, so small addresses are real pointers there. Lowering onto a hidden variant part was declined for the same renumbering. Keeping the form refused was declined: the representation needed no new backend machinery, and [1700] reads atoms as one idea wherever they appear.

Pinned by positive/pointer-union-several-atoms, positive/pointer-union-many-declarations, positive/pointer-union-many-widening, positive/r490-union-alias-tagged-pointer, runtime/pointer-union-many, runtime/r720-feature-interactions, negative/pointer-union-many-dereference, negative/pointer-union-many-comparison, negative/pointer-union-many-zeroed, negative/pointer-union-many-match-not-exhaustive, negative/pointer-union-many-frame-escape, negative/pointer-union-many-inout-is-exact, negative/pointer-union-many-two-pointers, the GDB and LLDB union views in compiler/tests/debugging, and the pointer.optional guarantee row.

D238 — A device access is an operation over an ordinary pointer

The tour said that a register is reached through a volatile ptr [0070] [0460] [0850], that a register is a parameterised type register(t, read:, write:, reset:) whose field reads as a t [0740], and that set(X) generates a packed struct of bool from an encoded union [0540] [0730]. D227 enabled scalar volatile accesses as compiler.volatile_load and compiler.volatile_store. D228 enabled the register image with its two explicit operations compiler.register_read and compiler.register_write, refused every synthesized device field update, and left the wrapper and set(X) unenabled. The volatile ptr shape was refused by name, and the checked-in device fixtures translated prototype 1 to D227 and D228 forms instead.

Chosen: all three are withdrawn. A device access is an operation — D227's two scalar operations or D228's two register operations — over an ordinary pointer, and a generated module writes one small typed function per register over them, with the image's decode and encode beside it and its reset value as a constant. The encoded union still places each named bool field of a set, and the generator writes those fields out; inside a larger image they are offset by where the set begins, as D228 already says. The volatile ptr shape keeps its named L0010, now a withdrawal with the four operations as its migration guidance. register(...) and set(X) never had a named refusal and remain an ordinary parse error and an unresolved type application. [0070], [0460], [0470], [0540], [0730], [0740], [0760] and [0850] are rewritten to the operation form, and prototype 1's preamble records the withdrawal while its sketch keeps the historical spelling as the design record, as the device fixtures already did for register and set.

The evidence is the executed derivation. The complete derived prototype-1 driver runs on Cortex-M under QEMU, with its synthetic device model, through the generated RP2040 modules' accessors and explicit bool image fields; it needed no volatile pointer type, no wrapper and no set former, and its derivation maps every sketch use to that form. D228 had already made the wrapper's central promise unrealizable as sugar: a field of register(t, ...) type would read and write through the device, D228 refuses every synthesized field update, and so the wrapper could only ever be the explicit read, local update and write that the generated functions spell. A volatile qualifier would be a second permission on every reference beside mut, which [0440]'s relaxation, addr, field projection and generic identity would all have to carry, while D227 already says what each access orders. set(X) is a type-level generator, which D3 and [1540] place in generator programs, and general SVD generation is the companion tool's.

The alternatives: a pointer qualifier with volatile .val accesses and field projection was declined as a second permission axis for a surface no executed program needed. A builtin register(t, ...) type whose field accesses call D228's operations was declined because the explicit read/update/write it would hide is what D228 requires to stay visible. A builtin set(X) former was declined for D3's reason. Keeping the three pending for a successor was declined because an executed driver is the evidence a successor would have waited for.

Pinned by negative/r491-volatile-pointer, whose recorded report carries the withdrawal note, runtime/r640-register-images, negative/r640-register-no-read, negative/r640-register-no-write, the complete driver of compiler/tests/driver/DERIVATION.md, and the packed.register guarantee row.

D243 — An inout reference place keeps its exact type

The tour said that a mut reference satisfies a plain one and never the reverse [0440], and that an inout parameter may replace the value it was handed and the change comes back [0900]. It did not say which of the two directions an inout argument is. [0440]'s own example is an in parameter.

Chosen: an inout argument whose parameter is a pointer or a slice must have exactly the parameter's reference type, permission included. ptr mut T does not fill inout slot: ptr T, and []mut T does not fill inout s: []T. This holds however the call is made: directly, through a function value, with a field or an element as the place, forwarding an inout parameter, or passing an inout match payload on. An in reference parameter keeps [0440]'s relaxation, and a pointer union place was already exact [1870].

A competent reader could have applied [0440] at every reference argument, which is what the compiler did through 0.2.0. It is unsound: the callee stores a read-only reference into the place, and the caller then holds it as ptr mut T and writes through it. The program

anchor: u32 = 5
store: (inout slot: ptr u32) -> none =
    slot = addr anchor
end store

called as store(p) with mut p: ptr mut u32 then wrote 7 into the immutable anchor without unchecked, which is [0440]'s reverse direction reached through [0900]'s way back. The other reading, that inout checks only the way in and the way out is the caller's problem, was declined because nothing the caller writes afterwards can show it: the store happened in another function.

Pinned by negative/inout-pointer-is-exact, negative/inout-slice-is-exact, negative/inout-pointer-through-function-value-is-exact, negative/inout-pointer-field-is-exact, negative/inout-pointer-forwarded-is-exact and negative/inout-pointer-match-payload-is-exact.

DECISIONS: ARRAYS, SLICES AND TEXT

Array identity and the contextual storage an array value is formed in, then slices and the text views over them.

D17 — An array's identity is its length and its element

The tour said that an array is a value, that assignment copies it and that its size is part of its type [0520]. It says what an array _is_ and never says when two of them are the same type, which for a struct [0710] answers by naming the declaration that wrote it.

Chosen: structural. [4]u8 and [4]u8 are one type wherever they are written, and [4]u8 and [8]u8 are two, and so are [4]u8 and [4]i8. D15's alias keeps that identity like any other, so row: type = [4]u8 gives the same type a second name. The evidence is [0520]'s own sentence: size is part of the type, which is a description of a shape and not of a declaration — and [0370]'s sizeof and lenof ask a type what it measures without asking where it was written.

Why not [0710]'s rule: that paragraph is about a struct, and it gives its reason in the same breath — a value typed as an anonymous struct "never becomes a same-shaped named type", because a struct body introduces a type where no existing type was. [4]u8 introduces nothing: it describes a shape that the length and the element already determine. D15 makes a declaration without distinct name an existing type, and this is one.

The alternative: nominal, one type per declaration, which would make two [4]u8 declarations different types and put arrays under [0710] with structs. It was declined because nothing in the tour reaches for it and because it would leave a program no way to write the type of something it did not declare: sizeof [4]u8 and a parameter of [16]u8 both name a shape rather than a declaration, and under a nominal rule neither would mean anything.

An array of a struct follows from this rather than needing its own answer, and is stated here so nobody reads the gap as a question. The array is structural and the element is whatever it is: two [4]point are one type exactly when the two points are, which is [0710] doing its own work inside this rule and not an exception to it. D122 supplies the aggregate element carrier, D127 its known whole-element contexts, and D134 the computed ones; the earlier aggregate layout evidence did not pretend its scalar-only array shape represented them.

Pinned by positive/array-type-is-declared, positive/array-types-alias-and-agree, positive/measurement-of-fixed-arrays.

D18 — An array index is usize, and an array fits the target's usize

The tour said that usize is the unsigned integer for byte counts and indices [0160], that an array's size is part of its type [0520], and that an index is checked before its address is computed [0580]. It did not say whether every integer type could index an array or how large an array type could be. Its packed-register example used u32, which answered differently on targets of different widths without stating that it meant to.

Chosen: an array index is exactly usize. An untyped literal in the index position receives usize as its context; a value already typed u32, u64, isize, or any other integer is refused rather than converted. The byte extent of an array must be no greater than the largest value the target's usize can hold. Thus [4294967296]u8 is a type on a 64-bit target and is refused on a 32-bit one, while [4294967295]u8 fits both.

Why the two answers are one rule: [0580]'s address computation consumes a byte offset. Its index and its greatest object extent therefore share the one target width [0160] gives for addressing; neither inherits a fixed width from the compiler host. The count is not itself bytes — an element may occupy more than one — so legality is decided from length * sizeof element, without performing that multiplication after it has already overflowed.

The alternative: accept any integer and compare it with the length. That looks permissive, but using a u32 where the operation consumes usize is an implicit conversion, which [0190] does not provide, and using i32 gives a negative case that the type of an index need not have. A fixed u32 limit was also declined: it needlessly truncates a 64-bit address space and cannot follow a target narrower than 32 bits.

Pinned by negative/index-is-not-usize, negative/index-past-the-default-type, the target-parametric checker case array extent follows usize, and runtime/large-array-offset-is-addressed on Linux x86-64.

D19 — A known element of a local array is assigned independently

The tour said that a local declared without a value has to be assigned on all paths before it is read [1910], that an array's elements are indexed from zero [0520], and that a compiler-known index is a literal or unary minus over one [1880]. It did not say whether assigning one element assigned the local or what fact a later element read required.

Chosen: a declaration-only fixed-array local has one definite-assignment fact for each compiler-known element that the function reaches. Writing items[2] establishes only element two; reading or stepping items[2] requires that same fact on every arriving path, and says nothing about any other element. Branches intersect these facts exactly as they intersect a scalar local's fact. The compiler keeps only facts the function actually reaches, rather than allocating bookkeeping proportional to the array length.

This decision does not define what a write through a computed local index establishes. Computed local indexing remains refused in this aggregate slice; computed indexing of module arrays remains enabled because D10 gives module state every element from the start. Whole-array local values and initializers remain refused as well; D20 admits the one direct storage-to-storage copy.

Why: treating one element write as assignment of the whole local would permit an uninitialized read from every other element. Requiring every element to be written before any one can be read would make large arrays unusable and would contradict [1910]'s local, path-sensitive question. Sparse facts preserve both the element boundary and D18's target-sized array lengths.

The alternative: one fact for the whole array, or a dense bit for every position. The first loses the safety check at the first partial write; the second makes compiler memory consumption depend on a target object that may be far larger than the host can enumerate. Both were declined.

Pinned by negative/local-array-element-not-assigned, negative/local-array-element-not-assigned-on-every-path, negative/increment-unassigned-local-array-element, and runtime/local-array-elements-are-independent on Linux x86-64.

D20 — A whole-array copy reads and assigns every element

The tour said that an array is a value and assignment copies it [0520], that two arrays are one type when their length and element type agree (D17), and that a local declared without a value is assigned before it is read [1910]. It did not say how a whole copy interacts with the independent sparse element facts D19 later introduced.

Chosen: destination = source, where both sides name fixed-array storage, reads every element of the source and assigns every element of the destination. The two array types must have the same D17 identity. A source local is wholly assigned when an earlier whole copy assigned it or when its sparse D19 facts cover its length; a zero-length source is therefore assigned vacuously. Module state is wholly assigned by D10. Self-copy follows the same rule, so it cannot turn unassigned storage into an assigned value.

A direct storage name resolves to a module or local binding. The name of a type declaration, even one whose declared type is the required fixed array, owns no runtime storage and is refused by the existing whole-value L0304 rather than being lowered as a copy source.

A branch merge intersects what the facts _mean_, not merely how they happen to be represented. Whole on both paths remains whole; whole on one path and sparse facts on the other keeps those sparse facts; sparse on both keeps their intersection. Completeness is decided by counting the sparse facts already present, never by walking an array extent that D18 permits to fill the target.

This kernel admits an array name as a whole value only in this copy context; D50 later lets either endpoint be a directly selected fixed-array field. D21 reuses only the direct-name storage read for initializers; D51 later admits a directly selected fixed-array field as the source of a local initializer only. Parameters, returns, discards, and other general value positions remain refused until their own aggregate or function slices. No array literal is enabled by this decision; D23 later admits one contextual initializer.

Why: expanding a copy into one operation per element would make compiler work and IR size proportional to a target object that the host may not be able to enumerate. Treating a copy as one compact storage operation preserves [0520]'s value semantics while the sparse whole fact preserves [1910] without pretending that a partial local was initialized.

The alternative: enumerate every copied element in definite-assignment state and IR, or let any one element write establish the whole. The first is not representable for every D18 array and the second permits reads of bytes the program never assigned. Both were declined.

Pinned by positive/local-array-copy, negative/local-array-copy-from-unassigned, negative/local-array-copy-not-assigned-on-every-path, negative/array-type-name-is-not-storage, and runtime/whole-arrays-copy-between-storage on Linux x86-64.

D21 — An array is initialized from a whole-array storage name

The tour said that a binding may name its type and give it a value in one form [0040], that an inferred form takes the value's type [0050], and that a local declared without a value is assigned before it is read [1910]. It said nothing about what value an array binding could receive at its declaration.

Chosen: a local or module array binding is initialized from a direct storage name in either its explicitly typed form — [mut] name: [N]T = source — or its inferred form — [mut] name := source. For a local, both copy every element exactly as D20's assignment does between two storage places. source names a whole array: a module binding, a prior local wholly assigned by D19's sparse facts or by a D20 copy, or a prior local likewise initialized from a name. The explicit form requires the source's D17 identity to agree with its written type; the inferred form gives the destination the source's exact D17 length and element type. The destination is wholly assigned by the copy alone, and both mutable and immutable binding forms accept it because a declaration is not an assignment [0080].

The source must be a storage binding rather than a type declaration. A type name that happens to declare the contextual array type is refused with L0304; it cannot supply an initial image or a local copy address.

At module scope source is exactly one resolved module storage name. Its initial-image chain follows declaration identities, across forward references and type-alias chains, and must terminate either at a module array whose initializer is omitted or at a module array whose initializer is D24's explicit literal. A chain that returns to a declaration is [1940]'s value worked out from itself. Each destination on the chain nevertheless owns distinct storage initialized with the terminal image rather than aliasing its source. Nothing runs before the entry point [1460], so no module-level copy instruction exists.

D70 later permits the same module image chain to pass through one directly selected fixed-array field. The selection remains a contextual initializer link rather than a general array value.

D60/D61 later apply the same declaration-identity chain to explicitly typed and inferred module ordinary structs. Their presently enabled terminal images are all zero, so no finite aggregate image is needed yet.

Every other array initializer value remains refused: D51 later admits a directly selected fixed-array field for a local binding and D70 its module counterpart, D23 admits one contextual local array literal [0520], D24 admits its module counterpart, while an inferred literal, zeroed [0540], repetition [0560], a slice [0570], a call, and every other indexed or selected subexpression are each their own later slice. This decision does not enable a general array value or an array as a parameter, return, discard, or struct field. A local source is read before the binding's scope begins [0110], so a local cannot initialize itself and an outer storage name may be shadowed.

Why: D20 already lowered a local whole-array copy to one Copy_Array instruction, D18's storage semantics already reached every ordinary local, and D19's flow state already gave a fully-copied array the single whole-array fact it needs. At module scope, following declaration identities proves the initial bytes without inventing initialization code or collapsing two storage symbols into one. In both scopes the restriction to a direct source name keeps compiler work and IR size independent of the target-sized D18 extent and defers every value form whose own semantic rule is a later slice.

The alternative: widen the initializer to any array-typed expression, or make the inferred spelling synthesize a general array value. Either admits constructs this decision does not recognise — D23's local array literal, zeroed, a slice, a call result, a selection or an index result — and each is its own decision. Reading D17's shape directly from named storage instead keeps the same narrow source rule as the explicit form without synthesizing an array Name_Reference anywhere else.

Pinned by positive/local-array-initialized-from-source-name, positive/module-array-initialized-from-source-name, negative/local-array-initializer-from-unassigned, negative/array-initializer-length-mismatch, negative/array-initializer-element-mismatch, negative/module-array-initializer-shape-mismatch, negative/module-array-initializer-non-name-refused, negative/module-array-initial-image-cycle, negative/array-type-name-is-not-storage, runtime/local-array-initializer-copies-storage, and runtime/module-array-initializers-copy-images on Linux x86-64.

D22 — Computed local array indexes use the whole-array fact

The tour said that indexing an array checks the bound at runtime [1950], that an index is usize [0160], that a local declared without a value is assigned before it is read [1910], that an array is a value and assignment copies it [0520], and that its elements are indexed from zero [0520]. D19 introduced one definite-assignment fact per compiler-known element and D20 introduced the whole-array fact a copy assigns, and neither answered what a computed local read must require or a computed local write must establish.

Chosen: a computed local array index is admitted where a compiler-known one is. Reading local[i] for a runtime usize requires the whole-array fact to hold on every arriving path — the same fact D20's copy and D21's initializer record, and the fact D19's element facts add up to once every declared position has been assigned. Writing local[i] = v for a runtime usize establishes no element fact of its own, and does not clear an existing whole-array fact: a copy followed by a computed write followed by a computed read is legal, and a computed write into an uninitialized local followed by a whole-array read is still refused. inc local[i] requires the whole-array fact because it reads and writes.

Module arrays are unchanged: D10 gives their state every element from declaration, so their computed reads meet no assignment requirement and their computed writes still assign nothing tracked. Every other refused value form — an inferred initializer not sourced by a direct storage name, a slice, zeroed, repetition, an array literal outside D23's one context, lenof, a general whole value of D46/D47's array-field struct outside D54's contextual copy and D55/D56's local initializers, or its array field as a whole value or place — stays refused. D48 separately admits one element selected through that field.

Why: treating one computed write as a whole assignment would admit uninitialized reads from every other position, exactly the failure D19 declined to introduce for known indexes. Requiring the whole-array fact before any computed read is the minimum rule that keeps [1910] path- sensitive without inventing element-range tracking the compiler would then have to compute for expressions no target can enumerate. Preserving an existing whole fact through a computed write is what makes D20 and D21 usable: without it, a copy followed by any computed update would need to be re-established a position at a time, and no sparse column of D19's fits an extent D18 permits.

The alternative: admit a computed read without a prior whole assignment (and leave every out-of-order write undiagnosed until run time), or have a computed write clear the whole-array fact. Both were declined for the same reason D19 refused to widen one element write to the whole local: they trade a compile-time refusal for a runtime that this compiler has no way to observe.

Pinned by positive/local-array-computed-element-after-whole-copy, negative/local-array-computed-read-not-whole-assigned, negative/local-array-computed-write-establishes-no-fact, runtime/local-array-computed-index-reads-and-writes, runtime/local-array-computed-index-traps, and runtime/local-array-computed-store-traps on Linux x86-64.

D23 — A written local array type gives a literal its shape

The tour said that an array is a value whose size is part of its type [0520], that a binding may write its type and value together [0040], that an integer literal takes the type of its context [0190], and that expressions are evaluated left to right [0410]. It did not say which of those supplies the shape and element context while array values are being introduced a slice at a time.

Chosen: a nonempty array literal initializes an explicitly typed local fixed-array binding: [mut] name: [N]T = [first, ...]. The literal contains exactly N elements, and the scalar T is the context for every element expression. Each element is evaluated and stored in source order. The fresh local is thereby initialized as a whole, so a later computed index meets D22's whole-array requirement without a preceding copy.

This is one contextual initializer and not a general array value. D24 later admits the explicitly typed module form, D25 the inferred local form and D29 assignment to an existing array. A parameter, return, argument or discard still refuses the literal. An empty literal, repetition [0560], zeroed [0540], slices [0570], nested array values and non-scalar elements remain outside this slice. In particular, this literal rule still requires one expression; D136 later accepts the zero-length type [0]T without adding empty literal syntax.

Why the written type: it gives both facts the checker needs without an array-value inference rule: D17's exact length and the scalar context [0190] applies to each expression. The literal's finite source run is also the one array extent it is sound for the compiler to enumerate. Lowering allocates the same compact frame slot as any local array and stores each source element into its position; it does not introduce an array-valued IR result or work proportional to a target extent that was not written in the literal.

The alternative: first infer the literal's length and element type, then allow that value in every compatible position. That is [0530] plus general array values rather than [0520]'s smallest executable case. It was deferred to D25 so module initial images, copying temporaries, parameters and returns did not become unstated consequences of accepting one local initializer.

Pinned by positive/local-array-literal-initializer, negative/local-array-literal-length-mismatch, negative/local-array-literal-element-mismatch, and runtime/local-array-literal-initializes-elements on Linux x86-64.

D24 — A written module array type gives a literal its static image

The tour said that an array is a value whose size is part of its type [0520], that a binding may name its type and give it a value in one form [0040], that an integer literal takes the type of its context [0190], that expressions are evaluated left to right [0410], that a module value is known when the compiler reads it [1940], and that nothing runs before the entry point [1460]. It did not say what shape the compiler admits as a module array's static initial image.

Chosen: a nonempty array literal initializes an explicitly typed module fixed-array binding: [mut] name: [N]T = [first, ...]. The literal contains exactly N elements, and the scalar T is the context for every element expression. Each element is evaluated in source order and its folded value becomes that array position's byte image at compile time. Every element must be [1940]-known and its fold must fit T — a literal or a bool spelling, an operator of [1820] [1940] enumerates over those, or a name bound to another module scalar binding whose own value is known. A forward reference is admitted for the same reason [1740] admits one for a scalar module value: a module is a set and the order between declarations is decided by identity rather than by their placement in the source.

D21's direct-name form remains admitted at module scope as well. Following declaration identity through a chain of [mut] name := source or [mut] name: [N]T = source bindings now terminates either at D10's omitted-initializer array (whose image is zero) or at a D24 literal (whose image is that literal's fold). Every destination on the chain still owns distinct storage, and each is initialized with the terminal image byte for byte — a chain does not alias its source.

This is D24's sole new module array initializer form. D26 later admits [mut] name := [first, ...] after D25 settles [0530]'s inferred shape. An empty literal, zeroed [0540], repetition [0560], slices [0570], nested array values, non-scalar elements, calls, selections and index results all remain outside these slices. Requiring one expression in the literal grammar still excludes an empty literal; D136 later accepts the zero-length type [0]T independently.

The [1820] operators [1940] admits over literals are folded during checking and again when lowering records the verified image: [0290]'s arithmetic, [0300]'s wrapping forms at the operand type's own width so u8 = 255 +% 1 is zero and every unsigned or signed size wraps the same way, [0320]'s shifts, [0330]'s bitwise set, [0340]'s logical words with short-circuiting, [0350]'s comparisons and [0370]'s measurements. Both walks take their widths from Landin.Types.Width against the compilation's target facts; the backend separately folds verified numeric scalar IR, while D177 records a bool datum directly from this same static-image walk so logical CFG cannot reach datum emission. Thus a shift past the width gives zero at exactly the width [0320] promises and a bitwise not occupies the same bytes the backend emits. The positive operator corpus and the negative fold agreement fixtures pin that checking settles every value or invalid operand before lowering is allowed to record an image. A member selection [0420], an array element index [0570] and a nested array literal are refused as D24-excluded constructs; [1940] admits an operator of [1820] applied to leaves, and these three would need the source aggregate or array to have its own image resolved before this one — a stage each has to arrive with its own slice. The refusal walks each element's whole subtree, so source[0] + 1 and state.x == 3 are refused for the same reason a bare source[0] or a bare state.x is: the operator at the root is admitted but the leaf it stands on is not. The same [1940] boundary applies to a scalar module initializer: selecting state.x or source[0] needs a static aggregate or array image that the corresponding later slice has not yet supplied, so checking refuses it rather than leaving the backend to meet an unreadable value.

A fold whose result walks past the compiler's widest kernel value is also refused with the same [1940] rule: an 18446744073709551615 + 1 and a 4294967296 * 4294967296 have no moment in which to trap and no folded value the compiler can hold, so each is refused at the element that produced the overflow rather than left to defect during image resolution. The same refusal applies to a scalar module binding whose value's fold overflows: k: u64 = a + 1 where a is already u64's maximum reports the overflow rather than silently deferring it to the backend and Constraint_Error at emit time.

Why the written type: it gives the checker D17's exact length and one scalar context [0190] for every element, without introducing an array-value inference rule at module scope. The written literal is the one array extent it is sound to enumerate at compile time; every other D18 length reaches four billion positions and no reader will type them out. Requiring each element to be [1940]-known keeps [1460]'s "nothing runs before the entry point" as the rule that decides what a module value is, and the finite element run makes the module fold a per-position walk that a target loader can consume by writing one directive per element into the object.

The alternative: admit a call or a general expression, or infer the length from the literal before settling the local rule. The first two turn [1460] into a promise this compiler cannot keep; the third would have coupled [0530] to static-image folding rather than first giving local and module bindings D25's one shape. D26 admits inference only after that shared rule; the first two alternatives remain declined.

Pinned by positive/module-array-literal-initializer, positive/module-array-literal-forward-scalar-reference, positive/module-array-literal-1820-operators, negative/module-array-literal-length-mismatch, negative/module-array-literal-element-mismatch, negative/module-array-literal-element-not-known, negative/module-array-literal-element-out-of-range, negative/module-array-literal-index-element, negative/module-array-literal-selection-element, negative/module-array-literal-nested-index, negative/module-array-literal-nested-selection, negative/module-array-literal-fold-overflow, negative/module-scalar-fold-overflow, negative/module-array-fold-agreement, negative/module-scalar-fold-agreement, negative/module-scalar-storage-selection, positive/module-scalar-wrapping-arithmetic, positive/module-array-literal-wrapping-arithmetic, and runtime/module-array-literal-holds-its-image on Linux x86-64.

D25 — A nonempty local literal infers one fixed-array shape

The tour said that a binding written with := takes the type of its value [0050], that an integer literal takes the type of its context [0190] and uses the default integer when there is none [0200], that an array's size is part of its type [0520], and that the length may be inferred from a literal [0530]. It did not say which element supplies the scalar type or which value positions that inference enables.

Chosen: a nonempty array literal directly initializing an inferred local binding has fixed-array type [N]T, where N is the number of source elements and T is the scalar type synthesized by the first element. When that first expression is an untyped integer, [0200]'s i32 is its context and therefore T; every later element is checked in that same T context. D18's complete N * sizeof T extent must fit the target's usize before the shape is recorded. D23's existing lowering evaluates and stores the finite source run left to right, and the resulting local is wholly assigned.

D241 later admits every non-scalar element in a local inferred literal; repetition keeps [0560]'s scalar element and the module form keeps D26's. D25 admits only the initializer in a local inferred binding. Its module counterpart remained refused until D26 connected the inferred shape to D24's separate [1940] static-image fold. A literal in general assignment, a parameter or return, an empty literal, a nested literal, repetition [0560] and every non-scalar element also remain outside this slice. In particular, inference does not create a general array-valued temporary.

Why the first element: [0530]'s literal has no surrounding element type, while [0050] requires the value to answer with one type. Letting the first source expression answer and checking the rest against it gives [0410]'s source order a single deterministic context, applies [0200] without an invented numeric join, and needs no conversions [0310].

The alternative: search all elements for a common type, defer every integer until a later element supplies one, or infer module static images at the same time. A common-type search would introduce conversion or least-upper-bound rules the language has neither stated nor wanted; deferral would make element order affect when errors appear without changing their source order; module inference would merge [0530] with [1940]'s independently constrained image fold. All three were declined.

Pinned by positive/local-array-literal-inferred-length, negative/local-array-literal-inferred-element-mismatch, and runtime/local-array-literal-infers-and-initializes on Linux x86-64.

D26 — An inferred module literal has the same static image boundary

The tour said that := takes the type of its value [0050], that the length may be inferred from an array literal [0530], and that every module value is known when the compiler reads it [1940]. D24 supplied static images only after a written array type, and D25 first settled how a nonempty literal infers one shape.

Chosen: a nonempty array literal directly initializing an inferred module binding has D25's [N]T shape: its source count is N, its first element supplies scalar T, an otherwise untyped integer first element defaults to i32 [0200], and every later element is checked in that same context. Once the shape is settled, every element must meet D24's module-image boundary: it is [1940]-known, target-aware folding produces a value held by T, and the values form one source-order static image. D21's direct-name chain may copy that image into typed or inferred module array storage, with a distinct datum for every binding.

All D24 exclusions remain exclusions: no call, member selection, element index or nested array can supply an image element, and checked overflow or an out-of-range folded value is refused before lowering. D18 limits the inferred complete byte extent before the shape is recorded. A local inferred literal continues to use D25's runtime evaluation instead; only module scope folds an image.

This does not admit a literal in general assignment, as a parameter or return, or as a general array-valued expression. It also does not admit an empty literal, repetition [0560], zeroed [0540], slices [0570], or a non-scalar element. No general array temporary is introduced.

Why reuse D25's shape before D24's fold: inference answers only which fixed array the binding holds; [1940] independently answers whether module storage can have that value before anything runs [1460]. Keeping those checks sequential makes local and module := mean the same type while preserving the module-only static-image restriction.

The alternative: infer a different element type from the complete folded image, or make module inference choose a written-width type from each value. Either would make the same literal have a different type at local and module scope and would invent a numeric join or narrowing conversion [0310]. Both were declined.

Pinned by positive/module-array-literal-inferred-length, negative/module-array-literal-inferred-boundaries, negative/module-array-literal-inferred-fold, and runtime/module-array-literal-infers-static-image on Linux x86-64.

D27 — An explicitly typed module array may spell its zero image

The tour said that zeroed denotes all-bits-zero when that image is valid for its context [0540], that a fixed array is zeroable exactly when its element is [0520], and that every module value is known when the compiler reads it [1940]. D10 already gives an omitted module initializer that image, but did not say where a program may request it explicitly while array values are enabled a slice at a time.

Chosen: zeroed directly initializes an explicitly typed module fixed-array binding: [mut] name: [N]T = zeroed. The written D17 shape is its context. Every scalar element type the kernel currently admits has an all-bits-zero image, so the complete array has one without enumerating its N positions. Lowering records no finite datum image, exactly as for D10's omitted initializer; the backend therefore reserves the distinct module storage in .bss. A D21 direct name chain may copy this terminal zero image while retaining one storage object per declaration.

This is a contextual initializer, not an array-valued expression or a runtime operation. D27 itself does not infer a type for name := zeroed; D28 separately admits a typed local array initializer, D30 an array assignment, D39 a typed module scalar initializer and D40 a typed local scalar initializer. Every inferred form remains refused. D27 introduces no IR opcode, temporary, startup copy, or source-order element evaluation. Repetition [0560], slices [0570], empty literals, non-scalar array elements, parameters, returns, arguments, and general whole-array value positions remain outside this slice.

Why preserve the absent image: materializing N zero values would make host work and IR size depend on D18's target-sized extent and would emit bytes for a value the object format can reserve without storing. The absence already means exactly this image for D10, keeps zero storage in .bss, and remains distinct from D24/D26's finite literal image.

The alternative: treat zeroed as a generally typed value, or infer an array shape from it. The first would silently admit local initialization, assignment, parameters, and other value positions that need their own runtime rules; the second has no source fact from which to derive either N or T. Both were declined.

Pinned by positive/module-array-zeroed-initializer, negative/inferred-zeroed-not-enabled, and runtime/module-array-zeroed-reads-zero on Linux x86-64.

D28 — A local zero image is one runtime storage operation

The tour said that zeroed denotes all-bits-zero when that image is valid for its context [0540], that a fixed array is zeroable exactly when its element is [0520], and that a local binding may carry an initializer [1810]. D27 supplied one static module context but deliberately introduced no runtime operation, so it did not say how a local array obtains the same image.

Chosen: zeroed directly initializes an explicitly typed local fixed-array binding: [mut] name: [N]T = zeroed. The written D17 shape is its context. Every scalar element the kernel currently admits has an all-bits-zero image, so one runtime storage operation clears the complete compact frame slot. The operation carries the destination identity, never one entry per element; its byte extent is derived from the target's width for T. The initialized local is assigned as a whole, so D22 permits a later compiler-known or computed index read.

Lowering records one target-neutral Clear_Array instruction with no operands and no result. D57 later gives field zero of that destination-only operation a whole aggregate's padded extent as well; its array meaning is unchanged. The Linux x86-64 backend forms the slot address and takes the target byte extent. It emits bounded scalar zero stores for one to six bytes or exactly eight bytes; other extents retain the forward rep stosb clear. Compiler work and IR size therefore remain independent of the target-sized length D18 admits, and no array-valued temporary or hidden zero datum exists.

This remains one contextual initializer. D28 does not infer a shape for name := zeroed; D30 separately admits array assignment, D39/D40 typed module and local scalar initializers, and D41 scalar assignment. zeroed as an argument, return, discard, nested or general expression remains refused. Module arrays continue to use D27's absent static image rather than this runtime instruction. Repetition [0560], slices [0570], empty literals, non-scalar array elements, parameters, and returns remain outside this slice.

Why one storage operation: lowering one store per element would make compiler work and IR size proportional to an extent deliberately permitted to approach the target address space. Copying a synthesized zero array would instead invent storage and a source the program never declared. A destination-only clear says exactly what [0540] requires and leaves representation to the target backend.

The alternative: treat zeroed as a scalar expression repeated N times, or enable it in assignment at the same time. The first imposes host enumeration and invents source-order evaluation where there is none; the second broadens the place/value boundary beyond fresh initialization and needs its own definite- assignment and evaluation decision. Both were declined.

Pinned by positive/local-array-zeroed-initializer, negative/inferred-zeroed-not-enabled, and runtime/local-array-zeroed-reads-zero on Linux x86-64.

D29 — Array literal assignment forms the value in its destination

The tour said that assignment copies an array [0520], that an assignment evaluates its destination place before its value [0410], and that aggregate parts initialize in written order. D20 admitted only a direct storage name as the value, while D23 admitted a literal only for a fresh local binding. Neither said whether assignment of a literal needs a hidden complete value or exposes its element order in existing storage.

Chosen: a nonempty array literal may be assigned contextually to a mutable fixed-array place: place = [first, ..., last]. The destination's D17 length and scalar element type are the context; the literal must contain exactly that many elements and each expression must have that element type. At this boundary the fixed-array places are direct local or module storage names. D52 later admits a directly selected fixed-array field under the same literal rule. [1900] still decides whether either may be written.

The destination place is reached first. Then each literal element is evaluated left to right and written immediately to its one-based destination position before the next expression begins. A later expression can observe an earlier write to the same array, and a runtime failure can leave the completed prefix changed. Lowering emits the existing scalar expression and field-store sequence for each source element; it creates no hidden array-sized temporary and no new array IR operation. The compiler work and instruction run are proportional to the literal text the program wrote, not to an implicit target-sized extent.

Definite assignment checks every right-hand-side read against the state arriving at the statement, then marks the destination array assigned as a whole only when the assignment completes normally. Thus assigning a complete literal makes a previously uninitialized array readable through a compiler-known or computed index, but an element written earlier in the same statement does not justify a source read that was unassigned on entry.

This is one assignment context, not a general array value. Array literals remain refused as arguments, returns, discards, scalar operands, nested elements, and other expression positions. Empty literals, repetition [0560], slices [0570], non-scalar element arrays, and zeroed assignment remain separate slices. A direct storage-name assignment continues to use D20's one compact Copy_Array.

Why expose the writes: evaluating every element before changing the destination would require a hidden second array as large as the value, obscuring a cost the language promises to keep visible. Writing each completed scalar uses only storage the program named and gives [0410]'s aggregate order an observable, deterministic meaning. Source text already contains one expression per store, so this does not introduce D18's host-enumeration problem.

The alternative: synthesize a temporary array and copy it only after every element succeeds. That gives transactional-looking assignment and prevents later elements from observing earlier writes, at the price of an implicit full array in every frame and a second full traversal. It was declined.

Pinned by positive/array-literal-assignment, positive/module-array-literal-assignment-runtime-elements, negative/array-literal-assignment-length-mismatch, negative/array-literal-assignment-element-mismatch, negative/array-literal-assignment-reads-incoming-state, and runtime/array-literal-assignment-is-source-ordered on Linux x86-64.

D30 — Zeroed assignment clears one complete array place

The tour said that zeroed is the all-bits-zero image supplied by a context [0540], that assignment evaluates its destination before its value [0410], and that array assignment copies a complete value [0520]. D27 and D28 admitted that image only while creating module and local storage. They deliberately left an existing destination to a later definite-assignment and runtime decision.

Chosen: zeroed may be assigned contextually to a mutable fixed-array place: place = zeroed. The destination's D17 length and scalar element type supply the context, and [1900] decides whether its direct local or module storage name may be written. Every scalar element the kernel currently admits has an all-bits-zero image, so the complete array has one [0540].

D49 extends this contextual assignment to one fixed-array field selected immediately from enabled struct storage without making the field a general array place or value.

The destination is reached first; zeroed evaluates no source expressions and names no source storage. Lowering emits one Clear_Array carrying that local frame slot or module datum; D49 additionally carries the declaration-order field identity, never a target byte offset. The verifier resolves its complete array shape, and the backend derives the byte extent from target facts. Linux x86-64 uses bounded scalar zero stores for one to six bytes or exactly eight bytes; other extents retain rep stosb. There is no hidden zero datum, array temporary, source operand, or compiler enumeration of D18's target-sized length.

A normally completed assignment marks a local destination assigned as a whole, so every compiler-known and computed element may then be read. There is no source-order prefix like D29's literal has: the source contains no elements and specifies no per-element evaluation. This does not promise an atomic machine operation; D227 defines concurrency and interruption limits.

This is one contextual array assignment. It does not infer a type for name := zeroed or assign a scalar; D39 separately admits a typed module scalar initializer, while local scalar initialization remains refused. Nor does D30 admit zeroed as an argument, return, discard, nested value, or general expression. Module and local array initializers keep D27/D28's distinct static and runtime paths. Repetition [0560], slices [0570], non-scalar array elements, and other zero-accepting types remain separate slices.

Why reuse the clear: lowering one scalar zero store per element would make compiler work and IR size depend on an extent whose source writes no finite run. Copying a synthesized zero array would invent both storage and a read. D28's compact destination-only operation already says the complete runtime effect and already follows target width for either storage kind.

The alternative: make zeroed a general array value and feed it through D20's copy. That would silently admit arguments, returns and other value positions while requiring source storage for an image that has none. It was declined.

Pinned by positive/array-zeroed-assignment and runtime/array-zeroed-assignment-clears-storage on Linux x86-64, together with the focused lowering and target-width backend cases for both storage kinds.

D31 — lenof counts a literal without forming it

The tour said that a literal's lenof is compile-time [0370]. D14 first implemented only a direct name, because a general expression operand would have made array values, calls, selections and slices one undivided decision. D25 later settled how a nonempty literal supplies a scalar element shape.

Chosen: lenof ([first, ...]) is a usize whose value is the number of expressions in the literal's source run. The literal must remain nonempty under [0520]. Its first element supplies D25's scalar type, including [0200]'s default for an otherwise untyped integer, and every later element must have that same type. This checks that the syntax denotes one array shape; it does not create an array value.

None of the element expressions is evaluated, read, folded, lowered or stored. The count therefore remains valid when an element is an unassigned local, a call, a selection or any other well-typed scalar expression. At module scope those expressions do not become module initializer inputs: the complete measurement is known from syntax alone. Definite assignment likewise reads no names beneath the measurement.

Lowering emits one existing usize Number holding the source element count. A static module binding records the same number directly. No array storage, temporary, element instruction, target query or backend operation is introduced. D18's maximum object extent does not apply because no object of the literal's shape exists.

This admits only a parenthesized nonempty array literal beside D14's direct identifier. The parentheses are part of the measurement syntax, not a general expression operand: without them, lenof[index] continues to index an ordinary binding named lenof, as [1760]'s contextual spelling requires. The direct identifier form also measures a slice's runtime length [0370]; selections, indexes, calls and other general expression operands remain outside [1820]'s measurement grammar. Empty literal syntax remains deferred. D136 later accepts [0]T source legality independently of that syntax.

Why type-check expressions that do not run: the brackets still claim one array literal, and D25 already gives that claim a deterministic scalar shape. Counting arbitrary comma-separated expressions regardless of their types would make malformed aggregate syntax valid only when placed beneath lenof.

The alternative: evaluate the literal and then ask the resulting array value for its length. That would make calls and reads observable despite the count being fixed by syntax, require hidden array storage, and prematurely admit a general array value. It was declined.

Pinned by positive/lenof-array-literal-does-not-read-elements, negative/lenof-array-literal-element-mismatch, negative/lenof-array-literal-needs-scalar-elements, and runtime/lenof-array-literal-is-compile-time on Linux x86-64; the runtime case also keeps an ordinary array named lenof indexable.

D32 — Full-array repetition evaluates one scalar once

The tour said that repetition writes [N of value], or [of value] when a context supplies the length [0560], that expressions run left to right [0410], and that assigning an array copies its complete value [0520]. It did not say whether value runs once or once per element, nor how a contextual repetition is represented without materializing a target-sized temporary.

Chosen: an explicitly typed local fixed-array binding may be initialized by [N of expression], and a mutable fixed-array place may be assigned either [N of expression] or [of expression]. The written local type or destination supplies D17's exact length and scalar element type. When N is written, it must equal that length exactly. The scalar expression must have the element type, including [0190]'s contextual commitment of an untyped integer.

At this boundary an assignment destination is a direct local or module array storage name. D53 later admits a directly selected fixed-array field under the same full-repetition rule.

The destination is reached first for assignment. The repeated scalar expression is then evaluated exactly once, and its target-width bit pattern is stored in every element. Normal completion initializes or assigns the destination as a whole for [1910], so a later computed index meets D22's whole-array requirement. The operation is not promised atomic with respect to interruption or concurrency.

Lowering evaluates the scalar into one ordinary value and emits one Fill_Array carrying that operand and the destination's compact frame-slot or module-datum identity. The verifier requires one scalar operand matching the destination element type and rejects a fill in a static datum initializer. The Linux x86-64 backend derives the element count and width from the destination shape and target facts, then uses the width-matched forward repeated store. Neither IR nor compiler work enumerates D18's extent, and no hidden array storage or temporary is formed.

This first repetition slice deliberately requires an explicitly typed local initializer or an existing mutable array place. D33/D35 later admit counted local and module inference, D34 the typed module static image, and D36--D38 the mixed-prefix forms. Argument, return, discard, nested repetition and general array values remain refused. Since of remains [1760]'s contextual spelling rather than a reserved word, [of, other, of] remains an ordinary literal whose elements may name a binding called of; repetition is recognized only where the token after of can begin its scalar expression. Thus [of + 1] also remains an ordinary one-element literal.

Why once: the source writes one expression, and evaluating it once makes the runtime work visible without multiplying side effects by a type-level count. A scalar register or spill plus one compact fill is sufficient even when D18 permits an extent the compiler host cannot enumerate.

The alternative: lower repetition as if the source had written one copy of the expression per element. That would make side effects and compiler work proportional to a target-sized count and contradict the single expression the program contains. It was declined.

Pinned by positive/local-array-repetition, negative/array-repetition-count-mismatch, negative/array-repetition-element-mismatch, negative/array-repetition-countless-inferred-initializer-not-enabled, negative/array-repetition-reads-incoming-state, and runtime/array-repetition-evaluates-once on Linux x86-64.

D33 — A counted local repetition supplies its inferred shape

The tour said that a literal may supply an omitted array length [0530] and that repetition writes a count before of when no surrounding type supplies one [0560]. It did not say whether the same count can supply the complete type of an inferred binding, or which expression supplies the element type.

Chosen: a counted full-array repetition directly initializing an inferred local binding supplies [N]T. N is the written nonzero integer count. The one repeated expression supplies T by D25's deterministic first-element rule: an untyped integer receives [0200]'s default i32, an already typed scalar retains that type, and no common-type search or conversion is introduced. The resulting byte extent must fit D18's target usize before the compact shape is recorded on the repetition and binding.

The repeated expression is read from incoming definite-assignment state and uses D32's lowering unchanged: it evaluates exactly once into one scalar IR value, followed by one compact Fill_Array for the inferred local frame slot. Successful initialization establishes the whole array. Neither checker nor IR enumerates the inferred extent.

A written zero count remains refused in this inference position because the repetition supplies no element-bearing source run. D136 later accepts an explicit zero-length fixed-array type; that does not make repetition an empty array literal or give an inferred zero-count repetition an element type. A count-less inferred initializer, module initializer, mixed-prefix repetition, argument, return, discard, nested repetition and other general array value remain outside this slice.

Why the scalar expression: unlike a literal source run, repetition has only one value-producing expression. Taking its settled scalar type gives every stored element the same type without inventing a second inference rule.

The alternative: require a written array type for every repetition. That would leave the explicit count unable to do the same shape work as [0530]'s literal count, despite already being checked against that shape by D32. It was declined.

Pinned by positive/local-array-repetition-inferred, negative/inferred-array-repetition-extent-overflow, negative/inferred-array-repetition-reads-incoming-state, negative/inferred-array-repetition-zero-count, negative/array-repetition-general-value-not-enabled, and runtime/array-repetition-evaluates-once on Linux x86-64.

D34 — A written nonzero array shape admits either repetition spelling

The tour said that [N of expression] may omit N when the type supplies its length [0560], and introduced repetition as a static pattern that lives in flash. D32 admitted only a counted explicitly typed local initializer, while D33 admitted a counted inferred local; neither slice supplied the module static image or explained what a zero folded pattern becomes.

Chosen: an explicitly typed fixed-array binding at module or local scope may be initialized by [N of expression] or [of expression] when its written contextual length is nonzero. The written type supplies D17's complete shape. A written N remains an exact assertion of that same length, and the one expression is checked against the scalar element type. This lifts D32's count requirement for an explicitly typed local without changing assignment or D33's inferred rule.

For module state, the expression obeys the same [1940] compile-time-known and D24 target-aware scalar-fold boundary as one element of a module array literal: literals, [1820] operators and module scalar names may compose; calls, storage selection, an element index and a nested array literal remain refused. The fold produces one scalar pattern. A nonzero pattern is represented in IR by that one Folded value plus D17's existing compact shape, including through any D21 direct module-array name chain. A zero pattern records no image, just like D10, D27 and D28, and therefore remains loader-zeroed storage rather than bytes in .data. Neither image resolution, copying, verification nor dumping enumerates the extent.

The Linux x86-64 backend emits a constant-size .rept/width-specific-directive/ .endr sequence for a nonzero repeated image. The scalar directive is .byte, .word, .long or .quad according to the target element width. In particular, the eight-byte form does not use GNU .fill, whose value operand contributes at most four bytes and would discard the high half of a u64 pattern. An absent zero image stays .bss.

A repetition whose written contextual length is zero is refused at the repetition. This is a construct-specific nonzero requirement. D136 later accepts [0]T as source, while repetition over that zero contextual extent remains refused. D33's zero-count inferred refusal remains for the same reason. An inferred module initializer remained outside this slice until D35. A count-less inferred initializer, every mixed-prefix context other than D36's typed local, argument, return, discard, nested repetition and every other general array value position remain refused.

Why one image value: repetition writes one expression and every destination position receives the same target-width pattern. Materializing one value per position would lose the compact representation precisely for D18's target-sized extents, and copying such a run through a module name would repeat the same fault.

The alternative: use GNU .fill count,size,value directly. Its compact count is attractive, but GNU assemblers truncate value to four bytes, so it cannot faithfully emit an arbitrary eight-byte element. The width-specific repeated scalar directive keeps both compact source and all pattern bits.

Pinned by positive/local-array-repetition, positive/module-array-repetition, negative/array-repetition-zero-context, negative/module-array-repetition-element-not-static, negative/module-array-repetition-index-element, negative/array-repetition-countless-inferred-initializer-not-enabled, and runtime/array-repetition-evaluates-once on Linux x86-64.

D35 — A counted module repetition may infer its nonzero array shape

The tour said that a counted repetition may supply an inferred local's length and scalar element type [0560]. D33 implemented that local form, while D34 supplied the compact static image only when module state wrote its array type.

Chosen: [N of expression] may directly initialize an inferred module binding when N is written and nonzero. The count supplies D17's length and the one expression supplies its scalar element type; an untyped integer takes [0200]'s i32 default. The resulting byte extent must fit the selected target's usize by D18, exactly as for D25/D26/D33 inferred arrays.

The repeated expression obeys [1940]'s known/static boundary and the same D24 target-aware fold and range checks as D34's typed module repetition. Literal and [1820] operator trees may reach through module scalar names; a call, storage selection, index or nested array value is refused before lowering. The checker folds the one pattern against the inferred scalar type, so no accepted out-of-range or overflowing pattern can reach lowering as a compiler defect.

D34's representation and emission apply unchanged: a nonzero pattern is one compact repeated image, direct module-array name chains preserve it, and a zero pattern is the absent loader-zeroed image emitted in .bss. Zero count, count-less inferred repetition and every general array value position remain refused. D36 later admits the explicitly typed local mixed form, D37 its assignment and D38 the explicitly typed module image.

Why only counted: without a written type or source run, [of expression] has no source for its length. The scalar can determine an element type but not an array extent, so accepting it would require a separate inference rule rather than completing the symmetry D33 began.

The alternative: infer only locals and require every module repetition to write its array type. That makes storage duration alter whether an explicit count and scalar can determine the same D17 shape, while D34's static image already represents the result. It was declined.

Pinned by positive/module-array-repetition-inferred, negative/inferred-module-array-repetition-element-not-static, negative/module-array-repetition-index-element, negative/inferred-module-array-repetition-extent-overflow, negative/module-array-repetition-fold-range, negative/inferred-array-repetition-zero-count, negative/array-repetition-countless-inferred-initializer-not-enabled, negative/array-repetition-general-value-not-enabled, and runtime/array-repetition-evaluates-once on Linux x86-64.

D36 — A typed local may mix a literal prefix with one repeated suffix

The tour said that repetition may follow values already written between the brackets [0560], that expressions run left to right [0410], and that a local binding may write its fixed-array type [0040]. It did not state which contexts first admit that mixed form, whether the repeated expression runs once, or how the compact fill identifies only the suffix.

Chosen: [e1, ..., ek, of repeated] may initialize an explicitly typed local fixed array of length N exactly when 1 <= k < N. The written type supplies D17's length and scalar element type. Each prefix expression and the repeated expression must have that scalar type, including [0190]'s contextual commitment of an untyped integer. A prefix that reaches or passes N is refused because no nonempty repeated suffix remains.

Lowering evaluates each prefix expression and immediately stores it into parts 1 through k, in source order. It then evaluates repeated exactly once and emits one compact Fill_Array beginning at one-based part k + 1. No hidden array temporary or array-valued IR result is formed. Fill_Array carries its one-based First part; every pre-D36 full fill passes First = 1. The verifier requires First to lie within the destination length as well as retaining the existing destination-shape and scalar-operand checks. Linux x86-64 offsets the destination by (First - 1) * element_size bytes and repeats exactly N - First + 1 width-matched stores.

The parser still does not reserve of. It recognizes the suffix marker only after a nonempty comma-terminated prefix and only when the token after of can begin an expression. Thus [of, other, of] remains an ordinary three-element literal and [of + 1] remains an ordinary one-element literal whose expression may name a binding called of.

This slice admits no mixed module initializer, inferred binding, argument, return, discard, nested array or other general array value. D37 separately admits assignment to an existing mutable fixed-array place, and D38 separately admits the explicitly typed module static-image form. Full-array repetition remains governed by D32--D35, so a prefix length of zero is not a mixed form and does not narrow those existing contexts.

Why local and explicit: it is the smallest context that already owns a runtime destination and supplies both N and the scalar type. Admitting module state would require a mixed static-image representation; inference would need a new length rule; assignment would expand D29/D32's contextual value boundary. Each remains independently testable rather than becoming an unstated result of this slice.

The alternative: materialize the prefix and repeated suffix as a complete array temporary, then copy it to the local. That would hide the observable prefix-store order, allocate storage proportional to D18's target-sized extent, and discard the compact fill representation. It was declined.

Pinned by the parser, checker, IR, verifier, lowering and Linux x86-64 public-seam cases; positive/local-array-mixed-repetition; negative/array-mixed-repetition-prefix-too-long, negative/inferred-array-mixed-repetition-not-enabled, negative/array-mixed-repetition-general-value-not-enabled, negative/nested-array-mixed-repetition-not-enabled; and runtime/mixed-array-repetition-is-source-ordered on Linux x86-64.

D37 — A mixed prefix may assign a mutable fixed array

The tour said that assignment reaches its destination before evaluating its right-hand side [0410], that a mutable binding may be assigned [1900], and that mixed repetition evaluates and stores its prefix before evaluating one repeated suffix [0560]. It did not say whether an existing array place could supply the mixed form's context, whether partial stores changed definite-assignment state, or whether both module and local storage used the compact suffix operation.

Chosen: [e1, ..., ek, of repeated] may be the right-hand side of assignment to a mutable fixed-array place of type [N]T exactly when 1 <= k < N. The destination supplies the complete length and scalar element type. Every prefix expression and repeated must have type T, including [0190]'s contextual commitment of an untyped integer. The existing place check retains [1900]'s mutability requirement, and a prefix that reaches or passes N is refused because no repeated suffix remains.

At this boundary the place is a direct local or module array storage name. D53 later admits a directly selected fixed-array field under the same mixed rule.

The destination is reached and evaluated before any right-hand-side expression. Lowering then evaluates each prefix expression left to right and immediately stores it into destination parts 1 through k. It evaluates repeated exactly once and emits the existing compact Fill_Array with First = k + 1. The same IR operation names either a local frame slot or a module datum; no array-sized temporary, array-valued result, verifier rule or backend operation is added.

Definite-assignment checks every prefix and repeated expression against the state incoming to the assignment. Stores made while evaluating the mixed form do not make an initially unassigned destination readable by a later expression in that same right-hand side. Only successful completion establishes the complete destination as assigned.

Inferred initialization, nested mixed forms and other general-value contexts remain refused. D38 independently admits explicitly typed module initialization; this assignment rule creates no static mixed image and no independently carried mixed array value, and only forms the result directly in existing mutable storage.

Why assignment: D29 and D32 already establish the destination-first, contextual assignment boundary for finite literals and full repetition. D36's ordered prefix stores and Fill_Array.First, plus their verifier and backend paths, express the mixed case without another representation. Extending only this boundary preserves the independently testable initializer and general-value refusals.

The alternative: form a complete temporary and copy it after all expressions finish. That would reverse the observable immediate-store semantics, consume storage proportional to D18's target-sized extent, and make the compact suffix fill transient rather than the destination operation. It was declined.

Pinned by the checker and lowering public-seam cases; positive/array-mixed-repetition-assignment; negative/immutable-array-mixed-repetition-assignment, negative/array-mixed-repetition-assignment-element-mismatch, negative/array-mixed-repetition-assignment-prefix-too-long, negative/array-mixed-repetition-assignment-reads-incoming-state, the retained initializer, inferred, nested and general-value refusal fixtures; and runtime/mixed-array-repetition-assignment-is-source-ordered on Linux x86-64.

D38 — A typed module mixed repetition has a compact hybrid image

The tour said that repetition is for static patterns in flash [0560], that a module value must be known when the compiler reads it [1940], and that a mixed prefix leaves one expression to fill its suffix. It did not say whether an explicitly typed module array could use that mixed form, how its static image was represented, whether a zero suffix selected .data or .bss, or whether a through-name copy preserved the representation.

Chosen: [e1, ..., ek, of repeated] may initialize an explicitly typed module fixed array [N]T exactly when 1 <= k < N. The written type supplies N and T; every prefix expression and repeated must have type T, and each must be compile-time known under [1940]. Every fold uses the selected target facts and must fit T, including each prefix independently and the one suffix value. Inferred module initialization, nested mixed repetition and every general-value mixed form remain refused.

Lowering folds the finite prefix in source order and the repeated expression once. IR records a hybrid image consisting of those k folded prefix values, one folded suffix value, the element type and the declared length. It never records N - k copies. Image verification checks the finite prefix and one suffix value; the dump renders the same finite run followed by repeat; direct-name image resolution copies that compact representation through chains. None of lowering, IR, verification, dumping or copying walks or allocates in proportion to N.

A hybrid remains a present image when its suffix value is zero, because its nonempty written prefix makes it explicit .data; Linux x86-64 emits the prefix with width-matched scalar directives and then a constant-size .rept N - k around one zero directive. A full repetition of zero retains D34's absent image and loader-zeroed .bss. For every nonzero suffix the backend uses the same .byte, .word, .long or .quad directive, so a 64-bit pattern reaches the assembler with all eight bytes rather than GNU .fill's truncated value field.

Why a hybrid image: a finite prefix plus one suffix pattern is the source's own information and is sufficient to emit every byte. Expanding the suffix would make compile time, host memory, verifier work, dump size and assembly size depend on D18's target-sized extent; treating a zero suffix as absent would discard the nonzero prefix and misclassify initialized data as .bss.

The alternative: lower the initializer to a complete per-position static image. That would reuse D24's literal run but erase the compactness guaranteed by repetition and make a legal target-sized declaration an impractical host-sized compiler computation. It was declined.

Pinned by the checker, IR, verifier, lowering and Linux x86-64 backend public-seam cases; positive/module-array-mixed-repetition; negative/module-array-mixed-repetition-prefix-not-static, negative/module-array-mixed-repetition-suffix-not-static, negative/module-array-mixed-repetition-fold-range; the retained inferred, nested and general-value refusal fixtures; and runtime/module-mixed-array-repetition-holds-hybrid on Linux x86-64.

D39 — A written module scalar gives zeroed its context

The tour said that zeroed denotes the all-bits-zero image of the type its context supplies [0540], and [1940] requires a module initializer to be known when the compiler reads it. It did not say whether a scalar declaration could supply that context, whether an alias changed the answer, or whether spelling the zero image required initialized data.

Chosen: zeroed may directly initialize an explicitly typed module scalar binding: [mut] name: T = zeroed. The written type must resolve, through any chain of type aliases, to one of [0120]'s enabled scalar types. That resolved scalar is the literal's context. Its compile-time-known value is false for bool and integer zero for every enabled integer type. The rule applies only to the complete initializer in that declaration. D40 separately admits the local initializer and D41 the scalar assignment; an inferred binding, a nested occurrence and every other expression position remain refused.

Lowering uses exactly D10's existing scalar-zero IR: a false Truth for bool and a zero Number of the resolved integer type. No new IR operation, startup code or static fold is introduced. Linux x86-64 therefore uses the existing zero-data classification and reserves the datum in loader-zeroed .bss; it does not write a zero directive into .data.

Why this boundary: the declaration already supplies every fact [0540] needs, and its static zero is the same module image D10 already represents. Restricting the rule to that direct contextual site admits no generally typed zeroed value and leaves local execution and assignment as independently testable slices.

The alternative: make zeroed a general scalar expression wherever an expected type is available. That would also admit locals, assignments, operands, arguments and returns in one step, erasing the contextual boundaries retained by D27, D28 and D30. It was declined.

Pinned by the checker, lowering and Linux x86-64 backend public-seam cases; positive/module-scalar-zeroed-initializer; negative/inferred-zeroed-not-enabled, negative/nested-scalar-zeroed-not-enabled; and runtime/module-scalar-zeroed-reads-zero on Linux x86-64.

D40 — A written local scalar gives zeroed its context

The tour said that zeroed denotes the all-bits-zero image of the type its context supplies [0540], and that an initialized local has its value before a later statement reads it [0110]. It did not say whether a local scalar initializer supplied that context, whether an alias changed the answer, or how the value reached local storage.

Chosen: zeroed may directly initialize an explicitly typed local scalar binding: [mut] name: T = zeroed. The written type must resolve, through any chain of aliases, to an enabled scalar type and supplies the literal's context. The value is false for bool and integer zero for every enabled integer type. The complete initializer establishes the binding as definitely assigned. D39 separately governs module initialization and D41 assignment; inferred initialization, nested occurrences and every other expression position remain refused.

Lowering emits D10's existing false Truth or typed zero Number, followed by the ordinary frame-slot Store. It introduces no new IR value, operation or local initialization path.

Why this boundary: an explicitly typed local already supplies the same complete scalar context as D39's module declaration, and the existing constant/store path represents the result without making zeroed a general expression.

The alternative: admit every expected-scalar expression context together. That would silently include assignment, arguments, returns and operands instead of preserving each contextual boundary for executable evidence. It was declined.

Pinned by the checker and lowering public-seam cases; positive/local-scalar-zeroed-initializer; negative/inferred-zeroed-not-enabled, negative/nested-scalar-zeroed-not-enabled; and runtime/local-scalar-zeroed-reads-zero on Linux x86-64.

D41 — A mutable scalar assignment destination gives zeroed its context

The tour said that assignment reaches its destination before evaluating its right-hand side [0410], that only a mutable binding may be assigned [1900], and that zeroed takes the all-bits-zero image of its context [0540]. It did not say whether a scalar destination supplied that context, whether aliases changed the answer, or when the assignment established local definite assignment.

Chosen: zeroed may be the complete right-hand side of assignment to a mutable scalar local slot or module datum. The destination type must resolve, through any chain of aliases, to an enabled scalar type and supplies the literal's context. The value is false for bool and integer zero for every enabled integer type. The ordinary destination check runs first, retaining mutability and every invalid-place or invalid-type refusal. Only successful completion establishes the destination as definitely assigned.

The destination is reached and evaluated before the right-hand side, as for every assignment. Lowering emits D10's existing false Truth or typed zero Number, then uses the ordinary scalar Store for a local slot or Store_Datum for a module datum. No new IR value, operation, temporary or backend path is introduced.

Inferred initialization remains governed by D39/D40 and is refused without a written type. Assignment to a scalar struct field or fixed-array element is governed separately by D42, and assignment to a named return is not this direct-storage slice. A nested occurrence, argument, return, operand, discard and every other general zeroed expression remain refused; this rule admits only the complete contextual right-hand side of a direct binding assignment.

Why assignment: the mutable destination already owns the scalar type and storage the literal needs. Reusing ordinary assignment preserves destination order, mutability, definite assignment and lowering rather than inventing a carried scalar zeroed value.

The alternative: synthesize an independently typed zero value before reaching the destination. That would reverse [0410]'s assignment order and make a contextual form appear to be a general expression. It was declined.

Pinned by the checker and lowering public-seam cases; positive/scalar-zeroed-assignment; negative/immutable-scalar-zeroed-assignment, negative/inferred-zeroed-not-enabled, negative/nested-scalar-zeroed-not-enabled; and runtime/scalar-zeroed-assignment-clears-values on Linux x86-64.

D42 — A scalar subobject assignment destination gives zeroed its context

The tour said that assignment reaches its destination before evaluating its right-hand side [0410], that selection reaches a struct field or fixed-array element [0520], that only writable places may be assigned [1900], and that zeroed takes the all-bits-zero image of its context [0540]. D41 supplied that context only for a direct mutable scalar binding.

Chosen: zeroed may be the complete right-hand side of assignment to an ordinary scalar struct field or fixed-array element selected immediately from a mutable local slot or module datum. The selected field or element type must resolve, through every representable alias, to an enabled scalar type and supplies the literal's context. The value is false for bool and integer zero for every enabled integer type. D62 later applies this same scalar rule when D48's element is reached through a fixed-array field of that directly named storage.

The ordinary place check runs first, retaining mutability and every invalid-place, invalid-selection and invalid-type refusal. The destination and a computed index are evaluated exactly once and before the right-hand side. A compiler-known index continues to use the existing Store_Field; a computed index continues to carry its ordinary bounds check into the existing Store_Element. The same slot-reaching forms serve local storage. No new IR value, operation, temporary or backend path is introduced.

Successful completion has the ordinary definite-assignment effect of writing that one field or compiler-known element. It neither assigns any sibling field nor the array as a whole; a computed element retains the existing per-element facts and bounds behavior. A failed or refused assignment establishes nothing.

D41's direct binding assignment remains unchanged. An immutable subobject, a selection from an invalid place, a nested subobject destination in this slice, and assignment to a named return remain outside it; D43 treats the last as its own contextual position and D62 later admits the one nested shape D48 already makes an ordinary scalar place. D49 separately treats one fixed-array field as a contextual zeroed destination without changing this scalar rule. D65 later applies the same typed scalar image to a field label inside D64's contextual struct literal. Inferred initialization and every nested, argument, return, operand, discard or other general zeroed expression remain refused.

Why the selected type: a scalar subobject already owns both the type and the storage that the contextual literal needs. Reusing the ordinary place and store paths preserves source order, definite assignment and bounds checks without turning zeroed into a general value.

The alternative: infer an independent scalar zero before selecting the field or evaluating the index. That would reverse [0410]'s order and bypass the place semantics this assignment must preserve. It was declined.

Pinned by the checker and lowering public-seam cases; positive/scalar-subobject-zeroed-assignment; negative/immutable-scalar-zeroed-assignment, negative/inferred-zeroed-not-enabled, and negative/nested-scalar-zeroed-not-enabled; positive/struct-array-field-element-zeroed; positive/struct-literal-array-field-forms; negative/struct-array-field-element-zeroed-immutable; negative/struct-array-field-element-zeroed-nested; runtime/scalar-subobject-zeroed-assignment-clears-values; and runtime/scalar-subobject-zeroed-computed-index-traps on Linux x86-64.

D43 — A scalar named return gives complete zeroed assignment its context

The tour said that a named return is a writable place [1800], that return carries the value previously assigned there [1810], that every return path must assign it [0930], and that zeroed takes the all-bits-zero image of its context [0540]. D41 supplied assignment context only from mutable local and module bindings, while D42 treated their immediate scalar subobjects separately.

Chosen: zeroed may be the complete right-hand side of assignment to a scalar named return. The return's declared type must resolve, through every representable alias, to an enabled scalar and supplies false for bool or typed zero for every enabled integer. The ordinary place check still runs before the right-hand side, and successful ordinary assignment establishes the named return for [0930]'s definite-assignment check.

Lowering reuses the named return's existing frame-slot Store path with D10's existing false Truth or typed zero Number. The explicit or implicit return then uses its ordinary load and Leave. No new scalar value form, temporary, IR operation, verifier rule or backend path is introduced.

D39--D42's initializer, binding and immediate-subobject contexts remain unchanged. Immutable and invalid destinations retain the ordinary place refusals. A named- return subobject is not admitted by this rule; aggregate named returns are not an enabled value context and remain a separate future question. Inferred initialization and every nested, argument, return-expression, operand, discard or other general zeroed expression remain refused.

Why the named-return type: the return place already owns the type and storage that the contextual literal needs. Its ordinary assignment is also exactly the flow event [0930] requires, so a special return initialization rule would duplicate both storage and definite-assignment semantics.

The alternative: make zeroed an independently inferred scalar value usable by any return-related expression. That would erase the complete-right-hand-side boundary and broaden general scalar values well beyond the evidence. It was declined.

Pinned by the checker and lowering public-seam cases; positive/named-return-zeroed-assignment; and runtime/named-return-zeroed-reads-zero on Linux x86-64.

D136 — Fixed-array bounds use a closed target-independent fold

The tour said that an array's length is a compile-time value [0370], that its size is part of its type [0520], that fixed parameters are compile-time [1290], and that parameterized types use substitution rather than execution [1350]. Prototype 3 wrote [64 * 1024]u8. None said which expressions could supply a bound or whether accepting a call there would execute user code.

Chosen: the syntax between an array type's brackets is an expression. Its fixed meaning is deliberately closed: integer literals, references to fixed formals, parentheses, unary -, and the non-wrapping arithmetic +, -, *, / and %. These operations use mathematical integer answers within the widest enabled integer magnitude; they do not acquire an operand width from a host or target. Every intermediate answer must remain in that range, division or remainder by zero is impossible under [1950], and a negative final answer is refused. When source legality otherwise admits the bound, the folded answer is D17's canonical element count and D18 checks its target byte extent exactly as it does for a literal bound. A final answer of zero is accepted: [0]T and any admitted fixed expression that folds to zero denote D17's canonical zero-element shape. Its size is zero, its alignment is one, and the ordinary rules for its context still apply; in particular this does not add empty literal syntax or make repetition valid in a context whose length is zero.

A boolean or a comparison/logical result is not an integer count. Wrapping, bitwise, complement and shift operations need an operand width and are not in this target-independent fold. A runtime or storage name is not a fixed formal; a type formal or another non-value name is diagnosed as such rather than called runtime storage. A call is syntactically valid in the brackets but is not a fixed expression: the compiler rejects it and never executes its body. No other expression form is admitted, and an implementation becoming better at ordinary constant folding does not enlarge this set.

The same evaluator handles a direct bound and an alias-template bound such as [n * 2]t. During symbolic template validation an unknown fixed formal remains unknown; during an application its substituted value is folded locally. Before a nested template application can inherit an application origin, the nested template is validated on its own. An unconditional inner defect is therefore reported once at the inner declaration regardless of declaration order. Only a failure that depends on substitution is primary at the application and relates the failing template expression, so two bad applications remain distinct. No instantiation writes a value, type or shape onto the template syntax, and fixed actuals in a type application remain D135's integer literal or forwarding fixed formal rather than growing a second expression grammar in argument position.

Why a closed mathematical fold: executing a helper would contradict [1350] and make compile-time effects possible. Reusing the ordinary target-width fold would make type identity depend on a selected target before D18 asks its layout question. Admitting whatever an optimiser happens to fold would move source legality between compiler versions. All three were declined.

Pinned by the parser, checking and lowering public-seam cases; positive/fixed-array-bound-expression and positive/fixed-array-bound-zero; negative/fixed-array-bound-call, which contains a valid user call whose body is never run; negative/fixed-array-bound-invalid; the generated lexical, construct and IR records; and runtime/fixed-array-bound-expression and runtime/fixed-array-bound-zero on Linux x86-64.

D141 — An empty slice uses the lowest aligned non-null base

The tour said that an empty slice has a canonical aligned address, is not null, cannot be dereferenced, and yields that base through base_of [0580]. It did not select one aligned address.

Chosen: the numerical address equal to the element alignment: one for a byte-aligned element, four for an ordinary u32, and so on. It is the lowest positive aligned address, depends only on target facts and element layout, and therefore remains stable across compiler runs without reserving real storage. The zero length is checked before any address arithmetic, so the address is never accessed.

The alternatives: a compiler-owned static sentinel, one sentinel per type, or any implementation-selected aligned nonzero pattern. A static symbol makes the observable integer address link-dependent; per-type sentinels add storage and identity with no language value; an unspecified pattern contradicts canonical once pointer-to-integer conversion can observe it.

Pinned by runtime/r250-references, the empty-slice IR verifier path, and the Linux x86-64 backend's target-derived empty-base emission.

D161 — Byte-context text is a pooled read-only datum and slice

The tour said that [0260]'s text literal takes utf8, []u8, utf16 or cstring from context, defaults to utf8, lives in read-only storage and carries an uncounted trailing NUL. [0270] closed its escape set and separated byte escapes from codepoint escapes. It did not state whether one literal context could be enabled before the text types, whether equal literals share an object, or which stage owns malformed spelling.

Chosen: the kernel admits a quoted literal only where a direct context supplies read-only []u8. Its unescaped source content must be shortest-form UTF-8; \n, \r, \t, \e, \\, \", \' and \xNN decode to bytes, including an arbitrary byte from \xNN. A well-formed \u{...} is text rather than bytes and is L0301 in this context. A literal with no context still defaults to the deferred utf8 and is L0304; utf8, utf16, cstring and their codepoint representation remain later text work at this decision. D181 supplies them.

Malformed UTF-8 source content or an unknown, incomplete or nonscalar escape is lexical L0320 at the offending run. The scanner first retains the complete escape-aware token, so an escaped quote cannot close it; the shared decoder then validates every token before configuration can hide a declaration. An unclosed token remains L0014. The parser retains one text node and its source span, and checking supplies its complete immutable []u8 reference descriptor.

Lowering decodes the content into one anonymous target-neutral fixed array of u8, appends one zero byte, marks the datum read-only and constructs each literal value as its base address plus the decoded length. Equal decoded byte sequences throughout the program use one datum, even when their source escape spellings differ; this identity is observable when their element addresses are converted to integers. Module values carry the same datum relocation and length as a static slice image. Anonymous datums are registered before item bodies are filled and completed in item order afterward, preserving the IR's contiguous-run invariant. The Linux backend emits them in .rodata; no text opcode, runtime initialization or writable copy was added.

The alternatives: enable utf8 and codepoint decoding at the same time, make a literal a fixed [N]u8, synthesize a writable copy in each context, give equal occurrences distinct storage, omit the trailing NUL, or let the checker and lowering each interpret escapes independently. Those choices either pull [0600]'s indexing and representation questions into this slice, lose [0260]'s contextual carrier or read-only promise, duplicate flash on the small targets the language preserves, contradict the stated C boundary, or permit two compiler stages to disagree about the bytes. All were declined.

Pinned by runtime/text-literal-bytes, negative/text-literal-codepoint-in-byte-context, negative/text-literal-malformed-codepoint-escape, negative/text-literal-needs-byte-slice, negative/text-literal-needs-read-only-slice, negative/text-literal-short-byte-escape, negative/text-literal-unknown-escape, negative/text-literal-write, the lexer and backend cases, and the source.lexical and text.literal-storage guarantee rows.

D181 — Hosted text views retain identity over pooled encoded storage

The tour said that [0600]'s utf8, utf16 and cstring are distinct views over []u8, []u16 and ptr u8; that [0260]'s quoted and [0280]'s raw literals take one of those contexts and default to utf8; and that [0270] separates byte escapes from Unicode scalar escapes. D161/D164 had enabled only the direct []u8 contexts. The tour did not settle whether representation identity could leak through structural generics, whether the terminator was a byte or an element, or how static pointer images name pooled data.

Chosen: the kernel admits quoted and raw literals in direct utf8, utf16 and cstring contexts and makes contextless literals utf8. Each is a canonical immutable reference identity distinct from the other two and from its backing pointer or slice type. That identity is carried by parameters, results, struct fields, control joins, exact generic actuals and evidence descriptors. Binding mutability remains separate and cannot grant write permission through a text view. Literal storage has static origin, so a literal may be returned without inventing a parameter-derived origin.

Unescaped source is validated as shortest-form UTF-8. In a text context, \u{...} must name one Unicode scalar value and is encoded as shortest-form UTF-8 for utf8 and cstring, or as one UTF-16 code unit or surrogate pair for utf16. The simple [0270] escapes denote the corresponding scalar values. \xNN remains exclusive to D161's byte-slice context, and \u{...} remains excluded from it. Raw content has no escapes: after D164's indentation rule, its validated UTF-8 scalars are retained for utf8/cstring or transcoded to UTF-16. Malformed source and escape spelling retain L0320/L0323; a valid escape used in the wrong context is L0301.

Lowering pools decoded content by element width. Equal UTF-8 byte sequences may therefore share one u8 datum across []u8, utf8 and cstring, while a UTF-16 sequence names a separate u16 datum. Exactly one zero element follows every datum. A slice image excludes it from its code-unit length; cstring carries only the base address. Module and aggregate images hold verified data relocations, including cstring fields, and the Linux backend emits every pool entry in read-only storage. No runtime initialization or text-specific opcode is introduced.

Literal construction establishes valid encoding, so every pooled cstring remains shortest-form UTF-8. D199 separately admits foreign C-text values whose only text-specific pointer precondition is accessible read-only backing through the first NUL byte. Such a value is not prevalidated UTF-8 merely because it has cstring identity: byte conversion scans its extent without decoding, while conversion to utf8 and scalar traversal validate. This distinction does not permit an ordinary pointer to acquire cstring identity.

This decision does not inherit operations from a representation. lenof continues to expose the existing slice length for utf8 and utf16, but integer or position indexing remains [0610]'s separate work. Range slicing and collection traversal likewise require their own text operation or evidence instead of treating a hosted view as an ordinary slice. Existing byte-slice literals, ranges, arrays, origins and evidence behavior are unchanged.

The alternatives: erase each view to its backing reference, give each occurrence distinct storage, count the terminator, store a cstring as a slice, accept byte escapes as Unicode scalars, or enable integer indexing with the representation. Those choices lose declared identity, duplicate read-only data, contradict [0260]'s length and C boundary, admit invalid text, or decide [0610]'s linear codepoint semantics without its own evidence. All were declined.

Pinned by runtime/hosted-text-views, retained byte-literal runtime fixtures, negative/cstring-literal-write, negative/text-literal-codepoint-in-byte-context, negative/text-view-byte-escape, negative/text-view-identities-are-distinct, the decoder, IR verifier and backend cases, and the source.lexical and text.literal-storage guarantee rows.

D182 — UTF-8 index type selects ordinal scan or direct position

Result superseded by D249 and D259. The two operations, their evaluation order and their traps stand. D249 replaced the []u8 result with the decoded u32; D259 replaced the exact u32 ordinal argument with usize. The reasoning below is retained as history, and the fixtures it names were reshaped or renamed by those decisions.

The tour said that [0610] gives utf8 two indexing conformances: an integer selects one codepoint by ordinal with a linear scan, while a position selects in O(1), and either returns that codepoint's bytes. [0600] had already made core/text.position an opaque byte offset for parser support. It did not say which integer type is exact, what happens at an invalid ordinal or byte position, which origin and permission the returned bytes have, or whether the operation reaches other text identities through their representations.

Chosen: utf8[u32] counts Unicode scalar values from zero by decoding their shortest-form leading-byte widths. An untyped integer literal in this position receives u32; every other integer value is L0301 rather than an implicit conversion. utf8[core/text.position] reads the exact public opaque position identity supplied by the repository-owned module and uses its byte offset without scanning the preceding text. A same-shaped nominal type is not that position. The source expression is evaluated and retained once before the index or position expression.

Both forms produce an ordinary read-only []u8 containing exactly the one to four encoded bytes of the selected codepoint. The slice excludes D181's terminator and derives from the complete utf8 source, so mutation is L0303 and returning it requires the ordinary exact from source declaration. An ordinal equal to or beyond the codepoint count traps. A position at the byte length or on a UTF-8 continuation byte likewise traps; only an in-bounds leading-byte boundary names a codepoint. These are [1950]/[1960]'s synchronous checked-address failures, not declared atom errors.

Lowering expresses both operations with existing target-neutral scalar comparisons, backward CFG edges, checked slice addresses and an ordinary slice result. It introduces no text opcode, allocation, writable alias, new datum or evidence-table representation. utf16 and cstring do not acquire indexing, and text slicing and traversal remain separate work. D181's validation, identity, pooling, terminator, origin and literal-error rules, plus existing array, byte-slice, range and evidence behavior, are unchanged.

The alternatives: take usize because arrays do (adopted later by D259 when the width limit became clear), accept every integer, expose a raw byte for position indexing, scan positions from the start, return u32, include the terminator, inherit indexing through every text carrier, or report a declared error. Those choices contradict [1270]'s written u32 conformance, introduce implicit conversion, disagree on the two result types, erase the promised O(1) operation, lose the encoded-byte view, expose storage outside the text, or make one checked-address failure unlike all other indexing. All were declined.

Pinned by runtime/utf8-indexing, runtime/utf8-ordinal-out-of-range-traps, runtime/utf8-position-at-end-traps, runtime/utf8-position-not-boundary-traps, negative/utf16-indexing-is-not-utf8-indexing, negative/utf8-index-needs-usize-or-position, negative/utf8-index-position-identity-is-exact, negative/utf8-index-result-is-not-a-place, negative/utf8-index-result-has-no-address, retained hosted-text and byte-slice/range fixtures, the generated IR record, and the text.indexing guarantee row.

D183 — Text ranges preserve identity at scalar boundaries

The tour said that [0570]'s range selection copies no elements, [0600] makes utf8 and utf16 distinct length-bearing views whose lengths count code units, and cstring carries no length. D181 kept range selection separate so the backing slice did not leak accidentally. It did not say which text identities have ranges, which type names their endpoints, how an endpoint interacts with a multibyte or surrogate encoding, or what identity, permission and origin the result retains.

Chosen: the exact utf8 and utf16 identities admit lower..<upper and lower..upper; cstring does not. Both endpoints are exact usize code-unit offsets, receiving that context when written as integer literals. A utf8 offset counts bytes and a utf16 offset counts 16-bit code units. No other integer type converts implicitly.

Both endpoints must be Unicode-scalar boundaries. For UTF-8, an in-bounds boundary is a shortest-form leading byte, never a continuation byte. For UTF-16 it is any non-low-surrogate code unit, including the high surrogate of a valid pair. The half-open form requires 0 <= lower <= upper <= lenof source; the length itself is a valid boundary, so an empty view at the end is valid. The inclusive form requires 0 <= lower <= upper < lenof source, and includes the whole scalar beginning at upper: one to four bytes or one to two UTF-16 code units. It never returns half a scalar. An invalid ordinary bound or a split-scalar endpoint traps synchronously through [1950]/[1960]'s checked-address mechanism and declares no atom error.

The result retains the source's exact utf8 or utf16 identity, immutable permission and complete source-derived origin. Binding mutability cannot make it writable, returning it requires the ordinary exact from source, and it cannot satisfy the other text identity or its ordinary backing-slice type. The source expression is evaluated and retained once, then the lower and upper expressions are each evaluated once in written order [0410].

Lowering copies the source's base/length carrier into temporary storage before either bound, applies the existing ordinary range check, classifies the two encoded boundaries with target-neutral scalar comparisons, and emits an ordinary base/length result. Inclusive selection advances its physical upper end by the selected scalar width. No text opcode, allocation, new datum, writable alias or evidence entry is introduced. D181's validation, pooling, terminator and literal errors, D182's indexing, and existing ordinary slice/range/array/evidence behavior remain unchanged. Collection traversal remains separate.

The alternatives: expose []u8/[]u16, admit cstring, use u32 codepoint ordinals, inherit ordinary range behavior without boundary checks, make inclusive upper select one physical code unit, or report a declared encoding error. Those choices erase the declared view, require a length that does not exist, turn constant-time code-unit slicing into scans, construct an invalid text value, split a scalar, or make the same checked-address failure recoverable only for text. All were declined.

Pinned by runtime/text-range-slicing, runtime/utf8-slice-lower-not-boundary-traps, runtime/utf8-slice-upper-not-boundary-traps, runtime/utf16-slice-not-boundary-traps, negative/cstring-range-slicing-has-no-length, negative/text-slice-needs-usize-bounds, negative/text-slice-result-keeps-identity, negative/text-slice-result-is-read-only, negative/text-slice-result-keeps-origin, retained D181/D182 and ordinary slice/range fixtures, the generated IR record, and the text.slicing guarantee row.

D184 — Hosted text traversal decodes scalar Items

The tour said that [0600]'s hosted text types are distinct views and that traversal is [1320]'s concept operation [1150]. D181 kept traversal separate from each backing carrier, and D183 again preserved that boundary after range slicing. The tour did not say which text identities traverse, whether an Item is an encoded unit, encoded view or Unicode scalar, which cursor identity is exact, where a C string ends, or how validation, origin and provider order apply.

Chosen: each exact utf8, utf16, and cstring identity has one closed intrinsic conformance to [1320]'s first, at_end, item, and next contract. It is a direct language realization like the existing range and storage traversals, not a source-declared evidence row: it neither searches nor changes the ordinary conformance register, and an ordinary []u8, []u16, or ptr u8 does not inherit it. The exact Cur type is usize, kept privately as a physical code-unit offset. The exact Item type is u32, the same Unicode scalar identity as [0250], copied immutably into the loop binding with no reference origin.

For utf8 and cstring, Cur counts bytes and item decodes one shortest-form UTF-8 scalar. For utf16, Cur counts 16-bit code units and item combines a surrogate pair when present. next advances by the decoded scalar's one-to-four bytes or one-to-two UTF-16 code units. The optional loop index remains [1150]'s scalar ordinal: it begins at zero and advances once with next, independently of Cur's physical increment. utf8 and utf16 end at their retained lengths. cstring ends before the first zero byte, whether that byte is an embedded U+0000 or D181's trailing terminator; the zero is never an Item.

The complete source expression is evaluated and retained once before first. Every test calls at_end; false calls item before the body; fallthrough and continue run cleanup and then next; break runs cleanup and skips next. This is D180's provider order exactly, without observable provider-expression evaluation because the four implementations are intrinsic. The retained text source stays immutable and keeps its complete origin until traversal ends.

D181 validation and D183 boundary-preserving slices make every reachable utf8 or utf16 encoded unit sequence valid. A pooled literal cstring is valid for the same reason. D199's foreign cstring boundary, however, promises only accessible backing through the first NUL. Its intrinsic traversal validates each shortest-form UTF-8 scalar before decoding it and traps synchronously on malformed, truncated, surrogate or out-of-range encoding, including inside unchecked; a continuation equal to NUL is rejected before any later byte is read. The operations still declare no atom error. A missing terminator or stale storage violates [0430]'s pointer validity non-guarantee rather than becoming a text error. Lowering uses ordinary target-neutral scalar loads, comparisons, conversions, arithmetic, checked traps and CFG. It introduces no text opcode, allocation, datum, mutable alias or evidence-table entry. D181--D183 pooling, terminators, identities, indexing, slicing, permissions and origins remain unchanged, as do range, array, slice and declared-evidence traversal.

The alternatives: traverse only the length-bearing identities, expose encoded u8/u16 units or codepoint byte slices, use core/text.position for one view, scan cstring past NUL to the pooled datum's unobservable end, let a user conformance replace the built-in semantics, or report decoding atoms. Those choices respectively lose the C text boundary, make one source character take several iterations or give two Item types, confuse the parser's public byte position with an intrinsic cross-encoding cursor, contradict NUL termination, make direct text traversal module-dependent, or add a recoverable failure after validation already made it impossible. All were declined.

Pinned by runtime/hosted-text-traversal, negative/text-traversal-item-is-read-only, negative/text-traversal-ordinary-pointer-is-not-cstring, retained D181--D183 and range/array/slice/evidence fixtures, the generated IR record, and the text.traversal guarantee row.

D249 — A UTF-8 index decodes the codepoint it selects

The tour said that [0610]'s two indexing operations each return the selected codepoint's bytes as a []u8, and D182 made that a read-only view with the source's origin. The same tour writes a character literal as a u32 [0250], and D184 made every scalar a traversal yields a u32. So s[i] and the ith scalar of for c in s were different kinds of value, s[0] == 'T' was refused as a comparison of a slice, and addr s[0] was accepted as a pointer to a slice descriptor that no storage held. Lowering could not form that pointer, and the IR verifier stopped the compilation as an internal defect.

Chosen: both operations decode the selected scalar and produce it as a u32, with no reference, permission or origin. D182's argument rules, evaluation order and traps are unchanged: u32 scans codepoint ordinals linearly, core/text.position reads its byte offset in O(1), and an absent ordinal, the end position or a continuation byte traps. The indexed scalar is a value, not a place. addr s[i] is L0337, and an assignment, inc, dec or inout argument through s[i], including one reached by indexing further, is L0303, each saying that the index decodes a value. The encoded bytes of one codepoint are D183's one-scalar inclusive range, which keeps utf8 identity and copies nothing.

D259 later changes the exact ordinal argument to usize; the decoded result and position form remain as chosen here.

Lowering checks the selected leading byte's address, lets its class fix the width and its payload mask, then folds six bits from each continuation byte in one loop shared by every width, with masks and shifts rather than D184's biased products, which Cortex-M0 widens to a 64-bit multiply call. D181's validation is what makes every continuation byte in a utf8 valid, so those reads add no check. There is still no text opcode, allocation or evidence-table representation.

The alternatives: keep the slice result and refuse addr of it, the same refusal a range selection already gets; give the usize byte index a u8 result, so that utf8 indexes like []u8; or return a one-codepoint utf8. The first repairs the defect and leaves the two scalar types. The second counts bytes where [0610] counts codepoints, and would drop the ordinal indexing retained position D1 keeps. The third makes a codepoint text, so it compares with text.eq rather than with a character literal. All were declined.

Pinned by runtime/utf8-indexing, runtime/utf8-ordinal-out-of-range-traps, runtime/utf8-position-at-end-traps, runtime/utf8-position-not-boundary-traps, negative/utf8-index-result-has-no-address, negative/utf8-index-result-is-not-a-place, negative/utf8-index-needs-usize-or-position, runtime/core-mem-initialized-objects, runtime/core-tree-indices, runtime/text-range-slicing, runtime/derived-containers, and the text.indexing guarantee row.

D259 — UTF-8 ordinal indexes span the text view

The earlier decision said that D182's exact u32 ordinal keeps [1270]'s written conformance and distinguishes it from the opaque byte position. But D181 permits a validated utf8 view with a usize byte length, and D183 and D184 use usize positions to reach its full extent. On a 64-bit target, 4,294,967,297 ASCII bytes form a valid view whose final scalar has ordinal 4,294,967,296. A u32 index cannot name it.

Chosen: the exact ordinal argument of utf8 indexing is usize. An untyped integer literal receives usize context; another integer type, including u32, is L0301 without an explicit conversion. The scan's counter and requested ordinal use usize, so every scalar of a view whose byte length is representable by usize has a representable ordinal. The counter advances only after an in-bounds leading byte; it cannot wrap before the end of a valid view. The core/text.position byte-offset form, decoded u32 result, evaluation order and checked-address traps stay as in D182 and D249. On a 32-bit target, usize remains 32 bits and matches the view's length domain without widening the machine representation.

The alternatives: retain u32 and cap utf8 views to that many scalars, or accept both u32 and usize ordinals. The cap would reject an otherwise valid byte view on 64-bit targets. Two ordinal types would add a conformance and make the same indexing operation depend on overload selection. One exact target-sized argument keeps the existing rule that the index type decides the operation and follows the view's representable size.

Pinned by runtime/utf8-indexing, runtime/utf8-ordinal-out-of-range-traps, negative/utf8-index-needs-usize-or-position, and the text.indexing guarantee row. Large-view reachability follows from the type domains; the fixtures do not allocate a multi-gigabyte view.

D250 — A range selection is a view, not a place

The tour said that [0570]'s range selection is a view, a pointer and a length that copies nothing, and the grammar's place is any indexed form, which includes a range selection. [1900] lists what may be written and does not name one. The checker accepted view[0..0] = other and inc a[0..<2], and lowering, which has no storage for a view that no binding holds, stopped the compilation as an internal defect. inout already refused the same selection as a temporary value.

Chosen: a range selection is not a place. An assignment, compound assignment, inc or dec whose target is one is L0303, saying that the range is a view. An element indexed through a range remains an ordinary place, with the write permission of the view it selects from, so view[1..<3][0] = 20 writes the storage behind view. The grammar is unchanged; this is a checking rule, as the writability of every other indexed form is.

The alternatives: copy the right-hand side's elements into the selected range, or rebind the view. The first is a hidden loop, with a length check and an overlap question, behind the syntax of a scalar store; the second replaces a view that no binding holds, so nothing could observe it. Both were declined; a copy stays the explicit loop or library call it is today.

Pinned by negative/range-selection-is-not-a-place and runtime/range-selection-element-is-a-place.

D209 — Numeric array arithmetic retains values before scalar loops

The tour said at [0590] both that comparisons were element-wise and that array equality returned one bool. D200 had already refused array comparisons. It also wrote a reduction name without defining a builtin or an ordinary body.

Chosen: keep D200's comparison refusal. Lift binary +, -, *, / and unary - over fixed arrays of enabled integer or float elements, and %, +%, -%, *% over integer elements only. Two arrays have exactly equal lengths and element types. An array and a scalar of its element type, in either order, produce that array type; literal context reaches the scalar element. There is no length-one array broadcast, implicit conversion, nested array arithmetic, bool arithmetic, bitwise/shift lifting or slice arithmetic. An empty array still checks both operand types and evaluates its operands, but runs no element operation.

Operands are evaluated exactly once, left to right. Each array operand is a complete retained value before the next operand is evaluated. The operation then visits ascending indices, applying the corresponding scalar semantics, including overflow traps, wrapping, division failures and IEEE values. An assignment evaluates its destination first and cannot overwrite an operand snapshot. Compound arithmetic assignment evaluates its place once, retains the old array value, then evaluates the right operand and applies the same rule. This does not change [0520]'s direct formation of a written array literal. Known-operand refusals still apply where the scalar rule requires them. Retaining an operand's value does not require copying it when its storage remains stable through the other operand's evaluation and the scalar loop. When that storage is disjoint from the destination, the loop may write the destination directly; an overlapping or effectful case still preserves the retained values.

No reduction builtin is added. [0590]'s sum_four is an ordinary function whose positive-zero initial value and left fold specify the rounding order. The compiler emits compact scalar loops, not one instruction or compiler metadata record per array element. Storage for a separate result and necessary snapshots is real; a 16 KB array does not fit for free on a 32 KB device.

The alternatives: mask-valued comparison, implicit whole-array equality, length-one array broadcast, per-element code expansion, or snapshot-free arithmetic into an overlapping destination. The first two contradict D200, the third hides a shape change, the fourth spends code and compiler memory in proportion to the bound, and the last changes by-value evaluation. All are rejected. SIMD and reassociated reductions are not required by this slice.

Pinned by the 4- and 4096-element programs generated from compiler/tests/quality/arrays.ldn.in and the numeric compactness checks in compiler/tests/quality/check.py, and by the arrays.arithmetic and arrays.element-traps guarantee rows, whose r450 fixtures pin the refusals, the operand snapshots and the element order of every trap.

D240 — Fixed arrays are the vector type, and the atomic wrapper is a library's

The tour said that the compiler module reaches the atomic and vector intrinsics [1560] and that the standard library wraps the atomics into a pleasant type [1620]. The note on a compiler.vector_* reference said the baseline code-generation work enables it; that work implemented D209's element-wise operators over fixed arrays instead and never enabled an intrinsic.

Chosen: the vector intrinsics are withdrawn. [0590] already makes fixed arrays the vector type, and a second spelling of the same operation is the second vector shape [0590] was written to refuse. A compiler.vector_* reference keeps its L0203, and its note now says it is withdrawn and points at element-wise operators. The wrapper type is transferred to the Broader standard library successor, which [1620] now names. Cortex-M0 refuses every read-modify-write atomic (D227), so a wrapper portable across the three targets would offer only loads, stores and fences there, and which operations a wrapper exposes is a design question for the program that needs one. No derived program or core module needed one: the driver uses core/cpu's interrupt masking and D227's barriers.

The alternatives: compiler.vector_* as aliases of the operators was declined as two spellings of one operation. A core/atomic wrapper now was declined: it has no consumer, and on the smallest target it would be a type whose operations change with the target. Leaving [1620]'s sentence as a promise with no owner was declined because [1830] and the construct inventory refuse an unowned promise.

Pinned by negative/r720-vector-intrinsic-withdrawn, runtime/r450-array-arithmetic-composition, negative/r630-m0-rmw and runtime/r630-memory-scalars.

DECISIONS: DECLARED TYPES, RANGES AND LAYOUT

The types a program declares for itself, and what a target may do with their storage.

D15 — A type declaration without distinct is an alias

The tour said that types are declared like any other value with type [0120], and that distinct makes a type with the same representation, a different type and no operations inherited [0650]. It does not say what a declaration without that word gives.

Chosen: another name for the same type. meter: type = distinct f32 is the only form that makes a new one, and count: type = u32 leaves count and u32 one type: a value of either is a value of the other, everywhere, with no conversion. The evidence is the word itself: [0650] spells distinct explicitly, and a modifier that changed nothing would not be written. The tour reaches for it exactly where it wants two types that share a representation to stop being interchangeable.

What this does not decide: a struct or variant body introduces a type that is nominal, because there is no existing type for it to be another name for, and [0710] says a value typed as an anonymous struct "never becomes a same-shaped named type". That is a different sentence from this one and the later aggregate slices are where it is implemented.

The alternative: every type declaration introduces a distinct type, reading [0120]'s "like any other value" as a definition and treating distinct as emphasis. It is one rule instead of two, and it was declined because it makes distinct a word that does nothing. An alias that needs a conversion at every use is not an alias, so the language would have no way to give a type a second name at all.

Pinned by positive/type-declaration-aliases-a-scalar, runtime/r490-distinct-scalars and negative/r490-distinct-identity.

D188 — A range subtype is its base type constrained, checked where it is stored

D236 later records the composite, reference and generic positions refused below as [0660]'s permanent source-form boundary; their reports keep L0304 and now say so.

The tour said that [0660] declares percent: type = u8 range 0..100 and that it is checked at assignment and conversion. It did not say what type an operator over one gives, whether an alias of one keeps the bounds, whether the constraint is part of a signature, what a bound may be written as, what an empty range means, what zeroed gives a subtype that excludes zero, or what a range subtype means inside a struct, an array, a slice or a generic.

Chosen: a range subtype is its base integer type restricted to a run of that type's own values, and not a new type. percent and u8 have the same representation, the same width, the same operand rules and the same operator results, so p + 1, p & mask, -p and p >> 2 are u8 values, p < q is a bool, sizeof percent measures u8, and there is no constrained arithmetic and no constraint join rule. That is why [1730] names distinct types and range subtypes as two habits and not one: [0650]'s distinct is this rule's complement. D213 implements distinct identities; composing them with a constrained representation keeps the constrained compositions refused below, which D236 decides.

The base is written as a scalar name or a declared name whose alias chain reaches an enabled integer scalar; a float, a bool, a struct, an array or a pointer base is L0338. Both bounds are D136's fold — integer literals, unary minus and target-independent + - * / % — so u8 range 0..(200 / 2) is written and u8 range 0..300 is L0300 because u8 holds neither bound. A lower bound above the upper is L0306 rather than L0300: an empty range names no value, so there is no constraint to perform at all. Only .. is admitted; an exclusive upper bound in a type is a parse refusal, because the tour writes none. range is a contextual word [1760] does not reserve, recognized only after a parsed base type at a type declaration's right-hand side, so a binding, a parameter or a label spelled range keeps its ordinary meaning and [1760] still reserves forty-nine words.

The check happens where [0660] says and nowhere else: storing a value into a place whose declared type is the subtype — a local or module binding initializer, an assignment, a compound assignment, [1900]'s inc and dec, a call argument and a named return — and applying the subtype name to a value [0700]. All of them reuse D168's exact-range path. A value the compiler knows and the bounds exclude is L0300, which includes [0540]'s zeroed, because zeroed is the base type's all-bits-zero image and that image is the value zero. Every other value reaches one runtime check that traps at [1950]'s existing edge. A compound assignment's check sits on the statement and not on either operand, because what it stores is [0290]'s result in the base type. percent(x) is D168's conversion to u8 followed by that check, so a source u8 cannot hold traps at the conversion and one it holds but the bounds exclude traps at the constraint; [0310] gives the program no way to tell them apart. Extending [0700] to a declared name is part of this decision and fixes D15's alias as a side effect: count: type = u32 makes count(x) the conversion u32(x) is.

The check is elided, not merely optimised away, when the source already carries the proof: its known folded value is inside the bounds, or its own declared subtype's bounds lie inside the destination's. It is likewise not emitted when the value never arrives: an expression whose every edge returns terminates the flow, so a destination waiting on one has nothing to hold to the bounds and no reachable place to hold it in. That is [1730] made mechanical, and without it the habit would cost a check per hop. An alias declaration carries the constraint unchanged under D15, because an alias is the same type and the constraint is part of what that type is. The constraint is part of structural function-signature identity, so a (v: u8) -> none value does not fill a (v: percent) -> none slot and an indirect call cannot lose the check, and an inout or sink argument must be a place of that same subtype, because the callee may write any value the subtype holds back through it.

A preceding successful comparison on an ordinary integer is not a carried subtype proof. For example, fail invalid when n > 100 followed by p: percent = n handles an out-of-range u8 recoverably, but the store still emits its trapping subtype check. The comparison establishes a control-flow fact at that point; it does not change n's declared subtype or construct a percent value. Even when n cannot change between those statements, D188 does not promise to infer the fact from the guard. Such an inference would need a separate flow rule for which conditions imply each bound and when a write or alias invalidates the fact. [1730]'s check-once habit applies once a checked value carries its proof as a subtype or a distinct wrapper, and then subsequent transfers need no check. A compiler may remove the redundant check only when it proves that the value entering the store remains within both subtype bounds there, including across intervening writes and aliases; guard dominance alone does not establish that. Such removal is an optimization, not a language guarantee. This is an intentional limit for recoverable validation followed by range-subtype construction.

Six positions are refused by name, and together they are what makes the guarantee true rather than decorative, because each is a path by which an unchecked value could enter constrained storage: a struct field, a fixed-array element, a ptr/[] target, addr of a constrained place, an extern (c) signature whose named return Landin never assigns, and a generic type argument. The first four and the last report L0304 by name; the external signature is refused by [1580]'s existing hosted-scalar boundary and keeps that report. []percent and []u8 would be one slice type, so a []u8 write of 200 would enter constrained storage with no check; a generic instance would quietly make f(percent) mean f(u8). A module binding of a range subtype must have a value the checker's fold reaches [1940], because an image has no moment in which to trap.

The neutral IR carries this as one instruction with one operand, two folded bounds and a result type equal to its operand's. It is not the existing Conversion generalized: this one neither widens nor narrows, so it is one extension, two compares and one ud2 in the base type's own signedness, and it composes with a conversion rather than absorbing it. [1120]'s region does not remove this edge, because D187 removes only edges whose absence leaves a value the destination type holds, and a value outside the bounds is not one.

The alternatives: making an operator over a range subtype give the subtype would make every operator a checked one, which [0660]'s own "at assignment and conversion" excludes. Giving a range subtype its own Type_Kind would make it a second nominal identity beside [0650]'s and duplicate every scalar rule. Reserving range in [1760] would retire an ordinary name for a word the tour writes contextually. Admitting ..< would invent a spelling the tour does not write. Generalizing Conversion to carry arbitrary bounds would rewrite the backend's most delicate sixty lines and every recorded Conversion line for no new behaviour. Admitting a range subtype in a composite position without deciding how the check composes would make the guarantee decorative. Refusing an inout convention outright on a constrained parameter, rather than requiring the same subtype, would be less useful for no less work. All were declined.

Pinned by positive/range-subtypes, positive/alias-conversion, runtime/range-subtype-checks, runtime/range-subtype-store-traps, runtime/range-subtype-conversion-traps, runtime/range-subtype-update-traps, negative/range-subtype-literal-out-of-range, negative/range-subtype-known-value-out-of-range, negative/range-subtype-zeroed-excluded, negative/range-subtype-base-is-not-an-integer, negative/range-subtype-bounds-inverted, negative/range-subtype-bound-outside-base, negative/range-subtype-exclusive-bound, negative/range-subtype-in-a-slice, negative/range-subtype-struct-field, negative/range-subtype-address, negative/range-subtype-inout-must-match, negative/range-subtype-signature-mismatch, negative/range-subtype-external-signature, negative/range-subtype-generic-argument, positive/range-subtype-exit-before-the-check, runtime/control-expression-edges-keep-source-order, the generated lexical and IR records, and the subtype.range guarantee row.

D210 — Optimal placement is explicit, stable and strictly smaller

The tour said at [0750] that ordinary fields retain source order and that layout(optimal) may save padding. It supplied no deterministic algorithm, tie rule, nested-field unit or target-width overflow rule.

Chosen: preserve natural and C layout. For an explicitly optimal nominal struct, calculate the natural padded layout and a candidate formed by stable descending target alignment. Equal alignments retain source order. Use the candidate only if its final padded size is strictly smaller; otherwise retain the complete natural order and offsets. Every field offset is still indexed by source identity, and initializer expressions still run in written order.

A complete nested aggregate, array field or variant part is one placement unit. Array storage repeats its padded element extent without array-sized placement metadata; a variant keeps its existing internal tag/payload rules. Nested nominal fields use their own declared policies. Anonymous structs stay natural. Zero-size fields still honor alignment. Target byte arithmetic checks rounding and extents, including the selected target's object-size limit, rather than using the compiler host's pointer width. Only the selected layout must fit that object limit; an unrepresentable arithmetic intermediate is refused.

Optimal layout is not C layout, packed layout, a byte-order attribute or a calling convention. No optimization flag silently reorders an ordinary struct. The build report states the chosen offsets/order, padded natural and selected sizes, alignment and saved bytes; size equality reports zero saved bytes.

The alternatives: reorder all structs under size optimization, search every permutation, reorder equal-size candidates, or flatten nested fields and variant payloads. They respectively break source-order layout, spend compiler resources disproportionately, add gratuitous layout churn, or erase semantic subobject boundaries. Stable alignment buckets keep the policy bounded and useful on the 32 KB end of the target range.

Pinned by compiler/tests/quality/layout.ldn, the opt foundations target layout cases and the backend plans layout-consumer cases. Synthetic-32 cases are target-layout evidence, never native 32-bit execution evidence.

D213 — Distinct types have opaque identity and transparent representation

The tour said that [0650] preserves representation, creates a different type, and inherits no operations. Prototype 3 uses this for node_id and prototype 4 for file. D15 settled ordinary aliases but the implementation still refused the general form after hosted parity required it.

Chosen: name: type = distinct base creates one nominal identity. A parameterized declaration creates one identity per complete normalized actual tuple, including fixed actuals which do not affect its representation. An alias preserves that identity. Two declarations with the same base remain different, and neither is implicitly interchangeable with its base. The base may be any enabled represented type, including another distinct identity, arrays, ordinary or variant-bearing structs, atoms, references, callable values and erased values. A range-constrained representation retains D188's constrained-composition refusal, which D236 records as a permanent boundary.

name(value) constructs that identity from one value of its exact base. base(value) extracts that same base from a distinct value; an ordinary alias may name a structural base. These operations preserve bytes and do not invoke user code. A contextual literal receives the base's complete descriptor. An integer or float conversion is a separate explicit step: extracting a distinct u32 as i32 directly is L0301, while i32(u32(value)) states both operations. Copying, assignment, parameter passing and returning preserve the identity; arithmetic, comparisons, indexing, dereferencing, field selection and calls require an explicit extraction first. No representation field is visible in source. In particular, two values of the same distinct numeric type still inherit no arithmetic operation.

Generic deduction, signature identity, reference referents and conformance keys retain the nominal identity. A distinct type may declare its own conformance, and that conformance supports ordinary constrained and erased dispatch. It inherits neither a user conformance nor compiler-owned zeroable membership, so zeroed is not an implicit construction. Wrapping or extracting a reference-bearing value preserves the existing origin and escape facts; these conversions neither erase provenance nor extend backing lifetime.

Representation means the base's exact target size, alignment and byte image. The compiler stores an opaque nominal descriptor with one unnameable representation child and uses the existing native aggregate calling convention. This is an internal ABI classification, not an extra stored field or an inherited source operation. Foreign C signatures continue to require [1975]'s admitted boundary types. A distinct identity whose base is admitted there has the same C layout and SysV transport as that base; its nominal identity still governs Landin signature compatibility. A distinct array, slice, atom, ordinary Landin record or erased view remains outside C exactly when its base does. Static construction and extraction preserve D132's module images and [1940]'s folds; they introduce no startup code or compile-time execution of user functions. A type declaration is not itself a runtime value. Static Boolean extraction uses Boolean bounds; optional-null, numeric-pointer and C-string images retain the ordinary pointer construction and relocation rules. A module storage address remains outside [1940]'s known-value forms, and wrapping it does not change that existing boundary.

The alternatives: accepting distinct as an alias would erase the property for which both prototypes use it. Rewriting source uses as ordinary named wrapper structs would leave [0650] unimplemented and expose fields the construct does not promise. Inheriting base operations or conformances would contradict its third sentence. A universal scalar identity rewrite is unnecessary when an opaque nominal identity already carries complete nested layout and generic keys.

Pinned by runtime/r490-distinct-scalars, runtime/r490-distinct-generic-representations, runtime/r490-distinct-generic-dispatch, runtime/r490-distinct-module-images, abi/r490-distinct-c-roundtrip, runtime/r490-review-generic-distinct-bool, runtime/r490-distinct-generic-bool-images, runtime/r490-distinct-generic-pointer-images, runtime/r490-generic-fixed-conversion-discovery, runtime/r490-generic-distinct-float-images, runtime/r490-generic-nonreading-measurements, negative/r490-distinct-no-inherited-length, negative/r490-distinct-float-static-field, negative/r490-distinct-type-value, negative/r490-distinct-alias-type-value, negative/r490-distinct-generic-type-value, negative/r490-distinct-generic-formal-type-value, negative/r490-distinct-discard-type-value, negative/r490-distinct-static-address, negative/r490-distinct-identity, negative/r490-distinct-no-operators, negative/r490-distinct-exact-base, negative/r490-distinct-no-fields, negative/r490-distinct-zeroable, negative/r490-distinct-origin, negative/r490-distinct-reference-identity, negative/r490-distinct-conformance, negative/r490-distinct-generic-identity, negative/r490-distinct-c-array, negative/r490-distinct-module-cycle, negative/r490-distinct-slice-cycle, and the IR unit case "atom images retain their declared set" in compiler/ada/tests/src/landin-tests-ir_suite.adb.

D228 — A packed image holds bits; extraction produces a validated value

The tour said [0730] fixes explicit positions and encodings, including holes, and [0740] forbids field writes through a volatile pointer. It did not say whether a hardware image containing an unnamed pattern was a language value, whether copying it inspected every field, or what an exhaustive match could assume. D227 deliberately left those questions here.

Chosen representation: a layout(packed) struct is a nominal raw image. Every stored bit belongs to the image, including omitted bits; there is no padding whose contents the compiler may discard. Positions are inclusive, numbered from the least significant bit of the unsigned carrier. All fields write at, positions are disjoint and in 0..63, and declaration order does not choose positions. The smallest carrier that covers the highest position is u8, u16, u32 or u64. layout(packed, u32) explicitly retains all 32 bits, even when the highest named bit is lower. Size and alignment come from that carrier in the selected target description. This implementation contract is little-endian; a different byte order requires a separate target decision. A storage layout does not establish a permitted device transaction width.

A packed boolean occupies exactly one bit. u1 through u64 are unsigned field representations whose written width equals the occupied range; a nonstandard width is admitted only directly in a packed field or its fixed array element. Extraction yields the smallest enabled unsigned scalar that holds it. This introduces neither general u12 arithmetic nor a u12 ABI. u1 yields u8 values 0 or 1; it is distinct from a boolean flag and does not add implicit boolean conversions. Requiring every one-bit field to be bool was an alternative, but would make numeric hardware fields change their value domain merely because of their width. Signed, floating, pointer, callback, nested aggregate and variant fields are not this representation. An array occupies count times element width, element zero at the low end. It is nonempty and fits the one carrier. The described set(X) generator form expands encoded bit numbers to named boolean fields; it is not a new runtime representation. The enabled kernel accepts the explicit boolean expansion, including the prototype-derived flag fixture, and does not yet provide the automatic set(X) or generated-register surface. A containing image adds the field-range base to each expanded bit. This fixes the representation contract without implementing general generation. An indexed operation checks the index before selecting bits. Its check stays in unchecked: an out-of-range bit selection has no computed byte address, and target-specific shift masking is not D187's removed-address-check result.

(internal = 0 | external = 1 | pll = 4) associates distinct unsigned fixed encodings with distinct atoms. Its width is at least one bit and otherwise the smallest width containing every encoding. An explicit base, as in u4 (internal = 0 | external = 1), can widen it. A field may give an encoded union additional bits; those additional patterns remain unnamed. Encodings belong to the union, not to an atom globally. The same atom may have a different encoding in another packed field. Outside an image, the value is still the ordinary atom identity with the existing software representation and calling convention. Encoding is not an implicit integer conversion. Compile-time type arguments retain the encoding map and declared width, including nominal/routine instance keys and conformance lookup. Unions with the same atoms but different maps cannot share a packed instance or silently select the other representation's evidence. Ordinary atom-value assignment, matching and equality still compare declaration identities, not encodings.

Raw and validated operations: every carrier pattern is a valid raw image. A whole-image copy, assignment, argument or return preserves all bits and never extracts fields. zeroed produces an all-zero raw image, even when zero is an unnamed encoding in one of its fields. This does not make a standalone atom set zeroable: [0540] still requires writing a named value. A direct encoded-field or encoded-array assignment also requires validated values; zeroed can clear the complete image or supply a raw constructor field/fill, but cannot manufacture an atom through such an assignment. A packed constructor builds a fresh zero image, evaluates labels in source order, then copies the resulting image into its destination. Unclaimed bits and fields supplied by a zeroed fill remain zero. Named fields still obey the existing label/fill completeness rule. A shared nonzero fill is evaluated once. This fresh-image construction is specific to packed images; D29's incremental ordinary-struct assignment and D214's ordinary fill ordering remain unchanged.

Reading a field extracts its bits. Booleans and unsigned fields have no holes. An encoded field checks membership before producing an atom identity; an unnamed pattern traps, including when the expression is discarded or is inside unchecked. Assigning a named atom inserts that union's encoding; an unsigned insertion checks the field width and traps if it does not fit. A known non-fitting value is a static diagnostic. Neither case truncates silently. A field insertion preserves every other bit, including holes in other fields. Copying a packed array as an array value extracts its elements; a whole image copy does not. Packed field extraction is not a static module initializer operation: L0305 requires a runtime extraction, even if a raw constant image is available. Static whole-image copies remain allowed; a module initializer cannot silently create an invalid ordinary enum array. Type/length measurements do not extract values. Array assignment snapshots its source elements before inserting them so that overlapping image storage does not corrupt the source of later elements. Fields have no independently addressable storage: addr, slices and inout cannot expose a packed field's byte address. Pass the containing image to update an indexed field.

Matching and equality on extracted enum values use atom identities. An exhaustive match covers validated members; it does not prove that all hardware patterns are members. The raw-image boundary remains observable before the match. Whole-image comparison, when performed through its unsigned carrier, compares all stored bits, including reserved bits; field equality is not a substitute. This decision introduces no general aggregate equality operator. Existing explicit integer/pointer operations can copy a complete carrier into or out of ordinary image storage, subject to their existing lifetime, alignment and backing-storage obligations. A pointer or external write does not confer validity on a subsequent typed enum read. Invalid software atom codes encountered by such a read trap; they do not create optimizer poison, unreachable control flow, or permission to rewrite earlier effects. The private call-failure status channel retains its existing zero-for-success transport code. IR-designated status-slot loads admit that sentinel before the failure test; it is not a named atom or a zeroable source enum value.

Device operations: a raw image read and a raw image write are separate operations. Each accepted operation performs exactly one transaction at its specified width. A read does not validate every encoded field. Normal and clear-on-read contracts permit an explicit read; no-read contracts refuse it. Normal and one-clears contracts permit an explicit write; no-write contracts refuse it. All synthesized device field updates refuse, including the normal read/write combination: the programmer must express the image read, local update and image write. A write-only register has no old image to preserve; a destructive read consumes state, and a one-clears readback is not a command image. No convenience lowering may insert a read, split or widen a transaction, or write reserved bits to simplify insertion.

The bounded compiler surface is compiler.register_read(pointer, read_mode) and compiler.register_write(pointer, image, write_mode, reserved_policy, named_mask). The pointer is to u8, u16, u32 or u64 and selects the transaction width; it is not a pointer to an encoded value. Read modes are compiler.normal_read and compiler.clear_on_read; compiler.no_read refuses. Write modes are compiler.normal_write and compiler.one_clears; compiler.no_write refuses. Reserved policies are compiler.preserve, compiler.write_zero and compiler.write_one; the named-bit mask is a fixed unsigned expression of the carrier type. Invalid mode/policy combinations, wrong mask width, unavailable target accesses and absent write permission refuse statically. A dynamic write violating write-zero or write-one traps before the single volatile store, even under unchecked. Mode and reserved arguments declare the platform contract; the compiler cannot verify that the physical address actually implements it. Consistency with that peripheral is an outside premise. These explicit raw-image intrinsics do not enable the general generated register(t, ...) wrapper or a synthesized update operation.

Reserved policy is part of the peripheral contract. Preserve means a supplied whole image carries the caller's reserved bits; it does not authorize a hidden read of the device. Write-zero and write-one require those values in every omitted bit of the supplied carrier. One-clears requires write-zero for reserved bits; zero in a named command bit means no action and one requests clearing. Read values, write commands and reset metadata are distinct even when they share a carrier. Reset metadata initializes neither software storage nor hardware. A normal read/modify/write sequence is not atomic and requires an independent device and concurrency justification.

A known whole image that breaks write_zero or write_one is refused with L0398 at the supplied image [0740]. L0300 remains the refusal for an image whose magnitude does not fit its carrier or target [1880]. A dynamic reserved bit violation traps before the store, including under unchecked [1120].

D227 is unchanged. CPU atomics, a volatile transaction, compiler boundaries, hardware barriers, interrupt exclusion and device completion are separate contracts. Prototype 1 retains an ordinary slice as its DMA buffer. Decode a copied status/count image only after its explicit read; the device contract must establish which buffer writes precede completion, then the required barrier and cache maintenance precede ordinary buffer reads. The barrier invalidates prior compiler knowledge of those bytes. A packed count does not solve wraparound, overrun, cache coherence, buffer lifetime or concurrent external writes. Interrupt notification alone remains insufficient.

Alternatives and rationale: eager validation would make a hardware snapshot or harmless copy trap because of a field the program never inspects. Treating holes as unreachable would import invalid-value undefined behavior and break exhaustive matching after external writes. Silent truncation loses commands; an implicit unknown atom changes the declared value set and its matches. Implicit device RMW introduces access events and reserved writes that may be forbidden by the peripheral. These alternatives are rejected. Raw images with checked extraction retain unknown information and keep the existing unsafe pointer guarantees explicit. General register generation and the complete SVD-derived fixture programme remain outside this semantic slice.

The choice boundaries and their executable pins are explicit:

choicealternative and rationalepin
One explicit or minimally rounded carrier, target alignment, LSB numbering and little-endian bytesByte-packed/C-bitfield rules or declaration-order placement would leave transaction width and reserved bits implicit; no foreign padding rule is importedruntime/r640-indexed-boundary, runtime/r640-packed-boundaries, negative/r640-overlap, negative/r640-c-abi
Unsigned field representations and one-bit booleans; numeric u1 remains numericGeneral scalar widths, signed field arithmetic or boolean coercions would expand value/ABI rules beyond this image contractruntime/r640-indexed-boundary, negative/r640-signed, negative/packed-field-width-is-not-a-scalar-name
Per-union maps, holes and type-argument/evidence identityAtom-global encodings or map-insensitive instance keys conflate distinct hardware layouts; software values still use atom identitiesruntime/r640-packed-enum-array, runtime/r640-generic-encoding, runtime/r640-encoded-evidence
Raw whole images and checked extraction, including discarded readsEager validation destroys harmless snapshots; unchecked holes/unreachable assumptions erase observable behaviorruntime/r640-packed-small-space, runtime/r640-static-hole, runtime/r640-volatile-hole, abi/r640-exhaustive-encodings
Fresh zero constructors and raw copies; explicit runtime field extractionImplicit RMW would add a device read; static array image copying must not bypass validationruntime/r640-packed-construction, runtime/r640-packed-nested-copy, negative/r640-static-array-extraction, negative/r640-zero-field
Arrays snapshot values; fields have no independent byte addressStreaming overlap or exposing an ordinary slice invents a false stride and may corrupt later source elementsruntime/r640-overlapping-array-copy, negative/r640-address, negative/r640-inout, negative/r640-slice
Named-value comparison/matching; explicit raw-carrier comparisonAggregate equality or integer-to-enum casts would confuse image bits with atom identitiesruntime/r640-packed-small-space, negative/r640-image-equality, negative/r640-enum-integer-conversion
Explicit one-event image accesses; no synthesized field operationsHidden reads, split/widened accesses and readback-based one-clears commands violate device contractsruntime/r640-register-images, negative/r640-register-no-read, negative/r640-register-no-write, negative/r640-register-one-clears-preserve, the synthetic device's literal trace
Required reserved patterns are checked, never repaired silentlyTruncating a supplied write or silently inserting ones conceals an invalid command; preserve performs no hidden readruntime/r640-reserved-value, abi/r640-reserved-trap, negative/r640-register-reserved-zero, negative/r640-register-reserved-one, the synthetic device's required-one register
D187/D227 remain independent of image layoutField RMW is not an atomic operation, and status decoding cannot make an ordinary DMA slice coherentruntime/r640-packed-index-bound, runtime/r640-packed-value-fit, abi/r640-dma-packed, negative/r640-m0-register64

Guarantee classes: positions, widths, overlap, encoding uniqueness, field kinds, known-value fit and addressability are static; dynamic membership, field fit and packed indexing are trap, retained by unchecked. Backing storage, pointer-origin erasure, device premises and external-write ordering retain D148/D227's existing outside and beyond-lifetime classifications. There is no invalid-encoding optimizer license. Natural, C and optimal layout retain their existing representations and ABI contracts. Packed structs are not C bitfield structs and cannot cross a C signature by value; explicit unsigned carriers or pointers use the existing C boundary.

Pinned by: runtime/r640-packed-fields, runtime/r640-packed-indexed, runtime/r640-packed-construction, runtime/r640-packed-array-copy, runtime/r640-packed-static, runtime/r640-packed-small-space and runtime/r640-packed-hole distinguish images, validated extraction, copies, calls and indexed updates. The independent targets/packed image algebra and access plans case and the retained synthetic device contract define separate image and transaction oracles.

D236 — A range subtype constrains scalar positions only

The tour said that [0660]'s range subtype is checked at assignment and conversion. D188 made a subtype its base type constrained rather than a new type, placed its one check where a value is stored into a place declared with the subtype, and refused by name the positions where that check could not hold: a struct field, a fixed-array element, a ptr or [] target, addr of a constrained place and a generic type argument, with an extern (c) signature kept by [1580]'s own report. It left how the check composes undecided.

Chosen: it does not compose. A range subtype constrains a binding, a parameter, a named return and a conversion, which are exactly the positions where D188's check runs on the way in. The five refused positions keep their L0304 permanently: its primary message now says the position cannot be a range subtype, and its second note says "this is a recorded source-form boundary". The external signature keeps [1580]'s report. [0660] now states the boundary and names distinct as the carrier for a checked value in storage, which is [1730]'s habit.

The reason is D188's own premise. Because percent and u8 are one type, []percent and []u8 would be one slice type, and addr of a constrained place would be an ordinary ptr mut u8: any write through the base type would reach constrained storage with no check. A composition that keeps the guarantee therefore needs the constraint to become identity in exactly the composite positions — []percent apart from []u8, a generic instance keyed by its bounds — which is a second nominal identity beside [0650]'s, with its own relaxation question, while [0440] calls its relaxation the one the language has. Measured against the checker, the composite descriptors carry no constraint (Landin.Checking.Field_Shape and Reference_Descriptor hold kind, element, nominal and reference facts only) and the check is a checker-owned fact emitted at two lowering choke points. A composite constraint would have to reach field shapes, reference descriptors, instance keys, zero-image eligibility (a subtype excluding zero has no zero image, so every containing aggregate would leave [0550]'s family), module static images, variant payload construction, match-arm inout aliases and erased evidence, and each of those store paths would need its own check for the guarantee to stay true. No program asked for it: prototype 1's baud_rate is a scalar parameter, and the complete derived driver replaced even that with plain u32 and declared recoverable checks.

The alternatives: a composite identity with a check on every store path was declined for the reasons above. Admitting fields and elements while keeping references and generics refused was declined because inout of a constrained field, slicing a constrained array, whole-aggregate zero images and payload aliases reopen the same identity question. Transferring the question to a successor was declined because its answer does not wait on a program: the conflict is with D188 and [0440], not with cost.

Pinned by negative/range-subtype-struct-field, negative/r720-range-subtype-array-element, negative/range-subtype-in-a-slice, negative/range-subtype-address, negative/range-subtype-generic-argument, negative/range-subtype-external-signature, negative/r491-refused-operand-cascades, whose recorded reports carry the boundary note, and the subtype.range guarantee row.

D239 — Byte order is converted where bytes cross, and the machine attribute words are withdrawn

The tour said that byte order is per field, with big u16 in a layout(c) packet [0750], and listed big and little among the attribute words and weak, inline and noinline as outside the enabled machine slice [0760]. None had a named refusal; each met an ordinary parse error.

Chosen: all five are withdrawn. A field holds the target's own byte order, which compiler.byte_order names [1560]; a program converts another order where the bytes cross, with shifts [0320] or an ordinary function. Inlining is the optimizer's decision under D211, and no source attribute requests or forbids it. A whole program links one definition per name [1610], and the compiler-owned vector image of D229 fills each unimplemented slot, which is what weak default handlers do in C firmware. The five words stay ordinary identifiers: big u16 remains an L0103 field error and link(weak) an L0103 link label without its :, and no named refusal is owed because the tour no longer describes them [1830]. [0750] and [0760] are rewritten.

No prototype, derived program, core module or example writes any of the five. A per-field order would make every load and store of that field a byte swap, leave addr of the field an ordinary ptr u16 that reads the wrong value, so that addressability would need the refusals packed fields have, put static images through a second byte order, and need DWARF's DW_AT_endianity for a debugger to show the value, a presentation this compiler has produced for neither native debugger. The compiler has no inliner: no IR pass inlines a call, so inline could only be a promise D211 would then have to keep. Weak linkage matters where separately compiled objects compete for a name, and this compiler sees the whole program.

The alternatives: a per-field storage order with addressability limits and endianity debug information was declined as a new storage attribute with packed-field restrictions for a need no program had, while an explicit conversion is ordinary code. inline and noinline as hints were declined: a hint nothing honours is text, and an obligation belongs to D211's optimizer contract rather than to source. weak for C interoperation was declined because the C boundary's link names are exact and no binding needed a weak one. Keeping the words described but refused by name was declined because they are not pending anything.

Pinned by negative/r720-field-byte-order-withdrawn and negative/r720-machine-attribute-words-withdrawn.

DECISIONS: STRUCTS, VARIANTS AND NESTING

The longest run in the register. Ordinary aggregates, the variant part, the paths that reach into both, and the contextual forms that fill them.

D16 — A field of a struct local is assigned on its own

The tour said that a binding declared with no value must be assigned before use [0080], and [1910] made that a rule about a name: at every read, the name has to have been assigned by every path that arrives there. It does not say what the thing tracked is when the binding has fields, because until a struct could be a local nothing written in a body had any.

Chosen: the field. p.x = 1 assigns p.x and nothing else, a read of p.x asks whether p.x was assigned, and a read of p.y after only p.x was written is refused and names p.y. inc p.x reads and writes the same field, so it wants that field assigned above it, exactly as inc n wants n. Every arm of an if merges its fields the way [1910] already merges its names; only written Boolean literals select an edge there too.

D54 later applies the same field boundary when an array-bearing struct is copied whole. Scalar fields keep these individual bits; a fixed-array field is complete only through its own D48 sparse facts or D49/D50/D52/D53 whole-field fact. Normal completion assigns every destination scalar bit and every destination array-field whole fact without conflating the two representations. A binding or assignment the checker has already refused reads nothing for definite assignment: the statement cannot execute, so its owning report is not followed by an L0302 from an otherwise unassigned source inside it. A named return the checker has refused is likewise not a destination [1910] can require at return or at the body's end; its owning ABI report stands alone.

Why the field and not the binding: [1910] tracks the thing an assignment writes, and an assignment to a place writes a field. It is also the answer that survives: a parameter of struct type arrives assigned in every field, a named return of one has to be filled in every field before [0930]'s return, and a construction assigns them all at once — each of those is a statement about fields, and a rule about the binding would have to be replaced to say any of them.

What this does not decide: a module binding of a struct type. D10 already says a binding with no value holds zero and [1460] leaves no moment in which anything could assign one, so its fields read zero and there is nothing here to check. This rule is about a body.

The alternative: two. Treat the binding as assigned once every field has been, which is one bit instead of one per field and never reads a field nobody wrote — declined because it refuses a function that fills two fields of three and reads only those two, which is ordinary code whose workaround is assigning a field the program does not use. Or zero a struct local where it is declared, extending D10 into a body, which removes the question entirely — declined because it is a store per field at a place the source does not mention, and this language does not do work a reader cannot see.

Pinned by negative/struct-field-not-assigned, negative/struct-field-not-assigned-on-every-path, runtime/struct-locals-hold-their-fields.

D44 — A named ordinary scalar-field struct has byte measurements

The tour said that sizeof T and alignof T ask the target for byte measurements and produce usize [0370], that a struct's fields are laid out in declaration order with target padding [0750], and that aliases denote the same type [0710]. D14 enabled scalar measurement and D17 enabled fixed arrays, but the implemented checker still refused every aggregate measurement.

Chosen: sizeof T and alignof T are admitted when T resolves directly or through any representable alias chain to a named ordinary struct whose fields are all enabled scalars. sizeof is the target's padded size of that field run and alignof is its required alignment. Both results remain usize. A malformed or unresolved measured type retains its one owning diagnostic rather than acquiring a second measurement refusal.

Lowering carries the struct compactly in target-neutral IR as its declaration- order run of scalar field types. It carries neither checker-computed offsets nor size or alignment constants. A backend with target facts replays that run through Landin.Targets.Place and reads Landin.Targets.Size_Of or Landin.Targets.Alignment_Of; module-scalar folds use the same backend seam. The checker also evaluates the leaf during [1940]'s target-aware validation, and lowering reads that same checked layout when a static module array image must contain the concrete answer. This preserves D24's fold agreement without putting a target answer into ordinary measurement IR. The verifier requires a measurement result to be usize, and the dump exposes the field run.

This decision does not enable array or struct fields, nested aggregate composition, inline anonymous struct measurement, lenof on a struct, aggregate values, aggregate parameters or returns, or a struct in any other expression or storage context. Scalar and fixed-array measurements are unchanged.

Why the field run: field types and declaration order are the complete representation-independent input to [0750]'s placement arithmetic. Carrying that small input lets every target derive one authoritative answer without putting a target choice or a checker cache into IR.

The alternative: lower the checker-prepared size and alignment as integer constants. That would make target-dependent checker results part of otherwise target-neutral IR and give downstream consumers no way to establish that the answer came from their own target description. It was declined.

Pinned by the lowering and backend public-seam cases; positive/measurement-of-structs; the one-report negative/measuring-refused-types; negative/struct-measurement-fold-overflow; the recorded IR dump; and runtime/measurements-answer-for-the-target on Linux x86-64.

D45 — A named ordinary struct may hold a fixed scalar array for measurement

The tour said that a struct field has a type [0670], that fields are laid out in declaration order with target padding [0750], that a fixed array is a value with a compile-time length [0520], and that sizeof T and alignof T ask the target for byte measurements [0370]. D44 admitted only scalar fields, so the first aggregate field still had no representation the checker and backend shared.

Chosen: a field of a named ordinary struct may be a fixed array of an enabled scalar, written directly or through an alias. Layout places that array once in declaration order, as one extent of length times target element size at the array's target alignment. D17's zero-element shape contributes size zero and alignment one here as everywhere else; D136 later accepts source spelling [0]T.

The complete padded struct must fit the selected target's usize. If it does not, the checker reports L0300 at the struct body, records no layout, and a later measurement adds no second report. L0300 therefore owns compile-time magnitudes that a context or target cannot hold, including D18's array extent and this enclosing aggregate extent; it is not limited to a literal token.

sizeof T and alignof T admit the resulting struct directly or through any representable alias chain and still produce usize. Lowering carries its declaration-order run in target-neutral IR: a scalar field is one scalar leaf, and an array field is one element-and-count leaf no matter how large its length. It carries no checker-computed offset, byte size or alignment. Each backend derives the padded answer from its own target facts. Module-scalar folds and static module array images use the same checked layout as D44. The verifier requires a scalar measurement leaf to have its canonical length one; the dump exposes an array leaf as [N]element.

At this decision a struct with an aggregate field still had no runtime storage or value context. D46--D65 later add its module and frame storage, indexed and whole-field places, contextual initializers, whole copies, zero images and labelled literals. D87 and D119 later admit ordinary struct fields and arbitrary-depth ordinary nesting; D94, D102 and D104 admit specified struct parameter shapes, and D106 admits specified struct result shapes. Those decisions retain their own limits on storage, expressions and calls. Inline anonymous struct measurement and lenof on a struct remain deferred. Scalar-field struct measurement is unchanged.

Why the compact leaf: D18 permits an array length no host or IR vector can enumerate, while its element and count are the complete representation- independent input to D17's extent rule. Replaying that leaf through target placement preserves D44's one authority for layout.

The alternatives: expand one IR field per array element, or carry the checker-computed size and alignment. The first cannot represent enabled extents and the second puts a target answer into target-neutral IR, so both were declined. Refusing a zero-length field specially was also declined: D17 already defines the shape, and D136 later accepts source [0]T uniformly rather than making a D45 exception.

Pinned by the checker, target, lowering, verifier and backend public-seam cases; positive/measurement-of-struct-array-fields; negative/struct-array-field-layout-overflow; the reworked one-report negative/struct-with-an-array-field; the recorded IR dump; and runtime/measurements-answer-for-the-target on Linux x86-64.

D46 — An array-field struct may be zeroed module state

The tour said that an array is a value whose size is part of its type [0520], that all-zero is a valid image for an aggregate of zero-image parts [0540], that a struct has its declared fields [0670], that those fields keep their order and target padding [0750], and that a module is a set of declarations [1740]. D45 gave the checker a complete layout for a named ordinary struct with fixed-scalar-array fields, but deliberately left every runtime storage and value context refused.

Chosen: a declaration-only module binding may have a type that resolves, directly or through aliases, to a named ordinary laid-out struct whose fields are enabled scalars or fixed arrays of enabled scalars. D10 supplies the whole object's all-zero image, so neither the array length nor the number of fields is expanded into initializer work. Module state has no local definite-assignment fact to establish: its scalar fields read as zero from declaration and ordinary mutable scalar fields may be assigned, including a scalar sibling after an array field.

This admits the containing storage, not the array field as a value or whole place. Selecting that field reported L0304 once at the selection in this slice; D48 supersedes that result only where the selection is immediately the base of an index. A local declaration of the same struct also reported L0304 in this slice because the frame's aggregate-slot representation remained scalar-field-only; D47 supersedes that storage boundary. An initializer, whole read or copy, parameter, return and every other whole-value context remain refused in this slice; D54 later supersedes the whole-copy boundary and D55/D56, after D47 supplies the frame representation, the explicitly typed or inferred local direct-storage-name initializer boundary. Struct fields of struct type and other nested aggregate composition remain outside D45 and therefore outside this decision. D17's zero-length field rule is unchanged; D136 later accepts source [0]T uniformly.

Lowering records the module datum as one declaration-order run of neutral field shapes. A scalar shape has canonical length one; a fixed-array shape carries one scalar element and one count. This is the same representation-independent shape D45 measurement IR uses, but item and measurement runs remain distinct so one cannot be mistaken for the other. The verifier rejects a noncanonical scalar shape and rejects a scalar Load_Field or Store_Field aimed at an array shape. No target offset, byte size, alignment or expanded element run is put into IR.

The backend replays those shapes through the same target placement used for measurement and reserves the complete padded object in zeroed storage. Scalar field operations use the resulting target offset. On x86-64, a nonzero offset in any aggregate containing an array field is added to the symbol address: an offset fitting a signed 32-bit arithmetic immediate uses an immediate add, while a larger offset uses a full-width register constant and register add. Neither case asks the assembler to encode a symbol-plus-displacement memory operand whose relocation a D18-sized field could put out of range.

Why module state first: it already has D10's complete image and needs only one compact datum description. Enabling the same type in a frame would require the slot representation and nested-place operations to describe the array; enabling a whole value would additionally settle copies, initialization, parameters and returns. Keeping those separate makes this slice executable without implying any of them.

The alternatives: flatten the array into one scalar item field per element, or admit array shapes in every aggregate slot and field operation at once. The first cannot represent D18's enabled lengths, and the second couples storage, nested-place and whole-value decisions that have different invariants, so both were declined.

Pinned by the checker, lowering, verifier and backend public-seam cases; positive/struct-array-field-module-state; negative/struct-array-field-selection-not-enabled; the recorded IR dump; and runtime/struct-array-field-state-scalar-siblings on Linux x86-64.

D47 — An array-field struct may be declaration-only local storage

The tour said that a declaration-only binding must be assigned before it is used [0080], that an array is a value whose length is part of its type [0520], that a struct has its declared fields [0670], and that those fields keep declaration order and target padding [0750]. D16 made each field of a struct local its own definite-assignment fact. D45 supplied the complete layout for scalar and fixed-scalar-array fields, while D46 deliberately stopped after module storage because the frame IR could describe only scalar fields.

Chosen: a declaration-only local binding may have a type that resolves, directly or through aliases, to a named ordinary laid-out struct whose fields are enabled scalars or fixed arrays of enabled scalars. The complete object is one frame cell with the padded extent and alignment derived from the selected target. Unlike D46's module state, this local is not implicitly zeroed and no stores are invented at its declaration.

D16 continues to track each accessible scalar field independently. A scalar sibling before or after the array must be assigned on every arriving path before it is read, and assigning one sibling assigns no other. The array field had no D16 fact in this slice because it was not selectable as a value or nested place: selection reported L0304 once and the definite-assignment recovery walk added no whole-struct report. D48 supersedes that boundary for an indexed element and gives it a field-qualified fact. A local initializer, whole read or copy, parameter, return and every other whole-value context remain refused in this slice; D54 later supersedes the whole-copy boundary and D55/D56 the explicitly typed or inferred direct-storage-name local initializer boundary. Struct fields of struct type and broader nested aggregate composition also remain outside the laid-out kernel.

Lowering records the cell as one aggregate slot whose declaration-order field run uses D45's neutral shape: a scalar leaf has canonical length one and a fixed-array leaf carries one scalar element and one count. Slot, item and measurement runs remain distinct. The dump exposes the slot run, the verifier rejects a noncanonical scalar slot leaf, and Load_Field or Store_Field may name only a scalar part. Thus the inaccessible array field cannot cross the verified scalar operation boundary even if lowering is damaged.

The backend replays every slot shape through the same target placement as D45 measurement and D46 module storage. D17's zero-element shape therefore contributes size zero and alignment one here too; D136 later accepts source [0]T. Scalar field operations use the resulting offset. On x86-64 the existing signed frame-displacement limit applies to the complete cell: a routine whose padded frame is not addressable reports L0504 before assembly is emitted, including when an array field is what makes it too wide.

Why storage without a value: the frame needs only a compact description and D16 already supplies the scalar-field initialization rule. Enabling the array field as a place requires an aggregate-aware nested-place representation and computed element addressing; enabling a whole value additionally settles initializers, copies, parameters and returns. None is required to allocate the cell and use its scalar siblings.

The alternatives: keep local storage refused until nested indexing, or enable array-field selection and whole values in the same slice. The first would preserve a storage-class distinction after item and slot IR can express the same neutral shape; the second combines independent representation, definite-assignment and calling-convention questions. Both were declined.

Pinned by the checker, lowering, verifier, driver and backend public-seam cases; positive/struct-array-field-local-storage; negative/struct-with-an-array-field; negative/struct-array-field-local-selection-not-enabled; negative/struct-array-field-local-unassigned-scalar; the recorded IR dump; and runtime/struct-array-field-local-scalar-siblings on Linux x86-64.

D48 — An element of a fixed-array field is a place

The tour said that an array element is a place [0520], that a computed index traps before an address is formed [0580], that a struct has its declared fields [0670], and that assignment uses the root binding's mutability [1900]. D46 and D47 admitted the containing module datum and local frame cell, but stopped before an array field could be reached.

Chosen: where s directly names D46 module state or a D47 local and f is a fixed array of enabled scalars, s.f[i] is admitted as a read, assignment destination, or inc/dec target. The index is exactly usize under D18. A compiler-known index outside the field length is refused under [1950]; every other index is checked at runtime and traps before any address is formed under [0580]. Writability is the root binding's. The selection s.f is typed as an array only in this index-base context: as a whole value, copy endpoint, or non-zeroed assignment destination it remains refused with L0304. D49 later supersedes the complete s.f = zeroed statement, D50 later supersedes the copy-endpoint boundary, and D52/D53 later supersede literal and repetition destinations.

D10 makes module state complete from declaration, so an indexed module-field read has no assignment requirement. A declaration-only local instead follows D19 and D22 per field. Its compiler-known element facts are keyed by binding, field, and position; assigning one position establishes only that fact. A computed read requires the whole-field fact, which holds once every declared position in that field has a fact on every arriving path. A computed write establishes no fact and clears none, and inc/dec first requires the read. A zero-length field is vacuously complete, preserving D17; D136 later accepts source [0]T.

Lowering carries the root storage identity, the declaration-order field position, and the index through the existing Load_Element and Store_Element operations. Field zero continues to mean that the storage is itself an array; a positive field selects an array shape inside an aggregate. No checker-computed byte offset enters IR. Even a compiler-known index through a field uses the element operation: adding a two-level static-part encoding for that optimization was declined. Array copy, clear, and fill operations still name whole storage only and therefore require field zero in this slice; D49 later adds a destination field identity to Clear_Array, and D50 adds source and destination identities to Copy_Array.

The verifier checks a positive element field against the aggregate field run before it reads the shape, and rejects an absent field or a scalar field. It then applies the existing usize, result, and stored-value rules to the array shape's element. The dump exposes the field identity. Each backend derives the field offset, length, and element width from its selected target. On x86-64 a module field base is formed in registers so a D18-wide preceding field remains addressable; a local uses the field displacement inside the L0504-bounded frame. In both cases the bounds trap precedes field and element address arithmetic.

Why the scoped selection: admitting s.f generally would also imply whole field copies and zeroed, which have separate initialization and lowering rules. D49 later settles only the contextual clear. Index-base typing enables the scalar subobject without pretending the array field is an ordinary value. Field-qualified local facts preserve D19's independent-element rule when one struct contains more than one array field.

The alternatives: enable module indexing first and defer locals, introduce new field-element opcodes, or lower an address-of-field value. The first leaves D47 storage unusable despite the same compact shape; the second duplicates the existing element trap and operand rules; the third introduces addresses into a target-neutral IR that has none. All were declined.

Pinned by the IR, verifier, lowering, and backend public-seam cases; positive/struct-array-field-module-state and positive/struct-array-field-local-storage; negative/struct-array-field-selection-not-enabled; negative/struct-array-field-local-selection-not-enabled; negative/struct-array-field-immutable-element; negative/struct-array-field-index-not-usize; negative/struct-array-field-index-outside; negative/struct-array-field-local-computed-unassigned; negative/struct-array-fields-keep-assignment-separate; negative/struct-array-field-element-not-assigned-on-every-path; negative/scalar-struct-field-is-not-indexable; negative/struct-array-field-zeroed-not-enabled; the recorded IR dump; runtime/struct-array-field-state-scalar-siblings; runtime/struct-array-field-local-scalar-siblings; runtime/struct-array-field-computed-index-traps; and runtime/struct-array-field-local-computed-index-traps on Linux x86-64.

D49 — zeroed clears one fixed-array field

The tour said that assignment reaches its destination before its value [0410], that an array's complete value may be all-bits-zero [0520], that zeroed takes its type from context [0540], that a struct has its declared fields [0670], and that writability belongs to the root binding [1900]. D48 admitted an element of a fixed-array field while deliberately leaving the field itself outside every whole-place context.

Chosen: where s directly names D46 module state or a D47 local and f is a fixed array of enabled scalars, s.f = zeroed is admitted as a statement. The selection is typed as an array only as the destination of that complete assignment. At this boundary, as a value, copy source or destination, non-zeroed destination, inc/dec target, operand, or nested zeroed expression it remains refused with L0304; D50 later supersedes the copy endpoints, D52 the literal destination and D53 repetition destinations. An immutable root reports L0303 first and alone under [1900]. The destination is reached first and zeroed evaluates nothing [0410]. Every enabled scalar has a zero image, so the complete field has one [0540].

D10 already makes a module field complete, so clearing it changes no assignment fact. Normal completion for a local records the whole-field fact keyed by the binding and field. Every compiler-known or computed element of that field may then be read; a later computed write keeps the fact under D22, and no scalar sibling or other array field is affected. A merge keeps the fact only when every arriving path has it. A zero-length field is vacuously complete and clears zero bytes, preserving D17; D136 later accepts source [0]T.

Lowering emits the existing compact Clear_Array with the root storage and the field's declaration-order identity. Field zero continues to mean that the storage is itself an array. At this boundary Copy_Array and Fill_Array remain field-zero-only, so this does not admit a whole field copy or fill; D50 later adds both copy endpoint identities. No checker-computed offset, source operand, temporary, or per-element instruction enters IR. The dump exposes a positive clear field.

The verifier checks a positive field against the aggregate run before it reads the shape, rejecting an absent field or a scalar field with the same faults D48 uses. Each backend derives the field offset, element width, and byte extent from its selected target. Linux x86-64 forms a module field base in registers so a D18-wide preceding field remains addressable, uses the L0504-bounded displacement for a frame field. It uses bounded scalar zero stores for one to six bytes or exactly eight bytes; other extents retain rep stosb. A zero extent gives rep stosb a zero count.

Why only the contextual clear: a field supplies exactly the shape and storage zeroed needs, while a general selection would also admit source reads, copies, literals, repetitions, arguments, returns, and hidden array-sized temporaries. Those operations have distinct source-order and definite-assignment rules. Keeping the selection scoped preserves their refusal.

The alternatives: admit general whole field places and copies together, emit one scalar store per element, put a field into every array-storage endpoint, or admit aggregate zeroed initialization in the same slice. The first and last broaden the value boundary, the second makes compiler work proportional to a D18 extent, and the third representation widens copy and fill before either can use it. All were declined.

Pinned by the checker, IR, verifier, lowering, and backend public-seam cases; positive/struct-array-field-zeroed-assignment; negative/struct-array-field-zeroed-not-enabled; negative/immutable-struct-array-field-zeroed; negative/struct-array-field-clear-keeps-fields-separate; negative/struct-array-field-clear-not-on-every-path; the recorded IR dump; runtime/struct-array-field-state-scalar-siblings; and runtime/struct-array-field-local-scalar-siblings on Linux x86-64.

D50 — A fixed-array field is a whole-copy endpoint

The tour said that assignment reaches its destination before its value [0410], that assigning an array copies its complete value [0520], that a struct has its declared fields [0670], and that writability belongs to the root binding [1900]. D20 admitted one compact copy between direct array storage names. D48 made an indexed element of a fixed-array field reachable, and D49 made the complete field a contextual zeroed destination, while both kept a field out of copy syntax.

Chosen: where s directly names D46 module state or a D47 local and f is a fixed array of enabled scalars, s.f may be either endpoint of D20's copy: s.f = t.g, s.f = name, name = s.f, and s.f = s.f. A direct name has field identity zero; a selection has its declaration-order field identity. Both endpoints must have the same D17 length and scalar element type. A disagreement is refused with D20's L0301 at the source, related to the destination. The destination root must be mutable under [1900]; L0303 owns an immutable destination first and alone. The destination is reached before the source under [0410], and neither endpoint evaluates an element.

The source is read as a whole. D10 makes a module field complete. A local source field must be complete on every arriving path: D49's clear or an earlier D50 copy supplies its binding-and-field whole fact, while D19/D48's sparse facts also suffice when they cover the declared length. A zero-length field is vacuously complete. Self-copy follows the same rule and therefore cannot make an unassigned field assigned. Normal completion records only the destination's whole fact; a scalar sibling and every other array field remain independent, and a branch merge keeps that fact only when every arriving path has it.

This is a copy context, not a general array value. A fixed-array field remains refused as a module initializer source, argument, return, discard, operand, or bare read, and as a literal, repetition, or other non-zeroed, non-copy assignment destination. D51 later admits it as a local initializer source without changing those positions, and D52/D53 later admit literal and repetition destinations. Whole copies of the containing struct keep D46's refusal in this slice; D54 later gives the field-wise lowering path an explicit array branch.

Lowering emits one compact Copy_Array carrying both root storage identities and both field identities, never target offsets, temporaries, or one operation per element. The verifier first checks that each positive field exists in an aggregate and has an array shape, then compares the two shapes; those explicit checks precede every shaped accessor in assertion-free builds. Fill_Array remains field-zero-only.

Each backend derives both field offsets, the source element width, and the byte extent from its selected target. Linux x86-64 register-forms a module field on either side when a D18-wide preceding field puts its offset outside a signed displacement and uses L0504-bounded frame displacements for local fields. It uses scalar register moves for one to six bytes or exactly eight bytes; other extents retain one forward rep movsb. Distinct fields and distinct storage do not overlap; an exact self-copy names the same range, which either transfer preserves. A zero extent gives the operation a zero count.

Why the contextual endpoints: the compact D20 operation already expresses the complete source read and destination write without enumerating D18's extent. Typing the selections only in this syntax reuses that rule without creating an array value that another expression, call, return, or initializer would have to carry.

The alternatives: admit a fixed-array field as a general value, enable field-wise copies of the containing struct, initialize storage from a selected field in this assignment slice, emit one scalar copy per element, put a field component into every Storage, or introduce a second copy opcode. The first three broaden distinct value and static-image rules, the fourth cannot represent every D18 extent, the fifth widens unrelated fill endpoints, and the sixth duplicates D20 for two identities. All were declined here; D51 later settles the local-initializer rule independently.

Pinned by the checker, IR, verifier, lowering, and backend public-seam cases; positive/struct-array-field-copy; negative/struct-array-field-copy-source-unassigned; negative/struct-array-field-copy-not-on-every-path; negative/struct-array-field-copy-shape-mismatch; negative/immutable-struct-array-field-copy; negative/struct-array-field-copy-keeps-fields-separate; the recorded IR dump; and runtime/struct-array-field-copy-endpoints on Linux x86-64.

D51 — A fixed-array field initializes a local array

The tour said that a binding may carry a value [0040], an inferred binding takes that value's type [0050], the value is read before the new name exists [0110], and assigning an array copies its complete value [0520]. D21 admitted both typed and inferred local initializers from a direct array storage name. D50 made a directly selected fixed-array field a complete copy source, but kept it outside initializer syntax.

Chosen: where s directly names D46 module state or a D47 local visible at the binding and f is a fixed array of enabled scalars, a local array binding may be initialized from s.f in either D21 form. In [mut] name: [N]T = s.f, the written type must have the field's D17 identity; a disagreement is D20's L0301 at the source, related to the binding. In [mut] name := s.f, the destination takes that length and scalar element type exactly. A declaration is not an assignment [0080], so either mutable or immutable binding accepts the initializer and the source root need not be mutable.

The source is read before the new name enters scope [0110] and as a whole. D10 makes a module field complete. A local field must be complete on every arriving path: D49's clear or a D50 copy supplies its binding-and-field whole fact, while D19/D48's sparse facts also suffice when they cover the declared length. A zero-length field is vacuously complete. The fresh local is completely initialized by the copy and, like every local declared with a value, needs no later definite-assignment tracking. A refused contextual value owns its report; [1940] does not add a static-module-value report after that node is ill typed.

This remains an initializer context rather than a general array value. D70 later admits the same selected field as a typed or inferred module initializer; it remains refused as an argument, return, discard, operand or bare read. It is not a literal or repetition destination at this boundary; D52 later admits the literal destination alone. Whole copies of the containing struct keep D46's refusal here and are admitted later by D54; fields of elements, struct-of-struct fields and nested arrays remain outside the laid-out kernel.

Lowering emits D21's one compact Copy_Array from the containing root storage, carrying the field's declaration-order identity as D50's source field, into the fresh frame slot at field zero. It emits no target offset, temporary or per-element operation. The verifier and backend therefore reuse D50's rules: the verifier checks the source field before reading its shape, and x86-64 register-forms a D18-wide module offset while ordinary frame addresses remain bounded by L0504. A zero extent gives the copy a zero byte count.

Why: D21's initializer already is D20's copy into fresh local storage, and D50 already represents and checks a selected field as that copy's complete source. Reusing both preserves D21's typed/inferred symmetry without adding a general value position or a new IR operation.

The alternatives: admit only the explicitly typed form, admit a module initializer from a field, make the field a general value, add a separate initializer opcode, or emit one store per element. The first makes D21's two spellings needlessly asymmetric; the second needed a static-image rule for subobjects and was later chosen by D70; the third broadens unrelated expression positions; the last two duplicate or cannot represent the compact D18 operation. The remaining alternatives were declined.

Pinned by the checker, lowering and backend public-seam cases; positive/local-array-initialized-from-field; negative/struct-array-field-initializer-source-unassigned; negative/struct-array-field-initializer-not-on-every-path; negative/struct-array-field-initializer-shape-mismatch; positive/module-array-from-struct-field; the recorded IR dump; and runtime/local-array-initializers-from-fields on Linux x86-64.

D52 — An array literal may be assigned to a fixed-array field

The tour said that assignment reaches its destination before its value [0410], that an array has its complete value [0520], that aggregate parts are initialized in written order, that a struct has its declared fields [0670], and that writability belongs to the root binding [1900]. D29 admitted a nonempty literal only when the complete destination was a direct array storage name. D48 made each element of a fixed-array field reachable without making the field a general place.

Chosen: where s directly names D46 module state or a D47 local and f is a fixed array of enabled scalars, D29's contextual assignment also admits s.f = [first, ..., last]. Direct and aliased root, field and scalar element types have the same meaning. The selected field's D17 length and element type are the context: the nonempty literal must contain exactly that many elements, and every expression must have the element type. A length or element mismatch uses D29's L0301 and relates the source to its destination. The root must be mutable under [1900]; L0303 owns an immutable root first and alone.

The destination is reached first. Each expression is then evaluated from left to right and written immediately to its corresponding element before the next expression begins, exactly as D29 specifies for direct storage. Thus a later expression can observe an earlier write to the same field, and a runtime failure can leave a completed prefix changed. Reads in every source expression are nevertheless checked against the definite-assignment state arriving at the statement; only normal completion records the binding-and-field whole fact. That fact makes known and computed reads complete without affecting any scalar sibling or other array field, and a merge retains it only on every arriving path. Module state remains complete under D10.

Lowering evaluates each element, emits a constant usize index, and uses D48's existing Store_Element operation with the root storage and the field's declaration-order identity. It creates no hidden array temporary and carries no target byte offset. D29's direct-array literal keeps its existing Store_Field run byte-for-byte. A constant field index deliberately retains the ordinary bounds check: introducing the two-level static-part encoding D48 declined is not part of this rule.

The verifier and backend reuse D48 without a new operation or invariant: the verifier checks the positive field exists and has an array shape before reading it, then checks the usize index and stored element type. Each backend derives the field offset, length and element width from its target. Linux x86-64 forms a D18-wide module field in registers and uses the L0504-bounded target displacement for a local; every bounds trap precedes address arithmetic.

This is D29's literal context, not a general field value or place. Full and mixed repetition are a separate decision admitted later by D53; zeroed other than D49, copies other than D50, module initializers, arguments, returns, discards, operands, bare reads, fields of elements, struct-of-struct fields and nested arrays keep their existing boundaries. Whole copies of the containing struct remain refused here and are admitted later by D54. In particular, D52 itself does not widen Fill_Array.

Why reuse element stores: a literal already names one expression per position, and D48 already represents the containing field plus an element index. Reusing that operation preserves D29's observable order and avoids both a hidden complete temporary and a second two-level part representation.

The alternatives: keep literals restricted to direct arrays, form a hidden array value and copy it, extend Store_Field with a nested part, or admit full and mixed repetition in the same slice. The first leaves otherwise usable field storage needlessly asymmetric; the second changes D29's order and frame cost; the third duplicates D48's identity; and the fourth requires a compact field-qualified fill rule that a literal does not need. All were declined.

Pinned by the checker, lowering and backend public-seam cases; positive/struct-array-field-literal-assignment; negative/struct-array-field-literal-length-mismatch; negative/struct-array-field-literal-element-mismatch; negative/immutable-struct-array-field-literal; negative/struct-array-field-literal-reads-incoming-state; negative/struct-array-field-literal-not-on-every-path; the recorded IR dump; and runtime/struct-array-field-literal-assignment-order on Linux x86-64.

D53 — Repetition may assign a fixed-array field compactly

The tour said that full repetition evaluates one scalar pattern [0560], that mixed repetition evaluates and stores its prefix before evaluating the repeated suffix, that assignment reaches its destination before its value [0410], and that writability belongs to the root binding [1900]. D32 and D37 admitted those forms only for direct array storage. D48 made the elements of a fixed-array field reachable, while D52 supplied the ordered prefix-store representation a mixed field destination needs.

Chosen: where s directly names D46 module state or a D47 local and f is a fixed array of enabled scalars, D32's full [N of expression] and [of expression] assignment and D37's mixed [e1, ..., ek, of repeated] assignment also admit s.f as their contextual destination. Direct and aliased root, field and scalar element types have the same meaning. The field supplies D17's length N and element type T: a written full count must equal N, every expression must have type T, and a mixed prefix must satisfy 1 <= k < N. Consequently neither form admits a zero-length field under D32/D37's construct-specific nonzero contextual rules. The root must be mutable; L0303 owns an immutable root first and alone.

The destination is reached first. A full repetition evaluates its scalar once and fills the field. A mixed repetition evaluates and immediately stores each prefix expression from left to right, then evaluates the repeated expression once and fills positions k + 1 through N. A later prefix or repeated expression can therefore observe an earlier prefix write. Reads in all source expressions are checked against the definite-assignment state arriving at the statement; only normal completion records the binding-and-field whole fact. That fact is independent of scalar siblings and other array fields and survives a merge only when established on every arriving path. Module state remains complete under D10.

Lowering represents a full field repetition with one Fill_Array, carrying the root storage, the field's declaration-order identity and First = 1. For a mixed field repetition it uses D52's constant-index Store_Element sequence for the prefix and one field-qualified Fill_Array with First = k + 1 for the suffix. The repeated value is one ordinary scalar IR operand; no hidden array temporary, target byte offset or operation per suffix element is formed. D32 and D37's direct-array instruction sequences remain unchanged with field identity zero.

The verifier first requires a positive field identity to name an array shape inside the destination aggregate, then applies D32/D37's existing start and element-type checks to that field's shape. These are explicit checks in assertion-free builds. Each backend derives the containing field address, suffix offset, count and element width from target facts. Linux x86-64 register-forms a D18-wide module field offset, composes the written prefix offset with it, and uses an L0504-bounded field displacement for a local on both 64- and 32-bit target descriptions.

This is one contextual assignment rule, not a general field value or place. Repetition in local or module initializers from a field, arguments, returns, discards, operands, bare reads, fields of elements, struct-of-struct fields and nested arrays remains refused. A whole copy of the containing struct remains refused in this slice and is admitted later by D54. D53 does not change module static images or admit a field as an independently carried repetition value.

Why reuse the compact fill: D32/D37 already evaluate one repeated scalar and keep IR size independent of the target-sized extent, while D48/D52 already carry the containing field and ordered prefix writes. Combining those existing identities preserves source order without inventing another array representation.

The alternatives: keep repetition restricted to direct arrays, expand the suffix into one element store per target position, form a hidden complete array and copy it, or make the selected field a general array place. The first leaves D32/D37 unnecessarily asymmetric with D52; the second makes compiler work proportional to D18's extent; the third changes observable prefix-store order and frame cost; and the fourth broadens unrelated value contexts. All were declined.

Pinned by the checker, IR, verifier, lowering and backend public-seam cases; positive/struct-array-field-repetition-assignment; negative/struct-array-field-repetition-count-mismatch; negative/struct-array-field-mixed-prefix-too-long; negative/struct-array-field-repetition-element-mismatch; negative/immutable-struct-array-field-repetition; negative/struct-array-field-repetition-reads-incoming-state; negative/struct-array-field-repetition-not-on-every-path; the recorded IR dump; and runtime/struct-array-field-repetition-assignment-order on Linux x86-64.

D54 — An array-bearing struct is copied field by field

The tour said that assignment reaches its destination before its value [0410], that assigning an array copies its complete value [0520], that a struct has its declared fields [0670], that named structs have nominal identity [0710], and that a declaration-only local must be assigned before it is read [1910]. D16 made each scalar field of a struct local an independent assignment fact. D46 and D47 admitted module and local storage with fixed-scalar-array fields, while their whole-copy boundary remained refused.

Chosen: destination = source is admitted when both directly name D46 module state or D47 declaration-only local storage of the same nominal ordinary struct, directly or through aliases, and every field is an enabled scalar or a fixed array of enabled scalars. [0710] still refuses two distinct, same-shaped struct declarations with L0301. The destination root must be mutable; L0303 owns an immutable destination first and alone. This is the existing contextual struct assignment, not a general aggregate value.

A module source is complete under D10. Before a tracked local source is copied, every scalar field must have D16's field fact and every fixed-array field must be complete under D48--D53: either its D49/D50/D52/D53 binding-and-field whole fact exists or its D48 sparse element facts cover the declared length. A zero-length field is vacuously complete. The first incomplete field owns D16's L0302 and is named in the report. Self-copy follows the same read rule, so it cannot turn an unassigned object into an assigned one. A merge retains only the contributing facts present on every arriving path.

Normal completion assigns every destination field independently. A scalar field receives its D16 bit; a fixed-array field receives its binding-and-field whole fact, without assigning a scalar sibling or conflating two array fields. Lowering visits fields in declaration order. A scalar field keeps the existing Load_Field and Store_Field pair. A fixed-array field emits one D50 Copy_Array whose source and destination carry that field's declaration-order identity. No target offset, hidden aggregate temporary, whole-aggregate opcode, or operation per array element is introduced. Exact self-copy names identical ranges and the existing forward byte copy preserves them.

The verifier and backends need no new boundary: D50 already checks both positive field identities before reading their equal array shapes, and D53's storage-address path derives datum and frame field addresses from target facts. Linux x86-64 therefore register-forms a D18-wide module field and uses L0504-bounded frame displacements on both 64- and 32-bit target descriptions.

Initializers, arguments, returns, discards, operands, bare whole reads and every other general value of the struct remain refused in this slice, as do struct fields of struct type, fields of elements and nested arrays. In particular, an explicitly typed or inferred initializer from an array-bearing struct name reports the existing L0304 once in this slice. D55/D56 later admit the typed and inferred local direct-storage-name forms, and D60/D61 their module static image counterparts. None admits the name of a struct type declaration as storage. Before D54, the inferred spelling could silently settle an aggregate binding with no nominal body or value representation; D54 first routed it through the ordinary whole-value refusal, and D56 later carries that missing identity at the one admitted boundary without changing forward-name or cycle ownership. Parameters and returns still need their own calling-convention decision.

Why field-wise copy: the enabled aggregate representation already names each scalar or compact array field, and D16 plus D48--D53 already state exactly what makes each one initialized. Reusing those identities keeps compiler work and IR size independent of D18's array extent while preserving the nominal struct rule and target-neutral layout.

The alternatives: keep whole copy scalar-only, flatten each array into a scalar operation per element, add one opaque aggregate-copy instruction, or make the struct a general value. The first leaves two equally laid-out storage classes needlessly asymmetric; the second cannot represent every enabled extent; the third hides the field-shaped verification and assignment facts; and the fourth settles unrelated initializer, call and return rules. All were declined.

Pinned by the checker, lowering and backend public-seam cases; positive/struct-array-field-whole-copy; negative/struct-array-field-whole-copy-source-unassigned; negative/struct-array-field-whole-copy-not-on-every-path; negative/struct-array-field-whole-self-copy-unassigned; negative/immutable-struct-array-field-whole-copy; negative/struct-type-name-is-not-storage; negative/struct-copy-across-types; the recorded IR dump; and runtime/struct-array-field-whole-copy on Linux x86-64.

D55 — A typed local struct may snapshot directly named storage

The tour said that a local binding may carry an initializer [1810], that assignment reaches its destination before its value [0410], that assigning an array copies its complete value [0520], that named structs have nominal identity [0710], and that fields keep declaration order [0750]. D54 admitted the same field-wise copy only as an assignment between existing storage.

Chosen: an explicitly typed local binding, mutable or immutable, may be initialized from a direct name of existing module or earlier local storage when both have the same nominal ordinary struct type, directly or through aliases, and that struct has an enabled D44/D45 layout. A struct refused at one of its fields already owns that report, so this context does not ask for its missing layout. The value is contextual: it is accepted only in this binding form and does not make a struct name a general aggregate value. Per [0110], the new name is not in scope in its own initializer, so a same-spelled source denotes an outer binding.

A module source is complete under D10. A tracked local source must satisfy D54's whole-read rule before the initializer executes: every scalar field has its D16 fact and every fixed-array field has either its binding-and-field whole fact or complete D48 sparse facts. A zero-length field is vacuously complete. The first incomplete field reports D16's L0302. Two distinct, same-shaped struct declarations remain nominally different and report L0301 at the source, related to the binding. An unresolved source keeps resolution's own report.

Lowering allocates the destination's complete aggregate frame slot, then visits fields in declaration order. A scalar field uses D54's Load_Field or Load_Slot_Field followed by Store_Slot_Field; a fixed-array field uses one D50 Copy_Array from the source field into the same field of the fresh slot. The initialized binding therefore owns storage independent of its source. No aggregate value, hidden temporary, target offset, new IR operation, verifier rule, or backend invariant is introduced. D50/D53 already verify the compact field shapes and derive the module and frame addresses from target facts on both 64- and 32-bit descriptions.

An inferred local binding remains refused in this slice and is admitted by D56 only when its value is a direct struct storage name. A module initializer remains refused in this slice; D60/D61 later admit its typed and inferred direct-name forms. At D55, a non-name initializer, zeroed, a struct literal, an argument, return, discard, operand or bare whole read remained refused; D57 later admits typed local zeroed and D64/D65 the typed local labelled literal. The checker reports the existing L0304 once for an unsupported binding form; a binding it has already refused reads nothing for definite assignment under D16. Parameters and returns still need their own calling-convention decision, and struct-of-struct fields, fields of elements and nested arrays keep their existing boundaries.

Why the typed local form first: its written type supplies the nominal destination identity and its fresh slot reuses D54 without changing expression typing or static images. It is the smallest executable initializer slice and gives both scalar-only and array-bearing ordinary structs the same contextual copy rule.

The alternatives: also infer the destination type from the source, admit a module static image, admit aggregate zeroed, or make a struct name a general value. Inference needs a separate rule for carrying nominal identity; a module initializer needs a static struct-image chain; zeroed needs its own per-field initialization rule; and a general value settles calls, returns and temporary representation. All were declined here; D56 later supplies the separate nominal-identity rule for local inference only, D57 later supplies the typed local zeroed context, and D60/D61 later supply the typed and inferred module static image chains.

Pinned by the checker, lowering and backend public-seam cases; positive/local-struct-initialized-from-name; negative/local-struct-initializer-source-unassigned; negative/local-struct-initializer-not-on-every-path; negative/local-struct-initializer-nominal-mismatch; negative/local-struct-initializer-non-name-not-enabled; negative/local-struct-initializer-source-not-declared; negative/local-struct-initializer-source-type-mismatch; negative/struct-type-name-is-not-storage; the recorded IR dump; and runtime/local-struct-initializer-copies-storage on Linux x86-64.

D56 — A local struct is inferred from directly named storage

The tour said that an inferred local binding takes its value's type [0050], that the new name is not in scope in its own initializer [0110], that named structs have nominal identity [0710], and that fields keep declaration order [0750]. D55 admitted only the explicitly typed spelling because its written type supplied the destination's nominal body.

Chosen: a mutable or immutable local binding whose type is omitted may be initialized from a direct name of existing module or earlier local storage of an enabled ordinary struct type. The destination is inferred to have exactly the source's nominal body, including through a type alias. The source must resolve to a module or local binding: a struct type declaration is a name but is not storage and reports the existing L0304. Per [0110], a same-spelled source denotes an outer binding rather than the declaration being introduced.

Inference carries the source body's declaration onto the new local before the declaration settles as an aggregate. That identity is the one later field selection, contextual whole copy and slot layout use; inference does not construct a structural type or a bodyless aggregate value. A scalar-field and a fixed-array-field struct follow the same rule. An unresolved source keeps resolution's own report, and the existing underway guard preserves the single report for a value worked out from itself [1940].

The source read is exactly D54/D55's whole read. Module storage is complete by D10; a tracked local must have every scalar D16 fact and every fixed-array field whole or complete sparse fact on every arriving path. An internal zero-length field is vacuously complete. The initialized destination is a fresh, untracked local whose later reads are complete.

Lowering needs no new path after inference: D55 allocates the aggregate frame slot and visits the inferred body's fields in declaration order, using scalar load/store pairs and one compact D50 Copy_Array for each fixed-array field. D50/D53's verifier and target-derived address rules are unchanged. No general aggregate value, hidden temporary, new IR operation, target offset or backend invariant is introduced.

Module inference from a struct name in this slice, any non-name initializer, aggregate zeroed, a struct literal, call result, selected field, argument, return, discard, operand and bare whole read remain refused. Explicitly typed local initialization remains D55, contextual whole assignment remains D54, and typed and inferred module initialization remain refused in this slice until D60/D61's static-image rules. Fields of struct type, fields of elements and nested arrays keep their existing boundaries.

Why: the inferred form differs from D55 only in where its nominal identity comes from. Copying the source's already resolved body declaration before settling the local makes that identity explicit and lets every later stage reuse D55 unchanged. Treating every name whose type is aggregate as a source would instead confuse type declarations with storage and recreate the bodyless aggregate defect D54 exposed.

The alternatives: infer structurally from the field shapes, admit any aggregate-typed expression, infer module initial images, or defer all inference until general aggregate values exist. Structural inference violates [0710]; general expressions need a temporary representation; module inference needs a static image; and deferral leaves the direct-storage case artificially asymmetric with D21. All were declined here; D61 later reuses D60's image chain at the direct-storage boundary.

Pinned by the checker, lowering and backend public-seam cases; positive/local-struct-inferred-from-name; negative/local-struct-inferred-source-unassigned; negative/local-struct-inferred-not-on-every-path; negative/struct-type-name-is-not-storage; the recorded IR dump; and runtime/local-struct-inference-copies-storage on Linux x86-64.

D57 — A typed local struct is initialized to its zero image

The tour said that zeroed is the all-bits-zero image of its contextual type and writes that complete image as one value [0540], that a local binding may carry an initializer [1810], and that struct fields retain declaration order and target padding [0750]. D55 supplied only a directly named storage source for an explicitly typed local struct.

Chosen: [mut] name: T = zeroed is admitted inside a body when T resolves through aliases to a named ordinary struct with an enabled D44/D45 layout. Every enabled scalar and fixed-scalar-array field has a zero image, so the complete padded object extent has one. The written type supplies the literal's aggregate kind and nominal [0710] body. Both mutable and immutable bindings accept it, and the initialized local is untracked by D16.

Lowering allocates the fresh aggregate slot and emits one operand-free Clear_Array naming field zero. At that identity the operation clears either whole fixed-array storage, as before, or D57's whole aggregate storage; a positive field remains an array field. The verifier explicitly admits only an array or aggregate at field zero before any shaped accessor. Each backend derives an aggregate's complete padded extent from target facts and clears every byte, including padding. Linux x86-64 uses bounded scalar zero stores for one to six bytes or exactly eight bytes; other extents retain rep stosb. No field enumeration, hidden zero object, target offset or new opcode is introduced.

An invalid struct body already owns its field/layout report and never reaches lowering. An explicit module struct zero image in this slice, inferred name := zeroed, whole assignment name = zeroed in this slice, arguments, returns, discards, operands, nested expressions and general aggregate values remain refused. D58 later supplies the whole-assignment context and D59 the explicit module zero image. Struct fields of struct type, fields of elements and nested arrays keep their boundaries.

Why the padded whole: field-wise scalar stores and array clears would leave padding unspecified, contradicting [0540]'s all-bits-zero image. Reusing the destination-only clear keeps compiler work independent of D18-sized fields and keeps target layout in the backend.

The alternatives: clear fields separately, add a second aggregate-clear opcode, synthesize a zero object, or admit module, inferred and assignment contexts together. The first misses padding; the next two duplicate an existing storage operation or invent storage; the last settles distinct static image and place rules. All were declined.

Pinned by the checker, lowering, verifier and backend public-seam cases; positive/local-struct-zeroed-initializer; negative/inferred-zeroed-not-enabled; negative/local-struct-initializer-non-name-not-enabled; the recorded IR dump; and runtime/local-struct-zeroed-reads-zero on Linux x86-64.

D58 — A struct place is assigned its zero image

The tour said that assignment reaches its destination before evaluating its value [0410], that zeroed is the complete all-bits-zero image of its contextual type [0540], and that assignment requires a mutable place [1900]. D30 supplied this context for whole arrays, D49 for an array field, and D57 gave field zero of the compact clear operation a padded aggregate extent.

Chosen: place = zeroed is admitted when place directly names mutable D46 module state or a mutable D47 local of a named ordinary struct with an enabled D44/D45 layout. The destination supplies the literal's aggregate kind and nominal [0710] body. Root mutability is checked first; an immutable root reports the existing L0303 alone. Type aliases preserve the same body.

The destination is reached first and the literal evaluates nothing. On normal completion every scalar field, every fixed-array field and every padding byte in the complete target object extent is all bits zero. For a tracked local, D16 marks each scalar field assigned and D48--D54 mark each array field wholly assigned; branch merges intersect those facts as before. Module state remains untracked and complete under D10.

Lowering emits D57's one operand-free field-zero Clear_Array naming the module datum or frame slot. The verifier admits the whole aggregate storage explicitly, while Copy_Array and Fill_Array remain array-only. Each backend derives the padded extent and base address from target facts; no source storage, field enumeration, aggregate temporary, target offset or new opcode is introduced.

An inferred initializer name := zeroed, an explicit module initializer in this slice, arguments, returns, discards, operands, nested expressions and general aggregate values remain refused. D59 later admits the explicitly typed module zero image. A struct selection cannot currently name a struct-typed field, and fields of struct type, fields of elements and nested arrays keep their boundaries.

Why both storage classes: D30 and D49 already clear module and local storage with identical runtime semantics, D54 copies whole structs into both, and D10 makes module definite assignment simpler rather than different. Restricting this rule to locals would create a new storage-class asymmetry with no representation or semantic cause.

The alternatives: admit only locals, clear fields separately, add a new aggregate-clear opcode, or admit every aggregate-valued zeroed context at once. The first is asymmetric; the second misses padding; the third duplicates D57's operation; and the last settles static images and general aggregate values this place rule does not need. All were declined.

Pinned by the checker, lowering, verifier and backend public-seam cases; positive/struct-zeroed-assignment; negative/immutable-struct-zeroed-assignment; negative/struct-zeroed-assignment-not-on-every-path; negative/struct-zeroed-assignment-nested-not-enabled; negative/inferred-zeroed-not-enabled; the recorded IR dump; and runtime/struct-zeroed-assignment-clears-storage on Linux x86-64.

D59 — A typed module struct has an explicit static zero image

The tour said that zeroed is the complete all-bits-zero image of its contextual type [0540], that module declarations may carry values [1740], and that nothing runs before the entry point [1460]. D10 already gives a declaration-only module struct that same zero image, while D57 admitted the explicit spelling only for a local binding.

Chosen: [mut] name: T = zeroed is admitted at module scope when T resolves through aliases to a named ordinary struct with an enabled D44/D45 layout. The written type supplies the literal's aggregate kind and nominal [0710] body. Mutability does not affect initialization, so mutable and immutable declarations both accept it. Each declaration still owns distinct module storage.

This is a static image, not executable initialization. Lowering records the same aggregate datum, field-shape run and operandless Leave as D10's omitted initializer. It records no finite per-byte or per-field image and emits no Clear_Array: such an instruction inside a datum would wrongly imply runtime execution and remains verifier-refused. The backend therefore reserves the datum's complete target-derived padded extent in zero-initialized storage, including every field and padding byte.

Module state is complete under D10, so D16 gains no fact or flow rule. An inferred module name := zeroed, initialization from another struct name in this slice, a struct literal, call, argument, return, discard, operand, nested expression and general aggregate value remain refused. D60 later admits the typed direct-name static image chain and D66--D71 the typed module labelled literal. Fields of struct type, fields of elements and nested arrays keep their boundaries.

Why no new image: the explicit spelling denotes exactly the image D10 already requires. A runtime clear cannot run before [1460]; a finite byte image would make compiler work proportional to a D18-sized field; and field-wise images would either omit padding or duplicate target layout outside the backend. Leaving the image absent preserves the established .bss contract.

The alternatives: emit a clear in the datum, record every zero byte, record one zero per field, or admit direct-name and inferred module struct images at the same time. The first is not static, the next two duplicate or misplace layout, and the last needs a separate static struct-image chain. All were declined.

Pinned by the checker, lowering and backend public-seam cases; positive/module-struct-zeroed-initializer; negative/module-struct-zeroed-initializer-nested-not-enabled; negative/inferred-zeroed-not-enabled; the recorded IR dump; and runtime/module-struct-zeroed-image-is-static on Linux x86-64.

D60 — A typed module struct copies a static image from a storage name

The tour said that a binding may write its type and initializer together [0040], that module declarations form one order-independent scope [1740], that ordinary structs have nominal identity [0710], and that nothing runs before the entry point [1460]. D21 gave a direct-name module array initializer a static image chain, while D55 supplied the corresponding runtime copy only for a local ordinary struct.

Chosen: [mut] name: T = source is admitted at module scope when T resolves through aliases to a named ordinary struct with an enabled D44/D45 layout and source directly names module storage of that same nominal type. The source must be a storage binding rather than a type declaration. An unresolved name keeps resolution's report, a type declaration keeps the existing L0304, and a different nominal body reports L0301 at the source, related to the binding. Mutability affects later writes rather than initialization [0080].

The initializer is D21's declaration-identity static image chain applied to ordinary structs. It follows forward references and type aliases and must terminate at a module struct whose initializer is omitted under D10, is D59's explicit zeroed, or later carries D66's written labelled image. A chain that returns to a declaration is [1940]'s value worked out from itself and reports L0305 once. Every declaration in a valid chain owns distinct storage initialized with the terminal image rather than aliasing its source.

At this decision every constructible terminal image was all bits zero, so the first implementation recorded no finite aggregate image and reserved each target-derived padded extent separately in zero-initialized storage. D66 later adds the target-neutral declaration-order field run this rule required for a nonzero terminal and copies it along the same chain. Omitted and whole zeroed terminals retain the absent-image representation.

Module state remains complete under D10, so definite assignment gains no fact. An initializer boundary that has already refused the written type or value is not read again for [1940], preserving its owning report without a cascade. An inferred module binding in this slice, a non-name initializer, struct literal, call, field selection, argument, return, discard, operand, nested expression and general aggregate value remain refused. D61 later admits the inferred direct-name form and D66--D71 the typed module labelled literal. D55/D56's local initializers and D57--D59's zero-image contexts are unchanged. Struct fields of struct type, fields of elements and nested arrays keep their boundaries.

Why a static copy: aliasing would make a later write through one declaration change the other, contrary to D21 and D54's value semantics. A startup copy cannot run before [1460]. Following identities keeps each symbol and target layout distinct; D66 later supplies the first nonzero producer and carrier.

The alternatives: alias the source, emit runtime initialization, add a field or byte image now, admit inferred module initialization at the same time, or defer the direct-name form until struct literals. The first two contradict value and startup semantics; the third would have invented unused representation at this slice; the fourth needs its own nominal inference rule; and the last leaves arrays and structs asymmetric without implementation evidence. All were declined here; D61 later supplies that inference rule without widening the other forms.

Pinned by the checker, lowering and backend public-seam cases; positive/module-struct-initialized-from-name; negative/module-struct-initial-image-cycle; negative/module-struct-initializer-nominal-mismatch; negative/struct-type-name-is-not-storage; the recorded IR dump; and runtime/module-struct-initializers-copy-images on Linux x86-64.

D61 — A module struct is inferred from directly named storage

The tour said that an inferred binding takes the type of its value [0050], that module declarations form one order-independent scope [1740], and that ordinary structs have nominal identity [0710]. D21 already inferred module array storage from a direct name, D56 carried a struct's nominal body into an inferred local, and D60 supplied the typed module static image chain.

Chosen: [mut] name := source is admitted at module scope when source directly names module storage whose settled type is a named ordinary struct with an enabled D44/D45 layout. The destination takes exactly the source's nominal body through any type alias. The source must resolve to a storage binding rather than a type declaration; an unresolved name keeps resolution's report and a type name keeps the existing L0304. Mutability does not affect initialization [0080]. Scalar and fixed-array sources retain their existing inference rules.

Inference settles an untouched forward source on demand, then records its body on the destination before settling that destination as an aggregate. The inferred binding therefore has the identity later layout, selection and lowering require; it is not D54's old bodyless aggregate. It joins D60's static image chain, which follows forward references and aliases to D10's omitted or D59's explicit zero terminal and gives every declaration distinct storage.

A chain made entirely of inferred bindings that returns to itself is detected while its type is being settled and reports [1940]'s L0305 once. A mixed typed and inferred chain settles each member's nominal body, then D60's image validator reports that same cycle once. The mechanisms are disjoint: a failed inference is Ill_Typed and is not visited as an image, while the validator only visits successfully settled arrays and aggregates.

At this decision every constructible terminal image was zero. Lowering reused the inferred body to record one ordinary aggregate datum, compact field shapes and an operandless Leave; no finite image, runtime copy, clear, new instruction or target offset was introduced. D66--D71 later added target-neutral labelled scalar, finite, repeated and hybrid field images and copy those terminal images through the same D60/D61 declaration chain into distinct padded objects on 64- and 32-bit descriptions.

A non-name initializer or zeroed without a written type, call, field selection, argument, return, discard, operand, nested expression and general aggregate value remain refused. D64--D71 admit a struct literal only in their explicitly typed contextual local, assignment and module-image forms; inferred literals and call-shaped construction remain refused in this decision; D72 later supplies nominal construction. D55/D56's local forms and D57--D60's contextual zero and typed module forms are unchanged. Struct fields of struct type, fields of elements and nested arrays keep their boundaries.

Why now: D56 already provides the only missing nominal-identity step and D60 already proves and represents the module image. Reusing both closes the last typed/inferred and local/module asymmetry without making a struct name a general value or inventing startup execution.

The alternatives: infer structurally, alias the source, emit a startup copy, admit non-name expressions too, or keep module inference refused. Structural inference violates [0710]; aliasing is observable through writes; startup execution contradicts [1460]; general expressions need aggregate temporaries; and continued refusal has no remaining semantic or representation cause. All were declined.

Pinned by the checker, lowering and backend public-seam cases; positive/module-struct-inferred-from-name; negative/module-struct-mixed-image-cycle; negative/module-value-from-itself; negative/module-struct-inferred-non-name-not-enabled; negative/struct-type-name-is-not-storage; the recorded IR dump; and runtime/module-struct-initializers-copy-images on Linux x86-64.

D62 — zeroed reaches a fixed-array field element

The tour said that assignment reaches its destination before its value [0410], that selection and indexing reach a scalar subobject [0520], that only writable places may be assigned [1900], and that zeroed takes the all-bits-zero image of its context [0540]. D42 applied that context to an immediate scalar field or fixed-array element, while D48 later made s.f[i] an ordinary scalar place without revisiting D42's structural destination list.

Chosen: zeroed may be the complete right-hand side of assignment to an Element_Index whose target is a fixed-array Member_Selection from a directly named mutable local or module binding. The element type must resolve to an enabled scalar and supplies false for bool or typed integer zero. This is D42's scalar image at D48's place: it does not make the selected array field a whole value or make zeroed a general expression.

The ordinary place check remains first. It resolves the containing struct and field, checks the index type and compiler-known bound, and retains root mutability and every invalid-place refusal before the value is considered. A computed index is evaluated exactly once and keeps D48's runtime bounds trap. A nested occurrence such as s.f[i] = zeroed + 1 remains refused with the existing L0304, and a refused destination produces no additional flow report.

Successful completion has D48's ordinary definite-assignment effect: a compiler-known index records only (binding, field, position), a computed index records no sparse fact, and neither assigns a sibling position or the array field as a whole. Lowering reuses D42's typed Truth or Number and D48's field-qualified Store_Element; the verifier and backend therefore gain no new operation, shape, ordering rule, address calculation or target invariant. A module root is runtime storage reached from a function body, not a module initial image, so D60's static-image boundary is unchanged; D66 later adding a written image does not turn this runtime store into initialization.

Why this place: D48 already types and represents its element as an ordinary scalar place. Keeping zeroed refused there would make the literal depend on the number of selectors rather than on the destination semantics it uses.

The alternatives: admit every scalar place accepted by Check_Place, or wait for general aggregate values. The first would silently choose the rule for future struct-of-struct and element-field chains whose representation is not settled; the second leaves a currently representable scalar place asymmetric for no semantic reason. Both were declined. The structural destination list is extended by exactly this D48 shape and may become a type-based test when deeper places are designed.

Pinned by the checker and lowering public-seam cases; positive/struct-array-field-element-zeroed; negative/struct-array-field-element-zeroed-immutable; negative/struct-array-field-element-zeroed-nested; negative/struct-array-field-element-zeroed-keeps-facts-separate; the recorded IR dump; and runtime/struct-array-field-element-zeroed-computed-index-traps on Linux x86-64.

D63 — Ordinary-struct literal spellings are refused by name

The tour said that an ordinary struct may be written as a parenthesized field image [0710] and showed call-shaped construction with named fields [0700]. The enabled expression grammar [1810] has neither form. Before this decision, (x: 1, y: 2) entered the parenthesized-expression parser and the first : produced an unnamed syntax cascade, while point(x: 1, y: 2) entered the ordinary-call parser and failed for the same reason.

Chosen: while ordinary-struct literals remain outside [1810], the parser recognizes their unambiguous opening shapes and refuses each complete or truncated construct once with L0010. A value-position ( followed by identifier : names [0710]'s struct literal. The contextual all-field form (of expression) names the same construct when of is followed by an unambiguous expression start: one that is not also a binary operator. Thus (of), (of + 1), (of - 1) and other ordinary uses of a binding named of remain parenthesized expressions, while (of zeroed), (of not ready) and (of ~mask) name [0720]'s contextual fill. An identifier call whose opening parenthesis is followed by identifier : names [0700]'s call-shaped construction. Ordinary (expression) and positional callee(arguments) keep their existing grammar and parse.

The refusal consumes balanced parentheses, including nested parentheses, or stops at end of input. It returns one error expression and does not create a dormant struct-literal node, field-name references or aggregate value. Any immediately following bracketed index is skipped as recovery rather than reported as a second refused construct. The automatic truncation suite holds every prefix to producing a finite, well-formed tree.

At D63 the normative grammar was deliberately unchanged. A negative fixture whose first report is the frontend's L0010 must remain underivable; adding a struct_literal production would claim the source is enabled while the parser still refuses it. The later literal slice must replace this lookahead with a real syntax node and grammar production, teach resolution that field labels are not ordinary name references, and migrate these fixtures to positive or later-stage evidence. D64 performs that migration and lowers local and assignment contexts field by field; D66--D71 add the target-neutral module static-image representation D60 deferred.

Why pin the refusal first: the named before-state separates migration from recovery. It lets the enabling slice prove exactly which L0010 refusals it removes without inheriting an accidental cascade as specification.

The alternatives: add the grammar and a dormant node now, let the checker refuse every use of that node, or leave the accidental syntax reports in place. The first two perform half of the enabling slice and require name resolution and whole-value policy before any value is admitted; the last has no stable construct owner or migration evidence. All were declined.

Pinned by the parser public-seam case; negative/struct-literal-not-enabled; the generated construct matrix and token dump; and the automatic parser truncation suite. D72 later migrates the construction fixture to the checker-owned contextual boundary.

D64 later supersedes this refusal for the nonempty labelled form by adding its grammar and contextual syntax node. D72 later supersedes the call-shaped construction refusal by attaching a nominal type to that same node. The all-of form alone retains D63's parser-owned refusal and recovery rule and is cited to [0720], its surviving construct, rather than [0710]'s enabled labelled form.

D64 — A labelled struct literal writes contextual local storage

The tour said that an ordinary struct image names fields in parentheses [0710], that their written order determines evaluation [0410], and that a trailing of supplies fields not written individually [0720]. D63 first gave the unambiguous spelling one parser-owned refusal. D23 and D29 separately settled the initializer and immediate-write assignment contexts for arrays, while D57/D58 supplied the corresponding whole-struct storage contexts.

Chosen: struct_literal and field_value are enabled by [1810]'s grammar. A labelled literal is admitted only as (a) the initializer of an explicitly typed local binding whose written type resolves to an enabled named ordinary struct, or (b) the complete right-hand side of assignment to a directly named mutable module or local binding of such a type. The context supplies [0710]'s nominal body. Inferred bindings, discards, operands, arguments, returns and every general aggregate-value position remain L0304. Module initializers remain L0304 in this slice; D66 later admits their scalar-labelled static-image subset. The call-shaped construction T(field: value) remains a parser-owned L0010 refusal until D72 supplies its nominal type. The all-fill spelling (of zeroed) remains refused by name.

Labels may appear in any order. Each must name a field of the contextual body; an unknown label keeps L0308. A field may be named at most once: the second label reports L0309, related to the first. Without a trailing fill every field must be named; one L0310 at the literal lists the missing fields in declaration order. Named fields in this slice must be scalar, and each value is checked in that field's resolved scalar context. D65 later supplies the same contextual destination to scalar zeroed and to D49--D53's fixed-array field forms.

The only trailing fill admitted is of zeroed. It writes every unnamed scalar field as typed integer zero or false and clears every unnamed fixed-array field with D49's compact whole-field operation. General of expression is L0304: one expression node cannot simultaneously commit to heterogeneous field types, and choosing an implicit conversion or duplication rule is deferred. The all-fill form remains refused because D57/D58 already spell the complete zero image directly as zeroed.

Named expressions are evaluated and committed immediately in source order, regardless of declaration or layout order. The fill follows them and visits unnamed fields in declaration order. Thus a later field expression observes an earlier field write to the same destination, exactly as D29 exposes array literal writes; no hidden aggregate temporary or atomic commit exists. Reads inside all named expressions are checked against the definite-assignment state arriving at the statement. On successful completion the destination receives D54/D58's whole-aggregate assignment facts: every scalar field and every fixed-array field is complete. A typed local initialized by the literal has a value and is consequently untracked, as other initialized locals are.

The tree carries one Struct_Literal with an optional fill slot and a written run of Field_Value nodes. A field label belongs to its Field_Value; it is not a Name_Reference and resolution never binds it. The checker records the nominal body on the literal and the declaration-order field identity on every valid label. Lowering emits an ordinary scalar field store immediately after each named expression, then typed scalar-zero stores and field-qualified array clears for the fill. It introduces no aggregate value, new IR operation, verifier rule, backend address form, target layout or static image. A module initializer remains refused in this slice; D66 later supplies the target-neutral nonzero terminal image for the scalar-labelled subset. A body whose earlier field or extent refusal prevented layout silently refuses the contextual literal as well: the owning field or L0300 report is not followed by a layout query or a second diagnostic.

Why this boundary: the two contexts already own aggregate storage, nominal identity, definite assignment and field-shaped lowering. Enabling them proves the literal's evaluation rule without opening aggregate temporaries or a nonzero module image. Including of zeroed also reaches array-bearing structs without making a nested array literal a field value.

The alternatives: admit only the local initializer, admit arbitrary named array fields, admit a general heterogeneous of expression, make the literal a general aggregate value, or add a nonzero module image at the same time. The first leaves D29's exposed-write question open; the next two need nested-array and per-field commitment rules; the fourth needs aggregate temporaries; and the last needs the representation D60 explicitly deferred. All were declined.

Pinned by the parser, checker and lowering public-seam cases; positive/struct-literal-contexts; negative/struct-literal-field-named-twice; negative/struct-literal-field-not-given; negative/struct-literal-unknown-field; positive/struct-literal-of-expression; negative/struct-literal-field-type-mismatch; negative/struct-literal-reads-incoming-state; negative/struct-literal-without-layout; negative/immutable-struct-literal-assignment; negative/module-struct-literal-inferred-not-enabled; negative/struct-array-field-layout-overflow; negative/struct-literal-not-enabled; the generated catalogue, construct, token and IR records; and runtime/struct-literal-order-and-fill on Linux x86-64.

D65 — A label is its field's contextual destination

The tour said that a struct literal takes its type from context [0710], that each written label supplies one field value and a trailing of supplies the rest [0720], and that evaluation follows written order [0410]. D64 admitted the literal but limited written values to ordinary scalar expressions. D42 and D49--D53 had already settled the corresponding contextual scalar-zero and fixed-array-field assignment forms.

Chosen: in D64's explicitly typed local initializer and whole-assignment contexts, each label is the same contextual destination as selecting that field for assignment. A labelled scalar field additionally accepts zeroed, which takes D42's resolved scalar type and all-bits-zero image. A labelled fixed-array field accepts exactly D49--D53's complete contextual forms: an array literal, full or mixed-prefix repetition, zeroed, a direct array storage name, or a selected fixed-array field of the same D17 shape. The array value node records the labelled field's element type and length; the label continues to record the declaration-order field identity.

Labels are still evaluated and committed in source order. An array literal writes its elements immediately in their own source order; a repetition writes its prefix then evaluates its repeated expression once and performs one compact fill; a copy is one compact field-qualified copy; and zeroed is one compact field-qualified clear. A later label therefore observes every earlier labelled write. D64's trailing of zeroed runs only after all of them and retains its declaration-order fill. Reads in every field expression are checked against the state arriving at the statement, while successful completion retains D64's whole-aggregate definite-assignment facts.

The checker delegates each array form to its existing contextual shape, count, element and source-read rule with Static_Image => False. Lowering uses one field-qualified writer over the existing Store_Element, Fill_Array, Copy_Array and Clear_Array operations; scalar zeroed uses the existing typed Truth or Number followed by a scalar field store. No grammar, syntax node, IR operation, verifier rule, backend address form, target fact, layout or static image changes.

A nested array literal remains refused as a scalar element, and no other general array value is introduced. At this increment a general trailing of expression was refused: the one expression node has one committed type, while omitted fields may be heterogeneous; converting it per field is not enabled, and evaluating it again per field would violate the once-only rule. Inferred literals still have no nominal body and wait for [0700]'s construction decision, which D72 later supplies. Module literals remain outside this slice; D66 later supplies D60's nonzero aggregate image carrier for scalar labels, D67 adds its finite-or-zero array-field form, D68 its repeated and hybrid forms, D69 a direct module-array image source, and D71 a selected module-array-field source. The all-of spelling remains D63's redundant parser refusal, and general aggregate values remain outside this slice. D214 supersedes the homogeneous-fill refusal: equal complete descriptors need neither multiple node types nor conversion, so one evaluated value can be copied into every omitted field. Heterogeneous fills remain refused.

Why the field destination: the selected field already owns exactly the shape, storage, diagnostics, ordering and target-derived operation the written value needs. Reusing those decisions closes D64's artificial label boundary without opening a second array representation or aggregate temporary.

The alternatives: admit scalar zeroed alone, restrict a general of expression to accidentally homogeneous fields, convert or re-evaluate that expression per field, infer a nominal body from labels, add nonzero module images, or admit the all-of synonym. The first is too small to justify a separate semantic principle; the next three contradict single-node typing, once-only evaluation or nominal identity; the fifth needs D60's deferred representation; and the last duplicates whole zeroed. All were declined.

Pinned by the checker and lowering public-seam cases; positive/struct-literal-array-field-forms; negative/struct-literal-array-field-shape-mismatch; negative/struct-literal-array-field-element-mismatch; negative/struct-literal-array-field-repetition-mismatch; negative/struct-literal-array-field-source-unassigned; negative/struct-literal-nested-array-value-not-enabled; negative/immutable-struct-literal-assignment; positive/struct-literal-of-expression; the generated token and IR records; and runtime/struct-literal-array-field-order on Linux x86-64.

D66 — A typed module struct literal is a static field image

The tour said that a module binding may carry a value [0040], that an ordinary struct image names its fields [0710], that the remaining fields may be supplied by of [0720], and that nothing runs before the entry point [1460]. D24 established target-neutral folded static images for arrays, D60/D61 established declaration-identity module struct image chains, and D64/D65 established the contextual labelled literal and its field rules at runtime.

Chosen: [mut] name: T = (field: value, ..., of zeroed) is admitted at module scope when T resolves to an enabled named ordinary struct with a layout. The written type supplies the literal's nominal body. D64's freely ordered, unique labels, L0308 unknown-field owner, L0309 duplicate owner and L0310 missing-field owner apply unchanged. Each explicitly named field in this first static carrier must be scalar. D67 later supersedes that boundary for a finite or zeroed fixed-array label, and D68 adds full and mixed repetition. A trailing of zeroed supplies zero or false to every unnamed scalar field and the absent zero image to every unnamed fixed-array field. A fixed-array field named explicitly is L0304 in this slice; D67 later admits its finite literal and zeroed forms through a compact per-field image, D68 admits repetition, and image copy remains a later decision until D69 admits the direct module-array-name form. Selected-field image copy remains outside that rule.

Each scalar field expression must be known without execution under [1940]: a literal, contextual scalar zeroed, an enabled operator over known operands, or a module scalar name whose value is known. A call reports L0305. A selected field, index or nested array image reports its existing L0304 static-image refusal, including beneath an otherwise foldable operator. Integer folding keeps D24's overflow owners: a fold beyond the compiler's widest magnitude or beyond the field's selected-target type reports L0300. An inferred module binding still has no nominal body and keeps L0304; a general of expression, the all-of spelling, call-shaped construction and general aggregate value remain refused in this decision; D72 later supplies contextual nominal construction.

The target-neutral aggregate image is one Folded entry per field in [0750]'s declaration order. A scalar entry is its folded value. An unnamed scalar entry is zero, and a fixed-array entry is the zero placeholder for its absent image. The representation contains no target byte, offset or padding. The verifier requires the image length to equal the field count, requires an array-field placeholder to be zero, and checks each scalar fold against the selected target before any backend accessor can consume it, including in builds without contract checks.

The backend lays out the field-shape run with the same target placement used by D45. It writes scalar entries with that target's width, emits zero for every array field, gap and tail-padding byte, and gives the complete padded object a .data image. A labelled literal whose folds are all zero remains a written image, as D24 decided for arrays; only an omitted initializer or whole zeroed retains D10/D59's absent image and .bss storage. Nothing is copied or cleared at startup. D60/D61 chains that terminate at the literal copy its field-image run into each declaration's distinct datum, preserving forward references, aliases and cycle ownership. The literal is a terminal image, so a cycle can arise only in the declaration-name chain that precedes a terminal; D60/D61's single L0305 owner remains unchanged.

Module state remains complete under D10 and no definite-assignment fact is added. The literal has no runtime evaluation order because its expressions are folded rather than executed. D64/D65's local initializer and whole-assignment rules remain immediate runtime writes and do not acquire this static-image semantics.

Why fields rather than bytes: folds preserve the same source image across 32- and 64-bit targets while target placement remains the only authority on widths, offsets and padding. A target-byte blob would make the neutral IR target-specific, and a startup routine would contradict [1460]. Restricting the first carrier to scalar labels proves the representation without expanding D24/D34/D38's finite, repeated and hybrid array forms inside every aggregate field.

The alternatives: emit a target-byte blob, synthesize a startup clear or copy, store fields at runtime, keep module literals refused, or admit every D65 array-field form at once. The first three violate target neutrality or static initialization; the fourth leaves D60's deliberate carrier seam unused; and the last needs a compact nested image representation before its verifier and backend invariants can be stated. All were declined here.

Pinned by the IR, verifier, checker, lowering and backend public-seam cases; positive/module-struct-literal-initializer; negative/module-struct-literal-inferred-not-enabled; negative/module-struct-literal-selection-not-enabled; negative/module-struct-literal-value-not-known; negative/module-struct-literal-field-out-of-range; negative/module-struct-literal-field-fold-overflow; the generated token and IR records; and runtime/module-struct-literal-image-is-loaded on Linux x86-64.

D67 — A labelled fixed-array module field has a finite or zero image

The tour said that an ordinary struct image names its fields [0710], that an array literal names its elements [0410], and that nothing runs before the entry point [1460]. D24 established finite target-neutral module array images, D60/D61 established declaration-identity struct image chains, and D66 left one zero placeholder for every fixed-array field until a compact field image could own its elements.

Chosen: a fixed-array label in D66's explicitly typed module struct literal accepts a nonempty array literal of exactly the field's D17 length and element type, or contextual zeroed. Each literal element must be known without execution under [1940] and follows D24's static exclusions and folding owners: a call reports L0305, a selected field, index or nested image reports L0304, and a fold beyond the compiler's widest magnitude or the selected target type reports L0300. A length or element disagreement keeps the existing L0301 owner. zeroed denotes the absent all-zero field image, including for D17's zero-length shape; a written finite literal remains nonempty, so it cannot initialize that shape.

D66's flat aggregate image remains one Folded placeholder per field in declaration order, and every array placeholder remains zero. A parallel per-field descriptor says Absent or Finite; a finite descriptor names an offset and count in one concatenated run of source folds stored after the flat field run. Repeated and Hybrid descriptor forms are reserved so the next slice can extend the carrier without replacing it; the verifier refuses either form in D67, and D68 later supplies their canonical meanings. The carrier contains no target width, offset, padding byte or machine identity.

The IR setter records the flat folds, descriptors and finite elements as one item image operation. The verifier first proves the flat and descriptor counts, canonical finite offsets, scalar-field absence, zero array placeholders and the total element extent; only then does it read each finite element and check that fold against the field's selected-target element type. These are explicit checks in builds without contract assertions. A malformed finite length, out-of-target fold, descriptor on a scalar field or reserved form is a verifier fault before a backend accessor can consume it.

The backend replays D45's target placement. An absent array field emits zero for its complete target extent; a finite field emits one directive of the target element width for each fold, while every inter-field gap and tail byte remains zero. A finite literal whose elements are all zero is still a written .data image, as D24 and D66 require; zeroed and an unnamed field supplied by of zeroed remain absent within that written aggregate image. D60/D61 chains copy every descriptor and finite fold into each distinct destination datum, so forward references, aliases, inferred links and independence after mutation remain unchanged.

Full and mixed repetition, a direct array storage name and a selected fixed-array field remain L0304 as labelled module images. Repetition needs the reserved compact suffix forms and is admitted by D68; copy needs image resolution through another datum and retains the existing refusal of a selected field as a module array initializer. Inferred struct literals, a general of expression, the all-of spelling, construction and general aggregate values remain outside this slice; D72 later supplies construction only. No grammar, syntax node, diagnostic code, runtime instruction, target fact or layout rule changes.

Why a descriptor beside the flat run: D66's scalar image and its verifier contract remain stable, while a field can own a finite source image without embedding target bytes or flattening element positions into aggregate fields. Keeping every segment in the item's existing image run preserves the IR's single-owner partition invariant and makes declaration-chain copying atomic at the representation seam.

The alternatives: admit every D65 form at once, admit only the finite form, add name-chain copy before a general carrier, flatten target bytes, or emit a startup routine. The first and third add recursive image and cycle questions; the second leaves a needless asymmetry with of zeroed; and the last two violate target neutrality or [1460]. The complete compact carrier with only finite and absent producers was chosen. D68 later supplies repetition, and D69 follows a direct module-array image. D70 then permits an ordinary module array image to take a selected field, and D71 permits a labelled field to take another selected field's image.

Pinned by the IR, verifier, checker, lowering and backend public-seam cases; positive/module-struct-literal-array-image; negative/module-struct-literal-array-image-length-mismatch; negative/module-struct-literal-array-image-element-mismatch; negative/module-struct-literal-array-image-value-not-known; negative/module-struct-literal-array-image-storage-read; negative/module-struct-literal-array-image-out-of-range; negative/module-struct-literal-array-image-fold-overflow; negative/module-struct-literal-empty-array-field-image; the generated token and IR records; and runtime/module-struct-literal-array-image-is-loaded on Linux x86-64.

D68 — A repeated module struct field image stays compact

The tour said that a full repetition writes one value into every array position [0560], that a mixed repetition writes its prefix before repeating one final value [0410], and that nothing runs before the entry point [1460]. D34 and D38 established compact repeated and hybrid images for module arrays; D67 reserved the same two descriptor forms beside each fixed-array field.

Chosen: a fixed-array label in D66's explicitly typed module struct literal also accepts D34's full repetition and D38's mixed-prefix repetition. The written or inferred count and the field's D17 length must agree; a mixed prefix must leave a nonempty suffix. Every prefix and repeated expression has the field's scalar element type, must be known without execution under [1940], and keeps D24/D34/D38's static-subtree, widest-fold and selected-target range owners. Thus a count or element disagreement reports L0301, a zero contextual length or excluded storage read reports L0304, an unknown call reports L0305, and an overflowing or out-of-target fold reports L0300.

A Repeated descriptor has count zero, a nonzero folded pattern and no element segment. A full zero repetition is canonicalized to D34's Absent image rather than carrying a redundant zero pattern. A Hybrid descriptor has a prefix count k with 1 <= k < length, stores exactly those k source-order folds in D67's concatenated element run, and carries one folded suffix pattern. A hybrid remains a written image even when its prefix and suffix are all zero, as D38 decided. The flat aggregate field placeholder remains zero in every case; the representation still carries no target width, field offset or padding.

The IR setter records all flat folds, descriptors and finite or hybrid-prefix elements in one item-owned run. The verifier first proves the aggregate-image and descriptor partitions, field count, canonical offsets, field kinds and form-specific count rules. Only then may it read a prefix or pattern and check each fold against the selected target. A repeated zero pattern and a hybrid whose prefix consumes the field are noncanonical verifier faults. These checks are ordinary release-build code rather than contracts.

The backend replays D45's placement, emits a finite or hybrid prefix with the field element's target directive, and emits a compact .rept suffix for a repeated or hybrid field. Absent zero repetitions, inter-field gaps and tail padding remain .zero. The same target-neutral descriptor therefore selects .long for usize on a 32-bit target and .quad on a 64-bit target without changing the IR. D60/D61 chains already copy each descriptor, its suffix value and its compact prefix into distinct destination datums, so no new image recursion or cycle rule is introduced.

A direct module array storage name or selected array field remains L0304 as a labelled module image in this slice. D69 later follows the former through another datum's finite, repeated, hybrid or absent image; D70 supplies the ordinary module-array initializer rule for the latter, and D71 then admits it as a labelled module image too. Inferred literals, heterogeneous of expression, all-of, construction and general aggregate values remain refused here; D72 later supplies construction. No grammar, syntax node, diagnostic code, runtime instruction, target fact or layout rule changes.

Why finish the reserved carrier first: repetition adds no image dependency: all its folds are children of the terminal literal. Name-copy labels would add a second datum to image resolution, while selected-field copy would cross an existing module-array boundary. Completing the local descriptor meanings keeps this slice acyclic and gives the verifier and backend one invariant at a time.

The alternatives: admit repetition together with direct and selected image copy, admit only full repetition, flatten the expanded field into target bytes, or synthesize startup stores. The first combines a compact producer with image recursion, the second leaves D38's already represented hybrid form unused, and the last two violate target neutrality or [1460]. All were declined.

Pinned by the IR, verifier, checker, lowering and backend public-seam cases; positive/module-struct-literal-array-image; negative/module-struct-literal-array-image-length-mismatch; negative/module-struct-literal-array-image-element-mismatch; negative/module-struct-literal-array-image-value-not-known; negative/module-struct-literal-array-image-storage-read; negative/module-struct-literal-array-image-out-of-range; negative/module-struct-literal-array-image-fold-overflow; negative/module-struct-literal-array-repetition-zero-length; the generated token and IR records; and runtime/module-struct-literal-array-image-is-loaded on Linux x86-64.

D69 — A module array image may fill a labelled fixed-array field

The tour said that a module initializer is an image present before the entry point [1460], that a fixed array's value is its element sequence [0520], and that struct fields have declaration-order layout while labelled values may name them in another order [0710], [0750]. D21 already follows a direct module array name to its terminal static image. D67/D68 already carry every canonical array image form beside a struct field.

Chosen: a fixed-array label in D66's explicitly typed module struct literal also accepts a direct name bound to a module fixed-array datum with the exact D17 length and element type. The field receives a copy of that datum's resolved static image: D24's finite folds, D34's nonzero repeated pattern, D38's hybrid prefix and suffix, or the absent zero image of an omitted, explicit zeroed or zero-pattern source. The source may be declared later and may itself be a D21 direct-name chain. Each struct declaration still owns distinct storage; a later write to the source array, the struct field or a D60/D61 struct-image copy changes none of the others.

A length, element-type or non-array storage mismatch reports L0301 at the source name and relates it to the field label. An unresolved or already refused source keeps its existing owner without a second report; a source array-image cycle keeps D21's single L0305. A type declaration, selected field or other value remains L0304 in this slice. D70 moves that boundary for ordinary module arrays, and D71 then lets a struct label reuse that contextual source.

Image resolution visits the named array before gathering the struct image, so a forward finite, repeated or hybrid source cannot be mistaken for absent. The lowering copies the source's canonical form into D67's existing descriptor, re-bases a finite or hybrid prefix at the field's running element offset, and calls the existing aggregate-image setter once. An all-zero finite image and an all-zero hybrid remain written; an omitted or zero-repetition source remains absent. The existing verifier rechecks descriptor form, count, offset and selected-target fit before reading it, and the backend consumes the same descriptor at D45's target-derived field offset. No IR, verifier, backend, target, grammar, syntax or diagnostic representation changes.

Why direct storage only: it completes D21 parity without making an array field a general value. Selected-field copy would read another aggregate's descriptor and contradict the ordinary module-array initializer boundary; construction or inferred literals need nominal-body and grammar decisions, which D72 later supplies together. Restricting the source to finite images would save no representation and would arbitrarily discard D34/D38 forms the carrier already represents. All were declined.

Pinned by the checker and lowering public-seam cases; positive/module-struct-literal-array-image-copy; negative/module-struct-literal-array-image-copy-shape-mismatch; negative/module-struct-literal-array-image-copy-source-cycle; negative/module-struct-literal-array-image-copy-source-refused; negative/array-type-name-is-not-storage; the generated token and IR records; and runtime/module-struct-literal-array-image-copy-is-independent on Linux x86-64.

D70 — A module array takes a selected field's static image

The tour said that a binding may name or infer its type [0040], [0050], that a fixed array's value is its element sequence [0520], and that nothing runs before the entry point [1460]. D21 follows module array images through direct storage names, D51 copies a selected fixed-array field into a fresh local array, and D67/D68 carry every canonical array image beside a struct field. None decided whether the same field could supply a module array image.

Chosen: [mut] name: [N]T = s.f and [mut] name := s.f are admitted at module scope when s directly names a module binding of an ordinary struct with a layout and f is one of its fixed-array fields. The explicit form requires [N]T to have the field's exact D17 length and element type; a disagreement reports L0301 at the selection and relates it to the binding. The inferred form takes that identity exactly. This is D51's contextual source at module scope, not a general value: the root need not be mutable, and the selection remains refused as an argument, return, discard, operand or bare read.

The destination receives a copy of the field's resolved static image in distinct storage. A D67 finite field becomes D24's finite array run, a D68 nonzero repetition stays compact, a hybrid keeps its finite prefix and suffix pattern, and an absent field leaves the destination's image absent. Thus an all-zero finite or zero-suffix hybrid remains written while an omitted, zeroed or zero-repetition field remains loader-zeroed. A later write to the struct field or destination array changes only that storage.

Image validation and lowering resolve the containing struct before reading its field descriptor. The struct may be declared later, may itself follow a D60/D61 aggregate image chain, and may have received the field through D69. D69's struct-to-array edge and this array-to-struct edge may form a real image cycle: a: [N]T = s.f; s: S = (f: a). The existing per-declaration Visiting state reports [1940]'s L0305 once at whichever declaration is first found revisited and marks the rest invalid silently. An already refused containing image likewise keeps its existing owner without a second report.

Lowering maps D67's existing Absent, Finite, Repeated and Hybrid descriptor forms to the existing array-image setters. It reads a descriptor only after the containing aggregate has a written image, reads prefix elements only for the finite and hybrid forms, and lets every downstream D21 array link copy the resulting ordinary array item. The existing verifier rechecks the array image on the selected target, and the backend emits it with the array element's target width. No IR, verifier, backend, target, grammar, syntax or diagnostic representation changes.

Why typed and inferred together: D21 and D51 already give those spellings one rule, and inference can carry the selected field's complete D17 identity without inventing a nominal or general value. Admitting only the typed form would add no safety or representation boundary. Delaying the whole rule would leave D69's reverse dependency artificially one-way. Admitting other.row as a label inside a struct literal is a second producer and validator edge; D71 adds that edge with separate cycle and descriptor evidence. All other widenings were declined.

Pinned by the checker and lowering public-seam cases; positive/module-array-from-struct-field; negative/module-array-from-struct-field-shape-mismatch; negative/module-array-from-struct-field-cycle-array-first; negative/module-array-from-struct-field-cycle-struct-first; negative/module-array-from-struct-field-source-refused; the generated token and IR records; and runtime/module-array-from-struct-field-is-independent on Linux x86-64.

D71 — A labelled fixed-array field takes a selected field's static image

The tour said that a module initializer is an image present before the entry point [1460], that a fixed array's value is its element sequence [0520], and that a struct literal supplies labelled field images [0710]. D65 already accepts a selected fixed-array field as the contextual source of a runtime label. D69 admits a direct module array as the corresponding static source, and D70 lets an ordinary module array take a selected field's static image.

Chosen: a fixed-array label in D66's explicitly typed module struct literal also accepts s.f when s directly names a module binding of an ordinary struct with a layout and f is one of its fixed-array fields with the label's exact D17 length and element type. A disagreement reports L0301 at the selection and relates it to the label. An unresolved or already refused root keeps its existing owner without a second report. A scalar selection, an element or nested selection, and a selection rooted at a type declaration remain refused. This remains a contextual image source rather than a general array or aggregate value.

The destination field receives a copy of the selected field's resolved image: D67's finite run, D68's repeated or hybrid form, or the absent zero image. The root may be declared later, may itself follow a D60/D61 aggregate image chain, and may have received the selected field through D69, D70 or this rule. Each declaration owns distinct storage; a later write to the source, destination or another image-chain member changes only that storage. All-zero finite and hybrid images remain written, while an omitted, zeroed or zero-repetition field remains absent.

Image validation follows the containing struct before accepting the label. The existing per-declaration Visiting state therefore also owns a pure struct-to-struct selected-field cycle and a cycle mixing D21, D69, D70 and D71: [1940]'s L0305 is reported once at the declaration first found revisited, and the remaining path becomes invalid silently. A refused source likewise does not acquire a second contextual report.

Lowering resolves the source aggregate before reading its field descriptor, copies only the finite or hybrid prefix elements carried by that descriptor, and re-bases their offset at the destination aggregate's compact element run. The same helper copies an aggregate image through D60/D61, so both paths retain one canonical offset rule. The aggregate-image setter is still called once; the existing verifier rechecks descriptor form, count, offset and target fit, and the backend consumes it at D45's placed field offset. No IR, verifier, backend, target, grammar, syntax or diagnostic representation changes.

Why the direct selected field: D65 already gives the runtime spelling this shape and D70 supplies the missing module-array image boundary. Reusing the same direct-root, whole-field rule closes the remaining edge between array and aggregate datums without making selection a general value.

The alternatives: also admit a selected scalar field, an indexed element, a nested selection, an inferred struct literal or a general aggregate value; or delay the rule. The first three cross D24's static-expression and the depth-one storage boundaries, the next two require nominal construction or aggregate temporaries (D72 later supplies only the former), and delay would leave D69/D70's contextual image graph artificially incomplete. All were declined.

Pinned by the checker and lowering public-seam cases; positive/module-struct-literal-selected-field-image; negative/module-struct-literal-selected-field-boundary; negative/module-struct-literal-selected-field-shape-mismatch; negative/module-struct-literal-selected-field-cycle-first; negative/module-struct-literal-selected-field-cycle-second; negative/module-struct-literal-selected-field-mixed-cycle; negative/module-struct-literal-selected-field-source-refused; the generated token and IR records; and runtime/module-struct-literal-selected-field-image-is-independent on Linux x86-64.

D72 — Construction names the ordinary struct a labelled literal builds

The tour said that construction applies a type to labelled fields [0700], that two ordinary structs have one type only when one declaration wrote both [0710], and that field expressions run in source order [0410]. D64--D71 had already implemented the same labelled run wherever a destination supplied its nominal body, but a bare inferred literal deliberately had no such source.

Chosen: T(field: value, ...[, of zeroed]) is a labelled Struct_Literal whose optional nominal slot names T. It is admitted in exactly the storage contexts already owned by D64--D71: as the initializer of a typed or inferred local or module binding, and as the complete right-hand side of assignment to a directly named mutable local or module ordinary struct. A typed binding or assignment place must have T's [0710] body; disagreement reports L0301 at T, related to the destination. An inferred binding records T's body before settling the declaration. Through a type alias, the body remains the aliased declaration rather than the spelling used here.

T must denote an enabled ordinary struct. A scalar type or a name denoting a function or binding is a permanent L0334 error; an unresolved or already refused type keeps its type-position owner. A body whose field or target-extent refusal prevented layout silently refuses the construction after that owning report. Positional T(value) remains the existing call/conversion-shaped refusal, and T(of zeroed) remains a parser-owned L0010 refusal. A bare inferred literal still has no nominal identity and remains L0304.

Every field rule is the one the literal already has. Labels remain freely ordered but unique; missing and unknown labels keep L0310 and L0308; scalar, array, repetition, zeroed, direct-name and selected-field values keep D64--D71's contextual checks. Runtime labels are evaluated and committed immediately in source order, followed by declaration-order fill, and a successful whole assignment records the existing complete aggregate facts. Module construction is a static image: known-value, folding, compact array-field descriptors, image chains, cycle ownership and target emission are unchanged. Construction is terminal as a literal and adds no image-graph edge.

The syntax tree uses no new node kind. Struct_Literal now has two fixed slots: [0720]'s optional fill and D72's optional nominal type, followed by the existing Field_Value run. Bare literals put No_Node in the nominal slot. Resolution treats the nominal as a type position; the checker records its body on the literal or inferred declaration. Lowering continues to write directly into the binding, assignment place or module image. There is no aggregate temporary, IR operation, verifier rule, backend address form, target fact or layout change.

Construction in an argument, return, discard, operand, nested expression or any other general expression position remained L0304 at this increment. D100--D105 later admit construction in the aggregate argument contexts, and D106--D116 close aggregate results. Construction does not enable [0700]'s scalar conversion form, anonymous struct types, struct-of-struct fields, heterogeneous of expression or the all-field synonym.

Why this boundary: the nominal prefix supplies exactly the identity that prevented D64's bare literal from supporting inference. All three destination contexts already have storage, definite-assignment and static-image rules, so admitting them together removes a syntactic asymmetry without pretending an ordinary struct is a first-class expression value.

The alternatives: parse a dormant construction refused everywhere, admit only inferred or local construction, add general aggregate temporaries, or include positional conversion and the aggregate ABI. The first repeats D63's declined half-migration; the next two arbitrarily split identical contextual destinations; and the last two require representation and calling-convention work this slice deliberately does not have. All were declined.

Pinned by the parser, checker and lowering public-seam cases; positive/struct-construction-contexts; negative/construction-not-enabled; negative/struct-construction-nominal-mismatch; negative/struct-construction-callee-not-struct; negative/struct-construction-type-not-declared; negative/immutable-struct-construction-assignment; negative/struct-construction-all-of-not-enabled; negative/struct-literal-without-layout; the generated construct, token and IR records; and runtime/struct-construction-order on Linux x86-64.

D73 — A contextual variant part is refused once as a whole

The tour said that an ordinary struct may contain one contextual name: variant part [0680], whose cases may be bare atoms or carry labelled payload fields [0690]. The enabled grammar [1795] still describes only an ordinary field ::= identifier ":" type, so the old parser read variant as a user type and then reported unrelated errors on the first case and the two closers.

Chosen: while reading an ordinary struct body, the parser recognizes the shape of [0680]'s contextual part, reports one L0010 at the part name, and skips through that part's own end name closer. Parsing then resumes in the containing struct, so a common field following the refused part and the outer end struct-name remain independently readable. Payload and bare cases, and an empty part written directly as end name, have the same single owner. A refused part counts as the field-like content that caused the declaration to be refused, so the recovery does not add the ordinary empty-struct report. If the part's closer is absent or misspelled, recovery falls back to the containing struct's closer rather than discarding later declarations.

variant remains an ordinary identifier rather than a reserved word. In this slice the lookahead therefore requires the following tokens to have a case or the part's matching closer shape; kind: variant followed by another ordinary field continues to mean that kind has the user-declared type named variant. D73 left the grammar unchanged and its parser-owned fixture underivable, as every parser-owned refusal requires.

No variant node, name scope, case identity, layout, value, image, IR operation, verifier rule or backend representation was introduced by D73. Later slices use executable evidence to decide duplicate cases, payload type checking, empty and single-case legality, tag width and position, payload-union alignment and padding, the zero image, construction and matching, and whether any spare bit may fold the tag. Until D74, the whole part was absent from the syntax tree and the containing type was rejected by its one owning report.

Why refuse before representing: accepting a declaration without a layout would create a legal but unusable type whose later consumers either fail silently or invent a diagnostic at every use. Defining layout immediately would instead decide tag and payload representation from measurement alone, before any value can prove it. Naming the complete omitted construct gives the parser stable recovery evidence without committing either mistake.

The alternatives: accept declaration-only variants, implement declaration and layout together, reserve variant, or postpone all variant evidence. The first has no owning report for the missing layout; the second crosses every representation layer in one unmeasured step; the third breaks the tour's contextual spelling and user types of that name; and the last leaves the later variant work with only accidental cascades. All were declined.

Pinned by the parser public-seam recovery cases and the corpus truncation sweep. D74 migrates the parser refusal into enabled declaration syntax and replaces its former negative fixture with layout and boundary evidence.

D74 — A variant declaration has one unfolded measurable layout

The tour said that an ordinary struct may contain a contextual variant part [0680] and that each case is an atom and may carry a labelled payload [0690]. It did not say where the tag sits, how wide it is, how payloads share storage, how their padding contributes to the containing struct, or whether a declaration may exist before values of it do.

Chosen: [1795]'s enabled grammar includes a variant_part as one member of an ordinary struct body. The parser keeps one Variant_Part node containing its source-order Variant_Case run; each case keeps a source-order run of the same scalar or fixed-array Field nodes an ordinary struct already uses. A part needs at least one case. A single case and an all-bare part are legal. The contextual word variant remains an ordinary identifier everywhere the case/closer lookahead does not prove this production, and the name after the part's end must repeat the part name.

Case names are declarations in the module scope. They may be used before the type that contains them, and resolution binds a use to their declaration identity. Two cases with the same name, cases in different variant parts with the same name, and a case colliding with an ordinary module declaration are therefore [1850]'s L0200, with the declaration encountered by the module's set-building pass as the deterministic owner. The part name and payload field names remain labels rather than declarations.

Within one case payload, a field label names one position and may appear only once. A repeated label is L0309, related to an earlier occurrence. Separate cases have separate payload label namespaces.

The representation is target-neutral and unfolded. A part is one field of its containing struct. Its tag is first and uses the smallest enabled unsigned scalar that can enumerate every case: u8 through 256 cases, u16 through 65,536, and u32 beyond. Cases are numbered in source order; D74 does not yet expose those numbers as values. Each payload is laid out independently by D44/D45's ordinary source-order, natural-alignment rule. The payload begins at the tag extent rounded up to the greatest payload alignment; its reserved extent is the greatest padded payload size. The part's alignment is the greater of tag and payload alignment, and its padded size is the tag, the alignment gap, the maximum payload extent and ordinary tail padding. An all-bare part is therefore only its tag. The containing struct places that complete part exactly as it places one scalar or fixed-array field.

The checking table carries this without offsets in the source-neutral shape: a Variant_Field names the tag, case count and a contiguous run of per-case payload slices; those slices contain only scalar or fixed-array shapes. Offsets, widths and padding are derived from the selected target facts. The top-level field-shape run and field-offset run have separate starts, because payload shapes share the shape vector but have no top-level offsets. An aggregate payload field remains the existing L0304 struct-of-struct boundary; if any payload leaf is refused, the containing declaration has no layout and later consumers add no cascade.

sizeof and alignof are executable evidence for this rule. Lowering copies the same neutral tag, case runs and payload shapes into the IR's aggregate measurement run. The verifier checks the tag, nonempty and in-range case runs, and scalar/fixed-array-only payloads before any payload accessor. The backend replays the layout rule against its target facts. D74 does not put that carrier in a datum or slot; D75 reuses it there without changing the layout.

A binding, parameter, named return, initializer, assignment, zeroed, copy, literal or construction that would create storage or a value of a variant-bearing struct was one L0304 at this boundary. D102/D103 later admit its aggregate argument contexts and D106--D116 its results; other sites used D74's Variant_Value refusal at [0680]. A case name used as a general value or construction callee has the same owner. D75 supplies storage and the zero image, D76 then admits contextual case construction without creating a general variant value, and D77 reads its tag through an exhaustive match.

Why unfolded, tag-first layout now: it gives both described targets one deterministic hexdump-compatible answer, preserves [0540]'s later opportunity for an all-zero image, and makes measurement evidence possible without pretending a variant value already exists. Spare-bit folding, tag-last placement, C-union layout and a target-sized tag were declined: each either hides the source-order identity, changes the zero image, or lets host/ABI policy choose a language layout. A future explicit layout policy may add a different representation without changing this default.

The alternatives: keep the D73 refusal, accept declarations with no layout, enable storage and construction together, or choose a target byte blob. The first leaves the title feature without evidence; the second creates a legal type every consumer must refuse afresh; the third crosses layout, images and values in one slice; and the last violates the target-neutral IR boundary. All were declined.

Pinned by the parser, resolution, lowering, verifier and target-layout public seams; positive/variant-part-measured; negative/variant-part-empty; negative/variant-case-duplicate; positive/variant-inside-an-element; negative/variant-case-value-not-enabled; the generated construct, token, IR and target-layout records; the backend seam against both target descriptions; and runtime/variant-part-measurements-answer-for-the-target on Linux x86-64.

D75 — A variant-bearing struct has storage and one zero image

The tour said that [0540]'s zeroed writes the all-bits-zero image of a type and that a struct contains its variant part [0680]. D74 fixed that part's unfolded layout as one tag and one selected payload, but deliberately created no datum or frame cell and did not say which tag the zero image selects.

Chosen: a named ordinary struct with a D74 variant part may be declared as module or local storage. A declaration-only module binding has D10's static zero image; a declaration-only local binding is one uninitialized aggregate frame cell. An explicitly typed module or local initializer may be zeroed, and a directly named mutable module or local place may be assigned zeroed. These are the only new value contexts. The tag value zero selects the first case in source order. Every payload leaf D74 admits is a scalar or fixed array of scalars and therefore has [0540]'s zero image, so zeroing the tag, maximum payload extent, common fields and every padding byte is one valid complete image. A future payload leaf without a zero image must make this contextual form fail rather than change what zero means.

Common scalar and fixed-array fields retain their existing field rules. A whole successful zero write establishes D16's scalar and D48's whole-array facts for those common fields; D77 gives the established variant part one tag fact, and D78 may expose the selected case's scalar payload through arm-local aliases. A selection of the part itself is one L0304 Variant_Value when read. D76 admits the directly selected mutable part as one contextual case destination; D79 admits inferred local construction, and D80 admits a contextual whole copy between runtime storage places. Static module copy chains, inferred module construction, arguments, returns and every general aggregate value remained refused at this increment. D102/D103 later admit parameters and D106--D116 named results. D77 owns tag matching and D78 scalar payload bindings.

The IR uses the same target-neutral Variant_Field_Shape for measurement, datum and aggregate-slot field runs. One unit-wide case-run and payload-shape carrier lets each top-level shape name its source-order cases without storing an offset, width or padding byte. The verifier proves the tag kind, case-run bounds and depth-one scalar/fixed-array payload leaves before any accessor for all three storage classes. A variant-bearing aggregate may have no written static image in this slice: omitted and explicit module zero images are the same absent image, while a malformed written image is refused before the backend can interpret it.

Lowering emits no variant instruction. Module storage is one ordinary aggregate datum; local storage is one aggregate slot. Explicit local zero initialization and whole zero assignment reuse D57/D58's operandless, field-zero Clear_Array, which clears the complete padded aggregate extent. The x86-64 backend derives that extent by replaying D74's tag-first maximum- payload layout against the selected target. Module zero storage is reserved as one distinct padded object in .bss; no startup instruction exists. The same recursive extent routine serves measurement, datum placement, frame layout and whole clear, so their answers cannot diverge between 32- and 64-bit target facts.

Why only storage and zero now: the all-zero image needs no payload expression, no tag operation and no aggregate temporary, so it exercises the runtime carrier and target layout without prejudging how a case is formed or examined. Field-wise stores were declined because they leave padding outside [0540]'s complete image; a new clear opcode duplicates D57's whole-storage operation; admitting copy or construction would cross D76's case-selection rule; and keeping the variant as opaque target bytes would abandon D74's target-neutral carrier. All were declined.

Pinned by the lowering, verifier and backend public seams; positive/variant-zeroed-storage; negative/variant-part-selection-not-enabled; the generated token and IR records; and runtime/variant-zeroed-storage-is-distinct on Linux x86-64.

D76 — A variant case is constructed into contextual storage

The tour said that [0690]'s bare case carries no payload and [0700]'s labelled construction supplies a payload by name. D74 fixed the case order and payload shapes, while D75 supplied storage and made tag zero select the first case; neither said how a later case is written.

Chosen: a case is written only where a destination supplies one D74 variant part. A typed local labelled literal or nominal construction may name a variant field with a bare payload-free case or with case(field: value, ...); a complete labelled literal or nominal construction may be assigned to a directly named mutable module or local struct in the same way. A directly selected variant part of such a mutable root may also be assigned either form. The case identity must belong to that exact part. A case from another part is L0334 at the value; an immutable root keeps L0303 first and alone. Module static struct images and inferred module construction remain outside this slice until D81; every general value position remains an L0304 Variant_Value boundary. D80 later admits a whole variant-bearing copy whose source and destination are direct runtime storage places.

A bare case is legal only when its payload is empty. A labelled case construction gives each payload field at most once, using D64's L0308/L0309/ L0310 ownership for unknown, duplicate and missing labels. Scalar payload fields accept their ordinary expression or contextual zeroed. A fixed-array payload field accepts only zeroed in this slice; selecting the case already clears that array's complete storage. A trailing of zeroed supplies every omitted payload field, while any other fill is L0304. Aggregate payloads stay D74's depth-one refusal.

The destination case is selected before any payload expression is evaluated. Selection clears only the selected case's padded payload extent and writes the case's zero-based source-order tag. A bare case therefore writes only its tag; the gap after the tag, inactive case storage and part tail padding have unspecified bytes. The clear gives omitted and fixed-array payload fields their zero image. Labelled scalar expressions are then evaluated exactly once in written order and stored immediately, so a later expression observes every earlier program write. A refused destination reads none of them. D16 records the complete selected part as assigned; D77 is the first consumer of that tag and D78 reads or mutates scalar payload leaves.

The IR adds two destination-only operations. Select_Variant carries a storage identity, top-level field identity and one-based case identity; Store_Variant_Field additionally carries a one-based scalar payload-field identity and one scalar operand. None carries a target offset. The verifier checks storage, aggregate field, variant shape, case run, payload field kind and operand type in that order with explicit release-build code, and refuses either operation inside a datum initializer. The backend replays D74's layout: selection clears the selected case's target-derived payload extent and writes case - 1 with the shape's tag width; a payload store derives the part, payload and field offsets for the selected target before storing at the scalar width.

Why contextual construction first: it exercises every case identity and payload offset without an aggregate temporary, a static nonzero variant image or an ABI rule. Clearing the selected payload as one extent retains its omitted fields' zero images without touching storage reserved for inactive cases. This revises D76's original complete-part clear: that rule made a bare selection's write count grow with the largest unrelated case. Whole copying waited until D80 fixed the source and destination as storage identities and copied the complete padded part. D84 later adds D52/D53's write sequence inside a fixed-array payload without changing selection's clear-and-tag operation. D77 adds tag matching; D78 adds scalar payload binding while retaining that fixed-array boundary. D79 also lets a call-shaped case construction infer a fresh local binding; D81 later supplies the nonzero static variant image and admits module inference.

The alternative: clear the complete padded variant part on every selection. That gives inactive bytes a zero value but makes a bare case write an extent set by an unrelated payload. Clearing each selected field separately would avoid those inactive bytes but leave gaps inside the selected payload uninitialized.

Pinned by the IR, lowering, verifier and backend public seams; positive/variant-case-construction; negative/immutable-variant-case-assignment; negative/variant-case-does-not-belong; negative/variant-case-payload-disagrees; the generated token and IR records; and runtime/variant-case-construction-runs-in-source-order on Linux x86-64.

D77 — A match exhaustively selects one variant case by its tag

The tour said that [1210] distinguishes every case of a variant and that missing cases are compile errors. D74 fixed the source-order case identity, D75 supplied the unfolded tag, and D76 made that tag executable by selecting cases; none supplied a way to examine it.

Chosen: match place.field directly selects a D74 variant part from a named module or local ordinary-struct binding. Each arm is case: statement; the case must belong to that exact part, every case is named exactly once, and source order of arms is otherwise free. A duplicate is L0311, a missing case is L0312, and a case from another part is D76's L0334 identity mismatch. This first boundary gives each arm exactly one statement, with an if usable as that statement when a nested run is needed. D78 adds [1220]'s parenthesized payload bindings. Wildcards, scalar or nested subjects and general variant values remain refused. D241 later makes a scalar subject a type error citing [1210]: an arm names an identity, and a number is compared with if.

The subject is read once before any arm. Definite assignment therefore asks for the selected part's established-case fact on entry; D75's whole zero image and D76's contextual case write establish it. Each exhaustive arm receives the same incoming state, and facts after the match are their intersection. An uninitialized local part is L0302, and a fact written by only some arms is not available after the match. Payload bytes are neither read nor bound here.

Lowering emits one Load_Variant_Tag, carrying source storage, top-level field identity and the tag's scalar type but no target offset. The tag is saved in one scalar frame slot, then compared with each source-order tag except the final exhaustive arm; control flows through sibling arm blocks and one merge. The verifier proves the storage and variant field before comparing the result type with the shape's tag type, in explicit release-build code. The backend replays D74's field placement, loads the tag at its described width, and uses the existing scalar comparisons and branches. No payload offset is computed.

Why tag-only and exhaustive first: it closes the first read of D76's runtime state without yet introducing a payload reference, origin, lifetime, or aggregate temporary. A wildcard was declined because [1210] already makes missing cases a compile error; implicit source-order fallthrough was declined because case identity is nominal; reloading the aggregate at each comparison was declined because [0410] gives the subject one evaluation.

Pinned by the parser, IR, lowering, verifier and backend public seams; positive/variant-match-exhaustive; negative/match-scalar-not-enabled; negative/variant-match-duplicate; negative/variant-match-not-exhaustive; negative/variant-match-case-does-not-belong; negative/variant-match-unassigned; negative/variant-match-not-on-every-path; the generated token, diagnostic and IR records; and runtime/variant-match-selects-tag on Linux x86-64.

D78 — Match-arm names alias scalar payload fields

The tour said that [1220] binds a selected case's payload by position and that inout is the spelling which permits a write. D77 selected the case and entered an arm, but deliberately left its payload bytes inaccessible.

Chosen: an arm may write a parenthesized, comma-separated binding after its case name. The names correspond positionally to every payload field in declaration order; when parentheses are present their count must match exactly (L0333), while omitting parentheses continues to ignore the complete payload. A plain binding is an immutable in alias and inout name is mutable. Both refer directly to the matched object: reading loads that payload field, and an inout assignment updates it in place. Each binding is visible only in its arm's sibling scope. Duplicate names retain L0200 and a use outside the arm retains L0201. [1910] keeps the selected payload storage live through each alias's last use, including scalar writes and addresses derived from the payload. Retagging or replacing that storage earlier is L0315. The live-payload negative fixture and last-use runtime fixture pin this rule.

This slice binds scalar payload fields. D85 later binds a fixed-array payload as an indexed array alias without making it a whole contextual value. Omitting bindings still permits a case with any payload, so D77's tag-only matching remains unchanged. D102--D116 later close aggregate parameters and returns.

Lowering records no copied local. It maps each arm-local declaration identity to the subject storage, top-level variant field, source-order case and declaration-order payload field. Load_Variant_Field carries those identities and its scalar result; an inout write reuses D76's Store_Variant_Field. The verifier proves the aggregate, case and scalar leaf before checking the result or operand type. The backend replays D74's payload placement on the selected target. These are explicit release-build checks, and no source or target byte offset enters the IR.

Why aliases rather than copied locals: [1220]'s inout makes an arm write observable after the match. A copy-in/copy-out rule would add hidden completion and early-return semantics, while a copied immutable binding would make the two conventions denote different objects. One direct alias rule answers both. Named rather than positional omission was declined because field identity is already declaration order; D85 later gives array payloads the same direct alias rule without silently copying a whole array.

Pinned by the parser, IR, lowering and verifier public seams; the resolution and checking fixture paths; positive/variant-match-payload-bindings; negative/variant-match-binding-count-disagrees; negative/variant-match-in-binding-is-immutable; negative/variant-match-binding-named-twice; negative/variant-match-binding-outside-arm; the generated token, diagnostic and IR records; and runtime/variant-match-payload-bindings-update-storage on Linux x86-64.

D79 — A case construction may infer its fresh local storage

The tour said that [0050] infers a binding from its initializer and that [0700]'s construction names the nominal type being constructed. D72 applied that rule to ordinary structs, while D76 kept a variant-bearing construction contextual to a written destination even after local aggregate slots and case selection existed.

Chosen: name := T(..., part: case(...), ...) is admitted inside a function when T is a D74 variant-bearing ordinary struct. The construction's type name supplies [0710]'s body before inference settles the binding, and the fresh aggregate frame slot is its contextual destination. D76 then applies: common and payload values are evaluated once in written order, the selected payload is cleared, its tag is written, and scalar payload fields are stored directly. The inferred local is distinct storage and may immediately be selected or matched under D77/D78.

An inferred module binding remains refused in this slice. Unlike a fresh local slot, it has no runtime destination: [1460] requires a static image, and D75 currently carries only the absent all-zero variant image. D81 later adds that representation and admits both the typed and inferred module forms. Arguments, returns and general aggregate values remain outside this contextual rule and retain their existing owners.

No syntax, IR, verifier or backend operation changes. Lowering already allocates an aggregate slot from the inferred declaration's carried body and D76 already writes a struct literal into that slot. The checker removes only the local half of its inference refusal; the module half remains explicit.

Why local inference before static images: the nominal constructor already answers which type is inferred, and a fresh slot makes evaluation executable without an aggregate temporary. Treating the same spelling as a module image would require a nonzero target-neutral variant image, while refusing both scopes merely because one lacks that representation would preserve an accidental asymmetry.

The alternative: require every constructed local to spell its type, or admit an inferred module binding as well. The first repeats what the construction's type name already says; the second has no runtime destination to receive the evaluated parts, which [1460] forbids running before the entry point.

Pinned by the lowering public seam; positive/variant-case-construction; the generated token and IR records; and runtime/variant-case-construction-runs-in-source-order on Linux x86-64.

D80 — A whole variant-bearing struct copies between runtime storage

The tour said that [0520] assigns values and [0710] makes an ordinary struct nominal. D54 copied a scalar/array-bearing struct field by field, while D75 supplied storage for the unfolded variant part and D76 supplied its first nonzero values. Keeping D54's copy refusal after both sides had complete storage was therefore a representation boundary rather than a language rule.

Chosen: a whole assignment between directly named mutable module or local storage of the same variant-bearing struct is admitted. An explicitly typed or inferred local initializer may likewise copy a direct module or local source name. The source and destination must share [0710]'s declaration identity; same-shaped declarations remain L0301. Module initializers remain static-image rules and are not widened by this runtime slice. A tracked local source must be complete on every arriving path, including its established variant part; the destination receives the complete whole-struct fact. An exact self-copy is legal and changes nothing.

Common scalar fields retain D54's scalar load/store pair and common fixed-array fields retain its Copy_Array. Each unfolded variant part is one Copy_Variant carrying source storage, destination storage and their shared declaration-order field identity. It carries no tag, case, payload offset, target extent or bytes. The verifier proves both endpoints are variant fields, proves their complete case and payload shapes before reading them, and requires the tag, case count, payload kinds, scalar types and array lengths to agree. These are explicit release-build checks.

The backend replays D74's tag-first maximum-payload layout for the selected target, forms both field addresses and copies the complete padded part. Extents of one to six bytes or exactly eight bytes use bounded scalar chunks; other nonzero extents retain one forward byte run. Distinct aggregate roots do not overlap; a self-copy names the identical range, which either transfer preserves. Copying the padded part also carries any unspecified inactive bytes; it need not inspect the source tag. An explicit zeroed source still has [0540]'s complete all-zero image. Scalar and fixed-array fields remain separate operations in declaration order, exactly as D54 specified.

Why a compact part copy: selecting the active case and copying only its payload would branch on runtime state and make the copy sequence depend on the tag. Copying the whole struct as one opaque byte operation would duplicate D54's established scalar/array paths and erase their verifier types. One compact operation for the only union-shaped field keeps the IR target-neutral and the existing field semantics visible. Static nonzero variant images and inferred module construction follow in D81. General aggregate values, arguments and returns remained separate decisions; D94--D116 later close the internal argument and result contexts.

The alternative: copy a variant-bearing struct part by part, or refuse whole copies of one altogether. Field-wise copying would have to know which payload is live and would skip the padding and tag a whole-storage copy carries for free; refusing the copy leaves [0540]'s value semantics with a hole where the tour has none.

Pinned by the IR, lowering, verifier and backend public seams; positive/variant-whole-copy; negative/variant-whole-copy-source-unassigned; the generated token and IR records; and runtime/variant-whole-copy-is-distinct on Linux x86-64.

D81 — A module variant construction is a static selected-case image

The tour said that a module binding may carry a value [0040], that nothing runs before the entry point [1460], and that a variant value selects one case and its payload [0680]--[0700]. D66--D71 gave ordinary structs a target-neutral static image, while D75 kept a variant part absent and all-zero and D76/D79 constructed nonzero cases only into runtime storage.

Chosen: an explicitly typed module struct literal or nominal construction may select D76's bare or labelled variant case. A call-shaped construction may also infer the module binding's nominal body, as D79 already does for a local. Every labelled scalar payload expression must be [1940]-known and must fit its contextual scalar type on the selected target; excluded storage reads remain L0304, an unknown fold remains L0305, and an overflowing or out-of-range fold remains L0300. A fixed-array payload still accepts only zeroed. Omitted payload fields covered by of zeroed retain their zero image.

The selected case is a static image, not startup code. The aggregate field's flat fold stays zero. Its top-level image descriptor has form Selected, a one-based case in Value, and an offset/count selecting one declaration-order payload-descriptor run appended after the aggregate's top-level descriptors. A scalar payload descriptor carries its folded value; a fixed-array payload reuses D67/D68's absent/finite/repeated/hybrid shape and element run, although only the absent zero form is produced in this slice. Offsets select descriptors or folds, never target bytes. The old setter delegates with an empty payload run, so every D66--D71 image keeps the same carrier.

The verifier first proves the top-level descriptor run, selected case and payload run before any payload accessor. It then proves each scalar fold and array descriptor against that case's D74 leaf shape and the selected target. Malformed nesting, case identities, counts, offsets, patterns and values are explicit release-build faults. The backend replays D74's tag-first placement, writes case - 1 at the tag width, inserts this target's gaps, writes scalar payloads at their widths, emits array payload images, and zeroes the inactive tail of the maximum payload extent. Selecting the first case explicitly is still a written .data image even when every byte is zero; D75's omitted or whole-zeroed value alone remains absent .bss storage.

D60/D61 module struct image chains copy the selected descriptor, payload descriptors and element folds into distinct destination storage. Forward references and cycles keep their existing declaration-identity validation; a cycle reports L0305 once. Later runtime writes never alias a copied image. General aggregate values, arguments and returns remained refused at this increment. D94--D116 later close the internal argument and result contexts. D82 adds finite and repeated fixed-array payload images, D83 copies those images from module array storage, D84 adds their contextual runtime write forms, and D85 adds indexed match aliases.

Why one extended descriptor run: target bytes would duplicate the image per target and abandon the IR boundary; startup stores would contradict [1460]; a second item-owned vector would introduce another partition invariant for data the existing field-image run already orders. One selected descriptor plus a contiguous payload run makes the case explicit, keeps every width and offset in the backend, and lets D60's existing image-chain machinery copy the complete value without inspecting target layout.

The alternative: build a module variant value by startup code, or refuse a selected case in a module image. [1460] leaves nothing to run before the entry point, and a refusal would make the one aggregate the freestanding driver most wants static, a device state machine, unwritable at module scope.

Pinned by the lowering, verifier and backend public seams; positive/variant-module-case-image; negative/variant-module-case-image-value-not-known; negative/variant-module-case-image-storage-read; negative/variant-module-case-image-out-of-range; the generated token and IR records; and runtime/variant-module-case-image-is-distinct on Linux x86-64.

D82 — A static selected case carries finite and repeated array payloads

The tour said that a case payload is labelled like a construction [0700] and that array literals and repetitions describe complete fixed arrays [0530], [0560]. D81 reserved the selected case's fixed-array payload descriptor and made only its absent zero image constructible.

Chosen: in D81's typed or inferred module construction, a labelled fixed-array payload accepts D67's finite nonempty literal, D68's full or mixed repetition, or zeroed. Its contextual length and scalar element type come from the selected D74 payload leaf. Length, count and element disagreements keep D17/D29/D32's L0301 owners. Every element, prefix and repeated pattern must be [1940]-known; an excluded storage read is L0304, an unknown fold is L0305, and an overflowing or out-of-range fold is L0300. D83 adds direct module array and selected array-field image sources without making the payload a general value.

No carrier changes. A finite payload descriptor owns its complete fold run; a full nonzero repetition carries one Repeated pattern; a mixed form carries its finite prefix plus one Hybrid suffix pattern. D34's full zero repetition is the absent image, while D38's mixed zero suffix remains written. The folds are appended to D81's one item-owned image run, and the payload descriptor's offset is rebased through that run. D60/D61 copies preserve every form in distinct module storage.

The verifier already proves these four canonical payload forms, their lengths, offsets and per-target scalar fit before reading any fold. The backend already replays the selected case's payload placement: it emits finite directives or compact .rept runs at the element width, inserts target padding and zeroes the inactive tail. D82 therefore changes only contextual checking and image production, while extending the public lowering, verifier and backend evidence over the carrier D81 established.

Why static forms first: they exercise every reserved array payload image without adding the two-level runtime address carried by later stores, fills and copies. Limiting D82 to finite literals alone would make zeroed and compact repetition needlessly asymmetric with D67/D68. D83 takes the separate static source-resolution edge; D84 supplies runtime construction and D85 supplies indexed match aliases.

The alternative: treat a fixed-array payload in a module image as a general runtime value, or admit only zeroed there. The first makes the image a computation; the second makes the initial state of a device table a copy loop the program has to write itself.

Pinned by the lowering, verifier and backend public seams; positive/variant-module-array-payload-image; negative/variant-module-array-payload-shape-disagrees; negative/variant-module-array-payload-not-known; negative/variant-module-array-payload-storage-read; negative/variant-module-array-payload-out-of-range; the generated token and IR records; and runtime/variant-module-array-payload-image-selects-case on Linux x86-64.

D83 — A static array payload copies a module array image

The tour said that a module value is present before the entry point [1460] and that an array assignment copies a complete array [0520]. D21, D69--D71 already follow direct and selected module array images through declaration identity; D82 made the same four compact forms representable in a selected variant payload.

Chosen: in D81's typed or inferred module case construction, a labelled fixed-array payload also accepts a direct module fixed-array name or s.f, where s directly names a module ordinary struct and f is one of its fixed-array fields. The source must have the payload leaf's exact D17 length and scalar element type; disagreement is L0301 at the source, related to the payload label. A scalar, type name, local storage, deeper selection or any other form keeps its existing owner. A source the checker has already refused adds no second report.

The payload receives a copy of the source's resolved static image: absent for an omitted, zeroed or zero-repetition source; finite for a written literal; repeated for a nonzero full pattern; hybrid for a written prefix and suffix pattern. All-zero finite and zero-suffix hybrid images remain written. The source may be declared later and may itself follow D21 or D60/D61/D69--D71's array and aggregate image chains. Validation follows the source declaration before marking the containing image valid; an existing cycle retains [1940]'s single L0305 owner. Each destination owns distinct storage.

No carrier, verifier or backend rule changes. Lowering resolves the source before any image accessor, counts its finite prefix in the aggregate's one item-owned run, then copies and rebases either the array item's compact image or the selected field descriptor. The unchanged aggregate setter records the selected case once; the unchanged verifier rechecks the descriptor against the payload leaf and target; the unchanged backend emits that form at the payload's target-derived offset. D60/D61 aggregate image copies preserve the rebased descriptor and folds.

Why both source forms: admitting only a direct name would leave the static payload behind D65's runtime source rule and behind the D69--D71 image graph, despite both representations already existing. This remains a contextual initializer edge: selected payload arrays are not general values. Runtime fixed-array payload writes follow in D84, while indexed fixed-array match aliases follow in D85.

The alternative: accept any expression as a static array payload source, including local storage and deeper selections. Only a static image can be resolved when the image is formed, so every other form keeps the owner that already refuses it rather than a second, image-specific report.

Pinned by the lowering and backend public seams; positive/variant-module-array-payload-image-copy; negative/variant-module-array-payload-image-copy-shape-mismatch; negative/variant-module-array-payload-image-copy-source-refused; negative/variant-module-array-payload-image-copy-source-cycle; the generated token and IR records; and runtime/variant-module-array-payload-image-copy-is-distinct on Linux x86-64.

D84 — A runtime case construction writes fixed-array payloads

The tour said that a labelled case construction writes its payload [0690]--[0700], while array literals, repetitions and copies write a complete fixed array [0520]--[0560]. D65 already admitted those contextual forms for an ordinary struct field, but D76 kept a runtime variant payload at zeroed even after D82/D83 supplied the same forms for a static selected-case image.

Chosen: a labelled fixed-array payload in D76/D79's runtime case construction accepts the same contextual forms as D65's ordinary fixed-array field: a finite literal, a full or mixed repetition, zeroed, a direct module or local fixed-array name, or a directly selected ordinary fixed-array field. The value must have the payload leaf's exact D17 length and scalar element type. Length, count, element and copy-shape disagreements keep their existing L0301 owners. A tracked local source is read as a whole before the case write; payload expressions read the state arriving at the statement. D241 later gives a payload array every expression an ordinary array field takes, still selecting the case first. A refused or immutable destination is reported first and reads no payload.

Selection remains one destination-first operation: it clears the selected case's padded payload and writes the source-order tag before labelled payloads are evaluated once in written order. Literal elements store immediately; repetitions evaluate their repeated value once; copies move the complete array. A nested zeroed payload retains the selected array's zero image; the array path may emit a redundant clear of that array. Both writes remain bounded by the selected payload extent. Normal completion retains D76's whole variant-field definite-assignment fact.

No new opcode is needed. Store_Element, Fill_Array and the destination of Copy_Array gain D76's case and payload-field identities in addition to the containing aggregate field. Those numbers are declaration identities, never target offsets; direct and ordinary-field array operations keep zeroes and their existing text. The verifier proves storage, containing variant field, case, payload leaf, array shape, index and value type in that order before any shape accessor, in release as well as debug builds. It retains the existing array and variant fault kinds.

The backend first performs the bounds check for an element store, then derives the containing field base and D74's target-dependent payload-field offset, and finally adds the scaled element index. Fills and copies use that same base; their width and byte extent come from the selected payload leaf on each target. Static module constructions remain D82/D83 image rules, not startup writes. D85 later reads and writes individual elements through a match alias; no selected variant payload becomes a general array value.

Why extend the existing array operations: a payload array is still one fixed array in known storage. A new opcode for each literal, repetition and copy would duplicate their ordering and verifier rules; an aggregate temporary would make the construction a general value. Carrying the two missing declaration identities lets the established compact operations reach the leaf without putting layout bytes into the IR, and is also the address carrier a later fixed-array match alias needs.

The alternative: restrict a runtime case construction's array payload to literals and zeroed, or evaluate the payload before the destination is selected. The first gives the payload a narrower rule than D65's ordinary array field for no reason the tour states; the second reorders D76's destination-first protocol.

Pinned by the lowering, verifier and backend public seams; positive/variant-runtime-array-payload; negative/variant-runtime-array-payload-shape-disagrees; negative/variant-runtime-array-payload-source-unassigned; negative/immutable-variant-runtime-array-payload; the generated token and IR records; and runtime/variant-runtime-array-payload-writes-target-storage on Linux x86-64.

D85 — A match-arm name aliases a fixed-array payload by element

The tour said that [1220] binds the selected case's payload by position, that inout permits mutation, and that indexing selects one array element [0520], [0580]. D78 implemented that direct alias rule for scalar payloads; D84 supplied the target-neutral address of a fixed-array payload but did not let a match arm name it.

Chosen: a binding corresponding to a fixed-array payload has that payload's D17 length and scalar element type. A plain binding is an immutable in alias; inout name is mutable. Either may be indexed to read an element, while only the inout form may assign, assign zeroed, increment or decrement an indexed element. lenof name reads the contextual length without reading storage. Constant indexes outside the payload length keep L0306; an unknown index keeps D48's runtime bounds trap and is evaluated once before the value of a write.

The alias denotes the matched module datum or frame slot directly. It creates no copied local and no separate definite-assignment fact: D77 already requires the complete variant part before its tag may be matched, and the binding exists only in the arm for the selected case. An inout write is observable through the original object after the match. A bare use of the binding remains L0304, as do whole-array assignment or initializer sources, arguments, returns, discards and operands; D241 later admits the discard and records the others as a boundary. This is an indexed contextual alias, not a general fixed-array value.

No new opcode is needed. Load_Element gains D84's containing-field, case and payload-field identities; Store_Element already carries them. Direct and ordinary-field element operations keep zero identities and their previous IR text. The verifier walks storage, containing variant field, case and array payload before it reads the payload shape, then checks the usize index and element result or operand type in explicit release-build code. The backend replays D74's target-dependent payload placement and the payload element width for both module and frame storage; no offset or width enters the IR.

Why an indexed alias rather than a copied array: copying would make in and inout denote different objects or require hidden copy-out behavior on every arm exit. Making the name a general whole-array value would widen D20, D21 and every argument/return boundary at once. The direct alias already used for D78's scalar leaves preserves [1220]'s one rule while indexing supplies the only scalar value an expression needs.

The alternative: copy a fixed-array payload into a fresh local binding at the arm, or refuse array bindings in a match arm. A copy hides the write an inout binding exists to make and costs the payload's extent on every match; a refusal leaves an array payload matchable but unreadable.

Pinned by the IR and lowering public seams; positive/variant-match-array-payload-bindings; negative/variant-match-array-binding-not-enabled; negative/variant-match-array-binding-is-immutable; negative/variant-match-array-binding-index-out-of-range; the generated token and IR records; and runtime/variant-match-array-payload-bindings-update-storage on Linux x86-64.

D86 — A named ordinary struct field has a measured layout

The tour said that fields stay in written order with their natural alignment [0750], that a named struct introduces one nominal type [0710], and that sizeof and alignof answer for a type [0370]. D44/D45 measured scalar and fixed-array fields, but a field whose type was another named struct still stopped the containing layout even though the child already had a complete target-parametric size and alignment.

Chosen: a top-level field of an ordinary struct may name a laid-out child ordinary struct whose own fields are scalar or fixed arrays. The child remains one declaration-order field. Its size is the child's complete padded size and its alignment is the child's alignment; the containing placement then applies [0750] exactly as it does to any other field. Aliases carry the same child body identity. This slice is deliberately depth one and excludes a child with a variant part or another aggregate field; a struct inside a variant payload keeps its existing L0304 boundary.

This is layout and measurement only in D86. D87 below admits declaration storage and the complete zero image; every nonzero value form stays separate. An inferred construction is refused from its nominal body before lowering, so the measurement carrier cannot leak into a datum or frame slot before D87.

The checking table carries the child declaration identity, never its bytes. Aggregate measurement IR carries an Aggregate_Field_Shape whose child is a bounded declaration-order run of scalar or compact fixed-array shapes. The verifier proves that run and its depth-one leaves before any accessor reads them, and rejects the same shape in datum and slot runs. The backend recursively replays those neutral leaves against the selected target. Thus a 32-bit target may give the child and parent different extents from Linux x86-64 without any target offset, padding or host representation entering the IR.

Why measurement first: variants followed this same D74/D75 split. It gives layout a target-executed fact before storage must decide nested selection, definite-assignment paths, images, clear and copy. Flattening the child into the parent would lose nominal provenance and make later debugger information reconstruct it; carrying a target byte extent would make the IR target-specific.

The alternative: flatten a child struct's fields into the parent's placement, or refuse a struct field until layout is general. Flattening loses the child's own alignment and padding and every alias of its body identity; the depth-one slice with the child's complete padded size is what the containers needed and no more.

Pinned by the checking, lowering and verifier public seams; positive/measurement-of-nested-struct-field; positive/module-struct-image-with-a-child; the generated layout, token and IR records; and runtime/nested-struct-measurements-answer-for-the-target on Linux x86-64.

D87 — A depth-one nested ordinary struct has storage and a zero image

The tour said that a binding may hold a named struct [0670], that every field remains in written order at its natural alignment [0750], and that zeroed supplies the complete all-bits-zero image of its contextual type [0540]. D86 had already proved the child and parent extents on both target descriptions, but deliberately kept that carrier out of runtime storage.

Chosen: a module or local binding may hold D86's depth-one nested ordinary struct when the child itself has only scalar and fixed-array fields. An omitted binding has the ordinary zero state. An explicitly typed binding may be initialized with zeroed, and a directly named mutable binding may be assigned zeroed. Each operation clears the complete padded parent extent, including the child's internal and tail padding, as one whole-storage operation. Module and local cells are distinct.

This slice does not make the child selection a value or place. s.child, nonzero labelled literals, construction, inference, whole copy, static nonzero images, deeper nesting and aggregate variant payloads stayed L0304 at this increment; D88--D132 close those contextual and internal-ABI boundaries. D88 separately admits s.child.field for scalar leaves. Those are value-path decisions, not hidden consequences of allocating a cell.

Runtime datum and slot shapes reuse D86's target-neutral Aggregate_Field_Shape: the parent points at one bounded child run of scalar and compact fixed-array leaves. The verifier proves that run before access and still rejects a child containing another aggregate or variant. The backend recursively replays the run against the selected target for datum reservation, frame placement and whole clears. Thus the same source clears 40 bytes on Linux x86-64 and 24 on the synthetic 32-bit description without carrying an offset, width or padding byte in the IR.

Why zero storage first: the complete zero image needs no nested path and no aggregate temporary, while a selected field or nonzero copy does. Flattening the child into parent fields would lose D86's nominal provenance; storing its target extent would make the IR target-specific. D88--D132 later close the remaining nonzero contextual and internal-ABI boundary.

The alternative: admit s.child as a value and place in the same slice, or give a nested struct no storage until every operation on it exists. The first drags construction, copy and static images into a layout increment; the second leaves D86's measured layout with nothing to measure.

Pinned by the lowering, verifier and backend public seams; positive/nested-struct-zero-storage; negative/struct-with-a-struct-field; positive/module-struct-image-with-a-child; the generated token and IR records; and runtime/nested-struct-zero-storage-keeps-neighbours on Linux x86-64.

D88 — A scalar leaf may be selected through one ordinary child

The tour said that member selection is left to right and may chain as a.b.c [0420] [1820], while D87 deliberately allocated a depth-one ordinary child without making any path through it a value or place.

Chosen: when a parent binding has D86/D87's one named ordinary child, a scalar field of that child is a value and a place as parent.child.field. The binding at the root decides mutability exactly as for a direct field. The intermediate parent.child remains neither a general aggregate value nor a whole place in this slice. D91 separately admits contextual whole-child assignment; discarding, passing and returning it remain L0304. D89 separately admits indexed scalar elements of a fixed-array leaf.

Definite assignment retains the two declaration-order field identities. A write establishes that nested scalar leaf and no sibling; a read requires that leaf on every arriving path. Assigning the whole parent zeroed establishes every child leaf, and branch merging treats that whole-child fact and the corresponding nested facts as two representations of the same assignment. Module state keeps D10's initialized rule unchanged.

Lowering carries the parent field and child field as two target-neutral identities on the existing scalar field load or store. The verifier proves that the first names an Aggregate_Field_Shape, that its bounded child run contains the second, and that the selected child shape is scalar. Only the backend replays the two nested placements against the target: the same usize leaf may therefore have a different module or frame offset on the two target descriptions without an offset or padding byte entering the IR.

Why not flatten the child: flattening would erase the nominal boundary D86 preserved and make debugger provenance reconstruct it. Treating the child as a general aggregate value would silently decide whole copies and the ABI this slice does not implement. Two field identities are the smallest carrier that implements the chain the tour already writes while retaining those boundaries.

Pinned by the lowering, verifier and backend public seams; negative/nested-struct-scalar-field-unassigned; negative/struct-with-a-struct-field; the generated token and IR records; and runtime/nested-struct-scalar-fields on Linux x86-64.

D89 — A fixed-array element may be selected through one ordinary child

The specification said that indexing takes what a selection named, explicitly including a.b[i] [1820], and D87 gives a depth-one child a neutral fixed-array field shape. D88 established the two-identity path to a scalar leaf but left that fixed-array leaf refused.

Chosen: parent.child.array[index] is a scalar value and place when array is a fixed-array field in D86/D87's ordinary child. Its index has the same usize context, compile-time refusal and runtime bounds trap as every other fixed-array element [1880] [1950]. The root binding decides mutability. Neither parent.child nor parent.child.array becomes a general value or whole place in this slice. D90 separately admits the fixed-array leaf as a contextual assignment destination or storage-copy source; passing, returning and discarding it remain L0304.

Definite assignment retains the parent and child identities together with D19's compiler-known element position. A write establishes only that element; a known read requires its own fact, and a computed read requires every element as D22 does. Assigning the whole parent zeroed establishes the nested array, and a branch merge preserves equivalent whole-parent, whole-array and sparse element representations rather than intersecting their encodings blindly. Module state remains initialized by D10.

The existing element load and store carry the parent field as their containing field identity and the child fixed-array field as a second neutral identity. The verifier proves that the first is an Aggregate_Field_Shape, its bounded child run contains the second, and the selected child shape is an Array_Field_Shape with the instruction's scalar element type. After the bounds check, the backend places the parent, then the child field, then the scaled index against the selected target. Neither offset enters checked IR.

Why not flatten or admit the whole array: flattening has D88's nominal and debug-provenance cost. Admitting the whole nested array would also decide contextual literals, fills and copies, while element access needs none of those operations. Two field identities reuse D48's compact element carrier without pretending that broader aggregate-value work is complete.

Pinned by the lowering, verifier and backend public seams; negative/nested-struct-array-element-unassigned; the generated token and IR records; and runtime/nested-struct-array-elements on Linux x86-64.

D90 — A nested fixed-array leaf has contextual assignment forms

The tour said that an array value may be copied, filled and initialized [0520] [0540], while D49--D53 deliberately implement those forms directly in existing storage. D89 reached scalar elements through one ordinary child but did not give the fixed-array leaf a whole-value carrier.

Chosen: a mutable parent.child.array is a contextual assignment place. It accepts an exact array literal, a full or mixed repetition, zeroed, or a storage copy from another direct or depth-one fixed-array place with the same length and scalar element type. The source is admitted only in that copy context. A nested leaf is not thereby a general expression value, parameter, return, discard or operand; those remain L0304. D92 separately admits an explicitly typed local initializer from the nested storage path. Root-binding mutability and [0410]'s source evaluation order are unchanged.

A successful assignment records the whole nested-array fact. A copy source requires every element on every arriving path; whole-parent, whole nested array and complete sparse-element facts retain the equivalence D89 established at branch merges. Module state keeps D10's initialized rule.

Element stores for literals retain D89's parent and child field identities. The compact fill and clear operations carry those same destination identities; a copy carries an independent pair for each endpoint. The verifier walks each bounded child run, checks an Array_Field_Shape, and requires source and destination length and element type to agree. The backend derives both nested offsets and only the leaf's scalar byte extent after target selection.

Why contextual assignment only: these forms already lower directly into known storage and need no aggregate temporary. Extending the leaf to every expression or initializer position would decide a first-class aggregate value and ABI merely because a path can now name its bytes. Keeping independent endpoint identities also avoids flattening either nominal child.

The alternative: make a nested array leaf a general value at once, or admit no assignment to it until it is one. The first pulls parameter, return and operand rules into a storage increment; the second leaves parent.child.array writable only through its parent, which is the copy loop the leaf exists to avoid.

Pinned by the lowering, verifier and backend public seams; negative/nested-struct-array-copy-unassigned; the generated token and IR records; and runtime/nested-struct-array-values on Linux x86-64.

D91 — One ordinary child has contextual aggregate assignment forms

The tour said that a whole ordinary struct may be zeroed, constructed and copied [0540] [0710], while D87 gave a parent one recursively laid-out ordinary child but intentionally left parent.child without value/place operations. D88--D90 then proved every scalar and fixed-array leaf path independently.

Chosen: parent.child is a contextual aggregate assignment place. It accepts zeroed, a matching labelled literal or nominal construction, and a storage copy from either a direct value of the child's nominal type or the same child path in another parent. The root binding decides mutability. The child remains no general expression value, inferred or module initializer, parameter, return, operand or discard; source selection is admitted only for the matching storage-copy context. D92 separately admits an explicitly typed local initializer.

A successful whole-child assignment establishes the parent-field fact, which already denotes every D88/D89 leaf. A whole-child copy source requires that fact on every arriving path; independently assigning some leaves does not invent an aggregate value. Module state remains initialized by D10.

zeroed uses one whole-child clear carrying the parent field identity. Construction lowers each scalar or fixed-array child leaf with that parent as its first identity and the child field as its second. Copy lowering does the same independently for source and destination, reusing scalar field and compact array-copy operations rather than adding an aggregate temporary. The verifier recognizes a whole Aggregate_Field_Shape clear and validates each leaf operation; the backend derives the child's padded extent and both endpoint offsets only after target selection.

Why not a general child value: every accepted form has known destination storage and can commit directly in [0410]'s order. A first-class child value would require temporary representation, ABI rules and expression lifetime without helping these assignments. Keeping its nominal parent identity on each operation also avoids flattening D86's boundary.

Pinned by the lowering, verifier and backend public seams; negative/nested-struct-child-copy-unassigned; the generated token and IR records; and runtime/nested-struct-child-values on Linux x86-64.

D92 — A typed local may copy from a nested aggregate leaf

The tour said that a local initializer may copy an array or ordinary struct from existing storage [0520] [0710]. D51/D55 implemented direct storage and a direct array field, while D90/D91 made depth-one array and ordinary-child paths contextual storage-copy sources.

Chosen: an explicitly typed local fixed array may initialize from parent.child.array, and an explicitly typed local of the child's nominal ordinary type may initialize from parent.child. The written local type must match the source length/element or nominal body exactly. Both copies require the complete source to be definitely assigned. Module initializers from either nested path remain L0304 because they need static image-edge decisions this runtime slice does not make. D93 separately admits inference for a local whose source carries the complete nested shape or nominal identity.

Lowering allocates the ordinary destination slot, then reuses D90/D91's independent source parent/child identities and a direct destination path. A child initializer visits declaration-order scalar and fixed-array leaves; an array initializer remains one compact copy. Verification and target replay are therefore unchanged from the corresponding assignment operations.

Why typed local only: its declaration already supplies the identity and fresh destination storage, so no aggregate temporary or inference carrier is needed. Module image copying and inferred aggregate values have different lifetime and cycle evidence and are not consequences of naming a runtime source path.

The alternative: admit module initializers from the nested paths in the same slice, or require a copy through a named local first. The first needs static image-edge and cycle decisions a runtime copy does not; the second makes the reader write the copy this decision performs.

Pinned by the lowering and verifier public seams; negative/nested-struct-child-initializer-unassigned; the generated token and IR records; and runtime/nested-struct-child-values on Linux x86-64.

D93 — A local may infer its aggregate identity from nested storage

The tour said that := gives a local the type of its initializer [0080]. D92 required an explicit local type even though a depth-one child already carries D71's nominal body and its fixed-array leaf carries D17's complete length and scalar element identity.

Chosen: a local may infer an ordinary child value from parent.child, or a fixed-array value from parent.child.array. The source must be one of the contextual storage paths D90/D91 admitted and must be definitely assigned as a whole. The inferred child keeps its nominal body; the inferred array keeps its length and scalar element. Module inference from these paths remains L0304 because static image edges and cycles are not runtime storage copies.

Lowering is D92's typed-local copy after the checker has recorded the inferred identity: allocate a fresh aggregate or array slot, then visit child leaves or emit one compact array copy with the source parent/child identities. No general expression value or aggregate temporary is introduced.

Why inference is sound here: the source path supplies exactly one complete identity before lowering, unlike a bare labelled literal. Restricting the rule to locals keeps it in runtime storage and does not silently extend module image graphs or the ABI.

The alternative: require the local's type to be spelled whenever its source is nested storage. The source carries the complete nominal identity or array shape, so a spelled type is a repetition the checker would only compare with what it already knows.

Pinned by the checker, lowering and verifier public seams; negative/nested-struct-child-inference-unassigned; the generated token and IR records; and runtime/nested-struct-child-values on Linux x86-64.

D118 — A subobject path is a run of steps, not a pair

The tour said that member selection is left to right and may chain as a.b.c [0420] [1820], and puts no depth on that chain. D88--D90 implemented one step below a parent field and spelt it as a second scalar identity beside the first, which is a pair and cannot say what a third selection reached.

Chosen: every target-neutral operation that names part of an aggregate carries a _path_: a run of steps, each naming a declaration-order position [0750] inside the run the step before it reached, and each carrying the one-based source-order case when the run it indexes is a variant part's payload rather than an ordinary field run. An empty path is the direct operation. The base field stays where it was, so a path of one step is exactly what D88--D90 already meant.

The verifier walks a path against the shapes alone: every step must name a part the run it indexes actually has, and the part the last step reaches must be the kind the operation needs. The backend derives one target offset per step from the same placement the checker used, and adds them. No step, and no sum of steps, is stored in the IR.

Why a run and not more scalars: a pair encodes a depth in its shape, so each further depth would be another field on every instruction, another parameter on every emitter and another branch in the verifier and the backend. A run makes depth data. It is also what makes an aggregate variant payload and an aggregate array element expressible without inventing a second nesting mechanism beside this one.

The alternative: keep a parent-and-child pair and add a third level when depth two arrives, or precompute offsets in the IR. A pair has a ceiling the tour never states; offsets are target facts the IR is designed not to carry.

Pinned by the lowering, verifier and backend public seams; the malformed case Path_Step_Below_A_Scalar_Leaf; and the generated IR record, which now names the base field and every step of every field operation.

D119 — Ordinary nesting has no depth

The tour said that a struct's field may have any type a binding may have [0670] [0750], and that member selection chains as a.b.c [0420] [1820]. D86 admitted exactly one named ordinary child and refused a child that had one of its own, because the pair of identities D88--D90 carried could not say what a third selection reached.

Chosen: an ordinary struct field may be an ordinary struct however deeply that composes. Layout is unchanged: a field's extent is its own body's already-computed layout, so the recursion is the one the checker already does over declarations. A scalar leaf and a fixed-array leaf are a value and a place at any depth, and a fixed-array leaf keeps every contextual assignment form it has at depth one.

Definite assignment keeps one fact per part, named by D118's run rather than by a parent and a child. A fact about a part follows from a fact about anything containing it, which is now "a fact named by a shorter run with the same steps"; branch joins intersect the runs and apply that same containment rule from either side. A whole child at depth two or more is D120's, and a variant part inside a child is D121's; both remain refused here.

Lowering resolves a selection chain once, into the name it started from, the first selection's field and D118's run of the rest. The verifier walks a nested field run recursively, under a budget the vector's own length gives, so a run that named itself is refused rather than followed.

Why no depth limit: every limit here would be an implementation's, not the language's — the tour writes a.b.c and stops. The one thing a depth costs is that the flow stage can no longer pack a path into an integer, which it did with a stride that would have overflowed silently at a field count and depth no rule forbids.

The alternative: cap ordinary nesting at some depth, or flatten nested structs at layout time. A cap is an implementation limit written into the language; flattening loses the child's body identity that aliases and calls rely on.

Pinned by positive/deep-nested-struct-leaves, negative/deep-nested-leaf-unassigned, the generated IR record, and runtime/deep-nested-struct-leaves on Linux x86-64.

D120 — A whole ordinary child is a place at any depth

The tour said that a whole ordinary struct may be zeroed, constructed and copied [0540] [0700] [0710]. D91 gave those forms to one named child of a parent; D119 then let a child hold a child, which left the deeper one with leaves but no whole.

Chosen: a.b.c… naming an ordinary child is a contextual aggregate assignment place at any depth, with exactly D91's forms: zeroed, a matching labelled literal or nominal construction, and a storage copy from the same nominal type reached by any chain. An explicitly typed local may be initialized from one, and a local may infer its nominal body from one. A nominal construction whose body has an ordinary child is admitted, because the labelled child value is already checked against that child's own body.

The root binding decides mutability, and the child remains no general expression value: no operand and no discard. D241 later admits the discard [1930]. D132 later gives a module initializer the same contextual child forms by recursively folding their static image rather than turning the child into a general value.

Lowering keeps one notion of place — a base field and D118's run below it — and descends into it. A literal fills a place; a copy visits the same fields in [0750]'s order one place deeper on each side; zeroed is one whole-part clear whose extent the backend derives from the shape the run reaches. The verifier recognises a whole child at the end of a run, not only at the base field.

Why not a general child value: D91's argument is unchanged by depth. Every accepted form still has known destination storage and commits in [0410]'s order, and a first-class child value would need a representation, an ABI rule and an expression lifetime that none of these assignments wants.

Pinned by positive/deep-nested-struct-children, negative/deep-nested-child-copy-unassigned, positive/module-struct-image-with-a-child, the generated IR record, and runtime/deep-nested-struct-children on Linux x86-64.

D121 — A variant case payload may be an ordinary struct

The tour said that a variant part's cases carry payload fields [0680] and that a struct's field may have any type a binding may have [0670] [0750]. D74 laid a payload out from scalar and fixed-array leaves alone, because the pair of identities every payload operation carried had no room for a third.

Chosen: a case payload field may be an ordinary struct. It takes the same contextual values a labelled ordinary child takes — zeroed, a matching labelled literal or nominal construction, and a copy from storage of the same nominal type — and a match arm's positional alias for it names the whole struct, so its fields are read and written the way any struct's are.

The payload is reached by D118's run: the case a step names is what says the run it indexes is a payload run rather than an ordinary field run. No opcode is added, and the two payload operations D76/D78 introduced keep their exact meaning for a scalar leaf. A payload struct that has a variant part of its own is refused. D132 later admits an ordinary-struct payload in a module image by recursively folding that payload's own image.

Why the alias is a struct and not a second kind of binding: D78's alias already denotes storage; making it denote a struct's storage rather than a scalar's changes what it names and nothing about what a name is. Every selection below it is then an ordinary step of the same run.

The alternative: restrict a variant payload to scalars and arrays, or copy a struct payload out into a local at each match. The first keeps prototype 1's device states unwritable; the second is the copy D85 already declined for arrays.

Pinned by positive/variant-struct-payload, negative/variant-struct-payload-mismatch, positive/variant-inside-an-element, the generated IR record, and runtime/variant-struct-payloads on Linux x86-64.

D122 — A fixed array's element may be an ordinary struct

The tour said that a fixed array is its element repeated [0520], that a struct's field may have any type a binding may have [0670] [0750], and it writes w.items[i].x and xs[i].items outright. D17 made an array's identity its length and its element, and every stage carried that element as one of [1790]'s scalar types.

Chosen: [0520]'s element may be an ordinary struct. Its extent is that struct's own padded layout repeated, so an array adds nothing but the repetition, and an array of one is storage anywhere an array of a scalar is: a struct field, a local, and a module binding. zeroed clears the whole extent, and two arrays of the same length and the same element copy whole.

a[i].f selects a leaf of an element and is a value and a place. [1820]'s indexed accordingly derives a selection after an index, which is what the tour already writes; the parser's by-name refusal of that spelling is retired. Definite assignment keeps a fact per known position _and_ per run inside the element, so writing a[0].x establishes exactly that leaf and reading it asks for exactly that fact — with a fact about the whole element, or about anything containing the array, covering it.

The neutral shape carries the element as a run of exactly one, built by D118/D119's own machinery; a scalar element stays where it was, so no array that existed before D122 changes. An indexed operation carries a second run, applied after the scaled index, which is the only new thing an instruction holds: an index is a value and cannot be a step. Two shapes are the same shape when they hold the same thing, not when their runs start in the same place.

Two forms stayed refused by name: a whole element as a value or a place, and an array whose element is a struct with a variant part. D127 admits both, by making a known index one step of the run rather than a value.

The alternative: forbid arrays of structs, or represent them as a struct of arrays. The first refuses the most ordinary table there is; the second changes what a[i].f means and what sizeof [n]s measures.

Pinned by positive/array-of-structs, positive/computed-whole-array-elements, negative/selection-from-a-scalar-element, the malformed case Element_Path_Below_A_Scalar_Element, the generated IR record, and runtime/array-of-structs on Linux x86-64.

D126 — A variant part is reached by a run like any other part

The tour said that a struct's field may have any type a binding may have [0670] [0750], and that a variant part is one of the things a struct declares [0680]. D86--D122 admitted an ordinary struct as a field, a variant payload and an array element, but only when it had no variant part of its own: every variant operation named its part by one base field, and a part below that field had no way to be said.

Chosen: the five variant operations — select, tag load, payload load, payload store and whole-part copy — carry D118's run down to the part, exactly as every other operation already does. An empty run is D74's variant part of the storage itself, which is where all five started. A copy names each endpoint separately, for the reason an array copy does: the two parts have one shape but need not sit in the same place.

So a struct with a variant part may be an ordinary child, and may be a variant payload; a match subject may be any chain that reaches a variant part, including one rooted at D121's payload alias; and the arm's own aliases carry that run with them.

Composing a run and a selected case fixes their order. The run reaches the part, and the case is then selected _inside_ the part, so the payload offset is the reached part's own and not the base field's. A run _below_ a selected payload is a Case_Index step of the same run, so nothing is ever added after the payload and one order suffices.

An array element was still refused here: a run reaches a part by identities, and an index is a value. D127 makes a known index one of those identities and admits it there.

The alternative: give variant operations their own base-and-part addressing beside D118's runs, or forbid a variant part below the storage's top level. The first is two path vocabularies for one storage model; the second keeps a state machine out of every struct that holds one.

Pinned by positive/nested-variant-parts, positive/variant-inside-an-element, the malformed case Variant_Path_Reaches_A_Scalar, the generated IR record, and runtime/nested-variant-parts on Linux x86-64.

D127 — A known index is an identity, so an element is a place

The tour said that a fixed array is its element repeated [0520], that a whole struct may be zeroed, constructed and copied [0540] [0700] [0710], and it writes w.items[i].x outright. D122 gave an array an ordinary struct element and made a leaf of one a value and a place, but left the whole element neither, and refused an element with a variant part: every whole-part and variant operation reaches its part by identities, and an index is a value.

Chosen: an index the compiler knows is one of those identities, so it is one step of D118's run. A whole array element at a known position is a value and a place wherever a whole ordinary child is one: zeroed, a labelled literal or nominal construction, a copy from storage of the same nominal type, a call's destination, and a call argument. An array whose element is a struct with a variant part follows, because the run now reaches the part.

Where a run may start is one question, asked once. Base zero with no run is the storage itself; base zero with a run is whole array storage the run starts at; a positive base is [0750]'s field of a struct, or [0520]'s element position of an array. A field operation names one part and then a run below it, so a run that starts at whole array storage gives its first step to the part — which is what a known index of a scalar array has always meant. That one promotion is the only place the two conventions meet.

This decision initially left a computed index refused because reaching a whole element needed an address the contextual forms did not form. D134 closes that boundary with a checked, unspellable storage address while leaving known positions as the identity steps chosen here.

Why not a new opcode or operand: an indexed operation already carries a scaled index and a run; a known position needs neither, because it is a position. Adding a second element operand would make every consumer ask which of two ways an element was named, and the neutral IR would hold a number that is a value in one form and an identity in the other.

The alternatives: admit a computed index by forming an address, keep the whole element refused and enable only the variant element, or give an element its own opcode. The first crosses the boundary that keeps every contextual form addressable by identity; the second leaves the array's own whole form the last one missing; the third duplicates D118's run at one depth.

Pinned by positive/whole-array-elements, positive/variant-inside-an-element, positive/computed-whole-array-elements, positive/variant-part-at-a-computed-index, the malformed case Whole_Element_Beyond_The_Array, the generated IR record, and runtime/whole-array-elements and runtime/variant-inside-an-element on Linux x86-64.

D132 — A folded aggregate image recursively contains aggregate fields

The tour said that a module binding already has its value before the entry point [1460], that a struct literal takes its nominal context from its use [0710], and that fields retain source order while each target supplies widths, alignment and padding [0750]. D120 admitted an ordinary child as a contextual runtime value and D121 did the same for an ordinary-struct variant payload, but both kept the corresponding module image refused because D67/D81 could carry only scalar and compact fixed-array leaves.

Chosen: a labelled or nominal module construction may give an ordinary child, at any depth, exactly D120's contextual forms: zeroed, a matching labelled or nominal construction, a direct module struct image, or one directly selected ordinary child of matching nominal type. A selected variant case may give an ordinary-struct payload the same forms. Written and inferred module constructions share the rule. Type aliases preserve the declaration that owns the child, and every copied image owns distinct storage.

These forms remain contextual. They do not make a child or payload a general operand, discard or independently evaluated aggregate expression. An omitted field, of zeroed, explicit zeroed, or a copied absent source has the absent all-zero image. A written nested construction remains a written image even when all of its folds are zero, as D24 and D66 require.

The target-neutral aggregate image keeps D66's flat top-level fold run and extends D67/D81's descriptor run with Nested. Its Offset and Count select one contiguous declaration-order run of direct child descriptors after the top-level descriptors. A child descriptor may itself be Nested or Selected; scalar descendants carry one fold or D131 routine relocation in their descriptor, while fixed-array descendants retain Absent, Finite, Repeated or Hybrid and share the item's existing fold run. Selected and Nested offsets count descriptors; finite and hybrid offsets count folds. Neither run contains a target width, byte offset, padding byte or host representation.

Direct image names and selected-child sources join the existing per-declaration static-image graph. Forward references and aliases are followed before an image is gathered. A path that returns to a declaration reports L0305 once, including a cycle that alternates ordinary-child selections, variant payloads and whole aggregate aliases; invalid members or nominal mismatches retain their contextual owner and add no graph diagnostic.

The verifier first proves both item-owned vector partitions. It then walks the recursive descriptor tree with monotonically increasing descriptor and fold cursors: each direct-child count must match its neutral shape, every offset is canonical and in range, every descriptor is consumed once, every ordinary scalar or compact array fold fits the selected target, and every D131 routine relocation agrees with its recursive signature. A nested form on another field kind, a skipped or backward descriptor run, an unconsumed descendant, a wrong child count, and a 32-bit-only range failure are ordinary release-build IR faults before a backend accessor runs.

The backend recursively replays the same neutral field and selected-payload shapes used for runtime layout. It writes scalar folds or routine symbols at this target's widths, emits compact array forms, and derives every internal gap, inactive variant tail and aggregate tail as zero padding. Thus one image may contain a .long usize child and occupy 20 bytes under the synthetic 32-bit facts while the same IR contains a .quad child and occupies 40 bytes on Linux x86-64. No startup code, target image blob or recursive aggregate SSA value is introduced.

A nonzero module array image whose element is an ordinary struct remains the separate array-literal value boundary: D132 adds recursion at ordinary fields and ordinary variant payloads, not a per-element aggregate image carrier.

Why one recursive descriptor run: flattening child leaves into their parent would erase nominal boundaries and variant ownership; target byte blobs would duplicate images per target; startup stores would contradict [1460]; and one new vector per depth would encode an implementation limit. The existing item-owned descriptor partition already represents a recursive shape once an ordinary child can point into it.

The alternative: admit only zeroed for a nested child in a module image, or unfold an image one level and stop. Both leave a configuration table a program has to build at startup, which [1460] forbids running.

Pinned by positive/module-struct-image-with-a-child, positive/recursive-module-images, negative/recursive-module-image-cycle, negative/recursive-module-image-nominal-mismatch, the recursive aggregate malformed-image verifier cases, the lowering and 32-/64-bit backend seams, the generated lexical and IR records, and runtime/recursive-module-images-are-laid-out-and-distinct on Linux x86-64.

D134 — A computed aggregate element has a checked internal address

The tour said that an array is a value and assignment copies [0520], that an enabled array element is a place [1810], that indexing checks the length before computing an address [0580] [1950], and that evaluation order is fixed [0410]. It never distinguishes a whole aggregate element at a known index from one at a computed index. D127 made the known position an identity step but left the computed form refused because the contextual aggregate operations then had no carrier for its address.

Chosen: every whole aggregate-element context D127 admits also accepts a computed index: typed and inferred local copies, whole assignment from zeroed, construction, storage, calls or non-loop control values, aggregate arguments and named results, and a variant part inside the element. Aggregate parameters and named results are ordinary storage endpoints in those same copies. A chain may contain more than one computed index; each is evaluated from the root outward, exactly once.

Lowering evaluates and bounds-checks a computed destination before evaluating its assigned value. It forms an internal storage address carrying the complete target-neutral shape reached, stores that carrier in an unnamed usize frame slot when it must cross a control edge, and applies the existing contextual aggregate operations through it. The address is unspellable in Landin source, is never a source pointer or alias, and creates no new source type or ABI position. Known indexes remain D127's identity steps and introduce no runtime operand.

The verifier proves that an indexed address starts at fixed-array storage, that its operand is usize, that the reached element shape agrees with the address slot, and that an arbitrary integer cannot substitute for it. The Linux x86-64 backend performs the bounds check before multiplying by the target-derived padded element extent and adding the result to the target-derived storage base. It derives every later child, array and variant offset from the neutral shape as before. D22's definite-assignment rule is unchanged: a computed read of tracked local storage needs the whole-array fact, and a computed write establishes no particular element fact.

A computed variant subject is copied once into independent shaped storage before its exhaustive tag cascade, so payload aliases of scalar, fixed-array or ordinary-aggregate shape all refer to that one subject value. A computed variant destination preserves its siblings in shaped storage while its selected case is formed in source order, then writes the complete element back. Calls registered by defer or undo use the ordinary complete-call parser and may therefore delay a selected function-field callee as well as a direct or locally stored function value.

Why an internal checked address: expanding one operation per scalar leaf cannot represent a target-sized fixed-array field compactly; exposing a source pointer would enable aliasing and pointer syntax the reference rules own; and one special computed-element opcode per construction, copy, call, control or variant form would duplicate the contextual operation family. One verified shaped address lets those existing forms compose without freezing target offsets in IR.

The alternatives: keep D127's computed refusal, materialise every computed element in a temporary and never address the original, or make every subobject path carry interleaved runtime values. The first contradicts [0520] and [1810] after every other element context exists. The second cannot update the original place without another carrier. The third would put block-local values into the shared identity path and make every existing path consumer distinguish two meanings. All were declined.

Pinned by positive/computed-whole-array-elements, positive/variant-part-at-a-computed-index, the malformed runtime-address verifier case, the generated IR record, and runtime/computed-aggregate-elements, runtime/r230-composition, and runtime/r230-composition-trap on Linux x86-64.

D214 — A trailing value fill has one exact type and one evaluation

The tour said [0720] permits of false when the remaining fields are bool and requires the fill to typecheck for every omitted field. D65 had refused all nonzero fills because one syntax node cannot have several types or be evaluated several times. The hosted-parity audit found that its homogeneous refusal was broader than that reasoning: one exact descriptor needs neither conversion nor re-evaluation.

Chosen: a nonzero trailing fill requires at least one omitted field, and all omitted fields have one complete identical descriptor, including array extent, nominal identity, reference permission and function signature. The omitted field supplies the same context as an explicit label. zeroed keeps its existing per-field zero-image rule and may cover heterogeneous fields or no fields. A nonzero fill with no omitted field is refused because there is no destination to supply its contextual type; an independently wanted effect is written as a separate statement.

Written labels commit in source order. The fill is then evaluated once into ordinary temporary storage and copied to omitted fields in declaration order. When exactly one omitted field receives an unpacked array repetition in an ordinary struct, the repeated element is evaluated before any array write and the repetition may write directly into that field. This avoids a full-array temporary and copy while preserving aliased reads and leaving edges during element evaluation. Other fills retain temporary storage. The temporary rule covers case payloads, whole assignments, construction calls and nested aggregate/array fields. A failure or control transfer during evaluation uses ordinary recovery and cleanup; no copy is performed on an edge that leaves. A module image requires the same compile-time values as explicit labels and reuses the existing recursive image representation. Reference-containing fills retain their origins, and repeated copies confer no ownership or allocation lifetime guarantee. This changes no allocator or arena rule.

The alternatives: evaluating a fill once per omitted field changes observable calls; assigning a separate inferred type to one node corrupts shared checking facts; converting per field changes the language's explicit-conversion rule. All remain declined. D65's exact-homogeneous alternative is enabled by the once-evaluated scalar, array, aggregate, pointer, callback and recovery evidence. The grammar still requires a named field before trailing of; the all-of spelling remains excluded, and complete zeroed retains its existing spelling.

Pinned by positive/struct-literal-of-expression, runtime/r490-generic-field-fill, runtime/r490-generic-fill-recovery, runtime/r490-generic-static-fills, negative/r490-fill-mixed-types, negative/r490-fill-array-shapes, negative/r490-fill-atom-sets, negative/r490-fill-pointer-permissions, negative/r490-fill-case-mixed-types, negative/r490-fill-no-omission, negative/r490-fill-frame-escape and negative/r490-fill-unassigned.

D216 — Atom storage retains its complete structural set

The tour said that an atom is a type [0630], a union names an enumeration [0640], and arrays and structs hold typed elements and fields [0520] [0670]. The inherited implementation admitted atoms across calls but omitted them from ordinary field and array descriptors; parameterized atom fields could fail before lowering, while the apparent numeric carrier lost their identity.

Chosen: atom sets compose as runtime leaves in fixed arrays, ordinary fields and variant payloads, including generic substitution. They retain the existing atom carrier and declaration identity; storage, instance keys, static images, slice views and payload bindings preserve the complete structural set. A write may supply a member of its destination set. Reading preserves the whole destination set, and aggregate or array copying requires the same complete descriptor. Neither the carrier nor a singleton set grants numeric operations, conversions or an all-zero value. D143's zeroability requirement still applies to an empty array for explicit zeroed or concept membership. D131's existing implicit empty module-array exception remains: no element exists to initialize. Recursive aggregate zeroability inspects atom metadata; an omitted module image cannot silently create a zero atom, pointer or function address. D214's fill requires equal omitted-field descriptors even when one source atom would be a member of each unequal set.

The alternatives: treating stored atoms as ordinary integers erases identity and admits invalid writes; making each loaded singleton a new storage type breaks structural generic keys. Both are declined. This completes the ordinary composition rule without changing atom equality, D189's optional-pointer restriction, C boundary eligibility or inference's complete-key requirement.

Pinned by negative/parameterized-struct-dependent-errors (the original source now refuses its missing atom initializers), positive/parameterized-struct-template-order-inner-first, positive/parameterized-struct-template-order-outer-first, positive/parameterized-struct-unused-shape (all original source bytes), runtime/r490-generic-atom-arrays, runtime/r490-generic-atom-fields, runtime/r490-generic-atom-storage, runtime/r490-review-generic-distinct-atom-array, runtime/r490-generic-static-selection-descriptors, negative/r490-atom-array-numeric-write, negative/r490-atom-array-wrong-member, negative/r490-atom-array-copy-identity, negative/r490-atom-array-arithmetic, negative/r490-atom-array-zeroed, negative/r490-generic-atom-field-member, negative/r490-fill-atom-sets, negative/r490-atom-aggregate-zeroed, negative/r490-atom-aggregate-zeroable, negative/r490-atom-module-arrays, negative/r490-atom-fill-zeroed, negative/r490-reference-module-arrays, negative/r490-review-generic-atom-zero-aggregate, negative/r490-review-generic-atom-zero-array, negative/r490-review-empty-module-zeroed, runtime/r490-review-generic-empty-module-nonzeroable and the verifier case typed indirect atoms are checked, whose corrupt-load and invalid-write controls preserve the distinction between exact reads and subset writes.

D241 — A general aggregate value follows its destination, and a discard takes what a binding would

The tour said that an array is a value [0520] whose length may be inferred from its literal [0530], that zeroed is an image its destination gives context [0540], that ordinary and variant-bearing structs are types [0670] [0680], that a case with no payload is an atom [0690] and that matching has constant patterns [1210]; [1930] says anything with a type may be thrown away. The aggregate work admitted aggregate values position by position, and every position not yet admitted was one L0304 whose note said that work enables it. At the construct audit thirty-four checker sites still carried that note, with the aggregate work complete.

Chosen: each site was reproduced and classified against the text that governs it, and the construct that owns it now says one of three things.

Implemented, where the normative text already says the form is language:

  • Discards. _ = e accepts every whole array or struct place — a binding, parameter, named return, match alias, field at any depth, element, .val target or slice element — and every expression an inferred local binding x := e accepts. A place is discarded where it stands: its computed indexes are evaluated and bounds-checked once and nothing is copied. Any other value is checked and evaluated exactly as x := e would be, then dropped. Discarding an unassigned local reads it and is L0302.
  • Inferred literals of any element shape. A local array literal takes its element type from its first element — a slice, text view, pointer, function, atom set, struct or array as much as a scalar — and every later element must match it. An inferred local may likewise copy a whole array or struct parameter or named return, which the typed form already could. Counted repetition keeps [0560]'s scalar element, module images keep D26's and an any element still needs a written array type.
  • Variant payload arrays. A fixed-array payload field takes every expression an ordinary struct's array field takes — an element, a call, try, array arithmetic, a control expression, a deeper field, a parameter, .val or a slice element — as D84 said it should. The case is still selected before its payload is evaluated (D76); a call fills a temporary that is then copied, and no IR destination form is added.
  • Two defects found on the way: discarding an element of an array of slices or text views crashed a later stage, and a struct whose field type had already been refused received a second report.

Reclassified as type errors (L0301), where the old report called a type error "not enabled": a value name used as a type, a type name used as a value, a whole struct, array, field or construction in a position that takes another type, a variant case where a whole struct belongs, a struct comparison (D200), zeroed as an operand, and a match on a number. The last follows [1210] as now written: a subject is an atom set, a variant part or a pointer union, and a number is compared with if rather than matched. The grammar has no literal arm, D77 left scalar subjects refused, and the derived parser needed none. The catalogue later gave these refusals codes by rule: misused aggregate values are L0334, a type name used as a value L0338, zeroed as an operand L0328, and a match on a number L0333; L0301 keeps genuine type disagreements.

Recorded as boundaries: the rest keep L0304 and their second note says "this is a recorded source-form boundary". An untyped struct literal needs a named type from its destination [0670]. An array literal takes its shape from an array destination or an inferred binding, and an uncounted repetition its length from an array destination, so a count-less inferred initializer is refused [0560]. Mixed repetition needs an explicitly typed destination, repetition a nonzero length or count, and a counted repetition infers only a scalar element. A variant part is a member of its struct with no value of its own, written with a case rather than copied [0680]; a variant case is written where its part is the destination [0690]. A match alias of an array is not copied (D85). A construction is a value, not a statement. A module image folds only what [1940] knows. Five guards that no source reaches keep the same wording rather than becoming compiler defects.

The alternatives: a bare case as a standalone atom value, as [0690]'s "It is an atom" could be read, was declined: a case identity belongs to its part (D74), and making it a first-class value would need a mapping from atoms to tags in both directions and a second widening path, for no program that wrote one. A variant part as a value of its own was declined because it is the general variant value D76 refused, a union with no struct around it. Copying a match alias of an array was declined for D85's reason. Matching numbers with literal arms was declined for the reasons above. Leaving the discards refused was declined because [1930] is kernel text. Keeping every site a pending promise was declined because the aggregate work is complete and [1830] forbids a note that promises nobody's work.

Pinned by positive/r720-discard-aggregate-places, positive/r720-discard-inferred-values, positive/r720-inferred-reference-literals, positive/r720-inferred-aggregate-literals, positive/r720-payload-array-values, runtime/r720-discards-evaluate-once, runtime/r720-discard-index-traps, runtime/r720-inferred-arrays-hold-references, runtime/r720-payload-arrays-take-values, negative/r720-discard-untyped-struct-literal, negative/r720-variant-part-has-no-value, negative/r720-variant-case-needs-its-part, negative/r720-counted-repetition-scalar-element, negative/r720-inferred-module-array-scalar-element, negative/r720-any-element-needs-typed-array, negative/r720-match-alias-array-not-copied, negative/r720-module-initializer-boundary, negative/r720-case-is-not-a-whole-struct, negative/r720-aggregate-comparison-refused, negative/r720-match-subject-type, negative/r720-refused-field-adds-no-cascade, negative/r491-inferred-repetition-refusals and negative/array-repetition-countless-inferred-initializer-not-enabled.

DECISIONS: LIFETIME, ESCAPE AND ALLOCATION

Which origin a reference carries, where it may reach, and who owns the storage a call consumes.

D140 — escaping precedes an explicit parameter convention

The tour said that in, inout and sink are conventions written before a parameter name [0900], that escaping is orthogonal to all three [0780] [0900], and that attributes are prefix words [0760]. It did not say how the two prefixes are ordered when one parameter carries both.

Chosen: escaping first, then an optional explicit convention, then the name: escaping inout item: ptr mut node. The parser retains explicit in apart from the omitted default even though both have the same language meaning. Type and fixed formals keep their existing spellings and admit neither runtime modifier.

The alternatives: convention first, or both permutations. Convention first makes the general prefix attribute interrupt the parameter it qualifies; admitting both creates two source spellings for one signature fact and makes recovery decide whether a repeated modifier was an order variation or a second modifier. Either is workable, and neither was selected by the tour.

Pinned by the parser case reference signature syntax is represented and the resolution case return sources retain parameter positions.

D149 — inout exclusivity is checked only for a provably identical place

The tour said that inout may replace its argument exclusively [0900], while [0770], [0860] and [1720] reject a borrow checker or whole-program alias claim. It did not state what a caller passing the same storage twice must prove.

Chosen: one call may not fill two inout parameters with the same provable binding-rooted place. Equality follows declaration identity and an identical ordinary field path; that case is L0337 at the later argument with the first as its related place. Distinct pointer paths and computed indexes may alias at runtime, but proving that requires alias analysis Landin does not claim. Such possible aliasing is accepted and explicitly outside the guarantees. The callee's writes still occur in [0410] source order; acceptance is not a non-alias promise.

The alternatives: accepting f(x, x) would make “exclusively” false in the one case the local checker can answer. Rejecting all pairs of pointer or index paths would reject ordinary code without proving overlap. Interprocedural alias analysis or ownership would reverse [0770]. All were declined.

Pinned by negative/inout-same-place-twice and runtime/inout-pointer-alias-is-unchecked.

D212 — Arena authority is explicit and allocation does not create a region

The tour promised a builtin arena type and arena name do block whose allocations had frame origin locally and independent allocated origin through a helper. W7 argued that every escaping result would pass the block's exit. D191 asked for a real type, backing, exhaustion and origin contract; D196 identified the helper-side-effect path that argument omitted.

Chosen: withdraw both builtin forms. An arena is an ordinary allocator value with explicit backing and extent, such as mem.arena_over. Ordinary conformance supplies allocation, optional in-place growth and free. The existing inout-receiver mem.allocator is a generic evidence contract, not itself object-safe; an ordinary pointer-receiver adapter permits calls through any without changing that contract. The frontend has no privileged knowledge of core/mem. The named refusals remain migration diagnostics pointing to this decision, not promises to enable these forms later. Declared names spelled arena remain ordinary.

The caller chooses backing and capacity on every target: a frame array through the explicit unchecked constructor, static storage, or storage explicitly acquired from another provider. Target-sized extents and checked request arithmetic determine exhaustion. A monotonic provider reports out_of_memory without changing state when the request does not fit; the counted provider can force the same edge. Nested ordinary scopes create no implicit provider or region. Separate backing yields independent exhaustion; reusing or overlapping backing remains manual lifetime policy. The backing owner releases acquired storage explicitly, arranging defer for normal, failure, return, break and continue exits when needed. No implicit cleanup, guessed frame buffer, hosted heap fallback or destructor is added.

Independent allocator results keep the existing no-from contract. It permits simultaneous allocations and helper results used by the caller, including pointer-containing aggregates, slices, erased values and callback state. The implementation's explicit integer-to-pointer conversion removes tracked origin under [0470]. A helper may retain its result in module storage without returning it through any caller boundary. Accordingly, arena_over and fail_over now require escaping base: an ordinary call cannot build either provider over tracked frame backing. Both representations are private, so a struct literal cannot evade this constructor rule. The explicitly named arena_over_unchecked and fail_over_unchecked allow local backing when the caller takes responsibility for all direct and helper-held results. Their handles still retain the base's origin. Backing validity, exact capacity and explicit release remain the caller's responsibility; neither constructor adds a lifetime borrow to allocation results. Explicit pointer-to-integer round trips remain [0470]'s separate opt-out.

Why not the alternatives: W7's omitted module-store path is executable without returning a value, so checking only the caller block exit is insufficient. Retaining the allocator's mutable borrow on each result would reject its next allocation and defeat the ordinary allocation idiom. A new region effect system across erased calls, callbacks and helper side effects would be a different semantic design, unsupported by the local origin model; pretending an unsafe integer conversion preserves that promise would be false. Permitting frame backing in the ordinary constructor left the same hazard at every allocator call. Requiring retainable backing there, while preserving an explicit local opt-out, keeps the existing allocator contract honest.

Pinned by runtime/r480-arena-independent-results, runtime/r480-arena-nested-exhaustion, runtime/core-mem-allocators, runtime/core-mem-arena-boundaries, runtime/arena-is-an-ordinary-name, negative/arena-block-names-owner, negative/arena-type-names-owner, negative/core-arena-frame-escape, negative/frame-origin-return, negative/r480-callback-frame-escape, negative/r480-helper-frame-retention, negative/array-reference-frame-return, negative/core-text-frame-slice-escape, negative/any-frame-origin-escape, and runtime/any-untracked-pointer-origin.

D217 — Retained stores and payload replacement follow backing storage

The tour said that frame references cannot be retained [0770], parameters are non-escaping by default [0780], origins join restrictively [0840], and payload aliases end at last use [1220]. It did not spell out destination-origin comparison or a whole construction's alias-check boundary.

Chosen: [1910] checks the backing of a retained store, not merely its root binding. A reference from the same parameter origin may update that origin's storage; another retained parameter must be escaping. Writes through known local address aliases join into the local's stored origins. An untracked alternative never erases a tracked restriction, and writing a pointee does not change the pointer descriptor's own origin.

Payload storage has its own lifetime even when its value is scalar. D76's direct case selection precedes its payload initializers. The local replacement check also requires last use before a whole containing construction starts; code that needs an old scalar saves it first. D134's computed value destination retains its existing temporary-and-copy-back order. These are local checks, not interprocedural alias analysis or a change to [0470]'s explicit boundary.

The alternatives: checking only module bindings misses caller-owned storage; treating scalar payload names as copies contradicts D78's aliases. Letting an untracked alternative dominate a tracked one contradicts [0840]. Tracking each field publication separately inside a whole construction would admit more initializer arrangements, but would make the borrow boundary depend on the construction's internal field schedule. The explicit last-use boundary keeps that rule visible at the containing assignment.

Pinned by negative/r491-retained-reference-stores, negative/r491-live-payload-aliases, runtime/r491-reference-store-origins, runtime/r491-payload-alias-last-use, the driver's refusal-without-effects case, and the existing pointer-vector growth and initialized-allocation fixtures.

D220 — A sink path stops at referenced backing storage

The tour said that a sink path has a binding root, no dereference and no computed index [0910]. D127 made a known fixed-array index an identity step. The implementation also admitted literal slice indexes, even though they reach storage through the descriptor's backing reference. Consuming through a local view could then hide an inout array's restoration obligation.

Chosen: [1910]'s sink-place check stops at every slice index, just as it stops at a pointer dereference. A literal index into a fixed array still names one contained place. A slice-valued binding, ordinary field or fixed-array element names descriptor storage and remains an eligible sink argument. The existing inout restoration rule applies to those admitted places on every exit. The same boundary applies after generic type substitution.

This distinguishes prototype 3's descriptor field l.items from an element reached through that descriptor. It also preserves prototype 4's consumed reader-field restoration. Copies and reference-origin checks keep their own rules; this does not add ownership or interprocedural alias analysis.

The alternatives: transferring restoration obligations through every slice view would require mapping aliases and view indexes back onto other bindings, beyond the chosen one-place model. Admitting a literal slice index solely because its spelling starts at a local leaves the no-dereference boundary unstated. Refusing whole slice descriptors would instead remove the consuming container-field idiom the prototypes require. All are declined.

Pinned by negative/r491-sink-slice-storage, positive/r491-sink-contained-places, negative/sink-through-dereference, negative/sunk-inout-not-restored and the small generic/concrete checker controls. The existing copy-before-sink and consumed-place runtime fixtures retain their separate language obligations.

D222 — Writable return sources cannot hide independent storage

The tour said that from states exact parameter dependencies [0790], independently of the return type's write permission. D217 permits a same-origin store through caller storage. A helper could join a parameter address with a module address, satisfy that parameter set, and return a writable view whose caller then knew only the parameter destination.

Chosen: a result with a nonempty from clause and a reachable writable reference must not carry a known independent storage alternative [1910]. The body is checked against the written contract. A helper choosing between two destinations receives both as arguments and names both in from; an explicit module actual then remains visible at the caller's retained-store check. A wrapper cannot hide that module actual behind a narrower writable contract. The rule includes instantiated generic results, aggregate carriers and nested references without deep const. Erased carriers and aggregate origin unions are conservative. It applies equally to bodies used as function values and concept providers; external declarations retain their written obligations.

Read-only results without reachable writable references retain their previous source comparison. Ordinary identity and container-subview accessors retain their parameter source; storage need not lie physically inside the parameter. Module-only and allocator results remain independent without from. Optional empty atoms retain D189's exception; empty slice literals add no destination and constructors of empty reference carriers do not waive exact source agreement. Integer-created pointers retain [0470]'s explicit untracked boundary. Joining one cannot conceal a separately known independent destination. No transitive lifetime or ownership guarantee is added to D217's local checks.

The alternatives: inferring every callee body at its calls would replace the written contract and complicate function values and external calls. Refusing every write through an accessor would lose valid same-origin updates. Keeping the previous dependency-only rule for writable results would retain the hidden-module store witness. All are declined in favor of an explicit, stronger writable return contract.

Pinned by negative/r491-writable-return-hidden-storage, positive/r491-writable-return-explicit-sources and the checker case writable returns keep all destinations, including direct and joined returns, explicit module and same-origin actuals, hidden wrappers, indirect calls, concept providers, instantiated generics, nested permissions, empty and raw boundaries and independent anonymous-result positions. Prototype 3's accessor and prototype 4's independent-allocation contracts remain separate.

D223 — Sink places are consumed at call entry

The tour said that arguments evaluate left to right [0410] and a sunk place becomes dead until assigned again [0910]. It did not say whether consumption happens while evaluating each argument or when the call begins. The compiler previously consumed each place immediately, including on an outer call whose later argument returned before entry.

Chosen: evaluate the callee and written arguments first, capturing each by-value argument at its own evaluation point. Commit consumption only when all arguments reach call entry. A later argument may therefore read an earlier sink place, as in use(value, value.count), or assign it. The callee receives the previously captured value; the original place becomes dead at entry even if a later argument replaced it. An early return or propagated failure during argument evaluation does not consume that outer call's pending places. Entered nested calls retain their own effects. Cleanup observes the state of the edge on which it runs; failure from an entered callee has consumed its sinks before recovery or propagation.

Pending sink places must remain live until committed in written argument order. Repeated or provably overlapping sinks are refused, as is a provable overlap between a sink and an inout argument in either order. A nested call may consume a pending place only if it is restored before outer entry. An inout argument names storage and must still be initialized on entry. D149's other alias rules and D220's sink-place forms are unchanged. This adds no ownership or transitive alias guarantee; separate copies remain live.

The alternatives: immediate consumption retains the old refusal of later reads and makes a call that never begins consume places. Call-entry timing preserves the place on that exit. Allowing repeated sinks or an inout alias of a consumed place would weaken the existing consumed-place and initialized-entry checks; postponing value capture would change [0410]. Neither is adopted.

Pinned by positive/r491-sink-call-entry, negative/r491-sink-entry-overlap and the checker case sinks commit at call entry, covering later reads, argument exits, named, indirect and generic calls, nested effects, restoration and cleanup. The positive derivative covers the descriptor and handle patterns shared by prototypes 3 and 4. Assembly and runtime evidence remain separate obligations.

DECISIONS: FUNCTIONS, CALLS AND RETURNS

The call convention for values too large for a register, function values, named returns, and the declared-error channel beside them.

D94 — An ordinary struct argument is copied into callee storage

The tour said that an unmarked parameter is in [0900], calls evaluate arguments left to right [0410], and an ordinary struct has nominal identity [0710]. The scalar internal convention had no rule for carrying the complete storage of one.

Chosen: a parameter may have an ordinary struct type whose fields are scalar or fixed arrays, without an ordinary-child or variant field. A call may supply a direct module or frame storage name of exactly that nominal type. The source must be definitely assigned in full. Construction, nested-child paths, struct-returning calls and other aggregate expressions remain refused in this argument position.

One aggregate occupies one position in the existing internal argument run. The caller forms a target-neutral Storage_Address carrier; the first six positions use integer registers and later positions use D86's eight-byte stack slots. The carrier is not a Landin pointer and cannot be named by source. The callee preserves every incoming aggregate carrier, derives the complete padded extent from its selected target, and copies an addressed source into a fresh aggregate parameter slot before the body runs. D97 clears that slot directly for a direct zeroed argument. Reads therefore use ordinary field and array operations against independent by-value storage.

Why an internal address and defensive copy: flattening fields would make one source parameter consume a target-dependent number of argument positions, while aliasing caller storage would change in from a value convention into a hidden reference convention. The neutral carrier keeps offsets, padding and extent out of verified IR; the callee-side copy makes the observable value independent and leaves the C boundary to classify C aggregates separately.

The alternative: pass a struct argument by reference and let the callee copy on write, or expand the struct into one register per scalar field. The first makes a later argument's side effect visible to the callee, which a later soundness repair met as a defect even under this convention; the second has no answer for a struct wider than the register run.

Pinned by the checker, lowering, malformed-IR verifier and backend public seams; negative/struct-argument-unassigned; the generated token and IR records; and runtime/struct-arguments-cross-calls on Linux x86-64.

D95 — A fixed array argument uses the same by-value transport

The tour said that a fixed array's length is part of its type [0520] and an unmarked parameter is in [0900]. D94's internal carrier and callee copy did not depend on nominal fields, but the checker and IR parameter builder still admitted only its ordinary-struct case.

Chosen: a parameter may have any enabled fixed-array type, and a call may supply a direct module or frame storage name with exactly the same scalar element and length. Every source element must be definitely assigned. An array literal, repetition, nested array field, returning call or other array expression remains refused as an argument.

The array occupies one existing internal ABI position. The caller emits D94's unspellable target-neutral storage-address carrier. The callee preserves that carrier with the struct carriers, derives length * target element size, and copies those bytes into a fresh shaped array parameter slot before running; D97 clears that slot directly for a direct zeroed argument. Register and stack positions therefore have one convention for scalar, ordinary-struct and fixed-array source parameters while their frame storage retains the distinct neutral shape each operation needs.

Why reuse the carrier: passing every element separately would make D18's largest arrays impossible to represent compactly and would make argument position depend on the selected target. Passing an alias without copying would not implement in as a value. D94's one-position transport plus defensive copy avoids both changes without introducing a source pointer.

The alternative: pass a fixed array as a slice, or expand it element by element. A slice is a view and [0520] says an array is a value; element expansion has no answer for a long array and a different answer for every length.

Pinned by the checker, lowering, verifier and backend public seams; negative/array-argument-unassigned; the generated token and IR records; and runtime/array-arguments-cross-calls on Linux x86-64.

D96 — Contextual nested storage may be an aggregate argument

The tour said that calls evaluate argument expressions left to right [0410]. D90/D91 made parent.child.array and parent.child complete contextual storage sources, while D94/D95 initially accepted only a direct storage name in an aggregate argument position.

Chosen: a flat ordinary-struct parameter may receive a depth-one ordinary child parent.child, and a fixed-array parameter may receive either parent.array or parent.child.array. Nominal identity or array shape must match exactly, and the selected child or array must be definitely assigned in full. Deeper paths, construction and other general aggregate expressions remain refused.

Storage_Address carries the independent declaration-order parent and child field identities in addition to its module-or-frame storage identity. It never carries an offset. The backend recursively places those fields for the selected target before transporting the resulting address through D94/D95's one ABI position; the callee performs the same defensive copy into independent shaped parameter storage.

Why preserve the path: flattening the child into a new datum would erase D86's nominal boundary, while recording the selected target offset would make checked IR target-specific. The existing contextual source already proves one complete extent, so extending its neutral path carrier to the argument boundary does not create an aggregate expression value.

The alternative: require a nested child or array to be copied into a named local before it is passed. The address carrier already names the parent and child field identities, so the copy would be a second copy of what the callee copies anyway.

Pinned by the checker, lowering, malformed-IR verifier and backend public seams; negative/nested-storage-argument-unassigned; the generated token and IR records; and runtime/nested-storage-arguments on Linux x86-64.

D97 — zeroed may directly initialize aggregate parameter storage

The tour said that zeroed takes its type from context [0540]. D94/D95 provided shaped by-value parameter storage, but required the caller to name existing storage even when the all-zero value needed no source object.

Chosen: zeroed may appear directly where a supported struct or fixed-array parameter supplies its complete type. For the internal convention, the caller passes a zero carrier in the aggregate's ordinary register or stack position, without allocating aggregate storage. At entry the callee recognizes that carrier and clears the complete target-derived extent of its own shaped parameter slot before the body runs. A nonzero carrier still names existing storage and is copied into that slot. This zero carrier is not a source pointer, and it is never used for a C ABI call or an aggregate result destination. A permitted C ABI aggregate argument keeps its existing caller materialization and C classification.

The zero carrier is target-neutral in verified IR, where only a direct all-zero internal aggregate argument may use it. The parameter's existing struct field shapes or array length and scalar element give the backend the padded extent. zeroed does not become a general aggregate expression. D102 and D104 also allow this carrier for their contextual variant-bearing and nested struct arguments, whose complete parameter shapes determine the clear extent.

Why clear in the callee: an all-zero value has no source storage or initializer effects to preserve. The zero carrier keeps argument order and register/stack placement identical to other arguments, while clearing the callee's own slot gives it the same independent by-value storage. A named zeroed local remains an ordinary nonzero storage carrier and is copied.

The alternative: require a named zeroed local before the call, or clear a fresh caller temporary and copy it into the callee. Both spend a caller extent and a whole-object copy for a value whose complete image is known without either operation.

Pinned by the checker, lowering, verifier and backend public seams; the generated token and IR records; and runtime/nested-storage-arguments on Linux x86-64.

D98 — An array literal may directly fill an argument temporary

The tour said that an array literal evaluates its elements in source order [0410] and a fixed-array parameter supplies a complete length and scalar element type [0520]. D95 initially required named storage, and D97 admitted only its all-zero contextual value.

Chosen: an array literal may appear directly in a fixed-array argument position when it has exactly the parameter's length and every element matches the parameter's scalar element type. The caller allocates a fresh shaped array slot, evaluates and stores each element left to right, then passes the slot's Storage_Address through D95's existing one-position convention. The callee copies it into independent parameter storage as usual.

The literal remains contextual: its parameter supplies shape before any element is checked, and no array-valued expression result or target-sized IR run is introduced. One scalar store is emitted per written literal element; D18's unbounded compactness requirement is unaffected because source text already contains exactly that many elements.

Why materialize in the caller: flattening literal elements into ABI positions would change the convention by source form and target, while a callee-only construction would reverse [0410]'s caller-side argument order. The temporary preserves both order and one-position transport.

The alternative: require an array literal argument to be bound to a local first, or introduce an array-valued expression result. The temporary keeps the literal contextual and the IR free of a target-sized run; a local is the same temporary with a name.

Pinned by the checker, lowering, verifier and backend public seams; negative/array-literal-argument-shape-mismatch; the generated token and IR records; and runtime/array-arguments-cross-calls on Linux x86-64.

D99 — Array repetition forms may fill an argument temporary

The tour said that repetition evaluates its repeated expression once [0560], and mixed repetition evaluates its explicit prefix before that one suffix expression [0410]. D98's shaped caller temporary provides the same complete fixed-array context at an argument boundary.

Chosen: full and mixed array repetition may appear directly in a matching fixed-array argument position. A written full-repetition count must equal the parameter length; a mixed prefix must leave at least one destination position. Lowering stores explicit prefix elements in source order, evaluates the repeated expression once, emits one compact suffix fill, and transports the temporary through D95's existing address convention.

The fill retains a one-based first destination identity and the temporary's neutral length and scalar element. Neither lowering nor verified IR expands the repeated suffix, including for D18's target-sized lengths; target byte width and extent remain backend facts.

Why both forms share one rule: their only semantic difference is the source-ordered explicit prefix. Giving arguments a separate repetition representation would duplicate the contextual assignment and initializer semantics without changing the ABI carrier or callee copy.

The alternative: expand a repetition into one store per element in lowering or in the IR. One compact fill keeps the IR target-neutral and the emitted code independent of the length; the expansion would make a 4096-element fill 4096 instructions.

Pinned by the checker, lowering, verifier and backend public seams; negative/array-repetition-argument-shape-mismatch; the generated token and IR records; and runtime/array-arguments-cross-calls on Linux x86-64.

D100 — A scalar-field struct literal may fill an argument temporary

The tour said that labelled struct construction evaluates fields in source order [0410], omitted fields may use of zeroed [0700], and ordinary structs are nominal [0710]. D97 supplied a zero carrier for an entirely zero aggregate, but labelled construction still needs a shaped caller temporary for its source-ordered field expressions.

Chosen: a bare or correctly nominal construction may appear directly where a flat ordinary-struct parameter has scalar fields only. Labels are checked against the parameter's nominal body, evaluated and stored in source order; of zeroed writes zero or false to omitted fields in declaration order. The caller then transports the complete temporary through D94's existing address convention and the callee copies it by value.

Structs with fixed-array, ordinary-child or variant fields remain outside this literal-argument slice; their labels require additional contextual leaf materialization. The temporary itself retains declaration-order scalar shapes, never target offsets or padding.

Why scalar fields first: it exercises nominal contextual construction and caller-side evaluation order without duplicating D65/D76's array and variant leaf machinery inside call lowering. Those shapes remain valid storage arguments by D94/D96; only direct literal construction is narrower.

The alternative: require a struct literal argument to be bound to a local first, or admit literals with array and child fields in the same slice. The first is the temporary with a name; the second needs the leaf materialization the later decisions add one kind at a time.

Pinned by the checker, lowering, verifier and backend public seams; negative/struct-literal-argument-nominal-mismatch; the generated token and IR records; and runtime/struct-arguments-cross-calls on Linux x86-64.

D101 — Struct literal arguments may contain fixed-array fields

The tour said that a labelled array field receives the same contextual array forms as standalone fixed-array storage [0520] [0700]. D100 restricted argument construction to scalar fields even though its caller temporary already carried compact fixed-array field shapes.

Chosen: a flat ordinary-struct literal argument may label fixed-array fields with literals, full or mixed repetitions, zeroed, or matching direct and D96 nested storage paths. Each label commits in source order. Explicit array elements are stored in order, repetition uses one compact suffix fill, zeroed clears the field extent, and storage sources use one compact copy. of zeroed clears any omitted fixed-array field after all labels.

Every operation targets the aggregate temporary by declaration-order field identity. Source copies retain independent parent and child identities. No field offset, padding byte or expanded repeated suffix enters checked IR; the complete temporary then follows D94's ordinary one-position transport and callee copy.

Why this closes only fixed-array leaves: D65 already supplies their finite contextual operation family and compact shape. Ordinary-child and variant fields require recursive construction or case selection and remain separate argument slices rather than being flattened here.

The alternative: require a struct literal's array fields to be written as zeroed only, or bind the literal to a local first. The first makes a small table argument unwritable inline; the second is the temporary with a name, and every array form here is one D65 already gives an ordinary field.

Pinned by the checker, lowering, verifier and backend public seams; negative/struct-literal-argument-array-shape-mismatch; the generated token and IR records; and runtime/struct-arguments-cross-calls on Linux x86-64.

D102 — Variant-bearing struct storage may cross an argument boundary

The tour said that an unfolded variant is part of its enclosing struct's storage [0680] and matching inspects the selected case [1210]. D74--D85 carry that shape through local and module storage, while D94 initially refused it at a parameter declaration.

Chosen: an ordinary struct parameter may contain unfolded variant fields, provided it contains no ordinary-child field. Direct matching storage or contextual zeroed may supply the argument. The complete variant field must be definitely assigned: a declaration-only local cannot cross the call until a case has been selected. Struct-literal argument construction with a variant label remains a separate slice.

The aggregate parameter slot retains the variant tag type, source-order cases and compact payload-field runs. D94 transports one storage address and copies the complete target-derived padded struct extent for a storage source; D97's direct zeroed carrier clears that extent in the callee instead. Tag matching and payload aliases then operate on the independent callee slot exactly as on any local aggregate.

Why opaque transport is sufficient: case classification affects storage layout but not this internal convention's one-position carrier. Reclassifying or flattening payload leaves at the call would duplicate the selected target's layout in neutral IR. Keeping the existing shape and copying its extent avoids that second authority.

The alternative: copy a variant-bearing argument case by case, or refuse it until struct literals can select cases. The whole-storage copy already carries the tag and the inactive bytes; a refusal would keep a device state, the aggregate the driver passes most, out of every call.

Pinned by the checker, flow, lowering, verifier and backend public seams; negative/variant-struct-argument-unassigned; the generated token and IR records; and runtime/variant-struct-arguments on Linux x86-64.

D103 — Struct literal arguments may select variant cases

The tour said that a variant label selects one case and evaluates its payload labels in source order [0690] [0700]. D102 carried existing variant-bearing storage through calls but left direct argument construction refused.

Chosen: a flat variant-bearing struct literal may appear directly in a matching parameter context. Its variant label selects a case in the fresh caller temporary before payload labels are committed. Scalar payloads store in source order; fixed-array payloads use the same literal, repetition, zeroed and storage-copy forms D101 gives ordinary array fields. of zeroed selects the first case for an omitted variant field.

Selection clears the selected payload before payload writes, so omitted payload leaves have the all-zero image while inactive bytes are unspecified. The IR retains field, case and payload-field identities; target tag placement, payload offsets and padded extent remain backend-derived. The finished temporary then uses D102's unchanged one-position by-value transport.

Why construction stays in caller storage: case and payload expressions are arguments and therefore belong in [0410]'s caller-side evaluation order. Flattening them into ABI operands would expose the selected target's unfolded layout and make equivalent named storage use a different convention.

The alternative: require a variant-selecting literal to be bound to a local first, or select the case after the payload labels are written. The first is the temporary with a name; the second writes payload bytes that the selection then clears.

Pinned by the checker, lowering, verifier and backend public seams; negative/variant-literal-argument-payload-mismatch; the generated token and IR records; and runtime/variant-struct-arguments on Linux x86-64.

D104 — A depth-one nested struct may cross an argument boundary

The tour said that an ordinary child retains its nominal boundary [0710] and D86--D93 represent one such child by parent and child field identities. D94 carried the child itself but still refused a parameter whose complete type contained that field.

Chosen: an ordinary struct parameter may contain one depth-one ordinary child whose fields are scalar or fixed arrays. Direct matching storage or contextual zeroed may supply the complete outer argument. Definite assignment requires every outer scalar/array field and the complete ordinary child; sparse assignment of one nested leaf is not enough. Direct outer struct-literal construction with an ordinary-child label remains separate.

The parameter slot retains an Aggregate_Field_Shape whose compact payload run is the child's declaration-order scalar and array leaves. D94's caller carrier still occupies one ABI position: the callee copies a storage source's complete recursively placed padded extent or clears it for D97's direct zeroed carrier. Child field and element reads then reuse D88/D89's neutral parent/child identities.

Why preserve one slot: splitting the child into ABI operands would erase its nominal boundary and make operand count depend on composition. The existing recursive target placement already derives its extent from neutral shape, so opaque one-position transport remains sufficient.

The alternative: flatten the child into the outer parameter's field run for the call, or copy the child separately. The parameter slot keeps the child's own shape so the callee's copy is one whole-storage copy, and definite assignment stays a fact about one complete outer value.

Pinned by the checker, flow, lowering, verifier and backend public seams; negative/nested-struct-argument-unassigned; the generated token and IR records; and runtime/nested-storage-arguments on Linux x86-64.

D105 — Struct literal arguments may construct an ordinary child

The tour said that a labelled struct literal evaluates fields in source order [0410] while an ordinary child's identity remains nominal [0710]. D104 carried complete nested storage but left a direct outer construction refused.

Chosen: a flat outer struct-literal argument may name its depth-one ordinary-child field with a bare or matching nominal child literal, contextual zeroed, or matching direct child storage. The child's scalar and fixed-array labels use their existing contextual forms. An explicit child constructor with a different nominal body is a type mismatch even when its fields coincide. of zeroed clears an omitted child as one complete padded subobject.

Lowering first clears a constructed child's complete padded extent and then commits its labels in source order. Scalar and array operations retain both parent and child identities. A storage source instead copies declaration-order leaves into the same destination child; target offsets and padding remain absent from neutral IR. The finished outer temporary uses D104's ordinary one-position transport.

Why clear before labels: this gives padding and an of zeroed omission one canonical all-zero image without introducing a nested aggregate value. Every explicit expression still runs exactly once and in source order before the call.

Pinned by the checker, lowering, verifier and backend public seams; negative/nested-struct-literal-argument-nominal-mismatch; the generated token and IR records; and runtime/nested-storage-arguments on Linux x86-64.

D106 — Aggregate results return into caller-owned storage

The tour said that a function's named return is an ordinary place [0930] and every call evaluates arguments before entering the callee [1920]. D94 established one-position by-value aggregate arguments, but no result convention made a returned struct's lifetime independent of the callee frame.

Chosen: a function with an ordinary, variant-bearing or depth-one nested struct result receives one unspellable internal usize parameter naming caller-owned result storage. It precedes all source parameters in the existing register/stack run. The named result keeps its complete checked shape. It may occupy an independent callee slot, copied into the hidden destination on each successful exit, or use that destination as its storage when D116's observational conditions hold. A typed local initializer may supply a matching aggregate-returning call as its value.

The checked IR item retains Aggregate as the declared result and keeps the complete neutral shape on its result slot. The call instruction itself has no aggregate value: its first operand is an opaque Storage_Address for the already-shaped destination, followed by source arguments. The verifier checks that operand against the hidden scalar parameter. Target offsets, padding and byte extent enter only during backend layout and any copy that is needed.

Why not return a pointer to callee storage: that pointer would escape a dead frame and would turn by-value semantics into an alias. Returning fields in registers would instead require target ABI classification in neutral IR and pre-empt the C boundary. Caller storage preserves value lifetime and the established one-position internal convention without either error.

Pinned by the checker, flow, lowering, verifier and backend public seams; negative/struct-return-unassigned and negative/variant-return-unassigned; the generated token and IR records; and runtime/struct-returns-cross-calls, runtime/variant-returns-cross-calls and runtime/nested-struct-returns-cross-calls on Linux x86-64.

D107 — Fixed arrays use the same caller-owned result convention

The tour said that a fixed array's identity is its element type and length [0520], and D17 keeps that shape independent of any target byte extent. D106's hidden destination therefore has all the information an array result needs as well as a struct result.

Chosen: a function may name a fixed-array return, assign it through the existing whole-array contextual forms, and initialize a matching typed local from its call. One leading unspellable usize parameter points at the caller's shaped array slot. The named result may use that storage under D116's conditions; otherwise each successful exit copies exactly length * element-size bytes from its independent result slot. The call itself still returns no IR value.

Definite assignment records a whole-array fact for the named return; assigning known elements independently also suffices once every position is covered. The neutral result slot carries element type and length, never the selected target's byte count.

Why share D106: a second array-specific return channel would make source aggregate category, rather than lifetime and target classification, decide the ABI. Both are fixed-size by-value storage and need the same caller lifetime.

The alternative: return a fixed array in registers when it fits, or as a pointer into the callee's frame. The register form has a different answer for every length and none for a long array; the pointer form aliases storage that is gone when the callee returns.

Pinned by the checker, flow, lowering, verifier and backend public seams; negative/array-return-unassigned; the generated token and IR records; and runtime/array-returns-cross-calls on Linux x86-64.

D108 — An aggregate-returning call may fill aggregate storage directly

The tour said that an expression body fills its named return [0880], while assignment evaluates its source before committing the destination [0410]. Once D106/D107 give a call caller-owned storage, routing its result through another aggregate value would add no semantics and would lose that direct destination.

Chosen: a matching struct- or fixed-array-returning call may initialize a typed local, assign a direct whole aggregate place, fill a named return in a block, or serve as that return's expression body. Lowering supplies the final place itself as the hidden result destination. Forwarding never materializes an aggregate SSA value or aliases one frame's storage into another. A callee using an independent result slot copies at its successful exits; a callee meeting D116's direct-storage conditions need not copy there.

Child-field destinations remain separate: they require a field-qualified hidden destination carrier before a returned call can fill them directly.

Why permit a boundary without a copy: by-value results require the same observable value and effect order, not a particular intermediate allocation. The independent slot remains available when direct storage would expose a partial result or change the named return's behavior.

The alternative: materialize an aggregate result as an IR value and copy it into the destination afterwards. That is a second copy of every result and an aggregate SSA value the IR was designed not to have; naming the final place as the hidden destination removes both.

Pinned by the checker, flow, lowering, verifier and backend public seams; the generated token and IR records; and the forwarding paths in runtime/struct-returns-cross-calls and runtime/array-returns-cross-calls on Linux x86-64.

D109 — Aggregate calls may return directly into field storage

The tour said that field and nested-element assignments are places [1900]. D88--D90 preserve their declaration-order identities, while D108 initially required an aggregate call's destination to be a whole slot.

Chosen: a matching struct result may fill a depth-one ordinary-child field, and a matching fixed-array result may fill a direct array field or one array leaf inside that child. The hidden Storage_Address carries destination parent and child identities exactly as aggregate arguments do. The backend derives the selected target address before the call; the callee remains unaware that its result storage is a subobject.

Definite assignment records the complete child or array fact after the call. No target offset, byte extent or source-level pointer enters checked IR.

Why destination qualification belongs on the address: copying first into a temporary and then into the field would be correct but would add an avoidable whole aggregate copy. Passing a qualified opaque destination preserves the same by-value result semantics when the callee either commits its independent named result at the exit or meets D116's direct-storage conditions.

The alternative: require a result destined for a field to go through a whole-aggregate local first. The hidden address already carries field identities for arguments, so the same carrier gives a field destination without a copy the reader would otherwise write.

Pinned by the checker, flow, lowering, verifier and backend public seams; the generated token and IR records; runtime/struct-returns-cross-calls, runtime/array-returns-cross-calls and runtime/nested-storage-arguments on Linux x86-64.

D110 — A local may infer aggregate identity from a returned call

The tour said that := infers the binding's type from its initializer [0050]. D93 already preserves nominal child identity from storage; D106/D107 now give a call the same neutral struct body or array shape without making its result an IR value.

Chosen: a local initialized directly by an aggregate-returning call may infer the callee's nominal struct body or fixed-array element type and length. The inferred binding receives its own shaped slot, which is supplied directly as D106's hidden destination. Module inference from calls remains forbidden by [1940], because module images run no call before entry.

Why inference changes no ABI rule: checking copies only source identity into the declaration, before lowering. Runtime uses the same caller-owned destination and D116 commit rule as an explicitly typed local.

The alternative: require the local's type to be spelled when it is initialized by an aggregate-returning call. The callee's signature names the body or the array shape completely; a spelled type would only be compared with it.

Pinned by the checker, lowering, verifier and backend public seams; the generated token and IR records; and the inferred locals in runtime/struct-returns-cross-calls and runtime/array-returns-cross-calls on Linux x86-64.

D111 — A returned aggregate may immediately cross an argument boundary

The tour said that arguments evaluate left to right [0410] and each in parameter receives a value [0900]. D106's result destination and D94's argument carrier can therefore meet in one caller-owned temporary without exposing an aggregate expression to neutral IR.

Chosen: a matching struct- or fixed-array-returning call may be supplied directly to an aggregate parameter. The inner call first fills a fresh shaped caller temporary through its hidden destination. Only after that call completes does the outer call transport the temporary's opaque address and perform its ordinary defensive callee copy. Nominal struct identity and array shape are checked at the source boundary.

When later arguments change blocks, the temporary address uses the same saved scalar carrier as any earlier aggregate argument, preserving block-local IR and source evaluation order.

Why the boundaries remain semantic: the inner return establishes a complete value in the caller and the outer in boundary establishes an independent callee value. The inner boundary need not copy under D116; optimization may combine argument storage only after proving neither identity can be observed. The language and verifier do not depend on either optimization.

The alternative: bind a returned aggregate to a named local before it may be passed on. The fresh temporary is that local without a name, filled by the inner call's hidden destination and copied by the outer callee exactly as a named one would be.

Pinned by the checker, lowering, verifier and backend public seams; negative/returned-struct-argument-nominal-mismatch; the generated token and IR records; and the nested calls in runtime/struct-returns-cross-calls and runtime/array-returns-cross-calls on Linux x86-64.

D112 — Discarding an aggregate call still gives its result a lifetime

The tour said that discarding a result is explicit [1020] [1930]. A scalar call can simply leave its produced IR value unused, but D106 requires valid storage through the aggregate callee's result commit.

Chosen: _ = call() for a struct or fixed-array result allocates a fresh shaped caller temporary, supplies it as the hidden destination, completes the call and then drops the storage. No field is read and no aggregate IR value is created. Calls returning none remain invalid discard sources because they produce no result at all.

Why not omit the hidden destination: the callee's writes and argument evaluation are observable even when the returned value is not. Running a different result convention only for discard would change the call rather than throw away its result.

Pinned by the checker, lowering, verifier and backend public seams; the generated token and IR records; and the explicit discards in runtime/struct-returns-cross-calls and runtime/array-returns-cross-calls on Linux x86-64.

D244 — A call that hands a result back is not a statement

The tour said that discarding a result must be explicit [1020], and wrote the discard as _ = double(5). [0960] adds that a call that can fail and whose result is discarded is an error, to be written try f() or discarded through an else. [1810] made a call a statement because a function returning none has nothing to bind, and in the same paragraph called a dropped result "the one place the kernel accepts an ordinary expression standing alone".

Chosen: a call standing alone must return none. One with a named return, several, a struct, an array or an any result, whether called directly, through a function value or with labels, is refused with L0331 and a note citing [1020]; so is a recovered call, g() else 0, whose recovery still produces a value. [0960]'s "discard through an else" is _ = g() else 0. A standalone try call stays a statement: [1810] says it discards any successful result, and the word is what makes the discard deliberate. That holds for every result shape, and a stored one — a struct, several results or an array — is given a temporary to land in, exactly as _ = try call gives it one; before this decision that path failed inside the compiler.

defer and undo register a call and are unchanged: the call they name runs at a block exit, and its result, of any shape, is dropped there. There is no defer _ = call to write instead, and the statement's own word already says the call is run for its effect.

A competent reader could have kept [1810]'s sentence, under which a dropped result was simply accepted, and every compiler through 0.2.0 did. That reading makes [1020] a rule about bindings only and leaves double(5) and _ = double(5) meaning the same thing, so the underscore would record nothing. The other alternative, refusing a result-bearing defer or undo too, was declined because it would need a second spelling for a registered discard and buys nothing a reader cannot already see.

Pinned by negative/call-result-dropped-by-omission, negative/call-struct-result-dropped-by-omission, negative/call-results-dropped-by-omission, negative/call-array-result-dropped-by-omission, negative/call-value-result-dropped-by-omission, negative/labelled-call-result-dropped-by-omission, negative/recovered-result-dropped-by-omission, runtime/standalone-try-discards-a-stored-result and runtime/deferred-call-drops-its-result; the one bare discard the corpus held, in runtime/r490-generic-recovery-frontier, is now written out.

D113 — An inferred function value is a code address

The tour said that a function is an ordinary value represented as a code address [0870] [1000]. The first executable slice does not need written function types to preserve that identity: a direct function name supplies its complete signature when a local uses :=.

Chosen: a local may infer a function value from a direct function name, store that value, replace a mutable binding with another function value, and call the binding indirectly. The inferred binding retains a first-class signature descriptor as its checking identity, independently of the concrete routine that first supplied it. Neutral IR materializes a Function_Address naming a routine item and carrying its descriptor; Indirect_Call carries a structurally agreeing descriptor, names no callee item, and takes the runtime code address as its first operand. The Linux backend emits RIP-relative address formation and call *address.

Arguments, scalar or aggregate results, stack positions and hidden aggregate result destinations otherwise use the existing internal convention unchanged. D117 adds one written infallible function type. D118 carries that value through parameters, results and static module storage and adds anonymous routines.

Why the indirect instruction retains a signature: a runtime address alone cannot tell the verifier how many operands or what result convention the call uses. Naming a semantic descriptor is target-neutral type evidence, not a claim that the runtime target is statically known.

The alternative: make a function value a closure with captured environment, or refuse to infer one and require a spelled function type. A closure is an allocation the language has no idiom for and [1000] promises a code address; a spelled type would only repeat the signature the named function already carries.

Pinned by the checker, lowering, verifier and backend public seams; negative/function-value-type-mismatch; the generated token and IR records; and runtime/inferred-function-values on Linux x86-64.

D114 — Indirect calls share the complete internal convention

The tour said that a function value has its signature as its ordinary type [1000]. Replacing an inferred function binding therefore requires equal parameter and result shapes, not merely another code address.

Chosen: mutable function values may be replaced only by a function with the same parameter count, declaration-order parameter types and result type. Nominal struct bodies and fixed-array shapes participate in that equality; parameter and result labels do not. An indirect call uses the complete direct-call convention: hidden aggregate result destination first, then source parameters across the six-register and stack run. The runtime code-address operand is verifier metadata and is not a source ABI parameter.

Why signature equality is checked before runtime: a code address carries no machine-readable Landin signature. Delaying disagreement until the call would turn a deterministic type error into register and storage corruption.

The alternative: give indirect calls a narrower convention with no hidden aggregate destination, or let a function value be replaced by any function whose parameters merely agree in width. The first splits the ABI in two for the same signature; the second lets a call read a struct where the callee wrote an array.

Pinned by the checker, lowering, verifier and backend public seams; negative/function-value-signature-mismatch; the generated token and IR records; and runtime/indirect-function-abi on Linux x86-64.

D115 — Aggregate call completion is an ordinary assignment fact

The tour said that a nonliteral condition is not believed and a name assigned in one branch but not another is not assigned after the branch [1910]. A call's hidden result destination does not create an exception to that rule.

Chosen: when an aggregate-returning call completes into a local place, that place gains exactly the same definite-assignment fact as a whole-place assignment. Branch joins intersect that fact normally. A guarded return does not erase a fact on its continuing edge, and it still requires every named return to be complete on the edge that exits.

Why this is not a call-specific flow rule: the hidden destination is only a transport convention. Giving it stronger flow semantics would let replacing a literal assignment by an equivalent call change whether later reads are legal.

The alternative: treat a completed aggregate call as assigning each part separately, or as no assignment fact until read. Per-part facts would have to be derived from the callee's layout for what is one whole write; no fact would refuse every read of a value the call just produced.

Pinned by negative/aggregate-call-result-not-assigned-on-every-path and runtime/aggregate-results-across-branches on Linux x86-64.

D116 — Aggregate-result exits commit a complete value

The tour said that every reachable return requires the named return to be assigned [1890] [1910]. Aggregate caller-owned storage makes the consequence observable at more than the function's lexical end.

Chosen: each accepted early or final exit from an aggregate-returning function delivers the complete named result to that call's hidden caller destination. The ordinary implementation keeps an independent named-result slot and copies its complete padded extent after that exit's cleanups. A compiler may instead construct the result in the caller destination and omit the final copy only when it can establish the same observable behavior: result construction makes no write to the caller destination on a failing path; no callee-visible alias, escaped result address, callback or cleanup can observe a partial or premature result; and source evaluation and cleanup still occur in order. This includes proving that any operation after the first direct write cannot fail or expose that write before a successful exit. When these conditions cannot be established, the independent slot and exit copy are required.

An aggregate call may complete the named result immediately before either exit. Flow checking refuses an exit reached without the complete result; another arm having completed and exited does not lend its fact to that path.

Why every exit commits: redirecting only lexical fallthrough would make an early return expose an unfilled caller image, while returning the callee slot's address would expose dead frame storage. Direct construction can avoid both a second full extent and its transfer when the result is built once and cannot be observed until that exit commits it.

The alternative: copy the named result once at a single merged exit block, or let one arm's completion satisfy another arm's exit. A merged exit runs cleanups in the wrong order relative to [1100]; a lent fact is exactly the soundness hole a path-insensitive join opens. Requiring a distinct slot even when direct construction is observationally equivalent adds storage and a whole-object transfer without protecting a value boundary.

Pinned by negative/aggregate-call-result-missing-at-early-exit and runtime/aggregate-results-across-early-exits on Linux x86-64.

D117 — A function value carries a signature, not a possible callee

The tour said that a function type is an ordinary type, written like its signature, and that a function value is a code address [0870] [1000]. It did not say whether the labels are declarations, how a stored address retains its type, or which written storage context opens the implementation slice.

Chosen: [1800]'s infallible signature is one written function type. Its parameter and result labels describe positions and declare nothing. It may be named by a type declaration and used for explicitly typed local storage; the local may be called indirectly and, when mutable, replaced by any function whose complete signature agrees. D118 extends the same descriptor to module storage, parameters, results and anonymous routines. Function-valued struct fields and declared-error signatures remain later slices.

Every declared function, written function type and inferred function value receives a first-class target-neutral signature descriptor. Agreement compares parameter count and declaration-order types plus the result type; labels and source sites do not participate. Scalar identity, nominal aggregate identity and fixed-array length and scalar element identity do. The verified IR carries the same semantic descriptor on routines, code-address values, function-value slots and direct or indirect calls. An Indirect_Call names no concrete routine: its address operand and descriptor must agree, and the descriptor alone decides the carrier count and result convention.

Why not keep the first function declaration as type evidence: a written type need not have one possible target, and a mutable local may successively hold several. Treating the first callee item as the type makes an incidental initializer an authority over later checking and prevents malformed IR from expressing the actual disagreement. A code address alone has no type metadata; target widths, registers and offsets would make the alternative descriptor an ABI record rather than a language signature.

Pinned by the parser, checker, type, lowering, IR, verifier and x86-64 backend seams; malformed signature and indirect-call cases in the verifier suite; negative/written-function-signature-mismatch; the generated lexical and IR records through positive/written-function-values; and runtime/written-function-values together with the existing inferred-function-value runtime cases on Linux x86-64.

D123 — Infallible function values use one recursive carrier rule

The tour said that a function is an ordinary code-address value [0870] [1000], that callbacks carry state explicitly because anonymous functions do not capture [1010], and that parameters and named results carry ordinary values [0900] [0930]. It did not say how a function type nested in another signature keeps its identity, which module images can hold one, or which scope a no-capture body can see.

Chosen: a function may be an infallible parameter or named result. A nested function position contains another structural signature descriptor; agreement recurses through it, still ignoring labels and source sites. At the internal ABI boundary every function value occupies one usize-sized code-address carrier. It therefore uses the existing register/stack position, scalar return register and named-result slot without adding an ABI parameter or flattening its own parameters. Aggregate results called through such a carrier retain D106's hidden destination unchanged.

A typed or inferred module binding may have a static function value. Its image must resolve through module function bindings to one declared or anonymous routine; there is no implicit zero code address, and a static chain that returns to itself is refused. Mutable module and local bindings use the same verified load, store and indirect-call operations.

An anonymous function is a separate no-capture routine. Its signature scope encloses the module rather than the lexical expression scope, so it can use module declarations, its own parameters, named result and body locals, but no parameter, return or local of an enclosing routine. Lowering allocates every anonymous routine item before filling any routine, after declaration items and in source then syntax post-order. Its code address names that deterministic item; the x86-64 backend gives an undeclared item a deterministic assembler-local symbol.

Declared error sets remain absent from this increment and arrive at D130. Function-valued struct fields are not enabled by this decision alone; D131 composes this carrier with the aggregate storage family.

Why one recursive descriptor and one carrier: flattening a callback's own signature into its caller would make source parameter count depend on nesting and would break the existing stack and hidden-result convention. Treating a module relocation or anonymous item as its type would again make one possible target the authority D117 rejected. A recursive language descriptor preserves structural checking while one code address preserves the established ABI.

Pinned by the syntax, no-capture resolution, checking and flow walks; recursive checking and IR descriptors; function parameter/result slots, static function datum targets, calls and verifier malformed cases; deterministic anonymous routine items and x86-64 local symbols; the generated lexical and IR records through positive/infallible-function-values; the negative fixtures anonymous-function-captures-local, function-parameter-signature-mismatch, function-result-signature-mismatch, function-result-unassigned, module-function-replacement-signature-mismatch, module-function-without-image and module-function-image-cycle; and runtime/infallible-function-values on Linux x86-64.

D128 — Multiple named returns form one anonymous structural aggregate

The tour said that a function may have multiple named returns [0920], that the return list is an anonymous struct bound whole or destructured by name [0990], and that every named return is assigned before an exit [0930]. It did not say whether result labels participate in function-value agreement, how the anonymous shape is laid out and transported, or how partial destructuring and control-expression joins retain it.

Chosen: a non-none return list contains one or more named positions. One position keeps the existing result type and carrier. Two or more positions form one anonymous structural aggregate whose fields are those positions in source order. Its value shape includes each field name and complete type, recursively including nominal aggregates, fixed arrays and D123 function signatures. The padded aggregate must fit the selected target. It has no source type spelling and no nominal declaration identity.

Function signature agreement compares the ordered result _types_ and ignores result labels, as [1000] requires. A call through a stored function therefore uses the labels written by that value's static function type while the runtime positions remain compatible. Outside function-signature agreement, two whole anonymous result values agree only when their ordered names and complete field types agree.

The internal ABI transports every multiple result as one aggregate. The caller supplies D106's one hidden destination, and each source named return writes its declaration-order field in the complete checked result shape. The callee uses an independent result slot and exit copies unless D116 permits direct storage. Direct and indirect calls, stack arguments and aggregate fields within the result add no second convention. A function-valued field is a usize carrier that retains its nested signature; aggregate-shaped field copies reuse the compact verified storage-copy operation.

A whole result can initialize or update an inferred local, cross D125's one consumer-owned control join, be read by field, or be destructured. Destructuring evaluates the source once and binds fields by name in any order. field keeps the field name as the local, field: local renames it, field: _ ignores that field, and one bare _ explicitly ignores every unbound field. Omission is also legal. Unknown and repeated fields use the ordinary field diagnostics; new locals enter scope only after the source is resolved and obey [1850].

Definite assignment tracks the named return declarations independently. Every reachable early return and final fallthrough requires every one; a direct expression body fills the complete anonymous aggregate on its fallthrough edge. A returning control edge supplies no joined aggregate but still proves all named returns, exactly as D124 requires.

Why one aggregate rather than one hidden pointer or register per return: the latter makes source arity rewrite the ABI and duplicates D106's caller-storage rule. One structural image gives whole binding, field selection, destructuring and control joins the same value while leaving target classification to the C boundary. Making the result nominal would invent a declaration the source never wrote and would contradict [0990].

The alternative: return several values in registers as a tuple the caller unpacks, or forbid more than one named return. A register tuple is a second calling convention with a size ceiling; one return makes the tour's (count, view) results unwritable.

Pinned by the return-list and destructuring parser/resolver/checker/flow walks; ordered checking and IR signature result runs; caller-owned result slots, direct and indirect lowering, function-valued result fields, verifier malformed result-slot cases and x86-64 aggregate copies; positive/multiple-named-returns; negative/function-type-return-name-duplicate, multiple-return-name-duplicate, multiple-return-unassigned, multiple-result-function-signature-mismatch, result-aggregate-assignment-name-mismatch, result-destructure-duplicate-field, result-destructure-local-name-duplicate, result-destructure-needs-multiple, result-destructure-unknown-field and control-result-field-name-mismatch; the generated lexical and IR records; and runtime/multiple-named-returns on Linux x86-64.

D130 — Errors are an orthogonal atom outcome, not a second result

The tour said that errors are payload-free atoms in one dedicated register, that try propagates them, and that call-site else handles them [0940] [0960] [1030]. It did not fix atom-set identity, recursive private inference, the success sentinel, the neutral IR carrier, or how scalar and aggregate results coexist with that register.

Chosen: [1980]. Atom and error sets are structural sets of declaration identities. A failing signature adds one orthogonal outcome to its existing successful result rather than wrapping, replacing, or adding a named return. Concrete sets are part of recursive function-type agreement; private ! ... is the least fixed point of local failures and tried callees, including mutually recursive routines. Every first-class or public signature stays concrete.

Neutral IR carries source atom identities and set metadata, one call failure slot, a semantic Failure_Test, and a distinct Fail terminator. A recovery joins only its fallthrough value with the success value; return and fail edges need no placeholder. The malformed-IR verifier checks set partitions, membership, widening, signatures, failure slots, and failure exits before a backend can assign bits.

Linux x86-64 uses dense nonzero 32-bit atom codes in declaration-identity order and %r10d as the dedicated call-failure carrier; zero means success. Ordinary atoms still use normal argument positions and %eax results. Scalar/function results remain in %rax, aggregate results remain in caller-owned storage, and neither direct nor indirect failing calls consume a source ABI position.

Why orthogonal rather than a result union: a none function may fail, an aggregate result already has independent caller-owned lifetime, and wrapping every result would change every value convention and indirect signature merely to represent an outcome the tour already assigns its own register. A hidden out-parameter would instead consume an argument position and make the declared channel alias ordinary storage. Both alternatives erase the one visible mechanism [0940] chose.

Pinned by positive/atoms-and-error-signatures, the negative declared-error fixtures, runtime/atom-values-cross-the-abi, runtime/declared-errors-direct-and-inferred, runtime/declared-errors-indirect-abi, the malformed-error verifier case, and the generated lexical, construct and IR records.

D131 — A function-valued field is one signature-carrying address leaf

The tour said that a function is an ordinary code-address value [0870] [1000], that a struct field may have any ordinary type [0670], and illustrated a callback as a function field plus explicit state [1000]. D117 and D123 kept function-valued struct fields as the remaining function storage form while the aggregate path and image carriers were still being established.

Chosen: an ordinary struct field or variant payload field may have a concrete function type. Its runtime representation is D123's one usize code address, while its complete recursive descriptor — including declared errors — remains target-neutral type evidence on the checked and IR field shape. Construction, individual assignment, whole-struct copy, aggregate parameters and results, nested ordinary children, variant payload aliases, and arrays whose element is such a struct all reuse their existing storage and path operations. This does not separately enable a fixed array whose element is a function value.

A selection of that field is an ordinary function value and a call callee. The complete callee selection, including a computed array index, is evaluated and checked for definite assignment before any argument. Every call through a field is indirect at runtime even when its current image names a declared routine; direct calls to declarations keep their existing instruction. Replacing a mutable field requires structural signature agreement, and the root binding still decides whether the field is writable.

A function address has no all-zero value [0540]. A struct, active variant case, or nonempty array of structs containing one therefore has a zero image only when every field selected by that zero image does. An omitted module image, whole zeroed, or trailing of zeroed cannot invent a null callback. A static module struct or selected payload may instead carry a declared function, a no-capture anonymous function, or a static function-binding chain. Neutral IR records one routine relocation on that scalar field; whole module-image copies copy the relocation into distinct storage. The verifier proves the relocation target and every field/element/payload load and store against the field's recursive descriptor before the Linux x86-64 backend emits a symbol or an indirect call.

Why retain a descriptor beside one machine word: flattening the callback's own parameters into its containing struct would make layout depend on what the address can be called with rather than what the value occupies. Erasing the descriptor would instead let a whole aggregate copy or an indexed field load turn a deterministic type mismatch into an indirect ABI mismatch. The same carrier-plus-descriptor rule at every storage depth is D123 composed with D118's path rather than a field-specific calling convention.

Pinned by positive/function-valued-struct-fields; negative/function-field-assignment-signature-mismatch, function-field-cannot-be-filled-with-zeroed, function-field-construction-signature-mismatch, function-field-error-signature-mismatch, function-field-has-no-zero-image, function-field-unassigned, function-variant-payload-signature-mismatch, and module-function-field-without-image; the malformed aggregate-image verifier case; the generated construct, lexical and IR records; and runtime/function-valued-struct-fields on Linux x86-64.

D186 — A caller parameter is an exact compiler-filled utf8 site

Superseded by D192. The string representation was refused because its filenames cannot be omitted from constrained builds. The original reasoning below is retained as history; the caller rules survive, and the fixtures named below now exercise D192's replacement (including the renamed needs-site case).

The tour said that [1040]'s caller parameter is filled with the call site and may be passed on only from another caller parameter. It sketched a distinct integer site, but did not say what a site contains, how it crosses the ABI, whether omission changes positional matching, how forwarding is distinguished from forging, or whether caller behavior belongs to a function type.

Chosen: a caller parameter is written caller name: utf8. Its type is exactly D181's immutable utf8 identity; another text identity or its backing slice is L0301. caller is mutually exclusive with escaping, in, inout and sink. The parameter is an immutable value in the signature scope, and its caller behavior is part of structural function-signature identity even though the label, as for every parameter, is not.

At an ordinary source call, positional arguments skip caller positions and every caller position not explicitly forwarded is filled by the compiler. The value is the UTF-8 spelling source-name:line:column, using the source name in the compilation snapshot and one-based coordinates at the call expression's first token. Its bytes and trailing zero share D181's width-and-content-keyed read-only static pool; the retained utf8 length excludes that terminator. It is an ordinary slice carrier and ABI parameter after injection, so the neutral IR, verifier and backend need no caller-specific instruction or calling convention.

A wrapper preserves an incoming site only with a named argument whose complete expression is the name of one of that wrapper's own caller parameters: wrapped(value, where: where). A positional argument cannot target a caller position, and a literal, local, result, selection or other utf8 expression cannot fill one by name. The extra positional argument is L0327; an invalid named forwarding source is L0327. Omitting the named forwarding argument deliberately reports the wrapper's internal call instead. These rules apply to direct, generic and stored function calls alike. A wrapper that does forward its site reads no pooled bytes at that call, so no site datum is registered for it: the read-only pool holds exactly the sites some instruction addresses.

caller is not added to [1760]'s keyword rule, and this decision is what says so. [1760] promises that a program avoiding a construct never trips over its keyword, and caller is a word an ordinary program writes: a parameter, a binding or a loop label naming whoever called is as plain a name as arena is in core/mem. So two tokens decide the modifier, exactly as D187's unchecked is decided on two and D191's arena on three — caller followed by a second name is the modifier, and nothing else is. A parameter of that name writes : next, so caller: utf8, in caller: u8 and escaping caller: ptr u32 all stay ordinary parameters, and caller = x, caller: loop do and inc caller are untouched. runtime/caller-is-an-ordinary-name pins that from the other side, with a parameter named caller beside a real caller position in one signature.

Changing the site's representation moved [1040]'s example off [1670]. That example called panic_handler(assertion, where) while a site was the tour's distinct integer, and a utf8 site cannot reach a handler [1670] declares as (kind: panic_kind, site: u32) and describes as "Two scalars, no strings". The example now calls a reporting function of the program's own, because the two paragraphs are about different callees: a caller parameter serves the assertion a program writes, and [1670] is the fixed symbol the compiler's own failed check calls with a number it assigns. [1670] is unchanged, and this entry decides nothing about it.

The alternatives: retaining the tour's unstructured integer would make a site target-sized and force every consumer to recover source data through an unstated global table. Treating caller as a default value would omit its function-type behavior and let positional insertion silently retarget later arguments. Accepting any named utf8 would make sites forgeable and would not enforce the wrapper rule [1040] states. A dedicated IR value or backend ABI would duplicate the exact slice representation already required at the source boundary. Reserving caller in [1760] was declined because it would make thirty-seven words out of thirty-six, delete the spelling from every program that never writes a caller parameter, and break [1760]'s stated promise for a word no construct outside [1040] mentions. Deciding the modifier on its spelling alone was declined for the same reason and was what this entry originally said: it refused (caller: u8), which the second alternative of [1800]'s own parameter production derives, and reported it as a keyword that [1760] does not reserve. Registering a site datum for every call whose callee has a caller position was declined once forwarding was distinguished from omission: it left one unreferenced read-only string in every forwarding wrapper.

Pinned by positive/caller-parameters, negative/caller-parameter-forward-needs-caller, negative/caller-parameter-needs-site, negative/caller-parameter-positional, negative/caller-parameter-signature-mismatch, runtime/caller-parameters, runtime/caller-is-an-ordinary-name, the generated lexical and IR records, and the functions.caller guarantee row.

D192 — Caller coordinates are three u32 fields; filenames are optional metadata

The tour said that a caller parameter identifies the source call and can only be forwarded from another caller parameter [1040]. D186 supplied that identity as a utf8 string. The user refused that representation and chose a 12-byte structured value after comparing debugger source-location models.

Chosen: a caller parameter has an ordinary nominal struct type with exactly three ordinary fields, in declaration order: file_id: u32, line: u32, and column: u32. Each scalar is the exact unconstrained u32 identity; scalar aliases are the same identity. A type alias of the struct qualifies too. The contract introduces neither a builtin type name nor a privileged core module; a library declares the struct it uses and wrappers use that same nominal type. Two qualifying struct declarations are still different types [0710].

The value occupies 12 target bytes with four-byte alignment on the enabled Linux x86-64 and synthetic-32 targets. The same three-u32 layout is required of future targets. It crosses the existing aggregate ABI through caller-owned storage, so 12 describes the value, not a promise about total stack use or instruction size. The compiler constructs three scalar fields at an omitted caller position. It creates no per-site static datum and no source string.

file_id is the nonzero source-snapshot number assigned within this whole compilation, including reached modules. It identifies a source, not a basename or a hash of a path. The line and byte column are one-based and identify the call's callee anchor, using [1750]'s source coordinates. Repeated executions and generic instantiations of that source call retain those coordinates; distinct columns on one line remain distinct. IDs are not persistent across builds, and no packed subfield truncates a coordinate. Compiler source-count and source-size limits remain the existing checked host-capacity limits.

D186's contextual two-token modifier, immutable binding, mutually exclusive conventions, skipped positional positions and function-signature identity all survive. Only a named argument whose complete expression is one of the current routine's own caller parameters can fill a caller position explicitly. A copy, construction, literal or field selection cannot forward. Omission at a wrapper reports its own call; forwarding preserves the incoming three fields. The value may otherwise be copied, stored or returned as an ordinary struct, and none of its coordinates borrows source storage.

Filename lookup is optional deployment data. The compiler emits an off-target <output>.sources.json when emitting code that injects coordinates. Each used file has one entry with its ID, exact path bytes encoded as hexadecimal, and its source SHA-256. Path bytes are length-independent data: colons, quotes, newlines and non-UTF-8 filesystem names are unambiguous. The artifact also records the assembly digest and a SHA-256 build identity over the file entries and assembly. An assembly comment carries that identity before the final assembly digest is computed, so source changes that preserve code cannot share an assembly mapping identity. Executable emission supplies the ELF build ID. scripts/source-location.py requires the matching assembly or build ID before resolving a triple. A manually linked assembly can use the assembly check. Neither the filename map nor a lookup routine enters the running program; without the map a diagnostic can still print all three coordinates. This is bootstrap artifact packaging, not a frozen debug format or stage protocol. Source debugging's --debug=full also emits this map, with every compilation source, and uses these same file IDs for native debugger line information. The default --debug=none retains the caller-only map. Debugger sections are optional off-target data and can be stripped from the executable without changing caller values or its ELF build identity. The source table continues to require exact assembly or build-ID matching; neither a basename nor a map from a different build is sufficient.

The alternatives: one u32 site token would reduce transport and saved-log storage to four bytes, but even its line would need a lookup table. The chosen structure keeps useful coordinates when all lookup data is omitted. A record containing a filename pointer or text view still retains filename storage; removing its file table would change or invalidate the value. D186's joined string has that same cost and additionally requires parsing. Raw code addresses would couple the language value to relocation and code transformations. These debugger formats inform the shared source model, not the runtime ABI. Removing [1040] or deferring it to source debugging was declined because the structured value solves its cost problem with existing aggregate machinery. Accepting any three words without field names was declined because their interpretation would then be unstated. Privileging a particular core type was unnecessary.

D232's compiler-check handler takes its separate site number. Both features follow [1670]'s no-mandatory-filename rule and share optional source/build identity packaging, without changing this caller-value contract.

Pinned by positive/caller-parameters, runtime/caller-parameters, runtime/caller-is-an-ordinary-name, the negative/caller-parameter-* corpus, driver/caller files are separate, and the functions.caller guarantee row. The runtime case retains coordinates after returns, verifies 12-byte size, and covers direct, forwarded, omitted, indirect, generic and multi-file calls.

D231 — Nonreturning calls and signature identity

From [0890], [0940], [0960], [1000], [1050], [1100], [1110], [1240], [1290], [1370], [1670], D11, D124, D148, D187 and prototype 1's start.

Decision: noreturn is an infallible return form. It is not an ordinary value type, a spelling of none, or an atom containing private call status zero. Ordinary declarations, anonymous functions, function types and concept entries may use it. Concrete and inferred error sets are refused: checked failure returns control to a caller and therefore contradicts this form. Generic instances and erased evidence signatures preserve the return form. Structural compatibility requires identical return form, parameters and calling convention; there is no implicit or explicit conversion between noreturn and none functions, or between either and result-bearing functions.

A call evaluates its callee and arguments in their existing order. If that evaluation reaches the call, the continuation ends. Existing local origin, sink and escaping-argument obligations still apply at call entry. Definite assignment merges only continuing edges. A nonreturning call can terminate a value-producing branch or recovery expression without contributing a value; other continuing branches must supply the context's complete value shape. Such a call does not provide a type for an otherwise unconstrained inferred binding. Ordinary none calls do not terminate control flow.

A definition must have no reachable successful return or body fallthrough. Flow analysis recognizes unconditional loop with no reachable exit, calls with this return form, and combinations of these with structured control. A conditional loop is not assumed to diverge from a runtime condition, even if the programmer expects it never to end. Unreachable source remains subject to ordinary name/type checking. Code after a proven terminating edge is not executed. Optimization neither invents divergence nor makes a returning signature nonreturning from its current implementation.

Calling such a routine does not unwind registered cleanup. A deferred nonreturning call is allowed and is evaluated only on its applicable cleanup edge, in the existing reverse registration order. It prevents remaining cleanup and the original transfer from executing. Consequently a written return whose cleanup necessarily diverges does not produce a successful return edge. undo still runs only on failure; it cannot by itself establish that an ordinary successful fallthrough diverges. Recovery handles declared failures, never divergence or a runtime trap.

C declarations and C function types may use this return form within each target's existing C surface. It promises that the external implementation never returns. Cortex retains its general C source refusals; no toolchain helper becomes source-callable through this rule. Interrupt and naked signatures remain exactly () -> none, with their separate machine return obligations. An ordinary nongeneric firmware entry can be () -> noreturn; a none entry retains the firmware entry's return trap. Hosted entry selection remains public main: () -> (code: i32) and the established linkage rules.

IR represents the return form in signature identity and a nonreturning call followed immediately by a terminal Halt. Verification rejects a continuation following that call, a returning body with this signature, or an evidence entry that loses the return form. Halt is a control/trap effect; it is not a value and cannot disappear as dead arithmetic. It traps if an external or otherwise invalid implementation violates the promise by returning. Linux and Darwin use their established undefined-instruction guards; Cortex uses its selected undefined instruction. D11's existing observable trap guarantee continues while the separate [1670] handler mechanism is implemented.

Alternatives and rationale: interpreting every result-free routine as nonreturning would break none callers. Treating noreturn as an ordinary value introduces values that cannot exist. Allowing checked failures would require a second continuation contract and ambiguous cleanup/dispatch rules. Inferring a promise from arbitrary loops or assembly would make source compatibility depend on optimization or programmer-written instruction text. These alternatives are declined.

Pinned by: checking/nonreturning control and identity checks all three target descriptions through verified IR; positive/r491-noreturn-signatures retains the former refusal's exact source as accepted syntax; D232 supplies panic dispatch.

D263 — A mistake is reported where it was made, not where it shows

The discrepancy: a checker refusal is often found by what it leaves behind. A misspelt argument label also leaves its parameter unfilled, and the call was reported for the missing parameter first and the label second; a local in a body with a named return's name declares a new name, and the only report was that the function could end with the return unassigned, at the function's head.

Chosen: the cause is reported and its consequence is not. A call with an argument label that names no parameter reports the label, with the parameter it is near, and not the parameter it leaves unfilled; a generic call's unmatched argument does the same. A body binding, or a destructured name, spelled like a named return that is then not assigned is reported at that binding as declaring a new name, with the return it hides; the function is not reported for the same return. A scalar type name written where a value belongs is reported as a type, with [0700]'s conversion, rather than as a name that is not declared.

A refusal poisons what it refuses. A write the checker refused, to a binding declared without mut say, is still where the place was assigned, so reading the place afterwards is not reported as unassigned. A binding whose write is refused for its mutability is reported once, at the first write, with the fix that declares it mut; the later writes are the same mistake. A value-producing control expression whose value is missing on more than one path is reported once: its arms and blocks report against the construct, and the construct's value is the one fact D124 decides.

The alternatives: refusing every body binding that shares a return's name, which also refuses a deliberate inner name in a nested block whose return is assigned elsewhere; keeping both reports and ordering the cause first, which still reports one mistake twice.

Pinned by negative/writes-to-an-immutable-binding-report-once, negative/a-refused-write-still-assigns and negative/a-control-value-missing-twice-reports-once, for the poisoning; negative/misspelt-argument-label-is-offered-its-parameter, negative/named-call-unknown, negative/local-shadowing-a-named-return-is-reported-there and negative/scalar-type-is-not-a-value.

DECISIONS: CONTROL FLOW

Branches, loops, traversal, the cleanup an edge selects, and what the checker will not believe about a condition.

D7 — Written Boolean literals fix branch reachability

The tour said that a binding declared with no value must be assigned before use [0080] and that every named return must be assigned before the function returns [0930]. Neither says what a checker may conclude from a condition.

Chosen: the written true and false literals select or skip an if arm for definite assignment [1910]. if true then r = 1 end if assigns r; a missing else contributes an unchanged path only when no written true arm covers it. Every other condition, including a name initialized with true, keeps both edges.

The alternative: treating even a written literal as unknown rejects programs whose only executable path assigns the result and makes L0302's reachability claim false. Folding nonliteral constant conditions would make legality depend on how clever the compiler's folding is, so adding an optimisation would change what compiles; that remains declined.

Pinned by positive/assigned-on-every-path, positive/literal-conditions-select-flow, negative/assigned-on-one-path-only, negative/condition-is-not-believed.

D124 — Control values distinguish fallthrough from return-compatible edges

The tour said that a block has the value of its last expression [1080], that an arm which leaves needs no placeholder [1030], and that every named return is assigned before return [0930]. It did not say which flow facts survive when value-producing and returning arms meet, nor how one rule covers an if, an exhaustive match, and a bare block without believing a nonliteral condition [1910].

Chosen: if, exhaustive match, and bare begin blocks are expressions as well as their existing statement forms. A block is its source-ordered statement run followed by an optional final expression. In a value context, every reachable edge that falls through must produce that final value. An edge that returns is compatible without producing one, but [0930] still requires the function's named result on that edge. A reached if with no else has an untaken fallthrough edge unless a written true arm covers the remaining tests; that edge cannot produce a value.

Every control edge carries the independent facts Falls_Through and Returns. Only states on fallthrough edges participate in a definite-assignment join; a returned edge cannot lend its assignments to a surviving sibling. A guarded return carries both facts because its untaken edge continues. Short-circuit and and or retain the left-hand skip edge when the right returns. The same walk applies when control appears inside a condition, index, operand, argument, assignment value, direct function result, or another control block, preserving [0410]'s source order and stopping later actions after an unconditional return.

One surrounding context reaches every fallthrough answer. It includes the complete fixed-array element body and extent, nominal aggregate body or D123 recursive function signature, not merely the broad Fixed_Array, Aggregate or function-value kind. Without a surrounding context the first written answer supplies that complete shape and every other answer must agree. Each arm and bare block retains [1840]'s own lexical scope. This decision introduces no loop syntax or loop edge: loop, while, for, break and continue belonged to later loop work, which has since enabled them.

Why two facts rather than one exited Boolean: one Boolean cannot distinguish "no path reaches the join" from "this construct may return but also has a continuing edge". Treating either as the other loses guarded-return assignment facts or admits a value-less fallthrough. Explicit facts make both the value obligation and the definite-assignment merge consequences of the same edge.

The alternative: give every syntactic arm a value regardless of whether it returns, or merge assignment states before removing returned edges. The first invents unreachable placeholders and contradicts [1030]; the second lets one path prove a read on another. Both were declined.

Pinned by positive/control-expression-values, negative/if-expression-missing-else, negative/control-expression-fallthrough-without-value, negative/control-expression-branch-type-mismatch, negative/control-expression-function-signature-mismatch, negative/control-expression-early-return-needs-result, negative/control-expression-fallthrough-does-not-borrow-returned-facts, negative/bare-block-unclosed, negative/bare-block-scope-does-not-leak, runtime/match-expressions-produce-values, runtime/control-expression-function-values, and runtime/control-expression-edges-keep-source-order on Linux x86-64, together with the parser, checker, flow and IR public-seam cases.

D125 — A control join writes storage owned by its consumer

The tour said that a branch-chosen value has one joined origin [0840], while the aggregate decisions keep layout out of checked shapes and D106 returns aggregates through caller-owned storage. It did not supply a target-neutral value carrier for a join, especially when an array or struct is not one scalar IR value.

Chosen: the operation consuming a control expression owns its join storage. A scalar control uses one unnamed scalar slot and loads it after all fallthrough edges meet. A function value uses the same code-address carrier in a slot that retains D123's signature. A fixed array or enabled aggregate uses a caller-owned slot carrying its complete neutral shape; each selected fallthrough block fills that same destination. A typed binding, assignment, named result, or aggregate call result can be the destination directly. An argument, explicit discard, or other context with no named destination receives one fresh shaped temporary for the duration of that operation.

No branch-local pseudo-value, aggregate SSA value, target offset, byte extent, or implicit full-size copy crosses the join. An early return writes no joined answer and follows D116's active named-result exit. The verifier sees ordinary stores, copies, addresses, branches and terminators over declared slot shapes; the backend alone lays out a selected target's cell. Linux x86-64 consequently passes the one joined aggregate address after the join and derives every copy extent from target facts.

Why the consumer owns it: choosing storage before branching makes the hidden lifetime and cost belong to the source operation that needs the value, allows contextual literals and aggregate-returning calls to construct in place, and reuses ordinary scalar, function and stored-shape representations without making target layout a checker concern.

The alternative: introduce phi values for scalars and a separate aggregate value graph, or construct one full temporary per arm and copy again at the join. The first freezes two representations and needs target-sized aggregate values; the second hides branch-count-dependent storage and copies. Both were declined.

Pinned by positive/control-expression-values, runtime/control-expression-aggregate-joins and runtime/control-expression-function-values on Linux x86-64, together with the IR, lowering, verifier and backend public-seam cases and the generated IR record.

D129 — A cleanup is selected by the edge that leaves its lexical block

The tour said that defer runs at the end of its block in reverse order, that its call is evaluated where it runs rather than where it was written, and that undo is the same machinery selected only by failure [1100] [1110]. It did not say whether a final block value precedes cleanup, how an early return crosses nested blocks, which definite-assignment state the delayed reads use, or what neutral control fact distinguishes a future failure from a trap.

Chosen: reaching defer call(...) registers that call in the current lexical block and performs no part of it. The callee and every argument are evaluated in [0410]'s source order only when the entry runs, so an indirect callee and a named place observe their values at that later point. Resolution is not delayed: the call's names bind in [1840]'s source-ordered scope where the statement is written, and a later declaration is not visible backwards.

Each active block owns a cleanup frame. On ordinary fallthrough its optional final expression first fills D125's consumer-owned value storage, then that frame's reached entries run in reverse registration order, and only then does the edge reach its surrounding join. A successful return runs every reached entry from the innermost active frame outward, reverse within each frame, before D116's result commit or scalar leave. Thus a defer written after a guarded return is absent from the guard's taken edge, while an inner arm or bare-block defer runs before an outer one. An entry is removed before its call runs: if a control expression in that call returns, the still-pending entries run exactly once and the entry already in progress is not entered again.

Definite assignment is checked at those execution points, not at registration. A value may therefore be assigned after the defer and before every applicable exit, and a cleanup argument may itself assign one or more named results before the successful return completes. Conversely, one earlier return edge on which a delayed read is unassigned is refused even when the normal end assigns it.

The neutral selector has five edge kinds: ordinary fallthrough, successful return, failure propagation, structured transfer, and trap stop. A deferred call applies to every language edge that unwinds a block and never to a trap; a failure cleanup applies only to failure propagation. D133 enables that failure-only policy as [1110]'s undo, while every loop transfer belonged to later loop work. No trap unwinds, whether it occurs in the body, in a final expression, or while a cleanup call is running.

Cleanup has no target-specific IR form. Once selected, a call lowers through the existing direct or indirect convention, including register and stack arguments. Fixed-array and enabled aggregate arguments retain their ordinary by-value transport, and a discarded aggregate result receives one caller-owned shaped temporary through completion. The verifier consequently sees only ordinary calls, storage and terminators; the backend owns neither a cleanup stack nor unwind policy.

The alternative: capture the callee and arguments when the statement is reached, which is Go's useful rule but contradicts [1100]'s explicit late read; or introduce a runtime cleanup stack and target-aware unwind instruction. Capturing changes which value a mutable place denotes and can consume it too early. A runtime stack makes registration observable work, duplicates the lexical control graph already known to lowering, and would force freestanding targets to carry unwind machinery for traps the language says do not unwind. Both were declined.

Pinned by positive/defer-evaluates-at-exit, negative/defer-cannot-see-later-local, negative/defer-read-not-assigned-on-return, negative/defer-needs-call, runtime/defer-cleanups-follow-control-edges, runtime/defer-call-shapes, and runtime/defer-does-not-unwind-traps on Linux x86-64, together with the parser, checker/flow, IR policy, lowering/verifier and x86 backend public-seam cases and the generated IR record.

D133 — Undo is selected only while declared failure leaves its block

The tour said that undo is registered lexically, runs in reverse order only when failure leaves its block, includes a failed try and failure from a deeper call, and excludes return, transfer and panic [1110]. It did not say how a caller's recovery divides the failing callee from its own block, how undo and defer registrations interleave, which state delayed arguments read, or how the failure atom survives calls made while unwinding.

Chosen: reaching undo call(...) appends a failure-only entry to D129's current lexical cleanup frame. It resolves the call immediately in source order but evaluates neither its callee nor any argument. The entry becomes active only after the statement is reached. When it is selected, its indirect callee and arguments are evaluated late, left to right, from the state at that failure edge, and the entry is removed before evaluation begins.

A direct or taken guarded fail, or a try whose call reports failure, creates a failure-propagation edge. The latter includes an atom produced by any depth of failing calls. Such an edge does not join a selected if, exhaustive match, or bare begin block: it runs reached entries in every lexical frame it leaves, innermost frame first. Within one frame all cleanup registrations remain in one stack. Reverse registration order selects every applicable entry, so defer and undo calls interleave on failure; normal fallthrough and a successful return select only defer. A caller's call-site else handles the failure without leaving the caller's block and therefore does not select that block's undo entries. Undo entries in the failing callee have already run as the failure left the callee.

Undo never applies to ordinary fallthrough, successful return, structured transfer, or trap stop. No trap is converted to declared failure and no trap unwinds, including one raised while evaluating a cleanup. Loops and their transfers belonged to later loop work, so this decision enables none of them.

Definite assignment uses only the failure edges on which an undo call actually runs. A delayed argument may consequently be unassigned on every normal, successful-return or locally recovered edge, but must be assigned on each propagating failure edge that reaches its registration. The failing atom is formed and stored before cleanup begins, then reloaded for the eventual failure terminator after all normally completing applicable calls. Cleanup evaluation cannot accidentally replace the failure being propagated.

Undo introduces no target-specific IR or runtime registration. A selected entry lowers as the same ordinary direct or indirect call as defer, including register and stack arguments, fixed-array and enabled aggregate values, and function-valued callees. A discarded fixed-array, nominal aggregate, or anonymous multiple-result aggregate receives an ordinary caller-owned shaped temporary. The verifier therefore checks the resulting calls, storage, failure carrier and terminator under existing rules, and the x86 backend owns only their established calling convention.

The alternatives: keep a second undo stack, which would place every undo before or after every defer instead of preserving lexical reverse order; run undo for every non-normal exit, which would make return a failure and could not distinguish a locally recovered call; or capture the callee and arguments at registration. The first changes source order, the second erases the declared failure edge [0970], and the third contradicts [1110]'s delayed compensating action. All were declined.

Pinned by positive/undo-evaluates-on-failure, negative/undo-cannot-see-later-local, negative/undo-needs-call, negative/undo-read-not-assigned-on-failure, runtime/undo-cleanups-follow-failure-edges, runtime/undo-call-shapes, and runtime/undo-does-not-unwind-traps on Linux x86-64, together with the parser, checker/flow, cleanup-policy, lowering/verifier and x86 backend public-seam cases and the generated lexical, construct and IR records.

D148 — Guarantee coverage is classified at observable failure boundaries

The tour said that Landin makes a deliberately smaller claim than memory or resource safety [1720], and named four kinds of answer for the operation table a guarantee register would establish. It did not say what counted as one operation, so two inventories could both look complete while one listed syntax nodes and the other listed only machine instructions.

Chosen: one guarantee row is one observable failure boundary. A source construct may occur in more than one row: pointer access, for example, has a statically checked permission boundary and a separate pointee-validity boundary outside the guarantees. static means the compiler rejects the stated bad case; trap means a value not decidable during compilation stops synchronously; beyond-lifetime means an explicit operation discards origin information and later lifetime use is permitted without analysis; outside means the operation is admitted but the stated property is never claimed. Ordinary accepted behaviour is evidence for a row, not a fifth guarantee class.

Guarantee coverage

The register below covers every construct for which the current fixture matrix claims acceptance or emission. check.py compares that set mechanically, validates each cited diagnostic and fixture, and generates the reading copy compiler/tests/guarantees.matrix. A new accepted construct therefore needs a classified failure boundary before the repository gate can pass.

OperationClassConstructsBehaviourEvidence
functions.nonreturningstatic0890, 0940, 1000, 1100, 1240, 1290, 1370, 1930, 1960D231 separates infallible nonreturning signatures from none, rejects reachable return/fallthrough and preserves termination through generic/evidence calls and applicable cleanuppositive/r491-noreturn-signatures, negative/r670-noreturn-fallthrough, abi/r670-noreturn
panic.contractstatic0890, 1670D232 selects only a canonical public ordinary nonreturning entry-module hook; L0506 rejects malformed declarations and unrepresentable u32 site spacesnegative/r670-panic-handler, abi/r670-panic
panic.dispatchtrap0300, 0470, 0570, 0890, 1100, 1670, 1950, 1960D232 dispatches kind/site at the failed operation, forbids later computation and cleanup, and terminates reentry; the default needs no reporting storageabi/r670-panic, environments/cortex-m/freestanding.py selected/default/interrupt controls
firmware.surfacestatic0760, 1000, 1460, 1500, 1550, 1560, 1570, 1630, 1640, 1650, 1990D229/D230 check target, machine signatures, placement, fixed assembly and scalar transport; D248 checks named operands against each target's registers; L0505 bounds static image materialization before section GCpositive/r660-machine-directives, positive/r670-scalar-assembly, positive/assembly-operand-forms, negative/r660-materialization, negative/assembly-synthetic-target
firmware.returntrap1550, 1570, 1650, 1990D232 dispatches entry return as unreachable/site zero; D229 naked fallthrough retains its undefined-instruction guard and separate hardware-fault obligationspositive/r660-machine-directives, environments/cortex-m/firmware.py boot and naked-fallthrough controls
firmware.assembly-obligationsoutside1550, 1560, 1570, 1630, 1990non-guarantee: fixed text is not a proof of device completion or correct naked stack/register/control-flow behavior; the programmer owns naked machine statepositive/r660-machine-directives
packed.extractiontrap0630, 0730, 1120Unnamed field encodings trap before producing a named value, including under unchecked; an image copy does not extract fieldsruntime/r640-packed-hole, runtime/r640-packed-small-space
packed.imagestatic0540, 0730, 0750Explicit disjoint positions, one target-sized carrier and packed-only unsigned widths; ordinary storage retains its existing representationruntime/r640-packed-fields, runtime/r640-packed-construction, runtime/r640-packed-static
packed.registerstatic0740, 0850L0344 rejects unavailable access modes, invalid masks and unsafe synthesized device field operations; a legal explicit image operation retains exactly its carrier width; L0010 names D238's withdrawn volatile pointer type and the explicit operations that replace itnegative/r640-register-no-read, negative/r640-register-no-write, negative/r640-register-one-clears-preserve, runtime/r640-register-images, negative/r491-volatile-pointer
packed.insertiontrap0730, 1120Dynamic field-width and packed-index checks remain enabled under unchecked; no silent truncation or machine shift maskingruntime/r640-packed-value-fit, runtime/r640-packed-index-bound
packed.reservedtrap0740, 1120L0398 refuses a known write-zero/write-one violation; a dynamic violation traps before the single volatile store, including under uncheckednegative/r640-register-reserved-zero, negative/r640-register-reserved-one, runtime/r640-reserved-value, abi/r640-reserved-trap
packed.deviceoutside0740, 0850non-guarantee: a declared access mode, width and reserved policy do not prove that an arbitrary address implements that peripheral contractruntime/r640-register-images, abi/r640-dma-packed
memory.eligibilitystatic0430, 0850, 1620D227: L0344 for invalid arity, type, permission, fixed ordering or target capabilitynegative/r630-load-release, negative/r630-immutable, negative/r630-m0-rmw, runtime/r630-memory-scalars, abi/r630-native-memory
memory.alignmenttrap0430, 0850, 1120, 1620D227: misalignment traps before access, even uncheckedruntime/r630-atomic-load-alignment, runtime/r630-volatile-load-alignment
memory.external-writersoutside0430, 0470, 0770, 0850, 1620, 1720D227 non-guarantee: backing validity, races, device completion and cache obligations remain caller/platform responsibilities; no race-based optimizer assumptionsabi/r630-native-memory
source.lexicalstatic0010, 0020, 0030, 0210, 0220, 0230, 0250, 0260, 0270, 0280, 1750, 1760, 1770, 1780, 1830L0010--L0014 or L0320--L0323negative/character-literal-empty, negative/character-literal-invalid-codepoint, negative/character-literal-multiple, negative/malformed-float-exponent, negative/malformed-hex-float-exponent, negative/malformed-integer-digit, negative/raw-literal-inconsistent-indentation, negative/text-literal-unknown-escape, negative/unterminated-raw-literal, negative/unterminated-text-literal, negative/unknown-byte
source.structurestatic1740, 1800, 1810, 1820, 1840L0100--L0112negative/variant-part-end-name-mismatch, unit/parser-nesting-limit
declarations.namesstatic0040, 0050, 0060, 0080, 0090, 0100, 0110, 0120, 0130, 0140, 1790, 1795, 1850L0200 or L0201negative/duplicate-in-a-module, negative/local-used-above-its-declaration
types.valuesstatic0070, 0150, 0160, 0170, 0180, 0190, 0200, 0210, 0250, 1870, 1880, 1890L0300, L0301 or L0304negative/character-literal-needs-u32, negative/float-literal-not-enabled, negative/float-type-not-enabled, negative/integer-literal-not-a-float, negative/literal-above-its-type, negative/refused-widths-name-their-owner, negative/type-name-is-not-a-type, negative/wide-integer-not-enabled
float.ieeestatic0170, 0210, 0220, 0230, 0240, 0290, 0350, 1940f32/f64 decimal and hexadecimal literals plus inherently typed infinity and canonical quiet NaN names follow IEEE binary32/binary64 through runtime and module arithmetic and comparison, preserving exact hexadecimal values, nearest-even rounding, gradual underflow, signed zero and unordered NaN behavior; arithmetic NaNs use the canonical quiet pattern, L0300 rejects a finite literal that becomes infinity, and L0301 rejects an invalid named special, a width mismatch, mixed classes and integer-only operatorsnegative/float-remainder-is-integer-only, negative/float-special-name-unknown, negative/float-special-on-integer-type, negative/float-special-width-mismatch, negative/hex-float-overflows-context, runtime/float-decimal-runtime, runtime/float-hexadecimal-runtime, runtime/float-named-specials, runtime/module-float-arithmetic
distinct.identitystatic0310, 0430, 0650, 0700, 1280, 1290, 1940, 1975a distinct declaration and each normalized generic application retain nominal identity with exact base size, alignment and bytes; explicit construction and extraction preserve origins, static images and compatible C transport; L0301 rejects identity mixing and inherited operations, L0308 refuses representation fields, L0318 refuses inherited conformance and zeroable membership, and L0314 preserves escape refusalsruntime/r490-distinct-scalars, runtime/r490-distinct-generic-representations, runtime/r490-distinct-generic-dispatch, runtime/r490-distinct-module-images, abi/r490-distinct-c-roundtrip, runtime/r490-review-generic-distinct-bool, runtime/r490-distinct-generic-bool-images, runtime/r490-distinct-generic-pointer-images, runtime/r490-generic-fixed-conversion-discovery, negative/r490-distinct-type-value, negative/r490-distinct-alias-type-value, negative/r490-distinct-generic-type-value, negative/r490-distinct-discard-type-value, negative/r490-distinct-static-address, negative/r490-distinct-identity, negative/r490-distinct-no-operators, negative/r490-distinct-no-fields, negative/r490-distinct-conformance, negative/r490-distinct-zeroable, negative/r490-distinct-origin
conversion.integertrap0150, 0190, 0310, 0470, 0700, 1120, 1460, 1670, 1880, 1940, 1950, 1960explicit conversion among enabled integer types preserves the mathematical value; L0300 rejects a known value outside the destination range and a runtime value outside it traps, without truncation, wrapping or signedness reinterpretation, outside [1120]'s regionnegative/integer-conversion-known-binding-out-of-range, negative/integer-conversion-known-out-of-range, runtime/integer-conversion-out-of-range-traps, runtime/integer-conversion-signed-overflow-traps, runtime/integer-conversion-unsigned-overflow-traps, runtime/integer-conversions
conversion.float-widthtrap0170, 0210, 0230, 0240, 0310, 0700, 1880, 1940, 1950, 1960explicit f32/f64 conversion widens exactly or narrows to nearest with ties to even, preserving signed zero and the infinity/NaN class; L0300 rejects a known finite narrowing overflow and an equivalent runtime conversion trapsnegative/float-width-conversion-known-out-of-range, runtime/float-width-conversion-overflow-traps, runtime/float-width-conversions
conversion.integer-to-floatstatic0150, 0170, 0190, 0210, 0310, 0700, 1880, 1940, 1960explicit conversion from every enabled integer to f32 or f64 preserves the mathematical value when exact and otherwise rounds to nearest with ties to even; the enabled integer range cannot overflow either float widthruntime/integer-to-float-conversions
conversion.float-to-integertrap0150, 0170, 0190, 0210, 0230, 0240, 0310, 0700, 1880, 1940, 1950, 1960explicit conversion from f32 or f64 to every enabled integer truncates toward zero and then requires the result to fit; L0300 rejects a known out-of-range, infinity or NaN source and an equivalent runtime conversion trapsnegative/float-to-integer-known-nan, negative/float-to-integer-known-out-of-range, runtime/float-to-integer-conversions, runtime/float-to-integer-nan-traps, runtime/float-to-integer-out-of-range-traps
conversion.bool-to-integerstatic0150, 0180, 0190, 0310, 0700, 1880, 1940, 1960explicit conversion from bool to every enabled integer maps false to zero and true to one; both results fit every enabled destinationruntime/bool-to-integer-conversions
conversion.bool-to-floatstatic0170, 0180, 0190, 0210, 0310, 0700, 1880, 1940, 1960explicit conversion from bool to f32 or f64 maps false to positive zero and true to exactly positive one; both values are exact in either enabled destinationruntime/bool-to-float-conversions
conversion.integer-to-booltrap0150, 0180, 0190, 0200, 0310, 0700, 1880, 1940, 1950, 1960explicit conversion from every enabled integer to bool maps zero to false and one to true; L0300 rejects every other known value and an equivalent runtime conversion trapsnegative/integer-to-bool-known-out-of-range, runtime/integer-to-bool-conversions, runtime/integer-to-bool-out-of-range-traps
conversion.float-to-booltrap0150, 0170, 0180, 0190, 0210, 0240, 0310, 0700, 1880, 1940, 1950, 1960explicit conversion from f32 or f64 to bool maps either signed zero to false and exactly positive one to true; L0300 rejects every other known finite or nonfinite value and an equivalent runtime conversion trapsnegative/float-to-bool-known-invalid, runtime/float-to-bool-conversions, runtime/float-to-bool-invalid-traps
text.literal-storagestatic0260, 0270, 0280, 0430, 0570, 0600, 1770, 1880, 1900, 1940L0301 for a mismatched identity, writable context, byte escape in text or codepoint escape in bytes; L0303 for a write through a read-only view; quoted and raw literals default to utf8, decode to validated UTF-8 or UTF-16, preserve canonical view identity and static origin, and share width-keyed read-only storage with one trailing zero element excluded from slice lengthsnegative/cstring-literal-write, negative/raw-literal-needs-read-only-slice, negative/raw-literal-write, negative/text-literal-codepoint-in-byte-context, negative/text-literal-needs-byte-slice, negative/text-literal-needs-read-only-slice, negative/text-literal-write, negative/text-view-byte-escape, negative/text-view-identities-are-distinct, runtime/hosted-text-views, runtime/raw-literal-bytes, runtime/text-literal-bytes
text.conversiontrap0310, 0430, 0570, 0600, 0660, 0790, 0940, 1050, 1650, 1880, 1950, 1960four exact immutable source-derived conversions connect []u8, utf8 and first-NUL cstring carriers; direct UTF-8 validation traps, checked core/text adapters report invalid_text, empty carriers retain origin, mutable views and pointer-to-cstring are L0301, and byte/decimal helpers allocate nothing and preserve output on refusalnegative/pointer-to-cstring-conversion, negative/text-conversion-exact-identities, negative/text-conversion-mutable-source, runtime/core-text-runtime-helpers, runtime/cstring-first-nul-validation, runtime/text-conversion-invalid-traps, runtime/text-conversion-overlong-traps, runtime/text-conversion-out-of-range-traps, runtime/text-conversion-truncated-traps, runtime/text-ordinary-conversions
text.indexingtrap0380, 0430, 0600, 0610, 1050, 1900, 1950, 1960utf8 indexed by exact usize scans linearly by codepoint ordinal; exact core/text.position supplies an O(1) byte offset; either decodes that codepoint to a u32 value, L0301 rejects every other argument or text identity, L0337 an address of the value, L0303 rejects writing through it, and an absent ordinal, end position or non-boundary position trapsnegative/utf16-indexing-is-not-utf8-indexing, negative/utf8-index-needs-usize-or-position, negative/utf8-index-position-identity-is-exact, negative/utf8-index-result-is-not-a-place, negative/utf8-index-result-has-no-address, runtime/utf8-indexing, runtime/utf8-ordinal-out-of-range-traps, runtime/utf8-position-at-end-traps, runtime/utf8-position-not-boundary-traps
text.slicingtrap0310, 0410, 0430, 0570, 0600, 0790, 1050, 1820, 1950, 1960utf8 and utf16 ranges take exact usize code-unit bounds, require scalar-boundary endpoints, preserve the immutable source-derived text identity, include the complete upper scalar for .., and evaluate source then bounds once; cstring and other bound types are L0301, mutation is L0303, L0316 enforces the return origin, and an invalid bound or split scalar trapsnegative/cstring-range-slicing-has-no-length, negative/text-slice-needs-usize-bounds, negative/text-slice-result-is-read-only, negative/text-slice-result-keeps-identity, negative/text-slice-result-keeps-origin, runtime/text-range-slicing, runtime/utf16-slice-not-boundary-traps, runtime/utf8-slice-lower-not-boundary-traps, runtime/utf8-slice-upper-not-boundary-traps
text.traversaltrap0250, 0410, 0430, 0600, 1130, 1150, 1160, 1320, 1650, 1950, 1960the exact utf8, utf16 and cstring identities retain one source, use private usize code-unit cursors, and yield immutable copied u32 Unicode scalars in first/at_end/item/next order; cstring stops before its first NUL and validates before decoding, malformed foreign encoding traps even in unchecked, ordinary carriers are L0348, and mutation is L0303negative/text-traversal-item-is-read-only, negative/text-traversal-ordinary-pointer-is-not-cstring, runtime/cstring-traversal-invalid-traps, runtime/hosted-text-traversal
arithmetic.knownstatic0290, 0300, 0390, 1950L0300 or L0306negative/compound-assignment-zero-divisor, negative/divisor-is-zero, negative/literal-above-its-type, negative/r480-recovery-zero-divisor
arithmetic.runtimetrap0290, 0300, 0320, 0390, 1120, 1950, 1960trap, outside [1120]'s region for +, -, * and unary -runtime/compound-assignment-overflow-traps, runtime/checked-overflow-traps, runtime/checked-subtraction-traps, runtime/checked-multiplication-traps, runtime/checked-negation-traps, runtime/signed-division-overflow-traps, runtime/a-zero-divisor-traps, runtime/a-zero-remainder-divisor-traps, runtime/negative-left-shift-traps, runtime/negative-right-shift-traps
arithmetic.totalstatic0320, 0330, 0340, 0350, 0390L0301 for an inapplicable operand; admitted nonnegative shifts and wrapping operations are totalnegative/compound-assignment-float-remainder, negative/condition-is-not-believed, runtime/compound-assignment, runtime/shifts-fill-with-zeros-beyond-the-width
ranges.measurementsstatic0360, 0370L0300, L0301 or L0306negative/lenof-scalar, runtime/measurements-answer-for-the-target
assignment.flowstatic0390, 0400, 0410, 0420, 1900, 1910L0302 or L0303negative/assigned-on-one-path-only, negative/assignment-to-an-immutable-binding, negative/compound-assignment-immutable, negative/compound-assignment-unassigned, runtime/compound-assignment, negative/r480-recovery-assignment
pointer.permissionstatic0380, 0430, 0440, 0450, 0460L0301, L0303, L0337 or L0342negative/any-readonly-source-for-mutable-entry, negative/sink-through-dereference, runtime/r250-references
inout.exact-aliasstatic0900L0337 when one provably identical binding-rooted place fills two inout parametersnegative/inout-same-place-twice
inout.possible-aliasoutside0430, 0770, 0900non-guarantee: distinct pointer or computed paths may still aliasruntime/inout-pointer-alias-is-unchecked
pointer.validityoutside0430non-guarantee: a permitted pointer may still be invalid or stale, including an old pool pointer whose address and extent match a later reuseruntime/r250-references, runtime/r420-pool-provider
pointer.integer-originbeyond-lifetime0470, 0810, 0860, 1690, 1720non-guarantee: integer-to-pointer conversion carries no origin through a direct or erased value, and D196 records it as the actual derivation cut [0810] describes without privileged core namesruntime/r250-references, runtime/any-untracked-pointer-origin, negative/frame-origin-return
pointer.integer-widthtrap0470, 1120, 1950, 1960trap, outside [1120]'s regionruntime/pointer-to-small-integer-traps
arrays.initializationstatic0520, 0530, 0540, 0550, 0560L0300--L0304 or L0313negative/array-initializer-length-mismatch, runtime/whole-arrays-copy-between-storage
arrays.arithmeticstatic0590L0301 refuses mismatched lengths, element types, nonnumeric lifting and every array comparison; D209 retains complete operand values in source order, allowing stable storage to supply them, and retains scalar element semanticsnegative/r450-array-length-mismatch, negative/r450-array-element-mismatch, negative/r450-array-bool-refused, negative/r450-array-comparison-refused, runtime/r450-array-snapshots, runtime/r450-array-compound-snapshot, runtime/r450-array-empty-operands, runtime/r450-array-float-order
arrays.element-trapstrap0290, 0300, 0310, 0590, 1120, 1960D209 executes element operations in ascending index order with the scalar overflow and division edges; unchecked removes no division edgeruntime/r450-array-later-overflow, runtime/r450-array-unary-overflow, runtime/r450-array-later-division-zero, runtime/r450-array-signed-division-overflow, runtime/r450-array-unchecked-division-zero
layout.explicit-policystatic0750, 0760D210 changes physical field placement only for explicit optimal policy and only for a strict final padded-size win; source identities and initializer evaluation order are unchangedpositive/r450-optimal-layout-source, runtime/r450-optimal-layout-composition
raw.prefixstatic0420, 0500, 0510L0202 prevents representation access; core/mem reports raw_full, uninitialized, raw_empty or raw_not_empty before an invalid transitionnegative/core-mem-private-representation, runtime/core-mem-raw-storage
raw.backingoutside0430, 0470, 0510, 1720non-guarantee: the supplied byte pointer may be invalid, misaligned or smaller than the declared capacityruntime/core-mem-raw-storage
allocation.failurestatic0300, 0940, 1230, 1280, 1290, 1310, 1360, 1975allocators report core/mem.out_of_memory, which a caller must handle or declare; arenas reject exhaustion and unrepresentable request arithmetic before mutation, vectors check extents and growth before provider calls and preserve the old list on failure, and heap refusal, finite pool exhaustion, injected refusal and delegated inner refusal use the same channelruntime/core-mem-allocators, runtime/core-mem-arena-boundaries, runtime/core-vec-pointer-storage, runtime/r420-vec-capacity-boundaries, runtime/r420-vec-growth-boundary, runtime/r420-vec-growth-transaction, runtime/derived-parser, runtime/hosted-heap-provider, runtime/r420-pool-provider, runtime/r420-failing-providers
allocation.backingoutside0430, 0470, 0770, 0820, 1360, 1720non-guarantee: backing validity and exact capacities remain the caller's responsibility; checked arena and counted-arena constructors refuse tracked frame backing with L0314 and private representations prevent ordinary construction around that check; their unchecked constructors expose the lifetime opt-out; tracked pool base and bookkeeping origins join, but one untracked constituent makes the whole provider untracked; D212 preserves independent direct, helper and side-effect allocator resultsruntime/r480-arena-independent-results, runtime/r480-arena-nested-exhaustion, runtime/core-mem-allocators, runtime/core-mem-arena-boundaries, runtime/r420-pool-provider, negative/core-arena-frame-escape, negative/core-arena-private-representation, negative/core-pool-frame-escape, negative/core-pool-bookkeeping-frame-escape
allocation.reclamationstatic0430, 0470, 0790, 1360heap release and a pool free of a currently occupied exact address and extent return real live storage; pool reuse is lowest-index first, stale same-address/same-size identity is outside the guarantee, and counted free delegates once with a live count exact only for valid-free useruntime/hosted-heap-provider, runtime/r420-pool-provider, runtime/r420-failing-providers
slices.bounds-knownstatic0570, 0580, 1950L0300 or L0306negative/index-outside-the-length, negative/readonly-slice-write
slices.bounds-runtimetrap0570, 0580, 1120, 1950, 1960trap, outside [1120]'s regionruntime/computed-array-index-traps, runtime/local-array-computed-store-traps, runtime/slice-index-read-traps, runtime/slice-index-write-traps, runtime/slice-half-open-upper-traps, runtime/slice-inclusive-upper-traps, runtime/slice-lower-after-upper-traps
atoms.setsstatic0630, 0640L0301 or L0312; equality compares declaration identities without requiring set inclusion, while ordering and atom/numeric mixing remain refusednegative/atom-match-not-exhaustive, runtime/atom-values-cross-the-abi, runtime/r490-generic-atom-identity, runtime/r490-generic-atom-arrays, runtime/r490-generic-atom-fields, runtime/r490-generic-atom-storage, negative/r490-atom-array-wrong-member, negative/r490-generic-atom-field-member
aggregates.fillstatic0410, 0670, 0710, 0720L0301 for unequal omitted-field descriptors and L0334 for a value fill without a destination; one exact contextual value is evaluated after written labels and copied in declaration order; ordinary origin and assignment diagnostics remainruntime/r490-generic-field-fill, negative/r490-fill-mixed-types, negative/r490-fill-array-shapes, negative/r490-fill-atom-sets, negative/r490-fill-pointer-permissions, negative/r490-fill-frame-escape, negative/r490-fill-unassigned
aggregates.variantsstatic0670, 0680, 0690, 0700, 0710, 0720, 0750, 1210L0301, L0308--L0313 or L0334negative/struct-literal-field-not-given, negative/variant-match-not-exhaustive
origins.escapestatic0480, 0770, 0780, 0790, 0800, 0830, 0840, 1220, 1910L0314--L0316; [0790]'s exact from comparison applies to an actual returned reference, while a provably empty optional-pointer arm has no origin and is not Untracked; a retained provider wrapper keeps its ordinary inner argument's origin without requiring that argument to be declared escaping, tracked pool constructor sources join, destination storage prevents retained frame or foreign non-escaping origins, payload aliases keep scalar storage live through last use, and D222 forbids hidden independent storage in writable from resultsnegative/r491-writable-return-hidden-storage, positive/r491-writable-return-explicit-sources, negative/frame-origin-return, negative/borrowed-source-inout, negative/returned-reference-missing-from, negative/core-arena-frame-escape, negative/core-pool-frame-escape, negative/core-pool-bookkeeping-frame-escape, negative/core-failing-frame-escape, negative/core-text-frame-slice-escape, negative/core-diag-frame-message-escape, negative/r440-parser-frame-arena, runtime/diagnostic-loggers-dispatch, runtime/r420-failing-providers, negative/r480-recovery-retains-borrow, negative/r480-recovery-exposed-storage, negative/r480-reader-live-line, negative/r491-retained-reference-stores, negative/r491-live-payload-aliases, runtime/r491-reference-store-origins, runtime/r491-payload-alias-last-use
origins.aliasing-limitoutside0770, 0910non-guarantee: a pre-existing copy or indistinguishable arena is not trackedpositive/reference-origins-and-consume, negative/use-after-sink
functions.abistatic0870, 0880, 0890, 0900, 0920, 0930, 0980, 1000, 1020, 1030, 1460, 1920, 1970L0301, L0302, L0327, L0331, L0343 or L0502negative/call-with-too-few-arguments, runtime/r230-composition, runtime/r480-generic-provider-entry
optimization.outcomesstatic0290, 0430, 1100, 1120, 1310, 1550D211 preserves effects, snapshots, cleanup, required traps, calling conventions and observable function identities under every optimization profile; malformed transformed IR is a compiler defect, never a source diagnosticruntime/r450-opt-effects, runtime/r450-opt-discarded-trap, runtime/r450-specialization-recursive-errors, runtime/r450-specialization-threshold, runtime/r450-x86-pressure, abi/r450-x86-callee-probes
functions.callerstatic0670, 0790, 1000, 1040, 1800, 1920caller positions have immutable three-u32 struct values (file_id, line, column) and structural signature identity, are compiler-filled without source strings, and accept an explicit argument only as a named forwarding of another caller parameter; L0339 rejects an invalid site type, L0301 a different signature, L0327 an extra positional argument or invalid forwarding source and L0303 rejects mutation, and caller decided on two tokens leaves the spelling an ordinary namenegative/caller-parameter-extra-field, negative/caller-parameter-field-order, negative/caller-parameter-field-width, negative/caller-parameter-read-only, negative/caller-parameter-forward-copy, negative/caller-parameter-forward-needs-caller, negative/caller-parameter-needs-site, negative/caller-parameter-positional, negative/caller-parameter-signature-mismatch, runtime/caller-parameters, runtime/caller-is-an-ordinary-name
extern.c-boundarystatic0430, 0570, 0750, 0920, 1000, 1570, 1580, 1600, 1975C convention and variadicness remain recursively distinct from the Landin convention; fixed positions at the selected boundary admit integers, bool, pointers, f32/f64, fixed C callbacks and compatible nonempty layout(c) structs, while L0346 refuses an ordinary Landin struct, a slice, a Landin error channel or a native-convention callback even when its machine shape matchespositive/external-scalar-c-boundary, positive/r440-external-float, positive/r440-c-signatures, negative/external-aggregate-boundary, negative/r440-c-slice-parameter, negative/r440-c-error-channel, negative/r440-c-native-callback
functions.linkagestatic1000, 1570, 1580, 1600, 1610, 1800, 1975link(symbol: text) changes only the linker spelling: standalone use retains the native convention and body requirement, C imports may have compatible repeated declarations, L0347 refuses an assembly expression, incompatible declarations or multiple definitions, and L0301 refuses treating a native linked function as a C callbackpositive/r440-c-signatures, positive/r440-compatible-link-declarations, negative/r440-link-assembly-expression, negative/r440-link-does-not-change-convention, negative/r440-link-duplicate-definitions, negative/r440-link-incompatible-declarations
host.arguments-startuptrap1580, 1600, 1650, 1660, 1960, 1975the no-argument Landin entry initializes the actual argument root before its body; C-owned startup must initialize it explicitly before hosted.host(); use before initialization, a negative argc, null argv, or replacement of either established root carrier traps, while an identical repeated initialization is a no-op and startup-independent bridge calls need no rootabi/r440-native-startup-initialized, abi/r440-native-startup-empty, abi/r440-native-startup-uninitialized, abi/r440-native-startup-replaced
host.iooutside0430, 1580, 1650, 1660, 1680, 1975non-guarantee: files, descriptors, arguments and streams reflect mutable host stateruntime/hosted-io-reads-parser-input, runtime/core-io-erased-system, runtime/derived-parser
capabilities.host-root-exclusionoutside1660, 1680, 1975non-guarantee: an ordinary hosted routine without an I/O or allocator parameter may call a public host constructor and use that authority; passing a replacement provider does not exclude this pathruntime/derived-hosted-memory
host.io-failurestatic0940, 0960, 1030, 1975core/io/hosted reports foreseeable host failure as declared atoms which callers handle or declareruntime/hosted-io-reads-parser-input, runtime/core-io-erased-system, runtime/diagnostic-loggers-dispatch, runtime/derived-parser
diagnostics.retentionoutside0950, 1680non-guarantee: core/diag.bounded(N) copies at most N messages of up to diag.message_capacity bytes and counts later or oversized notes in droppedruntime/diagnostic-loggers-dispatch, runtime/derived-parser
diagnostics.delivery-failurestatic0940, 0960, 0950, 1030, 1680a streaming diagnostic write reports io_failed, which a caller must handle or declare; bounded overflow does not use that channelruntime/diagnostic-loggers-dispatch, runtime/derived-parser
execution.resource-exhaustionoutside0950, 1770, 1970non-guarantee: the kernel sets no recursion-depth, stack, or host-resource boundruntime/recursive-fibonacci
consume.localstatic0910L0337 for a sink path crossing a reference boundary or using a computed index; L0302 or L0315 for consumed-place and restoration checksnegative/use-after-sink, negative/sunk-inout-not-restored, negative/r491-sink-slice-storage, positive/r491-sink-contained-places, positive/r491-sink-call-entry, negative/r491-sink-entry-overlap
consume.copy-beforestatic0860, 0910, 1720a value copied before the sink remains independently usableruntime/copy-before-sink-remains-live
errors.controlstatic0940, 0960, 0970L0329 for an undeclared or unhandled outcomenegative/unhandled-declared-error, runtime/declared-errors-direct-and-inferred, runtime/r490-generic-recovery-frontier, runtime/r490-generic-recovery-alias-chains, negative/r490-generic-error-key-cycle
results.destructurestatic0990L0200, L0302, L0308 or L0331negative/result-destructure-needs-multiple, runtime/r230-composition
functions.anonymousstatic1010L0201 for capture; complete signature checks otherwise applynegative/anonymous-function-captures-local, runtime/inferred-function-values
control.flowstatic1050, 1060, 1070, 1080, 1090L0200 or L0201 at a condition-binding scope boundary; L0301, L0302 or L0332 at every condition, reachable join and exitnegative/condition-declaration-body-shadowing, negative/condition-declaration-not-bool, negative/condition-declaration-out-of-scope, negative/if-expression-missing-else, runtime/condition-declarations, runtime/control-expression-edges-keep-source-order
control.loopsstatic1090, 1130, 1140, 1150, 1160, 1170, 1180, 1190, 1320, 1330L0301 for a non-bool condition, mismatched range, non-traversable source, missing/ambiguous/non-exact iterable evidence or an untried fallible traversal, incomplete/inconsistent value exit, or a value given to a labelled bare block's break; L0303 for a write to a read-only storage element or copied iterable item; a taken transfer runs active defers and targets its named loop or labelled block edge, or the nearest loop, while natural completion alone enters completenegative/loop-condition-not-bool, negative/loop-value-missing-break-value, negative/loop-value-missing-completion, negative/loop-value-type-mismatch, negative/for-range-needs-integer, negative/for-range-endpoints-disagree, negative/for-source-not-traversable, negative/for-collection-element-read-only, negative/for-array-element-read-only, negative/for-any-element-read-only, negative/for-iterable-ambiguous-evidence, negative/for-iterable-item-read-only, negative/for-iterable-missing-conformance, negative/text-traversal-item-is-read-only, runtime/loop-control-flow, runtime/loop-values, runtime/for-range-traversal, runtime/for-collection-traversal, runtime/for-aggregate-element-traversal, runtime/for-any-element-traversal, runtime/for-iterable-evidence-traversal, runtime/hosted-text-traversal, runtime/r480-recovery-loop-transfer, runtime/r480-loop-fresh-view, runtime/r720-labelled-block-transfers, negative/r720-labelled-block-break-value
cleanup.deferstatic1100the registered call is checked at every ordinary and successful-return edgenegative/defer-read-not-assigned-on-return, runtime/defer-cleanups-follow-control-edges
cleanup.undostatic1110, 1200the registered call is checked at every propagated-failure edgenegative/undo-read-not-assigned-on-failure, runtime/undo-cleanups-follow-failure-edges
generics.substitutionstatic1220, 1280, 1290, 1300, 1310, 1350, 1490, 1500, 1520, 1540, 1650, 1660, 1700L0300, L0301, L0306, L0307, L0313, L0318 or L0340; a concrete ptr T field retains the exact referent and permission descriptornegative/generic-routine-undeduced-formal, negative/generic-reference-field-permission-distinct, runtime/generic-explicit-static, runtime/generic-reference-fields, runtime/generic-structural-deduction, runtime/core-vec-pointer-storage, runtime/r480-generic-nested-recovery, runtime/r480-concrete-error-deduction, runtime/r490-generic-inferred-recovery, runtime/r490-generic-recovery-frontier, runtime/r490-generic-union-alias, runtime/r490-generic-erased-recovery-views, negative/r490-generic-recovery-conflict, negative/r490-recovery-expanding-generic
concepts.conformancestatic1230, 1240, 1250, 1260, 1270, 1340L0317--L0319 or L0341negative/conformance-collision, negative/constraint-not-satisfied, negative/compiler-concept-reserved, positive/r490-conformance-input-keys, negative/r490-conformance-input-alias-collision
any.constructionstatic1370, 1380L0314, L0318 or L0342negative/any-source-not-pointer, negative/any-readonly-source-for-mutable-entry
any.dispatchstatic1390malformed table positions cannot be produced by accepted source; verifier failure is a compiler defectnegative/any-entry-not-object-safe, runtime/any-heterogeneous-dispatch
modules.visibilitystatic1410, 1420, 1430, 1440, 1450, 1480L0006 or L0007 for an unresolved root; L0200 for duplicate import bindings, L0201 for missing selected names, L0202 for private members or representations and L0203 for reserved tool namesnegative/module-not-found, negative/imported-private-name, negative/core-mem-private-representation, negative/core-text-private-position, runtime/core-mem-raw-storage, negative/import-selected-private, negative/import-selected-missing, negative/import-selected-duplicate, runtime/import-alias-selected-identities, runtime/import-contextual-as
entry.pointstatic1650, 1970L0502 before executable emissionruntime/constant-return-exits-with-its-code, negative/r440-native-renamed-entry
module.imagesstatic0180, 0340, 0350, 0410, 1460, 1890, 1930, 1940L0300, L0304 or L0305; module-known bool not, and and or fold left to right into scalar and aggregate images, short-circuit and/or, and execute no initializer CFGnegative/module-value-from-a-call, runtime/module-known-short-circuit-bools, runtime/recursive-module-images-are-laid-out-and-distinct
unchecked.regionoutside0290, 0300, 0310, 0320, 0430, 0470, 0570, 0580, 0700, 1100, 1110, 1120, 1950, 1960non-guarantee: inside [1120]'s region the compiler emits no integer overflow edge for +, -, * and unary -, no element-index or slice-range edge, and no destination-range edge for an integer-to-integer or pointer-to-integer conversion; the results are [0320]'s wrapping value, [0430]'s pointer non-guarantee at the computed address, and the low-order bits of the source; every static refusal, every division, shift, bool and float conversion edge and every text boundary edge stays, and a [1100] defer or [1110] undo call keeps the edges of the place its registration is written rather than those of the exit that runs itpositive/unchecked-regions, positive/unchecked-marks-only-the-edges-it-removes, runtime/unchecked-arithmetic-wraps, runtime/unchecked-integer-conversion-truncates, runtime/unchecked-slice-index-passes-the-length, runtime/checks-return-after-the-region, runtime/unchecked-does-not-cross-a-call, runtime/unchecked-does-not-reach-an-anonymous-body, runtime/unchecked-keeps-the-divisor-check, runtime/unchecked-keeps-the-shift-check, runtime/unchecked-keeps-text-boundary-traps, runtime/unchecked-keeps-bool-conversion-traps, runtime/unchecked-keeps-float-conversion-traps, runtime/unchecked-pointer-conversion-truncates, runtime/unchecked-does-not-reach-an-outer-cleanup, runtime/unchecked-reaches-a-cleanup-written-inside, negative/unchecked-keeps-a-known-index, negative/unchecked-keeps-permissions, negative/unchecked-keeps-definite-assignment, negative/unchecked-region-end-name-mismatch
subtype.rangetrap0540, 0660, 0700, 1730, 1795, 1880, 1940, 1950, 1960storing into a place whose declared type is [0660]'s range subtype, and applying the subtype name to a value, check the value against both folded bounds; L0300 rejects a known value outside them, a runtime value outside them traps, and a value whose own subtype's bounds lie inside them is not checked again; a successful guard on an ordinary integer does not itself elide this check; [1120]'s region does not remove this edge; L0304 records D236's boundary for a struct field, an array element, a reference target, addr of a constrained place and a generic argumentpositive/range-subtypes, runtime/range-subtype-checks, runtime/range-subtype-store-traps, runtime/range-subtype-conversion-traps, runtime/range-subtype-update-traps, negative/range-subtype-literal-out-of-range, negative/range-subtype-known-value-out-of-range, negative/range-subtype-zeroed-excluded, negative/range-subtype-bounds-inverted, negative/range-subtype-in-a-slice, negative/range-subtype-struct-field, negative/r720-range-subtype-array-element
pointer.optionalstatic0430, 0440, 0470, 0480, 0630, 0640, 1210, 1870L0335 for every use that would read an atom case as an address, for a union of one atom and a pointer and for one of several atoms and a pointer alike — .val in a read, in an assignment target and under addr, an integer conversion, any construction, a comparison, a ptr T position, and ptr(n) into one — L0333 for an inout arm binding and L0338 for a union of two pointer types; L0328 rejects a many-atom union without a zero image, while the one-atom zeroed context remains L0301; L0333 for an arm outside the union, L0301 for a widening atom outside it, for a narrowing, for a permission the member does not relax to, and for an inout place of another union; L0311 for a case named twice and L0312 for a case no arm and no _ names; the bound pointer carries the subject's origin and an atom case carries nonepositive/pointer-unions, runtime/pointer-unions, negative/pointer-union-dereference, negative/pointer-union-assignment-target, negative/pointer-union-address-of-referent, negative/pointer-union-any-construction, negative/pointer-union-case-named-twice, negative/pointer-union-present-arm-named-twice, negative/pointer-union-is-not-a-pointer, negative/pointer-union-match-not-exhaustive, negative/pointer-union-frame-escape, negative/r440-parser-frame-arena, negative/pointer-union-comparison, negative/pointer-union-integer-conversion, negative/pointer-union-from-an-integer, negative/pointer-union-inout-binding, negative/pointer-union-zeroed, negative/pointer-union-two-pointers, negative/pointer-case-arm-is-not-an-atom, positive/pointer-union-several-atoms, positive/pointer-union-many-declarations, positive/pointer-union-many-widening, runtime/pointer-union-many, negative/pointer-union-many-dereference, negative/pointer-union-many-assignment-target, negative/pointer-union-many-address-of-referent, negative/pointer-union-many-any-construction, negative/pointer-union-many-comparison, negative/pointer-union-many-integer-conversion, negative/pointer-union-many-is-not-a-pointer, negative/pointer-union-many-result-is-not-a-pointer, negative/pointer-union-many-from-an-integer, negative/pointer-union-many-zeroed, negative/pointer-union-many-inout-binding, negative/pointer-union-many-case-named-twice, negative/pointer-union-many-pointer-arm-named-twice, negative/pointer-union-many-match-not-exhaustive, negative/pointer-union-many-foreign-atom-arm, negative/pointer-union-many-atom-outside-the-set, negative/pointer-union-many-does-not-narrow, negative/pointer-union-many-permission-does-not-widen, negative/pointer-union-many-inout-is-exact, negative/pointer-union-many-frame-escape, negative/pointer-union-many-return-frame, negative/pointer-union-many-two-pointers
configuration.fixedstatic1480, 1500, 1510, 1530, 1540, 1560, 1590, 1980L0200 for duplicate option names; L0203 for reserved tool names; L0300, L0301, L0305 or L0306 for invalid fixed evaluation; L0324 for a false compiler assertion; L0390 for invalid option declarations; L0391 for invalid tool directivesnegative/fixed-conditional-evaluator, negative/r430-assertion-false, negative/r430-option-cycle, negative/r430-option-duplicate, negative/r430-option-reserved, negative/r430-library-injection, positive/r430-fixed-options, runtime/r430-fixed-tools, runtime/r430-static-library

This is a coverage register, not an optimizer contract. D187 adds unchecked.region for [1120], which weakens the four trapping rows it names and no others; subtype.range is deliberately not among them, because a value outside a range subtype's bounds is not a value the destination type holds and removing that edge would leave no stated behaviour. D203--D208 add the selected C-call, export, linkage, allocation and hosted-startup boundaries now that the C boundary implements their source and backend paths; its generated binding integration is evidence rather than additional guarantee classes. D209--D210 add arithmetic snapshots, retained element traps and explicit placement without extending the pointer-validity guarantee. Driver and backend inability have diagnostic owners in diagnostics.matrix, but are host failures rather than source semantic operations and therefore are not invented as language guarantees here.

Conformance and evidence coverage

The conformance/evidence coverage register is separate because one semantic operation can travel through several physical mechanisms:

MechanismRulesEvidence
compiler-zeroableD143positive/compiler-zeroable-conformances, negative/nonzeroable-constraint
ordinary-directD142positive/concepts-and-conformances, negative/conformance-entry-signature-mismatch
ordinary-parentD142runtime/generic-composed-evidence, negative/composed-conformance-missing-parent
parameterized-providerD142, D144positive/parameterized-conformance-lookup, runtime/generic-parameterized-evidence
collisionD142negative/conformance-collision, negative/parameterized-conformance-collision
constraint-refusalD142, D143negative/constraint-not-satisfied, negative/nonzeroable-zero-length-constraint
generic-direct-tableD144runtime/generic-evidence-indirect, negative/parameterized-conformance-entry-signature-mismatch
generic-parent-tablesD144, D221runtime/generic-composed-evidence, negative/r491-static-entry-collision, positive/r491-static-entry-diamond
erased-direct-tableD145--D147, D154, D155runtime/any-heterogeneous-dispatch, runtime/diagnostic-loggers-dispatch, runtime/derived-parser, negative/any-concept-identity-mismatch
erased-parent-flatteningD147runtime/any-composed-dispatch
erased-parameterized-providerD145--D147, D154, D155runtime/any-parameterized-provider, runtime/diagnostic-loggers-dispatch, runtime/derived-parser
verifier-boundariesD144, D147unit/evidence-verifier
target-layout-64D144, D147unit/evidence-layout, runtime/any-aggregate-storage
target-layout-32D144, D147unit/evidence-layout
intrinsic-text-traversalD184runtime/hosted-text-traversal, negative/text-traversal-ordinary-pointer-is-not-cstring

The alternatives: classifying syntax-node kinds gives internal recovery nodes equal standing with user operations and misses one operation's several safety boundaries. Classifying only IR opcodes omits every statically refused operation. Treating every accepted operation as “safe” would overstate the language exactly where [1720] refuses that claim. Those inventories were rejected in favour of observable boundaries plus mechanical construct closure.

Pinned by compiler/tests/guarantees.matrix, compiler/tests/conformances.matrix, compiler/tests/diagnostics.matrix, the prototype and target matrices, and the full check.py coverage pass.

D156 — Loop transfers are ordinary CFG edges with lexical cleanup

The tour said that [1130] repeats unconditionally, [1140] tests before an iteration, [1180] gives break and continue optional guards, and [1100] executes deferred calls when a lexical block is left. It did not state the definite-assignment approximation at a back edge or whether a transfer selects [1110]'s failure-only cleanup.

Chosen: the first loop increment enables unlabelled loop and while statements and their unlabelled, valueless break and continue transfers. The neutral IR represents them only with its existing blocks, branches and jumps: the loop header is an ordinary backward target, and no loop opcode or backend-specific form is introduced. A guarded transfer branches after evaluating its condition once. A taken transfer is a Structured_Transfer, so it runs active defer entries from inner to outer through the loop-body boundary and never selects undo.

Definite assignment is intentionally conservative. The condition is checked with the incoming facts; the body is checked with those facts, but an assignment made only in an iteration does not establish a fact after the loop. This is sound for a while that may run zero times and avoids claiming a fixed point the checker has not computed. Origins join the incoming and one-body facts because that analysis is monotone union. Labels, break with, complete, value-producing loops and iterable for remain later loop work rather than being approximated in this first increment; D157 subsequently enables the labels and completion edge without changing this representation.

The alternatives: lower a loop to recursion, add a neutral loop opcode, skip cleanup on iteration edges, or treat one body pass as proof of assignment after the loop. Recursion changes stack behavior, an opcode duplicates the existing control-flow graph, skipping cleanup violates lexical registration, and the last choice is unsound for zero iterations. All were declined.

Pinned by negative/loop-condition-not-bool, runtime/loop-control-flow, the syntax, resolution, checking, flow, lowering and verifier seams, and the control.loops guarantee row.

D157 — Loop labels and completion select explicit existing edges

The tour said that [1180] gives loops ordinary-name labels and lets break and continue name one, while [1170] runs complete only when a loop finishes without break. It did not state how an implementation should retain those targets or whether a conditional loop's false edge and a breaking edge share one block.

Chosen: a label is retained on its loop syntax node and on each targeted transfer; it is neither a value declaration nor an IR operand. Resolution, flow checking and lowering select the nearest enclosing loop whose label matches, while an unlabelled transfer continues to select the nearest loop. The selected loop's existing cleanup boundary controls [1100]/[1110] exactly as it does for the nearest-loop form.

A while with complete has two distinct CFG destinations. Its false condition edge enters the completion block, whose ordinary fallthrough then enters the post-loop block. Every break targets the post-loop block directly and therefore skips completion. continue still targets the condition header. An unconditional loop has no natural exhaustion edge and consequently cannot carry complete. Definite assignment remains D156's conservative incoming state after either exit.

The alternatives: introduce labels into ordinary lexical name resolution, encode target depths in the syntax tree, add labelled IR jumps, or route break through complete and suppress it dynamically. The first creates a value namespace where the language promises only control names; the second is fragile under tree rewrites; the last two duplicate structure already stated by explicit CFG edges. All were declined.

Pinned by runtime/loop-control-flow, the syntax, flow and lowering seams, and the control.loops guarantee row.

D158 — Loop values reuse the caller-owned control join

The tour said that [1190]'s break with makes a loop an expression, that every break from such a loop yields the same type, and that a finite loop's complete path supplies its exhaustion value. It did not state where that value lives while lexical cleanup runs or how a labelled break crosses an inner loop.

Chosen: a value-producing loop has the same consumer-owned neutral join slot as D125's if, match, and bare-block expressions. Each taken break with evaluates its guard once, evaluates the value only on the taken edge, writes the target loop's join slot, performs D156's structured cleanup, and jumps directly to that loop's post-loop block. A labelled break selects both the cleanup boundary and join slot of the nearest matching loop; an intervening loop owns neither.

Every break targeting a value-producing loop must carry with, and all values are checked against the type and complete identity inferred from the first one or supplied by context. A conditional value loop must have complete, and that block must not fall through: it leaves through a compatible break with. An unconditional loop needs no synthetic exhaustion value because it has no natural exhaustion edge. Scalar, function, pointer and atom results use the join's ordinary slot. Fixed arrays, structs, slices and any use D125's destination-aware block-value path; a targeted break retains the complete destination path while nested control runs, fills it, and only then performs lexical cleanup. This keeps an arbitrarily nested result target-neutral without forming an aggregate IR value.

The alternatives: add a loop-result IR instruction, store the result in a compiler-global temporary, evaluate a guarded value before its guard, or pass an inner loop's destination outward implicitly. Each either duplicates the existing CFG/storage model, changes source evaluation order, or loses the explicit labelled target. All were declined.

Pinned by negative/loop-value-missing-break-value, negative/loop-value-missing-completion, negative/loop-value-type-mismatch, runtime/loop-values, runtime/loop-any-values, and the control.loops guarantee row.

D159 — Integer range traversal is retained bounds over ordinary CFG

The tour said that [1150] traverses a..<b and a..b, optionally binds an index, and shares [1170]--[1190]'s completion, labels and values. It did not state when bounds run, the index type, what descending bounds mean, or how an inclusive range ending at the integer maximum avoids an overflow after its last body execution.

Chosen: the first for increment admits ascending integer ranges. The lower bound runs once, then the upper bound runs once; both have one integer type. D219 lets either typed endpoint supply an untyped integer peer, with [0200]'s i32 default when both are untyped. The current element is an immutable copy of that type and the optional index is immutable usize, starting at zero. A half-open range tests <; an inclusive range tests <= and, after its body, checks equality with the saved upper bound before incrementing. Thus an inclusive range whose upper bound is the type's maximum completes without forming an out-of-range successor. A lower bound greater than the upper bound is an empty traversal.

Lowering uses only D156's slots, comparisons, branches and backward jumps. continue targets the shared step block, so both element and index advance exactly once; natural exhaustion selects [1170]'s completion block and break skips it. Bounds are outside the body scope. The iteration bindings are ordinary local declarations inside that scope, so name resolution, definite assignment and lowering use the same declaration side tables as any other local. The parser retains collection traversal too, but checking reports its named deferral until [1160]'s permission-sensitive element binding and iterable evidence are implemented.

The alternatives: re-evaluate the upper bound per iteration, desugar the header into source nodes, widen the element to create an inclusive sentinel, or give continue a separate increment sequence. These change observable order, invent source that was not written, fail for the widest type, or let the two paths drift. All were declined.

Pinned by runtime/for-range-traversal, negative/for-range-needs-integer, negative/for-range-endpoints-disagree, negative/for-iterable-missing-conformance, and the control.loops guarantee row.

D160 — Collection traversal aliases one element of the source's storage

The tour said that [1150] traverses a collection with the same binding shape as a range, and [1160] that the binding carries no marker because the type already decided: over []mut T the element is a writable place, over []T it is not, and over anything else that satisfies iterable it is a copy. It did not say how a fixed array traverses, when the source is evaluated, what an index over a collection counts, or whether a read-only element is a copy or a place.

Chosen: the source is evaluated once, before the first test, to a base address and an element count: a slice supplies both, and a fixed array supplies the address of its storage and its compile-time length. A hidden usize counter runs from zero while it is below that count; the optional index binding is that counter. Before each body run the element's address is formed from the base and the counter, and the element binding is an alias through that address for the whole body: reads and writes go through it, so a body that writes the storage by index sees the change through the element and vice versa. A slice element is writable when the slice is []mut T; a fixed array's element is writable when the array itself sits in a place the body could assign, which is the same question items[k] = v asks of items. Every other element is a read-only place, refused at a write by L0303 with [1160]'s note. An element whose type is a scalar, pointer, atom, function or struct is enabled. An array, slice or any element, and a source that is a struct or any value awaiting [1320]'s iterable evidence, keep the named refusal, L0304.

Lowering keeps this inside the existing alias table that D78's payload bindings and [0990]'s named returns already use: the element declaration maps to a runtime-address alias whose slot is refreshed in the loop body's first block. Scalar reads and writes of the element load and store through that address; struct elements reach their fields through the same rooted storage a slice index produces. No new IR opcode, slot kind or verifier rule was added. Origin analysis gives the element the source's facts, so a reference read out of an element derives from wherever the storage came from. Definite assignment treats every part of a struct element as assigned on entry to the body, as it does a copied struct.

The alternatives: copy each element into a local and write it back after the body, which would make items[k] and item disagree inside one iteration and would silently drop a write when the body leaves through break; hand out a pointer and require item.val, which contradicts [1160]; or desugar the loop into an index loop over source nodes, which invents source that was not written. All were declined.

Pinned by runtime/for-collection-traversal, negative/for-collection-element-read-only, negative/for-source-not-traversable, negative/for-iterable-missing-conformance, and the control.loops guarantee row.

D178 — Aggregate traversal elements keep their storage shape

The tour said that a fixed array's element type is part of its structural identity [0520], that a slice carries its element type and permission [0570], and that collection traversal binds an element place [1150] [1160]. D160 enabled scalar, pointer, atom, function and ordinary-struct elements but left fixed-array, slice and any elements together behind L0304. It did not require those three runtime representations to advance together.

Chosen: the next collection-traversal increment enables an element whose type is a fixed array or slice. The containing fixed array records the complete immediate element shape: an inner fixed array retains its length, scalar or nominal element and nominal identity; an inner slice retains its full reference descriptor. A slice source already carries the equivalent descriptor. The element binding receives that shape before its body is checked, and definite assignment treats the complete fixed-array value or the two slice cells as assigned on every entered iteration.

D160's source and control rules do not change. The collection expression runs once, the hidden usize counter visits addresses in increasing index order, and the binding remains an alias to the selected storage for the complete body. Replacing a whole fixed-array or slice element requires the write permission of the containing collection. Indexing through a slice element separately follows the mut permission carried by that inner slice. continue, labelled or unlabelled break, natural complete, and lexical cleanup retain their D157 and D158 edges.

A break with may copy the fixed-array value or the two-cell slice descriptor from the current alias into the caller-owned loop destination before cleanup. Target-neutral lowering represents the runtime alias with the existing address-shaped slot. A computed scalar index below a fixed-array alias forms an address and uses the existing indirect load or store; recursive neutral shape transport handles the complete fixed-array copy. No new IR operation, verifier rule, backend-only type fact or host-width query is introduced.

An any element and a struct or any source requiring [1320]'s iterable evidence remain the named refusal, L0304. They need erased element identity or evidence-driven value production, neither of which is implied by the fixed-size storage shapes enabled here.

The alternatives: copy an aggregate element into a detached local, flatten an inner array or slice into a scalar placeholder, enable any by treating its two cells as a slice, or invoke iterable evidence during lowering. Those choices lose element aliasing, lose structural identity or permission, confuse two unrelated two-cell representations, or bypass the checked evidence call. All were declined.

Pinned by runtime/fixed-array-reference-shapes, runtime/for-aggregate-element-traversal, negative/for-array-element-read-only, runtime/for-any-element-traversal, the retained negative/for-iterable-missing-conformance, and the control.loops guarantee row.

D179 — An any traversal element keeps erased identity and evidence

The tour said that collection traversal binds an alias to an element of a fixed array or slice [1150] [1160], and that any C is one erased data pointer paired with evidence for exactly C [1370] [1390]. D178 deliberately left that element type separate from fixed-array and slice elements: the same two-word size did not make an any a slice.

Chosen: a collection traversal admits an any C element. A containing fixed array records C in the target-neutral descriptor for its repeated element; a slice already records C in its referent descriptor. The loop binding receives that exact concept identity before its body is checked and aliases the complete two-word element in the selected storage. Dynamic entry selection therefore reads the element's data pointer and its own evidence table, including when one collection holds values erased from different concrete types.

D160's evaluation, permission and control rules remain unchanged. A computed slice source is formed once before its base and length are saved. The hidden usize index still advances in storage order. Replacing an element requires a writable slice or assignable fixed array; reading and dispatch through a read-only slice remains valid. continue, break, natural complete and lexical cleanup keep their existing edges. A break with copies both any cells into the caller-owned loop destination before cleanup, so the result keeps the selected erased identity and evidence.

The address-shaped alias and the existing two-cell storage-copy path are representation mechanisms only. No operation interprets an any data pointer as a slice base, interprets evidence as a length, or admits any C itself as a collection source. A struct or any source requiring [1320]'s iterable evidence remains the named refusal, L0304.

The alternatives: copy the element into a detached local, infer C again from the data pointer, treat the pair as a slice, or enable evidence-driven sources at the same time. Those choices respectively lose element aliasing, discard the erased identity, confuse unrelated representations, or couple a storage walk to an unimplemented evidence call. All were declined.

Pinned by runtime/fixed-array-any-shapes, runtime/for-any-element-traversal, negative/for-any-element-read-only, the retained runtime/for-iterable-evidence-traversal, and the control.loops guarantee row.

D180 — Struct and erased sources traverse through exact iterable evidence

The tour said that traversal uses [1320]'s iterable concept [1150], that its item result makes a non-storage element binding a copy [1160], and that evidence tables follow concept declaration order [1310]. D160--D179 had only enabled direct fixed-array and slice storage. Treating an any C source as the other existing two-cell carrier would instead confuse erased data and evidence with a slice base and length.

Chosen: the next collection-traversal increment admits a source whose type is a struct or any C when there is one unambiguous concept named iterable and exactly one conformance to it iterable supplies two associated type inputs and [1320]'s four entries in that order. The entries have the exact infallible signatures shown at [1320]: no convention, permission, error-set, result-origin, cursor identity, Item identity, or erased concept is inferred or converted. Conformance arguments remain label-addressed, while the retained provider table and calls remain in concept declaration order. Missing, multiple, malformed, or non-exact evidence is L0348.

Amended for fallible traversal: the infallible contract above remains exact. try for first seeks one conformance to the unambiguous concept named fallible_iterable, with type formals T, Cur, Item, and Errors and the same four ordered entries. Errors is an atom set, and every entry declares that exact set after !. The provider result, cursor, permission, convention and origin rules above still apply. If no fallible conformance exists, try for may use an ordinary iterable; plain for cannot select a fallible conformance. Missing, ambiguous, malformed, or non-exact evidence is L0348.

The source is still evaluated once. A failure from first, at_end, item or next propagates its original error atom after applicable defer and undo cleanup. It skips all later provider calls and never enters complete. A failure from next occurs after the body and its cleanup, before the next head. The enclosing function must declare or infer those atoms, and its caller may recover them through the ordinary call else. This makes the implicit provider calls visible at the loop site without changing ordinary call error handling.

The source expression is evaluated once and copied into independent traversal storage. Every provider receives a read-only ptr T to that same stored value; there is no further source-sized copy at provider entry. The pointer is non-escaping under [0780], and providers cannot write through it. first runs once against that stored source. Each head calls at_end; false calls item and copies its result into the immutable element binding. Body fallthrough or continue runs applicable cleanup, calls next, copies the returned cursor into the retained cursor, advances the optional immutable usize index, and tests again. break runs applicable cleanup but does not call next; natural completion alone enters complete. Aggregate, fixed-array, slice and any cursors and Items retain their complete checked identity. Aggregate cursor replacement uses separate result and retained storage, so a provider never receives an aliased input/output cursor. An any Item and an any loop result copy both erased cells.

Because [1320]'s item result has no from, its binding has no source-derived origin; an implementation returning such a reference must satisfy the ordinary exact result-origin rule at its own declaration. Assigning to the copied binding is L0303. The stored source is passed as [1320]'s read-only pointer parameter, so no traversal call obtains a new write permission. Ranges and direct array/slice traversal retain D159--D160 and D178--D179 unchanged. In particular, an any C source remains a data/evidence pair for C through every provider call and is never decoded as a slice. Its pointer refers to the retained two-word erased value, not the represented object.

The alternatives: pass the source by value on every call, choose the first conformance in source order, derive Cur or Item from provider bodies, share an aggregate cursor's result and input storage, make Item an alias, call next before cleanup, or reinterpret any as a slice. Those choices respectively require source-sized callee copies on each loop step even when providers only inspect the source, make declaration order semantic, lose associated-type identity, permit hidden result/input aliasing, contradict [1160], move effects across a loop edge, or confuse unrelated representations. All were declined.

Pinned by runtime/for-iterable-evidence-traversal, runtime/for-fallible-iteration, negative/for-fallible-requires-try, negative/for-fallible-undeclared-error, negative/for-iterable-ambiguous-evidence, negative/for-iterable-item-read-only, negative/for-iterable-missing-conformance, retained range and collection runtime fixtures, and the control.loops guarantee row.

D185 — A condition binding belongs only to the body it guards

The tour said that a declaration is allowed in a condition and is a plain type error unless it is bool [1070]. It showed only the inferred if form. It did not say whether a typed or mutable binding is admitted, whether elsif and while use the same form, which scopes see the name, whether the name is visible in its own initializer, or when a loop initializes it again.

Chosen: if, every elsif, and while accept either initialized binding form: mut? name := expression or mut? name : type = expression. A binding with no initializer is not a condition. The initializer is evaluated in the enclosing scope before the new name exists. Its result initializes the ordinary local binding, and that stored value is the condition; after ordinary binding checking it must have the exact type bool, with L0301 otherwise. The binding is definitely assigned on entry to the guarded body.

The binding shares that one body's lexical scope. It is visible throughout the body but not in a later elsif condition or body, an else, a loop's complete, or any following statement. It may shadow an enclosing name under [1850], while another declaration of that name in the guarded body is a same-scope L0200 duplicate. Each condition arm has its own such scope, so the same spelling may independently be declared by sibling conditions. A while evaluates the initializer, stores the binding, and tests it at every visit to the loop head, including after continue; its false edge reaches complete without exporting the binding. Plain expression conditions and exit when guards are unchanged. An unconditional loop has no condition to declare in.

Lowering needs no declaration-expression or loop opcode. The existing Binding node occupies the condition slot, resolution installs it in the guarded Block's scope after resolving its initializer, checking applies the ordinary binding rules before the bool requirement, and lowering stores the initializer in its ordinary local slot before emitting the existing CFG branch.

The alternatives: limiting the form to the one inferred if example would make equivalent condition positions and binding spellings disagree. Extending one binding across later arms, else, or complete would make sibling control paths share a name whose initializer may never have run. Giving the binding a scope nested inside its guarded body would permit an immediate redeclaration to hide it and would require a scope with no source block. Treating the name as visible in its initializer would reverse [0110]. All were declined.

Pinned by positive/condition-declarations, negative/condition-declaration-body-shadowing, negative/condition-declaration-not-bool, negative/condition-declaration-out-of-scope, runtime/condition-declarations, the generated lexical and IR records, and the control.flow guarantee row.

D187 — An unchecked region removes only the edges with one meaning everywhere

The tour said that [1120]'s checks may be switched off for a region, visibly, and [1720] said the region was not implemented first because what an optimiser may then assume should wait for a compiler that can be measured. It did not say which checks go, which stay, how the region is spelled or closed, whether it is an expression, whether it reaches through a call, or what a removed check leaves in place of the value it was guarding.

Chosen: unchecked begin ... end unchecked is a statement and a lexical block with its own scope. D225 supersedes this decision's original contextual spelling: unchecked and begin are now reserved by [1760], so neither can name a binding or label. The region is not an expression, it has no counter-word, and nesting one inside another says nothing new.

Inside it, and only for instructions lowered from what is lexically inside it, the compiler emits no overflow edge for integer +, -, * and unary -, no element-index or slice-range edge for arrays and slices, and no destination-range edge for an integer-to-integer or pointer-to-integer conversion. A removed overflow edge leaves exactly [0320]'s two's-complement wrapping result; a removed conversion edge leaves the low-order bits of the source's representation; a removed bound edge leaves the access at the computed address, which is [0430]'s existing pointer non-guarantee and nothing worse. arithmetic.total is unchanged: the wrapping operators already mean this, and the region only makes the checked ones agree with them.

Membership follows one rule: a check is removable when, on every target Landin describes, the operation without it has one stated behaviour and that behaviour produces only values the destination type holds. That excludes division and remainder by zero and signed-division overflow, because x86-64 faults and Cortex-M does not; a negative shift count, because x86-64 masks and ARM saturates; every conversion to bool, because [1870] fixes bool's zero-or-one image; every float conversion, because an out-of-range IEEE-to-integer result is a target instruction artefact; and [0600]/[0610]'s text boundary edges, because D181's validated view is what makes D184's decoder infallible and a non-boundary utf8 is not a value the type holds. Those text edges are emitted through the same slice-address operation as an ordinary bound, so lowering marks them required where it emits them.

Everything in D148's static class stays, without exception: types, definite assignment [1900] [1910], reference permission [0430], origins and escape [0770]--[0840], consumption [0910], exhaustiveness, declared errors [0940] and [1950]'s known-value refusals. The region is lexical and never dynamic — a call made from inside it enters a callee checked as that callee is written, and an anonymous function body [1010] written inside it is a separate item whose region depth starts at zero, because a function value runs where it is called and the region's visibility claim would otherwise be false at that call site. The region grants an optimiser nothing: it emits fewer checks and makes no fact available to a later pass. D211 preserves that rule under optimization, and the Darwin arm64 and Cortex-M0 targets keep it as Linux x86-64 does.

Cleanup is the one place the compiler emits an instruction for source written somewhere else, so lexical has to be said of it in particular: a [1100] defer or [1110] undo call is checked as its registration is written and never as the exit that reaches it. A return, break or fail inside a region keeps every edge of a cleanup argument registered outside one, and a registration written inside a region is reached by it as any other statement of it is. The alternative — the mode of whichever exit happened to run the call — would make one defer mean two things depending on which line left the function, which is the opposite of a word whose claim is meant to be readable where it stands.

The neutral IR carries this as one Boolean on an instruction, set only where the membership rule above holds, and the verifier refuses it anywhere else and inside [1940]'s module value. That rule reads an instruction's types and not only its opcode: a float +, -, * or unary - carries no overflow edge to remove, and a conversion carries a removable destination-range edge only from an integer or a pointer to an integer, so none of those is marked. The flag therefore says what it is named for wherever a backend reads it, instead of being true of instructions the Linux backend happens to decide before consulting it and the next backend would not. The recorded IR renders it, because an edge that is not emitted is otherwise invisible in a dump.

The alternatives: this decision originally retained contextual spelling; D225 later reserves unchecked with the other control words to remove their name ambiguity. Making the region an expression would add a fourth block form to [1810]'s list, which names only if, match and bare begin. A dynamic region reaching through calls would make the word's claim unreadable at the place it is written and would need a second lowering of every callee. A counter-word re-enabling checks inside a region would make the outer word mean less than it says, and [1120] spells none. Removing the divisor, shift, bool, float and text edges would make the same source mean different things on the Darwin arm64 and Cortex-M0 targets, whose parity with Linux was to be proved rather than assumed. Letting the region license an optimiser assumption is [1720]'s open question and not this one. All were declined.

Pinned by positive/unchecked-regions, positive/unchecked-marks-only-the-edges-it-removes, runtime/unchecked-arithmetic-wraps, runtime/unchecked-integer-conversion-truncates, runtime/unchecked-slice-index-passes-the-length, runtime/checks-return-after-the-region, runtime/unchecked-does-not-cross-a-call, runtime/unchecked-does-not-reach-an-anonymous-body, runtime/unchecked-keeps-the-divisor-check, runtime/unchecked-keeps-the-shift-check, runtime/unchecked-keeps-text-boundary-traps, runtime/unchecked-keeps-bool-conversion-traps, runtime/unchecked-keeps-float-conversion-traps, runtime/unchecked-pointer-conversion-truncates, runtime/unchecked-does-not-reach-an-outer-cleanup, runtime/unchecked-reaches-a-cleanup-written-inside, negative/unchecked-keeps-a-known-index, negative/unchecked-keeps-permissions, negative/unchecked-keeps-definite-assignment, negative/unchecked-region-end-name-mismatch, the generated lexical and IR records, and the unchecked.region guarantee row.

D234 — A labelled bare block is left by a break that names it

The tour said that labels use the ordinary name form on loops and bare blocks only, and that break and continue take one [1180]; [1090] showed only the unlabelled block. D157 retained loop labels on loop syntax and on each targeted transfer. A labelled block was outside the grammar: scope: begin parsed as a binding and its end closed the enclosing function, a defect a review found, and break scope met L0110.

Chosen: labeled_block ::= identifier ":" "begin" block "end" identifier is a statement. Its closer repeats the label with the same diagnostics a labelled loop's closer has. break name, with or without when, targets the nearest enclosing loop or labelled block carrying that name — equal nested labels resolve to the nearest, as D157 already does for loops — and control continues after the block's end name. Every scope the transfer leaves runs its applicable cleanup exactly as a loop break runs it: [1100]'s defer entries run innermost first and [1110]'s undo does not, and a loop crossed on the way out is left without its complete. An unlabelled break or continue still targets the innermost loop; a labelled block never captures one. The label is retained on the block node and on the transfer, like D157's, and lowering reuses the loop exit edge and cleanup boundary: no IR instruction, backend or debug-information change.

Three refusals keep the construct a statement. continue name naming a block is L0110, because a block has no next iteration. break name with v targeting a block is L0332, the report a value given to a statement loop gets. A labelled block in expression position is L0102. The reason is that a label exists only to be left early by break name, [1190] makes break with the value of a search loop rather than of a block, and a block expression (D125) gets its value from its final expression, which an early exit would skip.

Definite assignment after a labelled block is the meet of its fallthrough and every edge leaving it by break; unlike a loop, an assignment in the body is not held back, because the body runs once. The reference-origin and borrow checks merge the same edges; the check that a borrowed view is not read after a mutating call now assumes any break may resume after the block's end, which can only report more.

The alternatives: a labelled block that yields break name with v, as in languages whose blocks are search expressions, was declined because [1190] already gives that job to loops and a second value exit would duplicate D158's join for no program that needed it. Removing labels from bare blocks was declined under the inherited rule that a program not needing a construct is evidence, not automatic removal; the construct costs no new IR. Letting an unlabelled break leave the innermost labelled block was declined because it would change what every existing break inside a labelled block means.

Pinned by positive/r720-labelled-bare-blocks, runtime/r720-labelled-block-transfers, negative/r720-labelled-block-break-value, negative/r720-labelled-block-partial-assignment, negative/r720-labelled-block-break-origin, negative/r720-labelled-block-borrow-after-break, negative/r720-labelled-block-not-an-expression, the driver case labelled block refusals for the closer and continue reports, and the control.loops guarantee row.

DECISIONS: CONCEPTS, GENERICS AND RUNTIME DISPATCH

Concepts, the evidence that satisfies them, the instances a generic call deduces, and the erased pair behind any.

D135 — Parameterized type declarations collect their formals before their bodies

The tour said that type and fixed parameters are compile-time [1290], that a type takes them through its own declaration rather than a function [1350], and that fixed marks compile-time knowledge [1490]. It did not settle the binder spelling, the scope that owns those names, or whether textual order could make a fixed formal's declared type resolve differently.

Chosen: a parameterized type declaration is written name: type (t: type, fixed n: u32) = rhs, with fixed before its name. fixed is reserved. Its arguments are positional: a type application is name(type_argument, ...), where an argument is a type or an integer for a fixed formal. A fixed formal may supply an array bound, so [n]t is an alias body. The grammar admits that formal list before an alias type, atom-union body or struct body. The hosted-parity audit closed the earlier parameterized atom-union exclusion by applying the existing structural-set and alias-substitution rules. D142 later adds one direct concept constraint to a type formal without changing this positional substitution. The same compile-time-only binders are admitted in declared-routine syntax and resolution; D138 enables exact direct-call deduction, and D139 separately enables target-selected module declaration lists.

One type-declaration scope contains all of the formals. The resolver collects the complete formal list into that scope before it resolves any fixed formal's declared type or the declaration right-hand side. Thus a formal may name one written later, but the formals do not escape to the module or another declaration.

Union members are normalized recursively under the current substitution, including declared atom singletons, qualified names and fully applied aliases. Repeated atoms and source order do not change the interned structural set. Symbolic declaration checking validates independent members while leaving the result undecided; it never invents a partial atom-set key or records a concrete instance answer on template syntax. Proven pointer presence and up to two distinct atom identities survive symbolic alias substitution solely as diagnostic lower bounds, so unconditional pointer-count and tagged-pointer violations are refused even in unused declarations. An invalid concrete substitution names its application as the primary source and its template member as the related source. The resulting alias participates in the ordinary error-set, assignment and generic-key rules. A one-atom pointer union uses D189's existing descriptor, including the empty atom of a substituted optional-pointer alias. Two pointer members are still refused. Two or more atoms beside a pointer were refused by name here; D235 later gives them its two-cell union, including through a parameterized alias such as opt(t) = a | b | ptr t.

A fully applied alias is normalized during checking. Its enabled result is a scalar, fixed-array, atom-set, pointer or nominal aggregate descriptor; an alias around a parameterized struct instance keeps that instance's identity rather than introducing another one. A fully applied struct instead interns D137's nominal instance. A struct type formal accepts every enabled concrete identity: scalar, structural atom set, exact fixed array, nominal instance or structural function signature. The substituted field or payload position then decides whether that identity is legal there. A fixed formal has an integer type and accepts an integer literal; a nested application may forward its caller's fixed formal. Substitution therefore covers fixed bounds and every concrete field and payload shape the ordinary struct already admits.

A parameterized declaration named without arguments, an application with the wrong arity or argument kind, a fixed actual outside its declared integer type, a bound outside D136's fixed-expression forms, and recursive alias expansion are refused. The substituted extent of an array or nominal instance must fit the target usize. The declaration, its body and its formals are a compile-time template: formals have no runtime type, IR slot or ABI position, and no instantiation writes a type, length, layout or other per-application metadata onto a template syntax node.

A template is still a declaration and is validated even when never applied. The checker uses symbolic formals, not a guessed instantiation, to reject an unresolved or non-type free name, a fixed formal whose declared type is decidably non-integer, an unsupported decidable field or alias-result shape, duplicate field or case names, an unconditional alias-expansion cycle and D137's unconditional by-value nominal recursion. A question whose answer genuinely depends on an actual remains for application checking. Its primary is the application and its related label is the template field or expression; two distinct bad applications therefore remain distinct. Declaration order does not move an unconditional defect onto an outer application.

Why one declaration scope: resolving while reading would make a correct alias depend on its formal order, while making each formal a module declaration would leak its name and create collisions unrelated aliases cannot share. A function-shaped type maker would instead introduce execution where [1350] requires substitution. All were declined.

Pinned by negative/r490-union-alias-application-reports, negative/r490-union-alias-unused-pointer-shapes, positive/parameterized-atom-union, runtime/r490-generic-union-alias, negative/r490-union-alias-nonatom, negative/r490-union-alias-direct-array, negative/r490-union-alias-unused-nonatom, negative/r490-union-alias-two-pointers, positive/r490-union-alias-tagged-pointer, positive/r490-union-alias-optional-widening, positive/r490-union-concrete-optional-widening, negative/r490-union-alias-deduction-conflict, the checking case union aliases keep exact instance keys, and the parameterized-alias and parameterized-struct parser and resolution public-seam cases; the checking and lowering public-seam cases; positive/parameterized-type-alias-scalar, positive/parameterized-type-alias-fixed-array; the repository core/vec module and runtime/core-vec-pointer-storage; the positive/parameterized-struct-basic, positive/parameterized-struct-instances; the negative/parameterized-alias-*, negative/parameterized-struct-* and negative/nominal-struct-recursive-layout fixtures; the generated lexical, construct and IR records; and runtime/parameterized-type-alias-fixed-array and runtime/parameterized-struct-values on Linux x86-64.

D137 — A parameterized struct application is one canonical nominal instance

The tour said that ordinary structs are nominal [0710], that type and fixed parameters are compile-time substitution [1290] [1350], and that target layout is not host type identity [0750]. It did not say whether two applications of one struct declaration are the same nominal type, whether an unused formal participates, or where the instantiated field shape lives.

Chosen: a fully applied struct interns one checker-owned identity keyed by the source template declaration and the complete ordered tuple of normalized actuals. Aliases are erased before they enter the tuple. Scalar identities, structural atom sets, exact fixed arrays including nominal elements, nominal instances, structural function signatures and mathematical fixed magnitudes are the only key forms. Equal keys reuse one identity. A different actual or template remains a different nominal type even when every field, byte of layout, and used formal is otherwise equal. Identity is target-independent. Normalizing a nominal identity for a function-signature part or type-actual key does not request that identity's layout. When a formal carrying that descriptor is later substituted into a by-value field, payload or nominal array element, the checker reconstructs the binding from the interned template and actual tuple and materializes the required layout then. This promotion is recursive through nested nominal and nominal-array actuals, checks D18 at that value use, and treats a currently building identity as L0313. It applies even to an element of a zero-length array.

The checker substitutes the tuple while walking the source body and builds one layout for that canonical instance against the selected target when a value site requires it. Scalar, function, fixed-array, ordinary-child and existing variant payload shapes use the same field descriptors and contextual value paths as a nonparameterized struct. The body and formal nodes receive no instantiated answer, no synthetic declaration is created, and the template and its formals create no IR item, slot or ABI position. Lowering maps only concrete nominal identities and their instantiated neutral shape trees.

Every template is first walked symbolically. An identity-only nonconcrete struct or nominal-array actual retains a transient obligation containing its source template and symbolic binding run rather than collapsing to an unqualified unknown. If another template substitutes that obligation at a by-value position, the checker follows it through any number of used-formal wrappers; reaching an active nominal obligation is L0313. The obligation is local to declaration validation: it interns no guessed actual, writes no AST metadata and disappears with the checking run. A plain unused formal, phantom actual or function-signature mention never promotes it. Free names, decidable fixed-formal and field-shape errors, duplicate fields and cases, and unconditional by-value recursion are therefore rejected even when no instance is requested. A truly actual-dependent failure is primary at each application and relates the field or expression in the template. An invalid layout state stores no application provenance. The checking run caches the dependent diagnostics from the first failed layout attempt for a canonical key and gives each repeated use its own primary at that application's source span without walking the template body again. An attempt with no application provenance may be retried when a later application needs a site-specific primary. The key retains one identity and tuple. Fixed actuals remain integer literals or forwarded fixed formals. Parameterized atom unions are enabled under D135's structural-set and alias-substitution rules; its later hosted-parity audit superseded this decision's earlier deferral. D138 and D139 separately define generic routine instances and fixed conditional module declarations.

An alias expansion that reaches no type remains L0307. A nominal field, nominal array element or variant payload that would require a finite instance to contain itself by value is instead L0313, whether the cycle crosses aliases or templates. Function-signature references do not form such a value-layout edge: a function field is the already enabled one-usize carrier. This applies to parameter and result positions, recursively nested function signatures, and ordinary nonparameterized structs as well as parameterized instances. An ordinary signature lookup may therefore take the canonical empty-actual nominal identity before that struct's layout is ready and follows ordinary alias chains without settling them by value. Mutually recursive ordinary structs connected only by such signature references each have a finite pointer-carrier layout, independent of declaration order. When a declared or anonymous routine's multiple named results form D128's caller-owned aggregate, its direct result parts materialize before their target placement is measured; that ABI use does not promote a nested callback signature into a by-value edge. A failed application remains cached at its syntax node, so one written application has one primary while a second written application receives the canonical failure's diagnostic with its own primary. A zero-length nominal array at a field or payload still validates its element identity and is not an escape from the recursion rule.

Why the complete tuple: dropping an unused actual makes adding the first field that uses it silently change existing type identity. Structuralizing the instantiated body makes two declarations equal contrary to [0710]. Putting layout in the key makes a source type change with the selected target. Mutating the AST or synthesizing declarations makes one application overwrite another or leak compile-time binders into runtime representation. All were declined.

Pinned by the checking, lowering and verifier public-seam cases; positive/parameterized-struct-basic, positive/parameterized-struct-instances, positive/parameterized-struct-identity-only, positive/parameterized-struct-lazy-value-layout; positive/ordinary-struct-function-signature-recursion, positive/ordinary-struct-function-signature-alias-first, positive/ordinary-struct-function-signature-alias-last, the two positive/ordinary-struct-mutual-function-signatures-* order fixtures, and positive/multiple-named-generic-nominal-results; the negative/parameterized-struct-* (including the unused indirect, mutual and multi-wrapper recursion cases) and negative/nominal-struct-recursive-layout fixtures; the generated IR and diagnostic catalogue; and runtime/parameterized-struct-values and runtime/parameterized-struct-lazy-value-layout on Linux x86-64.

D138 — Direct generic calls deduce one checker-owned routine instance

The tour said that type and fixed parameters are compile-time-only [1290], that a call supplies runtime arguments [1920], and that specialization is an implementation choice rather than generic meaning [1350]. It did not say where facts about two concrete uses of one routine body live or which context may participate in deduction.

Chosen: a generic routine template has no standalone function value or IR item. A direct call first synthesizes each runtime argument without an expected parameter type. A context-free integer literal therefore takes [0200]'s i32. The checker then recursively unifies each written runtime parameter pattern with that independently synthesized normalized descriptor. Scalar and atom-set constants agree exactly. A direct type formal binds the complete scalar, structural atom-set, fixed-array, nominal, pointer/slice reference, any-concept or concrete function-signature descriptor; every repeat must agree exactly.

A pointer or slice pattern first matches its reference kind and ordinary view, then recursively matches its complete referent descriptor. When that written pattern is the outer runtime parameter type, a mutable argument may satisfy a read-only pointer or slice pattern under [0440]; the specialized parameter remains read-only. Permission in nested patterns still matches exactly, and a read-only argument never satisfies a mutable pattern. Deduction does not treat a text view or pointer union as an ordinary reference. Referent identity includes nested references, nominal identity, fixed-array extent, function signature and erased concept as applicable. A direct formal or stored nominal actual containing any C agrees only with that same C.

A fixed-array pattern recursively matches its exact element descriptor and bound. A direct fixed formal in the bound binds the argument length. A computed D136 bound never contributes an equation to solve: the checker defers it until another direct occurrence or an explicit static tuple has bound every formal it references, then folds and compares the result exactly. A formal that occurs only inside n * 2 or another computed expression remains undeduced. Nominal elements participate by identity. Pointer and slice elements retain their permission and complete referent descriptor; an any C element retains C. Fixed-array referents, generic actuals, results and stored fields carry the same immediate element shape. A shared target size never makes two element types equal; D178 and D179's existing stored-shape paths also apply through these positions.

A parameterized nominal pattern requires an argument instance interned from the same source template, then recursively matches every stored normalized actual in declaration order. This includes phantom type and fixed actuals that do not appear in the struct body. Ordinary aliases erase consistently; a parameterized alias pattern is expanded symbolically and its result is unified without inventing an actual. A function-signature pattern recursively matches parameter and result counts and types plus its infallible, concrete or still-inferred error form; parameter and result labels do not participate [1000]. A nested type formal may therefore bind from a nominal actual tuple, fixed-array element, function parameter, function result, reference referent or concrete function error set.

Validation of a parameterized struct leaves a field written ptr T or ptr mut T symbolic when T is still a type formal. Each concrete application then constructs the ordinary complete pointer descriptor, retaining the exact referent descriptor and permission; scalar, pointer and any C actuals are not collapsed into one placeholder reference type.

Every static formal must be bound. Deduction uses no return context, conversion, constraint search, arithmetic inversion or user-code execution. A call either leaves all static formals for deduction or names every type/fixed formal in its one named call list; a partial explicit tuple is refused. A saturated explicit static tuple bypasses binding and runs the same recursive walk as exact validation. Type actuals are resolved as type views, while a fixed actual is an integer literal or a forwarded caller fixed formal and must fit its substituted declared integer type. Fixed ranges are validated after the complete tuple is known. After deduction or explicit saturation, substitution builds the concrete runtime signature and ordinary call checking applies that signature. A generic routine may write a concrete declared atom error set; substitution carries it on the instance signature and bounds callers exactly like an ordinary declared set. For private ! ..., the template itself still has no signature. Each concrete routine identity instead publishes an initially inferred signature, then contributes its directly failed atoms and its instance-view call targets to the whole-program least fixed point. Calls from or to ordinary routines and same- or different-key generic instances use one graph; direct and mutual same-key recursion therefore close without syntax recursion. try, recovery and inference all resolve a call through the active view's recorded instance target rather than the deliberately absent template signature. Equal keys share one inferred set, while unequal keys retain separate signatures and may settle to different sets. An empty result becomes infallible; a nonempty result becomes a concrete atom set before body checking resumes and before lowering. Call recovery, try, fail, defer, and undo then use only that finalized ordinary descriptor. D215 closes error inference and generic discovery together: a recovered atom set and its aliases become deduction inputs only after their component's effects are complete. New instances may expose further components; the final inventory is frozen only after this frontier closes. A circular key/effect dependency that cannot supply a complete actual is L0340, without a provisional atom set or instance key.

The checker interns an opaque routine identity from the source template and complete normalized actual tuple. Equal keys reuse one identity; unequal keys remain distinct. The instance publishes its substituted signature before its body is checked, so recursion at the same key is legal. Re-entering the same active template with a different tuple is refused as non-finite expansion. Each instance owns a layered fact view keyed by that identity and the original source declaration or node. An unwritten fact falls back to module and nongeneric facts, while writes remain in that one view; no instance answer is put on syntax and no AST is cloned or synthesized. Template defects independent of actuals, including an impossible literal operand, are checked without a guessed instance; dependent operations wait for a concrete view.

Lowering selects that same view and creates one deterministic local routine item per ready identity in checker interning order. A generic call records its target identity in its caller's view, so nested and recursive calls remain stable. The template, type formals and fixed formals create no item, slot, runtime signature part or ABI position. This executable increment carries every enabled direct-formal descriptor through routine parameters, results, locals and calls, including atom sets, function signatures and nominal aggregate transport/layout. Recursive structural deduction changes no descriptor, transport, layout or ABI rule: static arguments have no runtime synthesis, flow fact, cleanup or ABI position, and lowering maps only written runtime arguments to runtime formals. A fixed formal used as an expression in the concrete body has its declared integer type and lowers to the instance actual as a target-neutral constant; it is not a slot or hidden parameter. A direct type formal still cannot bind a function descriptor whose error graph is currently inferred, because it is not yet a complete actual key. A generic template itself remains unavailable as a function value: only a direct call chooses the concrete instance signature.

Why an instance view: writing t = u8 on the template declaration or its nodes makes a later t = i32 call overwrite the first. Resetting shared tables around a recursive walk makes nested instances depend on traversal order. Cloning syntax invents declarations and provenance for a compile-time substitution. A checker-owned identity plus overlay avoids all three.

Pinned by the checking public-seam case routine instance views keep source facts, the lowering case generic routines lower once per key, negative/generic-routine-repeated-deduction-conflict, negative/generic-routine-undeduced-formal, negative/generic-routine-infinite-expansion, negative/generic-inferred-error-unhandled, negative/generic-inferred-template-not-function-value, negative/generic-try-infallible-instance, negative/generic-routine-unused-unconditional-defect, negative/generic-computed-pattern-undeduced, negative/generic-explicit-computed-pattern-mismatch, negative/generic-structural-repeated-conflict, negative/generic-wrong-nominal-template, positive/generic-structural-deduction, positive/generic-zero-nominal-array-signatures, negative/generic-reference-field-permission-distinct, runtime/core-mem-raw-storage, and runtime/generic-identity-deduction, runtime/generic-fixed-array-deduction, runtime/generic-direct-descriptor-deduction, runtime/generic-reference-results, runtime/generic-reference-carriers, runtime/generic-any-nominal-transport, negative/generic-any-nominal-deduction-conflict, negative/generic-reference-nested-permission, negative/generic-reference-referent-identity, negative/generic-reference-array-extent, negative/generic-reference-pattern-permission, negative/generic-reference-result-frame, negative/generic-reference-result-wrong-from, negative/generic-reference-result-immutable, negative/generic-reference-result-escaping, negative/generic-reference-carrier-live-view, negative/generic-any-carrier-frame-escape, negative/generic-slice-field-permission, negative/generic-slice-field-wrong-from, runtime/generic-structural-deduction, runtime/generic-zero-nominal-array-signatures, runtime/generic-declared-errors, runtime/generic-routine-inferred-errors, runtime/generic-try-effective-signature, runtime/generic-same-key-recursion, runtime/r420-small-vector, and runtime/diagnostic-loggers-dispatch on Linux x86-64. The malformed-error verifier case uses a generic-instance item to pin that only the finalized concrete signature and ordinary failure opcode reach neutral IR.

D142 — Concepts and conformances are collected before constrained instantiation

The tour said that a concept is a named requirement bundle [1230], a conformance registers a type [1240], a leading binder quantifies a parameterized type [1250], the key is (type, concept, input types) [1270], and every collision is an error [1280]. It did not settle the enabled grammar, the scopes, how an uninstantiated parameterized collision is found, or where a constraint lookup is performed without already having a generic evidence table.

Chosen: concept and is are contextual words. A concept declaration carries one nonempty collected type-formal list, zero or more direct parent concept names, and an ordered run of named complete function signatures. A concept entry's error set is infallible or concrete, never inferred. A direct is concept_name may constrain a type formal in a type, routine, concept or conformance binder. The concept and conformance scopes collect their complete static binder before resolving any target, input or signature type.

A conformance carries an optional leading type/fixed binder, one target type, one direct concept name, and a labelled run. Labels supply every concept input formal after the represented type and every direct concept entry exactly once. The whole-program key is the normalized represented type, concept identity and ordered normalized input-type tuple; function labels are payload, not key. Concrete supplied functions have exactly the substituted concept signature. Composed concepts require separate conformances to every named parent; having the child never synthesizes a parent.

The program is the closed graph of modules reachable from the entry directory after first-matching ordered-root selection. Every conformance in that graph is collected whether used or public; unreachable directories and later root matches contribute nothing. A conformance declares no module name, so public on one is refused rather than changing registration visibility.

A parameterized conformance quantifies one complete nominal type family. Its target is that declaration fully applied to the binder in the same positional order and kind, with every binder used once. This closed family form covers the container conformances that forced [1250], avoids arithmetic inversion and specialization, and lets collection reject a second family for the same target template and concept even if no generic call requests an instance. A concrete exception under such a family is also a collision. Lookup substitutes the family binder, checks its own constraints, and interns the resulting concrete key. There is no search by return context, conversion, precedence, weak entry, or orphan rule.

Collection retains parameterized supplying functions and the concrete binder tuple selected by lookup. The generic evidence schema turns that retained selection into evidence and validates the substituted generic entry at that ABI boundary (D144); collection emits no table and adds no generic dispatch operation.

Why the family restriction: arbitrary overlapping type patterns require a general unification and specialization order the language has neither stated nor wanted. Silently checking only requested overlaps would contradict [1280]'s whole-program rule. One complete nominal family gives parameterized containers their required quantifier while keeping collision collection finite and independent of use.

The alternative: resolve concepts and conformances in declaration order, or infer a conformance from a type's shape. Order-dependent resolution makes a program's meaning depend on file layout; inference is the structural typing the tour declined at [1340].

Pinned by positive/concepts-and-conformances, positive/parameterized-conformance-lookup, negative/conformance-collision, negative/parameterized-conformance-collision, negative/constraint-not-satisfied, negative/conformance-entry-signature-mismatch, negative/composed-conformance-missing-parent, and negative/concept-composition-cycle, plus parser, resolution and checker register cases.

D143 — zeroable is one closed compiler concept family

The tour said that the compiler alone supplies zeroable conformances because only it knows bit patterns [0550], while [0540] separately distinguishes having a zero image from accepting the contextual word zeroed. It did not say whether zeroable needs a source declaration, whether users may add a missing entry, or how zero-length and nested enabled shapes enter the set.

Chosen: zeroable is the sole compiler concept identity and needs no source declaration. A source declaration cannot impersonate that identity, and every source conformance naming it is L0319: users can neither synthesize a false entry nor override a true one. Lookup supplies a conformance for every enabled scalar; for a fixed array exactly when its element is zeroable, even at length zero; and for a nominal aggregate exactly when its recursively active all-zero field and first-variant-case payload shape has a zero image. Atoms, functions, pointers and slices are outside the family. The algorithm is the same checker predicate that admits an all-zero aggregate image, so contextual zeroed and the generic concept cannot drift.

The set is closed and named. No source query enumerates it, no declaration is synthesized, and no reflection hook asks whether an arbitrary representation happens to be zero. A successful constrained lookup interns only the concrete semantic key for later evidence work.

The alternative: let a source declare its own zeroable conformance, or derive zeroability from sizeof alone. A declared conformance could claim a zero image a type does not have; a size says nothing about pointers, atoms or function values inside it.

Pinned by positive/compiler-zeroable-conformances, negative/nonzeroable-constraint, negative/nonzeroable-zero-length-constraint, negative/compiler-conformance-reserved, the checker register case, and the existing aggregate zero-image fixtures.

D144 — Evidence order is semantic and physical layout is target-derived

The tour said that generic code receives a table of concept functions and that the evidence also carries the represented type's size and alignment [1310]. It did not state table identity, member order, hidden-argument order, composition, the physical cell layout, or how the first backend may share code without making an x86 representation the semantic schema.

Chosen: one evidence identity realizes one concrete D142 conformance key: the normalized represented type, direct concept identity and ordered input-type tuple. Parameterized families materialize only concrete keys selected by lookup; an ordinary collected key may be emitted without waiting for a call. The target-neutral logical run is the represented type's size, its alignment, then every direct concept function in concept declaration order. Conformance labels select providers and never reorder that run. Parent concepts retain the separate conformances D142 requires rather than flattening their entries into a child table. The compiler zeroable conformance consequently has only the two layout members and synthesizes no source provider.

Size is the complete padded target-byte size of one represented value and alignment is that value's target-byte alignment. Both are runtime usize values. A direct function member retains its substituted concrete signature and names the ordinary provider routine or selected generic provider instance; its concrete error set uses D109's existing orthogonal call outcome. The semantic schema contains no byte offset, register, relocation spelling or host-sized integer.

Every physical member is one target pointer-width cell, and the table is aligned to the target pointer alignment. Therefore Linux x86-64 places size, alignment and the first function at offsets 0, 8 and 16, while synthetic-32 places them at 0, 4 and 8. A table with N direct functions occupies (N + 2) * pointer_bytes. Landin.Evidence owns semantic positions; Landin.Targets alone derives these offsets, extent and alignment.

A ready concrete generic instance retains a hidden evidence position only for a table read by a direct constrained member selection in its checked body. Constructing any uses a static erased table and does not select a hidden generic evidence parameter. Selection uses the instance fact view after checking; the compiler keeps the direct table and each distinct table in its represented-formal constraint/parent closure only when that body selects its position. Equal conformance identities belonging to different type formals remain separate positions if the body selects both; selecting only one formal retains only its position. Retained positions follow depth-first concept declaration order within each formal, then generic-formal order. A concrete call supplies exactly that run, even when the caller itself is generic. This preserves D142's separate parent conformances while making inherited entries reachable without flattening a child table. The existing caller-owned aggregate result address remains first, retained evidence pointers follow, and written runtime parameters remain after them in source signature order. A body with no entry selection has no hidden evidence positions. Conformance lookup and checking still require the full constraint closure, independent of this physical run. Static type and fixed formals still create no runtime position. Inside the active routine view, T.entry(...) loads the declaration-order function word from that hidden table and makes the ordinary verified indirect call. D221 requires that selected name to identify one declaration across the distinct closure; the table traversal order grants no name-resolution precedence. Size and alignment remain table members even where the current concrete view answers sizeof T or alignof T directly by resolving the formal through that routine instance's type actual. The node's complete concrete descriptor lives only in the active instance overlay. Later shared and any consumers therefore use the same semantic measurement and provider schema; D147 gives the erased consumer a flattened table view without changing these direct generic offsets.

The Linux baseline may alias two concrete generic symbols to one emitted body only when a bounded IR comparison proves their signatures, slots, operand graph and allowed operations have one physical meaning on that target. Evidence identity may differ because it arrives through the hidden parameter; signed arithmetic, aggregates, static table addresses and every unproved operation prevent folding. A failed sharing proof emits separate concrete bodies and cannot affect source correctness. This is baseline code folding, not the direct-call specialization policy.

The alternatives: putting function words first was viable, but makes the two representation facts every evidence consumer needs a variable-position suffix; the fixed prefix was chosen. Reordering by conformance labels would make source-equivalent labelled payloads ABI-different. Flattening parents would make a child ABI change when a separately registered parent changed. Encoding .quad or eight-byte offsets in IR would turn the first backend into the language definition. Calling providers directly from constrained generic bodies would leave a table that no executed path proved. All were declined.

Pinned by runtime/generic-evidence-indirect, runtime/generic-composed-evidence, runtime/generic-any-construction-evidence, runtime/generic-parameterized-evidence, runtime/allocator-vec-pressure, and negative/parameterized-conformance-entry-signature-mismatch; the target case evidence ordering and layout; the lowering case generic instances keep selected evidence, erased construction adds no hidden evidence, and shared conformance keeps selected formals; the backend case generic evidence is ordered indirect and shared; IR verifier evidence identity, entry and signature checks; and the recorded target and lowering artefacts.

D145 — any C has direct-concept identity and explicit pointer erasure

The tour said that any C is a copyable data-pointer/table pair [1370], that construction is explicit and takes its concept from context where it can [1380], and that calls select table entries [1390]. It did not state whether any is reserved, whether parents imply conversions, how an omitted context is selected, whether a value may be copied into the pair, or how concepts with additional input types are written.

Chosen: any becomes the thirty-fourth reserved kernel word. any C is a structural type whose identity is exactly the direct source Concept_Id of C; aliases preserve it, while parent composition creates no subtype or conversion. The enabled source form admits a concept with exactly its one represented type formal and an empty D142 input tuple. There is no implicit conversion either from a concrete value/pointer or between two any types.

any(pointer) evaluates exactly one pointer expression and never copies the unknown-sized pointee. In a destination, argument or result context, that context supplies C and lookup selects the exact concrete D142 conformance key, materializing a parameterized family and generic provider when needed. Without a context, construction succeeds only when exactly one already collected source concept has an exact conformance for the pointer's referent; zero or multiple candidates require an explicit any C context. Compiler concepts do not participate. The construction node retains its concrete conformance solely so lowering can form a static table address; later copies carry no static concrete type fact. The enabled construction forms runtime storage; a module static image cannot yet carry the two relocations and is refused rather than fabricated.

The alternatives: erasing a by-value object would either copy an unknown size or create hidden storage. Choosing the first conformance by declaration order would make unrelated declarations alter meaning. Treating a parent as an implicit conversion would add concept subtyping the language has never claimed. Encoding input tuples without source syntax would guess part of the D142 key. All were declined.

Pinned by runtime/any-inferred-construction, runtime/any-parameterized-provider, negative/any-source-not-pointer, negative/any-construction-needs-context, and negative/any-concept-identity-mismatch.

D146 — Erased entries have one object-safe self pointer

The tour said that a mutable entry writes self: ptr mut T, that no extra permission marker belongs in the pair [1370], and that dispatch inserts the data pointer first [1390]. It did not bound other occurrences of hidden T, say whether binding mutability gates a call, settle inherited-name collisions, or state how origin analysis sees the pair.

Chosen: every entry exposed by the direct concept's distinct finite represented-formal-constraint/parent closure must have first runtime input parameter named self, of exact direct type ptr T or ptr mut T, where T is that entry's concept's represented formal. inout, sink, ptr ptr T and a parameterized referent that merely contains T are not that receiver ABI. Hidden T may occur nowhere in another runtime parameter or result: a caller that knows only any C has no source type with which to supply or receive it. The concrete provider keeps that substituted ordinary signature. value.entry is only the immediate callee operation; the two-word pair has no bound-method closure representation, so the selection cannot be stored as a standalone function value. An entry name must be unique across the closure when it is selected; an inherited collision is diagnosed rather than receiving source order precedence.

Construction requires its pointer permission to satisfy every exposed self: a read-only pointer cannot create a capability whose table includes mutable self. Once created, the pair needs no permission bit. Binding mutability says whether the two pair words may be replaced; it does not revoke write authority already carried by a valid mutable data pointer, just as an immutable binding may hold a ptr mut T.

The pair is reference-bearing for local origin/escape analysis. Construction copies the complete origin fact of its pointer operand; copies, aggregate storage, control joins, arguments and results carry that fact unchanged or through the existing conservative join. A dynamic call maps implicit formal one to the pair receiver and written argument one to formal two, so escaping, from self, borrow and return checks reuse the ordinary call rules. An integer- created untracked pointer remains untracked rather than regaining evidence.

The alternatives: storing a mutable bit would make the promised pair a third semantic field or give one any C two runtime types. Requiring a mutable pair binding to call a mutable entry would conflate replacement of the pair with authority already inside it. Calling an entry that mentions hidden T elsewhere based on one arbitrary conformance's signature would make another conformance ABI-incompatible. All were declined.

Pinned by runtime/any-heterogeneous-dispatch, runtime/any-return-origin, negative/any-readonly-source-for-mutable-entry, negative/any-entry-not-object-safe, negative/any-entry-not-bound-value, negative/any-self-not-exact, negative/any-self-convention, and negative/any-frame-origin-escape.

D147 — An any pair points at a flattened dispatch table

The tour said that the pair is two words [1370], that calls go through its table with data first [1390], and that erased and generic evidence are one semantic mechanism [1690]. D144 deliberately kept parent conformance tables separate and fixed direct table member offsets, so it did not say how one erased table pointer reaches inherited entries.

Chosen: the target-neutral pair order is data pointer then table pointer. Both are target pointer-width cells, the pair aligns to pointer alignment, and its extent is twice pointer width: data/table offsets are 0/8 and size/alignment 16/8 on Linux x86-64, and 0/4 with 8/4 on synthetic-32. The pair is transported by the existing shaped-value/caller-owned-result ABI and may be copied whole or stored as an aggregate field; neither word is a source-selectable field and zeroed cannot construct it. After D145/D146 checking, target-neutral IR may use the same private two-usize shaped carrier as a slice uses physically, just as it erases a checked pointer to one usize; that carrier creates no source array/index operation, while evidence descriptors and verifier checks still own every table function position and signature.

A concrete conformance used by any receives a distinct erased evidence identity. Its table repeats D144's size/alignment prefix and then flattens object-safe provider function words: direct concept entries first, followed depth-first by each distinct represented-formal constraint and named parent in declaration order. When the represented shape and ordered provider words match the adjacent direct table, both identities label the same physical cells; this includes a parentless conformance. Otherwise the erased table occupies separate cells. The parent conformance identities and their D144 direct tables remain separate; additional flattened entries repeat relocations rather than flattening semantic conformance identity. Consequently D144's generic table offsets remain unchanged; a generic instance's hidden arguments follow its selected evidence run. An inherited call uses its flattened semantic position.

Construction evaluates and stores the data pointer, then stores the selected static flattened-table address. Dispatch loads the pair's table, loads the verified function position, loads the data pointer, and makes the ordinary indirect call with data as runtime argument one and written arguments after it. Concrete provider signatures may differ in the referent identity of self, but D146 proves that this erased position is uniformly one pointer carrier and that every remaining parameter/result has one non-hidden source identity.

The alternatives: adding all parent table pointers to the value would break the two-word representation. Changing D144's direct table suffix would move existing generic ABI positions. Walking parent links would add links and loads while still needing an erased receiver rule. A flattened erased table keeps those concerns separate and was chosen.

Pinned by runtime/any-heterogeneous-dispatch, runtime/any-composed-dispatch, runtime/any-aggregate-storage, the target case evidence ordering and layout, the backend case any dispatch uses a flattened real table, the existing evidence verifier checks, and the generated target/lowering artefacts.

D215 — Error-dependent generic discovery closes before inventory freeze

The tour said that private inferred errors close over callees [0960] and that generic calls deduce their type from their arguments [1300]. D138 requires complete normalized instance keys. The inherited implementation nevertheless froze its signature inventory before the recovered error's type could discover an ordinary generic call. The hosted-parity audit reproduced the resulting compiler defect on the accepted derived hosted application without changing the program's inferred error spelling.

Chosen: error inference and generic discovery advance together. A recovery binding has the finalized complete set of its callee; an inferred local alias retains that type, and neither an unknown type nor a provisional set is cached as its answer. The checker closes effect components whose dependencies are known, then resumes dependent discovery in each caller's own instance view. Equal complete sets share a key; unequal sets retain separate instances. Ordinary and mutual recursive error components, same-key generic recursion, nested recovery, erased-provider discovery and traversal-header deduction use this same process. An undecided local alias is followed to its initializer's effect edge, including inside a recursive component; it need not first be demanded by a generic actual. Contextual erased-provider selection waits for the nominal actual reached through the same initializer dependency. Replayed recovery facts retain the caller's view without issuing an already finalized handler's diagnostic again. Deferred discovery retains its template-expansion ancestry so D138's non-finite different-key expansion refusal cannot be bypassed by recovery.

A circular key/effect dependency is refused with L0340 only after the available inference and discovery frontier stops advancing: completing a generic actual would require the inferred effects of the unresolved instance selected by that actual. The report names the deduction site and the generic declaration. This is the same complete-key boundary as D138's existing refusal of a still-inferred function descriptor as a direct type actual; it does not reject ordinary error recursion or recursive recovery into an infallible generic observer.

The alternatives: guessing an atom set makes an intermediate descriptor part of an instance identity; suppressing the inventory assertion conceals stale graph and cache state; requiring explicit errors everywhere removes an ordinary inferred composition. All are declined. General symbolic evaluation of a generic body to infer its own incomplete key is not part of deduction. Finalized concrete signatures remain the only error representation reaching verified IR, and the final signature-count assertion remains in place.

Pinned by runtime/r490-generic-inferred-recovery, runtime/r490-generic-recovery-frontier, runtime/r490-generic-alias-rethrow, runtime/r490-generic-recursive-alias, runtime/r490-generic-recovery-alias-chains, runtime/r490-generic-erased-recovery, runtime/r490-generic-erased-recovery-views, negative/r480-nested-infallible-recovery, runtime/r480-concrete-error-deduction, negative/r490-generic-error-key-cycle, negative/r490-generic-error-key-cycle-reordered, negative/r490-generic-error-key-cycle-nested, negative/r490-generic-inferred-function-actual, negative/r490-generic-recovery-conflict, negative/r490-inferred-recovery-immutable, negative/r490-recovery-expanding-generic and the checking case recovery deduction interns final sets.

D221 — A static concept entry has one declaring concept

The tour said that composed concepts retain separate evidence tables and that static selection reaches their entries [1310]. D144 specified table order; D146 required unique selected names for erased dispatch. Neither stated whether static selection used that same uniqueness rule. The checker chose the first matching parent, so reordering parents could change the selected provider.

Chosen: [1920] requires a selected static entry name to have one declaration in the direct concept's distinct represented-formal-constraint/parent closure. A direct child entry does not override an inherited entry. Two distinct concepts remain distinct declarations even if their signatures or providers agree. A shared ancestor reached through a diamond is one declaring concept and remains unambiguous. The collision matters when the entry is selected; declaring or conforming to a closure whose colliding entry is unused remains legal.

This is a lookup rule. It changes neither D144's separate parent tables and physical entry order nor D146/D147's erased receiver and flattened-table rules. Prototype 3's allocator and composed map concepts retain their uniquely named entries, as do prototype 2's diagnostic and prototype 4's world capabilities.

The alternatives: declaration-order precedence would make a parent reorder select a different operation. Treating a direct entry as an override would add an unstated override mechanism. Rejecting the entire concept closure would forbid programs that never select its colliding name. All are declined; the selection reports L0341 instead of choosing a provider.

Pinned by negative/r491-static-entry-collision, positive/r491-static-entry-diamond and small checker controls for parent order, represented constraints, direct/inherited collisions, distinct names and unused colliding closures. runtime/generic-composed-evidence retains the independent execution obligation for the unchanged parent-table ABI.

DECISIONS: MODULES AND COMPILE TIME

The module graph, what an import binds, and what is settled before ordinary resolution begins.

D139 — Fixed conditionals select module declarations without execution

The tour said that fixed marks compile-time knowledge [1490], showed a conditional on compiler.arch [1500], and forbade compile-time calls [1540]. It did not say where a conditional may occur, whether a false arm is parsed, or how target selection reaches whole-program resolution.

Chosen: fixed if expression then declaration* (elsif expression then declaration*)* (else declaration*)? end if is a module-declaration form only. It may nest, every arm may be empty, and an arm opens no scope: its selected declarations splice into the one module scope across all input files. It has no public modifier or trailing name, and is not a block, struct, signature or template-local form.

The parser retains every arm in immutable syntax and reports lexical, parser, refusal and recovery faults in false arms. A configuration stage runs after target selection and before resolution. It records an activity view rather than pruning syntax. Resolution, checking, template validation, identity interning and lowering use only that view; a name in an inactive arm has no semantic diagnostic or declaration identity, while an active use of it is unresolved normally. Nested conditionals in an inactive arm are parsed but not evaluated.

The original fixed expression is closed. It admits bool and mathematical D136 integers, the compiler-owned architecture values x86_64, arm64, cortex_m0 and synthetic_32, literals, parentheses, unary -, D136 arithmetic, integer comparisons, bool or architecture equality, and not, and, or. compiler.arch is the only intrinsic and is recognized only by this stage; its target identity comes from the selected Target_Facts constructor, never a target label. Structural validation visits both logical operands even when evaluation then short-circuits. Calls, runtime or module names, measurements, controls, aggregates, arrays and width-dependent operators are rejected and never execute. Every active if and elsif condition is validated and evaluated even after a true arm; the final answer must be bool.

Why an activity table: deleting branches would destroy parser diagnostics and mutate a shared syntax authority; making ordinary resolution decide the condition would introduce a compiler module and runtime execution before the hosted modules and toolchain directives. A selected immutable view preserves the whole-program declaration set without pulling options, build modes, widths, byte order or general builtin modules forward.

D202 extends this same configuration stage with global typed options, target scalar measurements, compiler facts and module tool directives. Its explicit rules supersede this first slice's exclusions of those forms; user execution and runtime-name lookup remain excluded.

Pinned by the target-description constructor and configuration-stage public-seam cases; positive/fixed-conditional-selects-declarations, positive/fixed-conditional-nested-inactive, positive/fixed-conditional-exclusive-duplicates, positive/fixed-conditional-cross-file-forward, and positive/fixed-conditional-symmetric-boundaries; the arithmetic and short-circuit/later-elsif call boundary case negative/fixed-conditional-evaluator; the active duplicate and active-reference-to-inactive cases negative/fixed-conditional-active-duplicate, negative/fixed-conditional-active-reference-inactive, negative/fixed-conditional-active-generic-error and negative/fixed-conditional-inactive-parser-error; the lowering and verifier cases, generated lexical, construct and IR records; and runtime/fixed-conditional-runtime and runtime/fixed-conditional-generic-runtime on Linux x86-64. The selected nested generic and inactive-template boundaries are positive/fixed-conditional-generic-activity and the lowering seam records that only a selected generic instance receives an item.

D150 — The reached module graph has one deterministic identity order

The tour said that a module is one directory [1410], an import searches ordered roots and binds its final segment [1420], imports are per file [1450], and the compiler receives roots rather than acquiring packages [1480]. It did not settle the file prelude, qualification in non-value positions, discovery order, cycles, visibility failures, compatibility invocation, entry selection or what “whole program” means to the conformance register.

Chosen: import is reserved and every source file begins with zero or more plain import a/b declarations before its module declarations. Each path is a nonempty slash-separated identifier tuple. D201 extends this original slice with aliases [1430] and selected imports [1440]. A plain import binds only the last segment in this file's import scope. Locals and signature declarations shadow that binding; it shadows the same spelling in the module scope for qualified lookup. Duplicate final-segment bindings are refused. Imports do not enter sibling files, inject members or re-export anything.

The namespace's first selection resolves a public declaration in the selected module and is available in every declaration-reference position, including a concept constraint and a declared error set. A private member is distinguished from a missing one and related to its declaration. Public declarations may mention private identities, but those identities stay unnameable across the boundary, and a value carrying one does not expose that private type's fields. A contextual literal cannot construct a private nominal from another module, including through a public wrapper's field; otherwise it could forge an initialized-prefix invariant. Array-field selection through a nested path obeys the same visibility rule. Variant cases inherit the containing type's visibility. A namespace itself is no runtime or type value. public on a conformance is refused; every unmarked conformance in the reached graph still enters the single D142 register.

The request supplies one entry directory and ordered roots. A module contains the bytewise-sorted direct regular .ldn children; other entries are ignored and an empty module is legal. Each import segment must match a listed directory entry exactly. Roots are tested in request order and the first complete directory wins without merging. Discovery visits the entry first, imports in source order and newly selected modules FIFO. A selected directory is loaded once, so cycles are legal. Symlink identity and root defaults are outside this guarantee. The explicit-file request remains a compatibility mode forming one synthetic module when no roots are supplied.

If a root or intermediate directory cannot be listed, the import reports that failure before considering later roots. An absent directory or missing exact segment remains a search miss, so a later root may supply the module.

Only after graph closure do configuration, resolution, checking and lowering run over that canonical source order. “Whole program” is exactly this reached graph, so unused reached conformances collide and unreachable or shadowed-root conformances do not participate. Only the designated entry module supplies [1970]'s hosted main.

The alternatives: recursively sweeping subdirectories would erase module boundaries; merging roots would replace [1420]'s precedence with accidental filesystem composition; injecting imported members would erase [1440]; making conformances public would make generic behavior depend on lexical imports; and choosing a reached library main would make the entry depend on traversal. Loading by filesystem enumeration or hash order would also make declaration identities and diagnostics host-dependent. All were declined.

Pinned by unit/module-graph, unit/module-conformance-register, negative/core-mem-private-representation, negative/core-arena-private-representation, negative/core-small-private-representation, negative/core-small-forged-storage, negative/core-text-frame-slice-escape, runtime/core-vec-pointer-storage, and the parser, resolution, driver and hosted-entry cases.

D201 — Import suffixes bind file-local names without new identities

The tour said at [1430] that an alias resolves namespace collisions, [1440] that an import may select names without a wildcard, and [1450] that imports belong to one file. It did not settle whether either suffix also binds the original namespace, how selections collide, or when an unused selection is checked.

Chosen: an import has at most one suffix: contextual as and one alias, or a nonempty parenthesized list of identifiers. A selection has no trailing comma, wildcard or member renaming. An alias binds only the written alias; a selection binds only the named public declarations. A plain import keeps D150's final-segment namespace binding.

All three forms share the file import scope. Repeating a bound spelling, including within one selected list or across different forms, is a duplicate with both sites reported. Parameters and locals may shadow these bindings. A namespace binding shadows a module declaration only for qualified lookup; a selected declaration also shadows it for unqualified lookup. No import enters a sibling file or re-exports a declaration. Selected members are resolved after the reached modules' active declarations have been collected, so declaration order and import cycles introduce no forward-reference exception. A private or missing selected member is refused at its import even if unused; the private-member diagnostic relates its declaration.

A selected binding refers to the original declaration rather than copying it. Its nominal identity, generic formals, mutability, error atoms and private representation restrictions therefore remain those of its defining module. The same binding is available in every declaration-reference position.

The alternatives: also binding the original namespace would make aliases retain the collision they are meant to solve. Copying selected declarations would create new nominal or conformance identities. Checking only used names would let a misspelled import remain latent. Combining aliases and selections, member renaming, trailing commas and wildcards would add syntax the tour does not promise. All were declined.

Pinned by runtime/import-alias-selected-identities, runtime/import-contextual-as, negative/import-selected-private, negative/import-selected-missing, negative/import-selected-duplicate, negative/import-selected-immutable, negative/import-selected-private-representation, negative/import-selected-reserved, negative/import-selected-namespace-unbound, negative/import-alias-selected-collision, negative/import-selected-alias-collision, negative/import-alias-original-unbound, negative/import-alias-reserved, negative/import-option-collision, and the parser/resolution import cases.

D202 — Hosted tool configuration is fixed before ordinary resolution

The tour said at [1480] that the compiler receives ordered roots, at [1500]-[1530] that targets, assertions and declared typed build switches configure compilation, and at [1540]/[1560] that tool directives execute no user code. [1590] places a static-library directive beside its declarations. It did not settle switch discovery, override precedence, configuration namespaces, target-fact units, the assertion fold or library argument order.

Chosen: the driver preserves the explicit ordered roots of D150, with no implicit environment roots. It completes the reached graph before configuration, resolution and checking. Every source remains part of one whole program; this introduces neither a cache format nor a stable interface.

Contextual option name: type = expression declares one globally unique configuration value. An option is unconditional at module level, without public; an option in any fixed arm is refused even if that arm is inactive. The complete option set must exist before selecting arms. Its declared type is bool or an enabled integer scalar, with target bounds for usize/isize. Within a closed configuration expression, integer option values participate as D139's mathematical integers; the declared scalar bounds apply when an option's value is established, rather than at each arithmetic intermediate. An option cannot reuse a compiler-owned configuration atom name: x86_64, arm64, cortex_m0, synthetic_32, little, big, debug or release. That collision is L0390; a reserved tool namespace name is L0203. An option inside any fixed arm or with a type other than bool or an enabled integer scalar is likewise L0390, even when its default is a fixed value. An invalid tool directive argument count, library argument form or library name is L0391. In configuration, L0305 remains a failure to produce a value with the closed fold; elsewhere it also covers a required module initial image that cannot be supplied implicitly, including a function value with no initializer. All options are collected before evaluating their defaults. Defaults may refer forward to options in any reached source; cycles and invalid defaults are refused even when the request overrides the option. A dependent default uses the referenced option's effective overridden value.

An option's bare name is available in fixed conditions, option defaults and compiler assertions. It has no runtime storage or module export. An active use outside those configuration positions receives L0201 explaining that boundary, rather than claiming the option was never declared. An active module declaration or import binding cannot reuse an option's name; local bindings may use it because configuration directives do not occur in bodies. The three bare tool namespace names are unavailable as declaration or import bindings, including parameters and locals, without becoming lexical keywords. Fields and member labels do not declare a tool namespace. Explicit imports of exactly landin/compiler, landin/assembler or landin/linker, including alias and selected forms, receive a named refusal before filesystem lookup: these built-ins already inhabit the configuration scope. No root can replace one of them with source.

--option=NAME=VALUE supplies a bool literal or signed decimal integer text. Unknown or duplicate override names, malformed values, wrong types and target range violations are errors. --build-mode=debug|release supplies a separate request fact, default debug; it does not change runtime checks or optimization. compiler.arch retains D139's constructor-selected architecture; compiler.word_size counts bits and compiler.byte_order is little or big. D204, D226 and D256 add the C ABI bools compiler.c_sysv_lp64, compiler.c_darwin_lp64 and compiler.c_aapcs64_lp64, and D255 adds compiler.feature.NAME, a bool for each feature of the selected CPU feature level. D264 adds compiler.os in its own equality domain, with linux, darwin, freebsd and freestanding values. These facts are fixed configuration values. Word size is eight times sizeof usize, including on a synthetic 32-bit target hosted by a 64-bit compiler.

The existing closed configuration fold gains those facts, options, and sizeof/alignof of the enabled scalar types, measured in target bytes. It retains D139's mathematical integer arithmetic, typed equality and bool operations, structural validation of both short-circuit operands, and absence of user calls. Both operands are type-checked even when evaluation will skip one; dead arithmetic is not evaluated. Nominal or aggregate measurements and runtime/module-name lookup are outside this fold and receive a precise refusal. A module-only compiler.assert(expression) requires bool and diagnoses false at its source. All active assertions use that same fold; inactive assertions have no effect.

A tool directive is a direct compiler, assembler or linker member call with positional arguments, without recovery. linker.library takes one fixed text literal, decoded by the ordinary text decoder. Its nonempty name contains only ASCII letters, digits, underscore, hyphen and dot, cannot begin with a hyphen and cannot consist only of dots. Active library directives produce separate tool arguments after the program assembly in canonical source/declaration order. Repeated requests are preserved: archive resolution may need a library more than once. The Linux adapter selects archives for this run while leaving hosted runtime linkage to the platform driver. Darwin resolves each libNAME.a through the selected driver's -print-file-name query and passes the resulting existing file directly. Missing archives fail; a same-named dynamic library is never a substitute. Apple's driver can return the bare filename, which must then exist in the invocation directory; a custom driver may provide a different archive search policy. Neither target changes the source order or repetition of archive operands. This is the ordering exception to [0130] and [1740]'s order-independent module name lookup: moving an active directive can change archive resolution. Inactive directives add no arguments. D227 enables scalar atomic operations; D229 enables Cortex-M0 body assembly, placement annotations and explicit firmware requests, and other targets refuse placement and firmware. D248 checks assembly on every target with registers and states where this compiler lowers it. assembler.block is a body operation, not a module initializer; Cortex firmware refuses linker.library. No fourth namespace or general build language is introduced. The checked-in device fixtures' vendor provenance and fixture policies are off-target generator inputs/comments, not compiler-recognized directives. Its checked-in declarations derive into D228 images and D227/D228 scalar accesses without enabling new syntax.

The alternatives: conditional switch declarations make switch discovery depend on their own values. Last-override-wins hides repeated configuration; ignoring an overridden default hides misspellings and cycles. Reusing option names for module declarations gives fixed and ordinary lookup different meanings for one spelling. General compile-time evaluation would reverse [1540]; moving scalar target queries through host layout would reverse the target-facts boundary. Searching for built-ins on disk would let root order replace compiler meaning. Deduplicating or sorting libraries changes archive resolution, while whole-executable static linkage takes hosted-runtime policy from the driver. All were declined.

Pinned by positive/r430-fixed-options, positive/r430-inactive-tools, runtime/r430-fixed-tools, runtime/r430-static-library, negative/r430-assertion-false, negative/r430-assertion-type, negative/r430-assertion-call, negative/r430-assertion-nominal, negative/r430-option-cycle, negative/r430-option-duplicate, negative/r430-option-conditional, negative/r430-option-type, negative/r430-option-range, negative/r430-option-reserved, negative/r430-fixed-dead-types, negative/r430-library-injection, negative/r430-library-runtime, negative/r430-library-arity, negative/r430-tool-member, negative/r430-builtin-import, and the driver's option permutation, target-fact, ordered-library and pre-root builtin-import cases, plus negative/option-outside-configuration, negative/tool-namespace-bindings and negative/function-tool-refusals for the ordinary-resolution boundary.

D242 — A refused import answers for its name

The tour said that a file may import selected public members of a module [1440] and that a file's import scope gives one name to one thing [1450], and [1860] says a name that names nothing is refused because it is a misspelling. Nothing says what the name of a refused selected import is afterwards. It is not a misspelling — the program wrote a name its module does say, or one the module keeps to itself — and the import already reported exactly that.

Chosen: the refused import answers for the name. The file's import scope records that the name was refused there, and a later use of it is resolved to nothing without a report. The import's verdict and its exact report stand, the program is refused, and the exit status does not change. A name a refused import wrote is neither bound nor available: visibility is unchanged, so this decides what the compiler says and not what it accepts.

A competent reader could have reported every use, which is what the compiler did: the report is individually true, and a reader who saw only the third one would still learn something. That was declined because the first report is the only one that names the mistake, the rest say "misspelling" of a name that is spelled correctly, and a program importing one private helper used ten times received eleven errors of which ten were misleading. Binding the name to an error declaration instead, so that the checker reported type errors at each use, was declined for the same reason and a worse one: it would move a visibility question into the type stage, where [1410]'s answer is not available. Leaving the refusal to suppress *all* later reports about the name, including a genuine second import of it, was declined because [1450]'s duplicate-import rule is about the scope and not about this name's fate; Has_Import therefore keeps its meaning and only the misspelling report is withheld.

Pinned by negative/r740-refused-private-import-adds-no-cascade, negative/r740-missing-import-adds-no-cascade, negative/import-selected-private, negative/import-selected-missing, negative/imported-private-name, negative/import-selected-namespace-unbound and runtime/import-alias-selected-identities.

D247 — A routine and a struct each hold at most 16,384 of what they declare

The tour said nothing about size. A program may be as large as its host allows, and a routine may declare, and a struct may hold, as many names as it writes. The compiler checks a whole program at once, so what one routine or one struct costs is paid in one process.

Chosen: one routine makes at most 16,384 declarations, counting its parameters, named returns and every local and binding in its body, and one struct body or variant case has at most 16,384 fields. A program over either bound is refused with L0325 before any checking begins: a routine at its name, and a struct or case at its first field past the bound, related to the body. Every place over a bound is reported, in source order, and nothing else is checked. The declaration limit bounds declaration-indexed checking and flow facts, and the field limit bounds field-indexed struct work. Neither limits the number of IR values in a routine. The bounds are Landin.Stages.Checking.Declaration_Limit and Field_Limit. They are an implementation limit, like L0111's nesting depth, and not a rule of the language: a larger compiler may raise them without changing what any program at or under them means.

Pointer-provenance verification uses a separate representation: it indexes stores and reads and follows uninitialized paths for each read slot. Its scratch grows with blocks, slots, IR values and uses, not their block-by-slot product. Every input-sized scratch array, including reachability and work queues, has scoped heap ownership with checked allocation sizes and cleanup on early return or allocation failure. Successors are read directly from validated terminators; no returned graph or automatic construction queue is needed. Zero-use items avoid slot/value dataflow storage while retaining signature, true reachability and ordered pointer/storage checks. This adds no block, value or slot limit: existing accepted workloads and the source bounds above remain unchanged. An unrepresentable scratch size or an allocation failure retains host-resource exhaustion reporting, exit 71. Heap ownership does not establish a bound for the compiler's total memory or remove the other per-routine automatic arrays described below.

The numbers are measured, not chosen for their shape. Origin tracking keeps, for each declaration the routine can name, a fact with one bit for each of them, so a routine's storage still grows with the square of its declarations, though a branch or loop now shares every fact it does not change: at 16,384, with a loop, the release compiler peaks at 130 MiB, and at 65,535 at 1.3 GiB. A struct's field shapes are copied through layout, lowering and emission; 55,000 fields exhausted an 8 MiB host stack. 16,384 of each leaves a factor of three below the struct's failure and ten below a gigabyte for a routine on the host that measured them. A program that stays under both checks without exhausting that host at any size the scaling benchmark generates.

A competent reader could have set no bound and let the host fail. That was the behaviour before, and it is not a diagnostic: exit 71 says nothing about which routine or struct did it, and on a smaller host it arrives at a smaller program. A single bound on the whole program's declarations was declined for declaration-indexed checking and flow facts and field-indexed struct work, which grow with individual routines or structs. The whole-unit IR optimization scratch addressed here is heap-backed and no longer imposes a whole-program stack bound. Specialization, simplification and rewriting still use automatic arrays indexed by a routine's IR values; L0325 does not bound their lengths. Bounds high enough never to matter, 65,535 or 2**20, were declined because a program just under them would still exhaust an ordinary host, which is the failure the bound exists to replace. Making the storage sparse so that no bound is needed was deferred: the reference pass's per-declaration derivation bits are its representation, and replacing them is a change to that pass rather than to its bound.

Pinned by unit/checker-size-bounds, the checking case size bounds refuse past their limit, which generates a routine and a struct at each bound and one past it: a program that meets either is too large to keep in the corpus, as L0111's is. Pointer scratch is pinned by the verifier cases scratch arithmetic and zero uses and address initialisation is checked, including injected allocation failures, and the optimization case cyclic islands, which retains the 10,000-block reachability verdicts.

D262 — An import with no root to find it under is refused at the import

The discrepancy: [1420] finds an import under the roots --root names, and a compilation of named files has none. The import was read, bound nothing and was never reported: every use of its name was then reported as "not declared in any scope", with [1860]'s note that it is a misspelling, which it is not.

Chosen: with no root, an import that names a module is refused at the import, once, as the module not found, with a note saying to compile the module's directory with --root. Its names are refused as D242 refuses a name an import could not supply, so no use of them is reported again. D202's import compiler, import assembler and import linker name the toolchain, need no root and are unchanged.

The alternatives: searching the source's own directory as an implicit root, which makes a file's meaning depend on what sits beside it; leaving the import silent and improving the use's message, which reports the same mistake once for every use.

Pinned by negative/import-without-a-root-is-refused-there.

DECISIONS: THE TOOLCHAIN, C AND THE MACHINE

The C boundary, the machine directives, the entry point, and the contract an optimization has to keep.

D12 — The first hosted path accepts one main shape

The tour said that hosted main follows the system C ABI, calls the no-argument form ordinary and keeps the C argc and argv form available [1650]. Its derived hosted capability example shows public entry: () -> (code: i32) acquiring the roots, with the application's public main: () -> (code: i32) delegating to it [1660]. D208 specifies how hosted startup initializes the argument root before that no-argument main begins. The example does not say which shape the first native slice must implement.

Chosen: [1970]. The minimal Linux x86-64 path accepts one public no-argument main and returns its host status through the one named i32 return code. This is an implementation boundary for that slice; it does not remove [1650]'s C form from the language.

The alternative: implement the C argc and argv shape in the first slice too, permit a different public function to be selected by the build, or treat the return's name as immaterial. Each is workable, but makes the first executable slice carry an entry-selection or argument representation rule it does not need; freestanding builds already have the explicit-entry rule [1650].

Pinned by runtime/constant-return-exits-with-its-code, runtime/add-exits-with-its-sum, and the driver suite's L0502 refusal of a hosted program without public main: () -> (code: i32).

D203 — C convention and variadicness are recursive signature facts

The tour said at [1000] that function values have structural signatures, at [1570] that a convention is selected explicitly, and at [1580]/[1600] that imports and exports meet C. It did not separate convention from bodylessness, visibility or linker spelling.

Chosen: [1800] and [1975] separate those facts. Named private and public C definitions use extern(c); C function types carry that prefix too. Only a final ellipsis after fixed parameters marks varargs. A symbol literal follows the C convention when one is written, or stands alone before a native function name; the standalone form retains the native convention and ordinary body requirement. The decoded link name is a logical external identity with the safe ASCII shape [A-Za-z_.$][A-Za-z0-9_.$]*. Whitespace, @ suffixes and arbitrary assembler expressions are excluded. [1975] maps that identity through the platform prefix before target-assembly quoting; no source spelling bypasses that mapping. ELF preserves it and Darwin adds exactly one underscore. C signatures cannot declare Landin failures. Agreement recursively includes convention and variadicness, independently of labels and symbol names. Variadic calls are positional-only and limit the unnamed tail to scalars, pointers and fixed C callbacks. Fixed callback signatures and nonempty C array fields delimit the selected subset explicitly rather than borrowing C extensions accidentally.

The alternative was to infer C transport from an import flag, public name, or a matching machine shape. That loses the convention as soon as the function is stored or passed indirectly and silently miscalls nested callbacks. A new error bridge or implicit callback thunk would change the language contract; both are declined.

Pinned by positive/external-scalar-c-boundary for the retained bodyless import form, positive/r440-c-signatures for C types, definitions and the standalone native link form, and negative/r440-link-does-not-change-convention for the independence of linkage and convention. The target-contract suite pins ELF/Darwin spelling, leading underscores and punctuation; the lowering seam keeps an explicit native _entry identity equal across both 64-bit targets. negative/r440-c-variadic-identity and negative/r440-checker-recursive-inner-signature pin variadicness and convention as structural identity, down to an inner callback's element; negative/r440-c-error-channel, negative/r440-c-variadic-aggregate-tail and negative/r440-c-variadic-label the refusals at the C boundary; and negative/r440-link-assembly-expression that a link override is a symbol spelling.

D204 — C layout and transport follow one selected target ABI

The tour said at [0750] that C layout keeps C offsets, and at [1580] that a foreign declaration describes the actual C value. It did not specify the data model, recursive aggregate classes or target guard on C scalar aliases.

Chosen: [1975]'s Linux SysV AMD64 LP64 matrix, signed C char, recursive nonempty C structs and separate INTEGER/SSE banks define this boundary. compiler.c_sysv_lp64 (and D226’s compiler.c_darwin_lp64 and D256's compiler.c_aapcs64_lp64) is a fixed bool supplied by the selected ABI; core/c asserts it and supplies ordinary aliases rather than new scalar kinds. Register exhaustion rolls an aggregate wholly onto the stack; MEMORY results use the C hidden destination. The internal Landin convention is unchanged.

The alternatives: using host Ada layout breaks cross compilation. Guessing LP64 from 64-bit pointers admits other data models. Flattening every aggregate into integer words breaks SSE and mixed values; passing large records by the internal pointer carrier is not C by-value passing. Universal boxed records would impose unnecessary storage and indirection on the small target. All are declined in favor of target-selected layout and signature-selected transport.

Pinned by positive/r440-c-aliases, positive/r440-external-float and runtime/r440-c-aliases for the ordinary aliases and admitted f64 signature. abi/r440-native-aggregates, abi/r440-native-banks and abi/r440-sret-pointer-observation pin aggregate transport in both directions, the independent register banks and the hidden result pointer; abi/r440-native-callbacks, abi/r440-native-varargs and abi/r440-varargs-pointer-callback pin callbacks and the variadic tail.

D205 — Headers describe ABI shapes, not lifetime policy

The tour said at [1580] that declarations were handwritten and no header was read. That workflow cannot meet a complete C binding's pressure without repeating signatures manually.

Chosen: the separate deterministic clang-AST generator described at [1975] extracts C declarations and emits explicit adapters for forms outside the native grammar. Policy fills semantic gaps and extraction schemas; it does not replace signatures by hand. Enums retain C integer values; C unions and bitfields are not Landin tagged variants or hardware packed fields. Globals and TLS use accessors; nullable callbacks require their own code-pointer representation. Native receiving-varargs definitions are refused in favor of schema-defined generated C entries. Ownership, nullability, from, retention, foreign unwinding and callback-state validity are never inferred from an ordinary C prototype.

The alternatives: parsing headers inside refine couples the language frontend to C preprocessing. A C/LLVM backend replaces the chosen native backend rather than solving bindings. Adding native union, bitfield, TLS and va_list syntax merely for adapters widens the language and burdens the freestanding path. Handwritten signature replacement disguises the old workflow as generation. These alternatives are declined.

Pinned by bindings/generate.py, its Clang-backed bindings/test.py suite and abi/r440-bindings-generated, with negative/r440-c-variadic-definition for the receiving variadic definition that has to go through a generated adapter instead.

D207 — Foreign failure detail stays in the provider

The tour said at [0950] to represent foreseeable conditions directly and at [1660] to pass host authority explicitly. Prototype 2's diagnostic sink and prototype 4's replaceable world both need detail without a second error system.

Chosen: [1975]'s immediate errno capture, explicit system state and hosted.last_errno preserve the exact terminal libc detail while ordinary not_found, no_access and io_failed remain payload-free atoms. A successful operation clears the remembered detail; a local refusal invents no errno. Interrupted open/read/write attempts retry only under the selected platform's no-progress guarantee, and writes resume after the completed prefix. Close consumes its handle once even if it fails; EINTR does not authorize retry.

The alternatives: reading errno after cleanup can report the cleanup's failure instead. A global last-error value loses the capability boundary and thread-local meaning. Retrying every EINTR can close a reused descriptor or repeat completed output. Adding exception payloads changes the error model rather than preserving foreign detail. All are declined.

Pinned by runtime/r440-errno-detail and runtime/r440-io-partial-progress for the explicit-state and progress contracts, and by abi/r440-errno-interposition and abi/r440-errno-thread-local, which hold errno and the partial-I/O policy under C interposition and across threads.

D208 — Hosted argument capabilities retain one C startup root

The tour said at [1650] that the hosted world retains the incoming argument table and that C's argc/argv entry remains available, and at [1660] that the entry point mints the host capability. It did not say how a C-owned entry starts Landin exports, when the argument root exists, or how long its backing lives.

Chosen: [1975]'s compiler/runtime ABI emits the global hidden ELF entry void _landin_host_initialize_arguments(int argc, char **argv); with hosted bridge support. The ordinary no-argument Landin main calls it before its body; a C-owned startup calls it with its real carriers before hosted.host() or any thread that may acquire the argument capability. Exports and callbacks never call it implicitly. Startup-independent bridge operations need no argument root, and retaining core/io alone does not initialize one.

The first nonnegative-count, non-null-table call establishes one exact (argc, argv) root without copying or allocation. An identical later call is a no-op; an invalid call, use before initialization, or replacement of either root carrier traps. The C owner retains the table and strings for as long as any derived Landin world, view or callback can use them. The published sequence omits argv[0]; its count is max(argc - 1, 0), and retained-state indexed lookup checks both the bound and selected pointer.

The alternatives: initialize every export or callback, fabricate an empty argument table, copy the vector into hidden allocated storage, permit root replacement, or gate every hosted bridge operation on argument startup. The first has no authentic carriers and breaks reentrant callbacks; the second mints a false capability; the third adds an allocator and an unstated release lifetime; the fourth can dangle already published views; and the last prevents startup-independent file and stream work. All are declined.

Pinned by abi/r440-native-startup-initialized, abi/r440-native-startup-empty, abi/r440-native-startup-uninitialized and abi/r440-native-startup-replaced, which pin one initialization across callbacks, an empty table that is still nonnull, the trap before C initializes the root and the refusal to replace a live one.

D211 — Optimization changes implementation, not authority or outcomes

The tour said at [1310] that specialization was optional but promised one erased body for every representation, automatic specialization of a sole instance and disappearance of evidence. Those promises did not distinguish semantic instantiation, proof, profitability and the physical hidden ABI.

Chosen: semantic instantiation remains necessary without optimization. Optional dispatch specialization requires proof that every retained incoming path supplies the concrete table, including separate parent/concept evidence. Expected-instance metadata alone is not that proof. Address-exposed instances and unknown incoming evidence remain unspecialized; heterogeneous any calls remain indirect. Public/exported identities, function addresses, image relocations and evidence-provider references all participate in exposure. Recursive evidence proof is conservative and cannot assume its own conclusion. No speculative guard, clone or fallback runtime allocation is required.

The bootstrap specializes proved entry calls in existing concrete bodies. It retains their hidden aggregate-result destination and the evidence parameter positions selected for that body under D144, error convention and calling convention. Dispatch specialization does not remove a used evidence position. A replaced indirect call must have exactly the provider's physical argument/result meaning. Evidence size and alignment remain available with specialization off. Physically equal bodies may share only after complete retained machine meaning, relocation, convention and observable address-identity checks; IR spelling equality alone is not permission to fold different code.

Profitability uses E = min(32, proved entry-call sites) and L = min(4, maximum source nesting depth at those sites). Let T = min(16, ceil(sum of represented target bytes / target pointer bytes)). The benefit score is B = 8 * E * (1 + L) + T. Growth G is the sum of weighted IR operations: calls cost 6, other memory/control operations 2 and other scalar operations 1. These are policy estimates, not machine bytes. For multiple eligible normalized instances of one template, speed requires B >= G; size and none require B >= 4 * G. One eligible normalized instance bypasses profitability, never proof. all bypasses profitability for every eligible instance; off performs no dispatch specialization. Count instances, not repeated calls to one instance. Caps and target-byte arithmetic make the policy deterministic without a runtime profiler or per-object machinery.

--optimize=none|size|speed defaults to size and independently selects baseline simplification, selection and allocation. --specialize=off|auto|all defaults to auto. --build-mode=debug|release selects source configuration, not these axes. The explicit reference profile is none/off; none/all is meaningful. Malformed or repeated controls are misuse. Optimization controls require a source compilation and cannot accompany help/identity; a build report also requires emission. Checking without emission still checks the same language.

--build-report=PATH requests deterministic typed JSON separate from source diagnostics, written only after successful emission/tool completion through the platform interface. A write failure fails the request. Collisions with source snapshots, assembly, executable or source-map paths are refused before artifact writes. The source adapter retains exact path bytes in hexadecimal, source-content SHA-256 and item origins; equivalent inputs and controls produce byte-identical reports without clocks or temporary output paths. Routine metrics are emitted instruction sites and frame/register/spill/save and static stack-traffic counts. Actual assembled text bytes are measured externally by compiler/tests/quality/check.py, not fabricated from an IR count. For a successful Cortex-M0 executable link, firmware adds measured flash_used and static_ram_used as the highest ELF PT_LOAD physical payload end from flash origin and RAM memory end from RAM origin, respectively. The paired limits and remaining bytes describe the selected 32 KiB flash and 12 KiB static RAM budget, with the other 4 KiB reserved for stacks. These occupied extents include alignment gaps, flash copies of initialized RAM, retained runtime helpers and linker veneers. runtime_members lists the selected libgcc archive member names from the linker map, without toolchain paths. Assembly-only reports have no firmware field.

Every optimization preserves observable side effects, error/cleanup order, traps, exact integer widths and floating-point signed zero/NaN behavior. No floating reassociation, fast-math, invented no-alias fact or undefined-behavior license follows from unchecked. D187 removes only its named lexical check edges and establishes no positive fact for a later pass. Unused operations that may trap or touch memory cannot disappear merely because their value is unused. Inputs and outputs of each transformation remain verified IR.

The alternatives: universal monomorphization, metadata-only devirtualization, a profile-guided runtime, erasure of evidence used by the checked body, or new optimizer freedom inside unchecked. They respectively make code duplication semantic, confuse expected and incoming evidence, add target machinery, break indirect and aggregate calls, or change existing programs' outcomes. All are rejected.

Pinned by runtime/generic-evidence-indirect, runtime/generic-composed-evidence, runtime/generic-erased-aggregate-try, runtime/any-generic-storage, the opt driver fake-platform cases and compiler/tests/quality/check.py. The fixture harness requires each original runtime and ABI oracle under none/off, size/off, size/auto and speed/auto; focused generic/erased cases additionally run none/all and speed/all.

D226 — Darwin C transport is a separate platform contract

Chosen for Darwin arm64: [1975] enables Apple's arm64 C subset with its own compiler.c_darwin_lp64 fact, aggregate/HFA transport, x8 indirect results, fixed stack scalars and HFAs packed at natural size while any other stack composite takes whole eight-byte slots, and stack-only variadic tails. The scalar alias layer admits either supported LP64 ABI explicitly. The binding generator verifies the selected Apple triple, macros, sysroot and C layouts. Logical link names keep the isolated target contracts' platform-prefix rule. Static archive directives resolve exact files through the selected driver before Darwin linking.

The alternatives: treating LP64 as SysV would misplace floats, aggregates, results and variadic arguments. Passing ordinary -lNAME could select a dylib. Cross-linking Mach-O on Linux would not establish native execution evidence. None is adopted. C boundary eligibility, origins, errors and cleanup semantics remain unchanged; source debugging and full hosted parity have separate gates.

Pinned by compiler/tests/darwin/transport.ldn, varargs.ldn, the native platform program and the generated-binding/archive execution runner, together with the shared native aggregate and callback differential cases, and abi/darwin-stack-composite-slots for which stack arguments pack. They run natively on a Mac. The gate runs abi/darwin-stack-composite-slots on Linux and compiles, links and executes it on macOS arm64 in its darwin-parity job through compiler/tests/darwin/check.py --parity.

D227 — Explicit memory events, synchronization and external writers

Chosen for the concurrency memory model: [1620] supplies the scalar primitives below. Their names are compiler members, not ordinary callable values. Each call evaluates its runtime arguments once, from left to right. Ordering operands are the fixed compiler atoms compiler.relaxed, compiler.acquire, compiler.release, compiler.acq_rel and compiler.seq_cst, usable only in these positions. No runtime ordering, consume, optional pointer, signed/float/bool carrier, subtype, distinct wrapper, aggregate atomic or implicit library lock is enabled. The pointed-to scalar must be exactly u8, u16, u32 or u64; writes require ptr mut T. Initialization may use ordinary storage before publication. All participants subsequently use the same width and address for an atomic object until synchronized retirement; an overlapping ordinary or differently sized access is not an atomic access to that object.

CallResultPermitted orderings
compiler.atomic_load(p, order)loaded Trelaxed, acquire, seq_cst
compiler.atomic_store(p, value, order)nonerelaxed, release, seq_cst
compiler.atomic_exchange(p, value, order)previous Tall five
compiler.atomic_add(p, value, order)previous T; stored sum wraps at T's widthall five
compiler.atomic_compare_exchange(p, expected, desired, success, failure)observed T; stores desired iff observed equals expectedsuccess: all five; failure: relaxed, acquire or seq_cst, no stronger than success
compiler.volatile_load(p)one loaded Tno order argument
compiler.volatile_store(p, value)none; one written Tno order argument
compiler.compiler_barrier()nonecompiler ordering only
compiler.thread_fence(order)noneacquire, release, acq_rel, seq_cst
compiler.device_barrier()nonetarget's full system data ordering barrier
compiler.completion_barrier()nonetarget's full data completion barrier

Compare-exchange is strong: no spurious failure; its returned old value tells the caller whether the comparison succeeded. Failure acquire is legal only with success acquire, acq_rel or seq_cst; failure seq_cst only with success seq_cst. Atomic addition has no overflow trap even outside unchecked. All memory accesses require natural alignment equal to the scalar width. Misalignment traps before the access, also in unchecked; pointer validity, live writable backing and memory attributes remain caller obligations [0430]. Static type, permission, arity, ordering and target refusals use L0344. There is no declared error result, recovery arm or runtime library fallback.

Linux x86-64 and Darwin arm64 implement all rows through eight bytes, for ordinary coherent RAM. The Cortex-M0 contract admits one-, two- and four-byte loads/stores and barriers, and refuses exchange, add and compare-exchange: ARMv6-M has no exclusive instruction pair. It does not silently substitute interrupt masking, an unavailable libatomic helper, or a stronger core. The Cortex-M backend emits that admitted subset. Synthetic-32 admits no memory intrinsics. The planned ESP32-C3 RV32IMC target likewise has no hardware read-modify-write atomics. When implemented, it must admit aligned one-, two- and four-byte atomic loads/stores and thread fences, and statically refuse exchange, add, compare-exchange and eight-byte atomic accesses with L0344. It gains no implicit libatomic or interrupt-masking fallback. This records the planned target contract; ESP32-C3 support is not enabled today. Device addresses must use volatile accesses, never CPU atomics. Even a CPU instruction that is atomic in RAM says nothing about peripheral bus semantics.

Events and happens-before

A CPU execution context is a thread or interrupt handler, not a new Landin function type. Within a context, evaluation order establishes sequenced-before. Two memory actions conflict when their byte extents overlap and at least one writes. A data race is a conflicting pair in different CPU contexts, not ordered by happens-before, unless both are accesses to the same atomic object. Naturally aligned ordinary and volatile instructions are not atomic-language operations. Volatile supplies no inter-thread synchronization.

Every atomic object has one total modification order, consistent with happens-before. A read takes its value from an actual modification, including initialization; it cannot read a modification that happens after it. Atomic write/write, write/read, read/write and read/read coherence preserve the order of modifications across happens-before. A read-modify-write reads the immediately preceding modification and inserts its successful write indivisibly. A failed compare-exchange is a read and creates no modification.

A release write synchronizes with an acquire read that reads that write or its release sequence: the contiguous following read-modify-write modifications of that object. An intervening plain atomic store ends that sequence. A release fence before a write synchronizes with an acquire read of that write or its release sequence; a release write similarly synchronizes with an acquire fence after such a read. Release-fence/write/read/acquire-fence is also a synchronization path. A fence alone, with no such observation, does not synchronize contexts. Acq_rel combines acquire and release; relaxed gives atomicity and coherence but no synchronization edge. Seq_cst loads acquire, stores release, and successful read-modify-writes do both; a failed comparison uses only its failure read ordering. A seq_cst fence has acquire and release semantics in addition to the SC constraints below.

Happens-before is the transitive closure of sequenced-before, these synchronizes-with edges, and explicitly specified platform synchronization. For hosted threads, successful creation synchronizes with the first action of the new thread: actions sequenced before creation happen-before its actions. The thread's completion synchronizes with successful return from joining that thread: its actions happen-before actions sequenced after the join. Failed creation or join establishes no such edge. These edges also order ordinary memory; accesses made concurrently between creation and join still need their own synchronization. The interrupt exclusion protocol below supplies another platform edge. Happens-before is acyclic. Sequentially consistent operations and fences additionally have one total order consistent with happens-before and each object's modification order. For precision, A is coherence-before B on one atomic object when A precedes B in modification order, A supplies B's read value, or A reads a modification that precedes B in modification order; take the transitive closure of these edges. Successful RMWs have both read and write roles, without a self edge. For every coherence-before pair A, B, the SC total order S must satisfy:

  • If both A and B are SC, A precedes B in S.
  • If A is SC and B happens-before an SC fence Y, A precedes Y in S.
  • If an SC fence X happens-before A and B is SC, X precedes B in S.
  • If an SC fence X happens-before A and B happens-before an SC fence Y, X precedes Y in S.

Together with coherence, these rules determine the eligible SC read sources, including intervening non-SC modifications; fences alone do not manufacture a synchronizes-with edge. No read can justify its own producing write through a cycle of value dependencies. The implementation may strengthen orderings; programs cannot require that a weak outcome actually occur.

A race is outside the deterministic-value guarantee, not C/C++ undefined behavior and not permission to infer race freedom. Ordinary accesses may be coalesced or kept in registers between synchronization boundaries; a racing poll without a boundary has no eventual-visibility promise. Where a racy machine access occurs, its bytes come from actual writes or the prior storage contents; tearing can combine bytes. There is no invented value or write, retroactive removal of earlier observable behavior, or assumption that the racing path is unreachable. Subsequent use of a raced invalid address remains [0430]'s ordinary unsafe-pointer boundary. Races supply no additional optimizer license, and unchecked still removes only D187's named checks.

Volatile, compiler knowledge and hardware ordering

A scalar volatile primitive performs exactly one access of the written width: no removal of a discarded load, duplication, merging, widening or splitting. Two such accesses are sequenced in source evaluation order at the compiler boundary. In the selected ordinary RAM, each admitted naturally aligned scalar load or store is a single-copy, nontearing CPU access at that width. This does not make a sequence atomic or establish happens-before. MMIO bus atomicity and peripheral tearing are separate device premises; no RAM instruction guarantee is transferred to an arbitrary bus bridge. Unsupported wider accesses refuse. A register image read-modify-write remains two separate events and can lose an intervening hardware or interrupt update. D228 defines packed image fields and explicit register-image access modes without changing this memory model. The generated register(t, ...) and volatile ptr surfaces remain separate from these scalar intrinsics. A fresh local image construction cannot preserve previous device bits without an explicit read. Whole-image stores do not imply such a read. Unnamed encodings remain raw bits until extraction, which validates membership; they never authorize unreachable-code assumptions.

All explicit memory primitives above are full compiler memory boundaries. Ordinary stores before one must be materialized, and ordinary loads after one must use memory anew wherever external writes can reach the storage. This includes module data, address-taken locals, ordinary slices, escaped buffers, byte/integer-created aliases and aliases through calls or evidence. An immutable view controls writes through that view; it never proves that DMA, another alias or another context cannot change its backing. The compiler must not infer disjointness from different pointer element types. A retained scalar value loaded earlier remains that value, rather than changing in place.

Opaque foreign/assembly calls have the same memory effect; known calls and specialized/evidence-dispatched bodies must preserve every such effect. Aggregate copies are ordinary byte transfers, not atomic snapshots. They may tear, but must not cross a boundary or overwrite bytes outside their destination. No optimizer may move, remove or merge the observable accesses or boundaries because a result is unused, a function was specialized, or a source region is unchecked. Proven private computations can still be optimized.

A compiler barrier emits no required CPU instruction and orders no bus traffic. A thread fence orders coherent CPU memory, with the observation rules above. A device barrier also orders explicit accesses in the target's full system scope; a completion barrier waits for the target-defined completion of prior explicit accesses. Neither establishes that a device has finished a command, flushes a cache, or substitutes for a documented status/acknowledgment protocol. The target guide specifies the selected instructions and memory attributes.

Interrupts and DMA through an ordinary slice

On the selected single-core M0, a critical section saves PRIMASK, disables maskable interrupts, and restores exactly the prior PRIMASK on every exit. Its entry and exit are opaque compiler memory boundaries. Ordinary accesses shared only with those excluded handlers are serialized: a completed handler precedes subsequent protected CPU accesses; protected writes precede a handler admitted after restoration. Nested sections preserve the prior mask. This contract excludes NMI, HardFault, unmasked priorities, other cores and DMA. A handler must not spin waiting for interrupted code to release a lock. Interrupt entry belongs to the compiler-owned firmware rules, and the ordinary target CPU module to the freestanding core; this decision introduces neither a scheduler nor a second Io implementation.

Prototype 1 deliberately keeps escaping buf: []mut u8, retained as ordinary []u8. The origin check prevents a tracked frame buffer from escaping; it proves neither the physical lifetime after origin erasure nor DMA coherence. The driver must keep the allocation alive, the descriptor valid, and all conflicting CPU writes stopped while DMA owns each byte. Before enabling DMA, materialize initialization and descriptors, perform required cache maintenance, then a device barrier. A documented completion/count observation must certify that the corresponding device writes precede that observation; then perform a device barrier and any required cache maintenance before ordinary CPU reads. The barrier invalidates compiler knowledge of the buffer, even through the retained immutable slice and even when no Landin call wrote it.

An interrupt notification alone is not DMA completion. Masking interrupts can delay the notification while DMA continues writing. The selected synthetic device model copies a byte before count/status, and is cacheless; its ordered count observation supplies the device premise only for that model. A circular counter is not a stable snapshot: the caller must ensure the consumed interval cannot be overwritten during the copy, and must prevent/latch overrun rather than confusing a full wrap with empty. A concurrently overwritten byte has the external-write/race limit above. The complete derived driver instantiates these obligations; its explicit synthetic drain/count contract and failure evidence are indexed in compiler/tests/driver/DERIVATION.md. That device protocol is not an additional language guarantee. Ordinary slices are retained.

For noncoherent cached RAM, receive handoff must remove dirty CPU copies (clean as needed to preserve unrelated data, then invalidate), complete that maintenance before enable, and invalidate stale or speculatively fetched copies after completion before reading. Transmission cleans CPU data to the point observed by DMA before enable. Cache-line rounding requires exclusive control of every affected line: invalidating unrelated dirty bytes loses CPU writes, while cleaning a stale line after receive can overwrite device data. Maintenance must cover all relevant cache levels and aliases and complete at the platform's DMA visibility point. CPU coherence between threads alone does not establish device coherence. Cacheless M0 needs no cache operations; this is not evidence for cached platforms. Privileged cache operations and hosted DMA mapping are not portable user-mode intrinsics; no cache helper is enabled on these targets. Platform providers must establish those obligations before claiming a cached device profile.

Alternatives and rationale: importing C/C++ race undefined behavior would add optimization assumptions unsupported by this unsafe language. Treating volatile as acquire/release would confuse CPU accesses with device protocols. Automatically masking interrupts for atomics cannot synchronize other cores or DMA and would hide privilege and latency. Replacing the buffer with an ownership or volatile-buffer type would evade prototype 1's alias pressure. These alternatives are rejected. Full compiler boundaries and initially stronger native ordering are conservative implementation choices, not promises of competitive code generation or wait-free progress.

Guarantee classes: arity/types/orders/target eligibility are static; misalignment is trap; integer-created pointer origin remains beyond-lifetime; races, backing lifetime, device premises, overrun and cache provider correctness are outside. Accepted calls retain their specified observable event semantics. Models check bounded consequences under stated assumptions; native executions check emitted instructions. Neither emulator success nor failure to observe a weak outcome proves this entire model.

Pinned by runtime/r630-memory-scalars, abi/r630-native-memory, abi/r630-dma-slice, negative/r630-load-release, negative/r630-cas-failure-stronger, negative/r630-m0-rmw, runtime/r630-atomic-load-alignment, runtime/r630-volatile-load-alignment and ir opt/memory events. The mandatory Cortex-M probe path retains independent CPU/interrupt/DMA controls and the bounded cache/store-buffer models.

D229 — Compiler-owned firmware and explicit machine boundaries

From [1460], [1550]–[1570], [1630]–[1660], [1940], D202, D227 and D228.

Decision: [1990] defines the enabled Cortex-M0 source/request contract. The compiler owns reset, the fixed constrained linker script and the vector image; source annotations contribute typed handler references and placement. This is a toolchain slice, not a new initialization language or package system.

ChoiceAlternative and reason for declining itExecutable pin
Explicit source entry and compiler-owned initializationTreating the Cortex-M backend's external test harness as language startup hides initialization and cannot validate the compiler/toolchain requestcortex ABI/firmware path, firmware.py cold boot/reset
Kept compiler vector image with typed slot referencesA heterogeneous raw array conflates SP, reset, reserved zero slots and handler conventions; unrestricted vector replacement could bypass reset initializationcortex ABI/machine directives, generated SVC/IRQ and RAM vectors
Distinct interrupt/naked signatures with no failuresOrdinary-call conversion loses EXC_RETURN and invents a caller for failuresmachine signature/call/conversion refusals and nested execution
Ordinary frames in handlers; programmer-owned naked bodiesOmitting ordinary leaf/handler frames contradicts the frame contract; applying that prologue to naked code contradicts no-prologue semanticsindependent C/assembly frame control, generated MSP/PSP and nested-handler controls
Conservative opaque assembly with restricted ordinary registers/control flowUnstated clobbers corrupt live values; treating a compiler boundary as a hardware barrier invents ordering/completiongeneric opaque-memory and ordinary-live-value execution, generated interrupt/DMA trace
Flash immutable images, RAM data/BSS and explicit RAM code load imagesLeaving initialization to test setup or treating load addresses as execution addresses conceals relocation failurespoisoned boot, copied RAM handler, veneer and libgcc execution
Section retention separate from calling conventionKeeping every handler changes reachability and code size; dropping relocation targets breaks vector/data imageskept/discarded sections, first-class handler and text relocations
Explicit constrained script, bounded materialization and one-frame checkA larger board hides overflows; a general script/build ecosystem exceeds this slice; materializing giant unreachable images before GC wastes unbounded resourcesflash/stack overflow, L0505/L0507 and misplaced-vector controls

The physical startup/exception premises are outside language memory safety; shape, convention, placement and assembly restrictions are static checks; accepted runtime checks still trap under D187. D228's raw-image preservation, invalid-encoding checks and exact volatile widths are unchanged. D227 retains ordinary DMA slices and requires actual device completion before consumption; masking does not stop DMA and a notification alone is insufficient.

Pinned by: compiler/ada/tests/src/landin-tests-cortex_suite.adb and environments/cortex-m/firmware.py, its retained source, assembly, linker, GDB and device inputs, plus the unchanged independent and generated lanes of the Cortex-M execution profile, layout, memory model, packed encodings and backend.

D230 — Scalar transport through the ordinary assembly boundary

From [1360], [1550], [1570], [1620], [1630], [1990], D202, D227 and prototype 1's X8.

Decision: [1990]'s bounded two-argument assembler.block(text, operand) transports one u32 through r0. It is an ordinary body expression and remains an opaque read/write, call and trap boundary even if its result is discarded. The operand's effects complete before assembly begins; the result is saved before subsequent Landin evaluation. All ordinary register/frame restrictions still apply. This form is available inside an interrupt's ordinary framed body, but neither an interrupt signature nor a naked body acquires parameters. D248 makes this form the shorthand for inout value: u32 at r0 = operand without an operand name, so its text names r0 directly. Hosted targets refuse it by name, because r0 is Cortex-M0's; they check the operand form instead.

This permits core/cpu to implement PRIMASK save/disable/restore with ordinary Landin functions. It does not add a CPU intrinsic namespace, an assembly template language, pointer operands or a new calling convention. The saved mask is explicit caller state; nested sections restore their own prior mask. The selected ARMv6-M PRIMASK bit affects configurable exceptions only. It does not exclude NMI, HardFault or DMA. WFI can wake spuriously or with an enabled pending masked interrupt; callers must recheck the condition they wait for. Hardware barriers and compiler boundaries retain D227's separate meanings.

Alternatives and rationale: the former result-free surface could disable interrupts but could not return the prior mask without an undocumented memory or register convention. A new intrinsic namespace would contradict X8's ordinary-module boundary. General constraints/clobber lists would add a new register-allocation interface when a single low-register carrier suffices. Implicit memory-output tricks would bypass the frame/storage restrictions. Those alternatives are declined for this slice; D248 later adds typed operands without constraint strings and keeps this form as their shorthand.

Guarantees and pins: positive/r670-scalar-assembly pins target-fixed parsing without enabling hosted assembly. Checking and IR verification reject malformed carrier, target and naked combinations (cortex ABI/machine directives and cortex ABI/assembly IR). Compiler-generated core-cpu.ldn observes nested masks, deferred restoration, actual interrupt execution and the interrupted hardware/software state in QEMU. The independently asserted peripheral trace in freestanding.py uses the same ordinary-slice completion protocol as firmware.py. Assembly instructions and indirect writes remain programmer obligations; no ownership or interrupt-safety proof is introduced.

Pinned by: positive/r670-scalar-assembly, the Cortex source/IR cases and the compiler-generated core-cpu.ldn and ordinary-slice DMA execution in environments/cortex-m/freestanding.py.

D232 — Compiler-check panic dispatch and optional site identity

Chosen: [1670] is a source-level hook on all three emitting targets. core/panic declares public atoms out_of_range, overflow, bad_conversion, unreachable, and their union panic_kind. They use the ordinary nonzero u32 atom ABI, in declaration-identity order across the final compilation; their integers are not fixed enumerator encodings. Zero remains private call success and is not admitted into this source atom domain.

A module-level declaration named panic_handler in the entry module selects replacement. It must be a public, defined, nongeneric, ordinary Landin routine with two by-value parameters, the exact canonical four-atom domain and plain u32, and infallible noreturn. Equivalent aliases of that domain are accepted; independently declared same-spelled atoms are different. Parameter names are not part of identity. C, interrupt, naked, external, generic, failing, returning, inout/sink, constrained or distinct site types, caller-inserted parameters, extra-parameter and explicit-link-symbol forms are refused. Normal resolution rejects duplicates. A declaration with that name in another module or a local scope is not the entry hook. These rules also apply to checking requests; L0506 identifies an invalid handler contract. Source replacement is supported by this selection, not by weak symbols or accidental link ordering. The handler remains an ordinary D231 function value for calls and evidence.

No selected declaration means the compiler supplies the terminal default: Linux ud2, Darwin brk #1, Cortex udf #1. Calling this known terminal implementation is folded to that instruction, with no mandatory thunk, data, strings or allocation. A selected handler receives exactly (kind, site) at the check's failed edge, through the unchanged ordinary target ABI. The failed computation never resumes: its later stores, argument evaluations, recovery, defer and undo actions do not run. The handler's own terminal computation may perform ordinary actions. This is D11's evaluation-point and no-continuation guarantee, not unwinding or a checked error outcome. Foreseeable allocator exhaustion remains out_of_memory under D193.

The complete enabled check disposition is:

Check familyKind and site
Checked integer add/subtract/multiply/negation; zero divisor for division or remainder; signed division overflowoverflow at the arithmetic operation. Wrapping operations and D187's suppressed overflow checks do not acquire a panic. The defined lowest-signed remainder by minus one remains zero.
Fixed-array and slice bounds/order; range-subtype membership; negative shift countout_of_range at the indexing, slicing, range check or shift. Large nonnegative shifts retain their defined result.
Integer, bool, float and pointer-address conversion fit; nonnull pointer construction; malformed text decodingbad_conversion at the conversion/decoding operation, with D187's existing exceptions unchanged. Ordinary floating arithmetic retains its existing IEEE behavior.
Volatile/atomic scalar address alignment; atom-domain validation; packed encoded membership, packed field-width fit or reserved-bit pattern validationbad_conversion at the operation that validates the value. Raw packed copying still preserves every bit without extracting or validating fields.
A callee returns despite noreturnunreachable at the call, before any continuation.
Compiler-owned firmware entry returns; invalid/uninitialized hosted argument-root bridge or legacy bridge contractunreachable, synthetic site zero. Normal entry cleanup runs before an ordinary entry return reaches this guard.
Recursive/concurrent panic entry, or a selected handler somehow returnsTerminal default instruction; no second handler invocation.
Naked assembly fallthroughTerminal default instruction: the programmer has not supplied the required machine transfer or a safe ordinary-call frame.

Hardware faults, invalid raw-pointer/lifetime assertions, foreign ABI violations other than the explicit noreturn guard, assembler faults and private Arm helper faults do not become language checks. They keep their machine or programmer obligations. The compiler does not catch faults and reinterpret them as bounds/alignment panics, split volatile accesses, or synthesize atomics on Cortex. Startup's unhandled-exception loop remains a separate hardware fault sink. There is no user-code module initialization.

Each selected image has one private four-byte zero-initialized panic-entry latch. The handler claims it before executing source actions. A second entry traps, including a check in a transitively called helper and an explicit recursive call. Linux uses a locked exchange and Darwin an exclusive acquire/release loop for this private latch; the scope is the whole process image, not one thread. Cortex uses ordinary word accesses: on its single core, an interrupt before publication takes over the nonreturning computation; after publication it sees the latch and traps. This introduces neither exclusive accesses nor hidden interrupt masking on ARMv6-M. No latch is needed for the inlined default. The selected handler must establish any desired reporting capability itself and locally handle any declared failure; no reporting library or heap is imported automatically.

The compiler-owned reset initializes the latch with other BSS before enabling configurable interrupts and calling firmware entry. Panics in an interrupt use the same handler on the interrupted stack and do not return through EXC_RETURN. The existing [1990] assumption of no NMI/fault during reset initialization remains: a custom early NMI/HardFault cannot assume initialized storage or this latch before BSS has been cleared. This is not a new promise about reset-time hardware faults. Call-bearing ordinary frames, including a handler that calls, retain the previous-frame/incoming-return record and target alignment. Eligible leaves use SP-relative homes and preserve incoming LR in its register.

Site zero is reserved for synthetic guards without a source operation. Other sites use a deterministic, collision-free compilation-local space. In canonical source order, each source byte position, including its one-past-end position, reserves four numbers in the above atom-name order. The first source begins at one; the next begins after the previous source's complete range. A site's number is base + 4 * first_byte_offset + family_offset, where family offsets are zero through three. Multiple machine guards for one source operation and family share a site. Distinct families at that position have different sites. Unused positions cost no image bytes. A source-space total that cannot fit u32 is refused as L0506, never truncated or hashed. Sites are not persistent across changed source inputs, even comment-only changes.

Numbering precedes and is independent of optimization. Specialization and inlining retain the originating source operation, not the clone's allocation order or the caller's coordinates. Dead operations leave gaps. Body sharing must preserve observable kind/site immediates; the existing native-body and atom-domain/shape equality checks therefore cannot merge differently numbered selected-handler edges. Default terminal checks may retain their established body sharing. Kept data and selected handler references remain reachable.

--panic-map adds optional fields to <output>.sources.json: source-byte ranges and line-start offsets alongside D192's exact path bytes, source hashes and assembly/build identity. It requires emission. scripts/source-location.py --panic-site NUMBER resolves a nonzero site only with matching assembly, ELF build identity or Mach-O identity. Zero is explicitly synthetic, not a filename guess. Stripping source/debug tables does not change the scalar site; constrained builds need no map, filenames, formatting, heap or reporting storage. The optional identity section is accounted for in an image that requests it. Caller coordinates remain their separate three-scalar D192 contract; they do not become panic numbers. Cortex source debugging is separate evidence.

Alternatives declined: linker interposition does not validate a source signature; a new panic intrinsic namespace is unnecessary; per-emission dense numbering changes with optimization; address-based sites change with placement; hashes admit collisions; mandatory filenames or a runtime lookup table impose cost on every constrained image. The byte-position scheme spends unused u32 numbers to remove a mutable check-discovery ordering and needs no runtime table. A returning or failing handler would contradict D11 and [1670].

Pinned by driver/panic handler contracts, abi/r670-panic, core-panic.ldn, the off-target identity refusal tests, and the inherited default-trap fixtures.

D248 — Assembly operands name their registers

From [1560], [1570], [1620], [1630], [1990], D227, D229, D230 and prototype 1's X8.

The tour said that inline assembly is for what has no builtin [1630], and [1990] enabled it on Cortex-M0 alone, with one u32 through r0 (D230). A routine that needs a second value, a register other than r0, or a hosted target had nothing to write. GCC's answer, a constraint string per operand and a clobber list of register names in quotes, puts a target-specific language inside a string literal, which is exactly what a type checker cannot see into.

Chosen: [1990]'s operand form. An operand has a direction, a name, an integer type and a register, and the register is a name the target's table answers for or the one class general. The block's value is its named outputs, as a function's is its named returns. Every ordinary block overwrites the target's call-clobbered registers and flags; a callee-saved register is declared, which makes the routine save it; frame, stack and link registers are never named, and the language reserves no register beyond them. Every block keeps the opaque read/write, call and trap boundary on every target, so the verified IR sees one instruction with declared register effects. D230's form is kept as the shorthand for inout at r0.

ChoiceAlternative and reason for declining itExecutable pin
A register is a name in the target's table; general is the one class, spelled the same everywhereGCC's constraint strings ("=r", "+a") and at "r0": a register in text is invisible to the checker and a misspelling is a string mismatch. Register names as argument labels leave no room for a direction or a class, and inout would need one label twicenegative/assembly-register-is-text, negative/assembly-register-not-on-target, negative/assembly-register-twice
The type selects the register's width in the textGCC's width modifiers (%w0, %k0) are a second language in the templatepositive/assembly-operand-forms
Outputs are the block's value, bound like a call's named returnsOutputs that write existing places need rules for when the place is evaluated, its permission, definite assignment and aliasing with an input; a value reuses binding, assignment, destructuring, discard and D244 unchangednegative/assembly-outputs-dropped-by-omission, core-cpu.ldn
Operands are exact integer scalars one register widePointer operands would convert implicitly across the boundary where X6 says origin ends, and a pointer output would hide ptr's zero trap; usize(p) and ptr(u) say it where it happens. bool, distinct types and range subtypes would each need a check or construction inside the blocknegative/assembly-operand-types
Float operands are transferred to Language evolutionCortex-M0 has no float register, the float work assembly would reach is a builtin by [1560]'s rule, and the control registers hold integers; a program that needs one, or a target with float registers, is what brings it backnegative/assembly-float-operand
Every block overwrites the call-clobbered set and flags; callee-saved registers are declared with out _ or as an operandClobber-nothing by default (GCC, Rust) makes a forgotten clobber a silent miscompile and buys precision no allocator here uses; a separate clobber list states what out _ already doesnegative/assembly-reserved-registers-x86-64, negative/assembly-reserved-registers-arm64, negative/assembly-discard-names-register
Frame, stack and link registers and the platform's are never named, and the language reserves no otherLetting a block name the frame pointer loses backtraces and the stackful-fibre route [1680]; reserving a register for the language is what the ambient environment cost and lostnegative/assembly-reserved-registers-cortex, negative/assembly-reserved-registers-x86-64, negative/assembly-reserved-registers-arm64
The memory effect is fixed: every block reads and writes memory, may call and may trapGCC's "memory" clobber and Rust's nomem and readonly let a block promise less. The default is always correct, no optimisation here would use the promise, and the case assembly exists for, a critical section, is the one a narrower promise breaks; a measured need in optimisation reopens itcore-cpu.ldn
Every output gets a register distinct from every input unless it is inoutRust's lateout shares an input's register with an output; it saves a register and asks the programmer to know when an input is deadnegative/assembly-register-twice
general counts only the registers the block does not otherwise nameCounting the whole class accepts a block the compiler cannot give registers to, and leaves the failure to emissionnegative/assembly-general-exhausted
D230's (text, u32) form is the shorthand for inout at r0, Cortex-M0 onlyWithdrawing it leaves two spellings through a transition and core/cpu unwritable until lowering exists; giving it a hosted meaning would invent a register conventionnegative/assembly-shorthand-hosted, negative/assembly-shorthand-after-operand, positive/r670-scalar-assembly
The operand form was specified and checked on every target before any lowered it, refused by one stated lowering limit until each didParsing alone would collapse every rule into one refusal; accepting before lowering exists would emit a program with a silent holethe runtime assembly-* fixtures, negative/assembly-synthetic-target

The text rules that were Cortex-M0's are uniform where they can be: size, ASCII, lines, no directive, comment, separator or label, and straight-line control in an ordinary block except for Cortex-M0's svc exception entry. The instruction allowlist is an armv6-m implementation limit; at higher M-profile levels and on hosted targets the checker refuses control transfer by mnemonic and leaves which instructions exist to the assembler. Implicit register effects and indirect writes into compiler storage remain programmer obligations that no check can prove.

Pinned by positive/assembly-operand-forms, the negative fixtures named above, negative/assembly-operands-on-another-call, negative/assembly-template-names, negative/assembly-naked-operands, negative/assembly-hosted-straight-line, negative/assembly-arm64-statement-separator, the runtime assembly-* fixtures, backend/assembly blocks keep their registers, negative/assembly-operand-without-register and negative/assembly-output-with-value.

D252 — A source has one layout, and the compiler lays it out

From [1060], [1750] and [1780].

The tour said that space separates tokens and means nothing else [1750], that no newline is ever required [1060], and that a comment is space [1780]. It said nothing about how a program should be laid out, so every program chose, and core and the examples agreed with each other only as far as their writers happened to.

Chosen: one layout, decided by the compiler and not by the program: refine fmt. It decides space and nothing else. It never adds, removes or changes a token, never changes a comment's bytes or moves one past a token, and never breaks or joins a line; what it decides is where each line starts, the space between two things on one line, that a run of blank lines is one and none begins or ends a file, and that line ends outside raw literals and block comments become one LF. Line ends inside those protected bytes remain unchanged. It reads the scan and the tree and nothing later, so a program is formatted whether or not its names and types are right, and one that does not parse is refused with its report and not touched. The rules, each with a program as written and as formatted, are docs/format.md's, which the test program holds the implementation to; they were measured on core and the examples before any was written, and where those disagreed the majority was taken. Formatting changes byte offsets, so a caller location (D192), a panic site (D232) and debug information follow the formatted source; nothing else a program does can change.

The alternatives: a style with options, which is a second opinion the language would then have to settle between two programs that follow different ones; the one layout is what makes a formatted file mean one thing to a reader. A printer that breaks and joins lines at a width, which lays out every expression from scratch and so moves every comment's line, every caller location and every debugger breakpoint whenever a name's length changes; no width is enforced here, and one that is would bring such a printer with it. Keeping each file's own line ends outside raw literals and block comments, which leaves three spellings of ordinary line boundaries in one repository; [1750] admits three on input and ordinary layout needs only LF on output. Leaving the layout to the tools of the editor that happens to be open, which is what the language had before and what core shows.

Pinned by positive/comment-forms, positive/space-forms, positive/line-ends-crlf, positive/line-ends-lone-cr, positive/line-ends-mixed and positive/no-final-line-end, which the formatting/every source keeps what it says case requires to be formatted, negative/unclosed-block-comment and negative/latin1-byte-in-name, which it requires to be refused, and formatting/the page is the layout.

D253 — An editor is answered past a broken body, and a build is not

The discrepancy: nothing in the language says what a tool may report about a program that does not parse, and the compiler reports only what the scan and the parse found: each stage stops on a refusal, so a hole does not cascade into reports about everything it swallowed. That is right for a build and wrong for an editor, where nearly every edit leaves some body half written and a server that stopped at it would say nothing about the rest of the program while a person types.

Chosen: refine is unchanged, and a server answers past a hole only where a hole cannot take a name away from anything else: inside a routine body, because nothing a body declares is visible outside it. When every error in a source lies inside the bodies of module routines whose name and signature parsed, the server checks a stand-in: the same bytes, each such body blanked with its line ends kept and loop do end loop written into it, which every signature accepts because it never finishes, so every offset, line and column is the source's own. The unchanged stages check the stand-in. The server reports the source's own syntax errors, then whatever the stages report that touches no stood-in body, and no warning, because D251 admits one only on a program the compiler accepted. A body is not stood in for when it belongs to a generic or a routine whose error set is inferred, because the body is what decides them; when it is not closed by the end the parser matched; when a line inside it begins in the first column, where recovery may have read a declaration as a statement; or when it is too short to hold the stand-in. Any other hole, and any error outside a body, leaves the source reported exactly as refine reports it.

The alternatives: teaching every stage to skip a subtree with a hole in it. That is a mode in each of five stages, and in a checker that sweeps every node of a tree in more than a dozen places, none of which has ever seen a hole; a stand-in is legal source that the stages already check, so it cannot reach a path they have not taken. Letting refine report past a hole too, which moves the report of every program the parser refuses and makes a build's verdict depend on how well recovery guessed. Answering nothing past a syntax error, which is what an editor had before.

Pinned by server/a broken body is stood in for, server/only a body is stood in for, server/analysis continues past a body, server/analysis agrees with refine and server/refused sources are served.

D260 — A parse reports a mistake once, inside the construct it is in

The discrepancy: nothing in the language says where a parser resumes after a mistake, and the compiler resumed wherever a declaration could begin. One misplaced word in a body, v: u32 mut = 41, ended the body there: the function was reported never closed although its end main was two lines down, and every later line of the body was read as a declaration of the file and reported again. Of 1,829 refused single-token changes to the bodies of the positive programs, 596 gave one report on the changed line.

Chosen: recovery keeps to the structure the program writes, and only after a mistake, so a program the parser accepts is read exactly as before. A function's closer is found before its body is read: the first end name after it that begins a line no deeper than the declaration's, or shares its line, or a bare end alone on such a line when it comes first. Nothing in the body is read past that closer: to the body it is the end that closes whatever is open, and recovery that would skip further stops there, so a mistake is never reported in another routine. Inside the body, a statement reports at most once, and what follows on its line, including a construct opened there, is the rest of that mistake; lines inside a bracket it opened are part of it too, as are the lines after it that begin with an operator only a binary expression takes, and the lines after it indented deeper than its own, which are the body of the construct it failed to open, such as the arms of a match whose word is out of place. The first line no deeper begins anew, so a mistake inside a construct that line opens is its own. A refused declaration at a file's top level is the same: the lines indented under its header and the end that closes them are passed over. A header that lacks then or do where it belongs begins its body after one written later on its line. A transfer's label is written on its line, so a name on the next line begins the next statement. A value with more of its block after it is reported as not being a statement, and the block goes on. A closer that no open construct takes, such as end written twice, is one report and is passed over. An end beginning a line, with a word that no construct around it takes exactly, closes the innermost construct that wanted a word, and is reported with the closer it needed. "Never closed" is said of a construct only when the closer that ends it belongs to a construct around it; a file that ends inside several constructs is one report, at the innermost, naming the others. Declaration recovery passes over brackets as well as parentheses. A report that a token is missing goes on the token written in its place when that token is on the same line, and says what it is: "followed by then, not the name thne". At a line's end, and before end of file, it stays where the token belonged.

The alternatives: resuming at the next line whatever it holds, which reads a continued expression as a new statement. Treating indentation as structure, which [1750] rules out: the fence is found by indentation, but only to choose between closers the grammar already accepts, and a program that parses is never read differently. Reporting every mistake a statement holds, which reports the first mistake's consequences as if they were others.

Pinned by the mutation suite, parser/calls respect the nesting limit, negative/misspelt-keyword-is-offered-the-keyword, negative/arms-of-a-refused-match-head-are-not-reported, and negative/a-nested-mistake-after-a-refused-statement-is-reported, whose second, independent report the indentation does not quiet.

D261 — A refused statement is reported as the smallest change that mends it

The discrepancy: a parser reports what it needed where it stopped, which is often not what a person wrote wrong. v: u32 mut = 41 needs a name after mut, and "a name belongs here" at = names neither the word nor the fix; r = reported at the next line's else sent a reader to the wrong line.

Chosen: the first error the parser reports on a line of a routine body is tried against one-token changes of that line alone, in the order they are offered: a word written twice in a row with one copy removed; mut, try, inc, dec or public moved to the line's start; two neighbouring tokens swapped; the token the parser asked for written where it stopped, before any other token or at the line's end; and last, any token removed. The ones that keep every token written come first, because they keep what the person wrote. A change counts when the line parses on its own as one statement, or as its block's value where it ends the block of a routine that returns one, and when the routine with it parses to the end of the line and reports no more after it than before. Changes that leave the same tokens are one repair. The report moves to the token the first repair touches, says what the change is, gives the line as the source would read with only that edit, and offers up to three repairs.

A repair is Likely. It is Exact, which a tool may apply unasked and an editor prefers, only when every change that mends the line writes the same line and that line removes one copy of a token written twice in a row: x:: u32 and 1 + + 2 have one reading, and nothing is guessed. A stand-in for a name, a value or a type is never Exact.

A line is not tried when it is a closer or a divider, a match arm, the line a routine's signature is written on, longer than forty tokens, or when the report spans a construct of its own.

A line the grammar read as continuing the one above, after an operator, an =, a ,, an opener, a ., or a word that asks for a value after it (when, addr, not, and, or), is tried differently, because a statement ends where its grammar does and a line break says nothing to the parser. If that line parses on its own as the statement it begins, or begins one that goes on past it, or is the first arm under a match, the line break is the candidate: the line above is tried with the value it asked for written at its end, or a name after a . or addr. The repair counts when the routine, with only that line changed, parses to its end with no report before the changed line's end and no more after it than before. The report is the missing value, L0102, or the missing name, L0100, at the token that asked for it; the report the parser made on the following line is not given. Only a program the parser has refused is tried, so a value the grammar accepts on the next line, at any indentation, keeps its meaning.

A report that carries a fix of its own is not tried, except where the line break is the mistake, and there the structural repair replaces the report's fix. local = then r = local reads local = r = local, whose = the parser offers to make ==; but local == r = local is still refused, so that fix mends nothing, and every fix offered must leave a program that compiles. Where no line break is involved, as in if x = 1 then, the report's own fix stands, and the structural search is not run. Nor is it tried when a value was asked for and a word that begins only a statement stands there: b = inc a is reported as a statement where a value belongs, because removing inc would mend the line by changing what it does. For the same reason no repair removes a word that says what a statement or an operand does: inc, dec, return, fail, defer, undo, in and inout.

Where a form is plainly another construct written in its wrong place, the parser names that construct instead of what it stopped on, and reads on as if it were written right: sizeof(t) is a measure with a call's parentheses, name: concept (...) a concept missing its type =, else (_) an error binding that binds nothing, (a, b) = value a destructuring written with an assignment's =, f().x a selection from a call, and general after an operand's : the register class where its type belongs. addr takes a named place, so addr 3 and addr make() are said at the value; end struct names the kind of thing closed rather than the struct; brackets written before a generic function's list, id: [t: type] (x: t), are its formals out of place; an operand first in a call has no block text before it. No repair removes addr, lenof or the name a lenof measure is given, since each would change what the line measures or points at. A : or := that begins a line belongs to that line, so the name at the end of the line above is a value, and an assignment operator beginning a line is a binding or an assignment whose name was left out. A closing word written again, as end if if or end end match, is one copy and is said once; the copy after end if opens nothing, because an if needs its condition on its line, so removing it is Exact. These are the grammar's own constructs, recognised by their tokens, not a table of other languages' spellings.

The alternatives: Exact whenever one repair alone mends the line. It was the first rule and was withdrawn: a repair found by parsing alone still guesses what was meant, and the guess is unique only because the search stopped; an Exact fix is applied by editors and agents without asking, so a wrong one silently changes what a program does. Searching every keyword and punctuation mark at every position, which finds more repairs at about a hundred parses a token. Running the trial inside the parser in the statement's own block, which reaches into every token access of the parser.

Pinned by the mutation suite, which applies every offered repair and requires its line to parse; negative/misplaced-mut-is-moved-to-the-front, whose recorded report offers the move first and the removal second; negative/missing-colon-is-written, negative/stray-end-in-a-statement-is-removed, negative/doubled-operator-is-removed, negative/doubled-equal-is-removed, negative/doubled-colon-is-removed, negative/doubled-mut-is-removed, negative/measure-in-parentheses-is-written-bare, negative/concept-without-type-is-given-it, negative/unnamed-error-binding-is-removed and negative/missing-right-operand-is-reported-at-its-operator, negative/closing-word-written-twice-is-removed, negative/value-left-out-before-a-line-break-is-written-there, whose every offered repair the fixes suite compiles clean; negative/statement-where-a-value-belongs-is-named, negative/names-assigned-as-a-list-are-refused-there, negative/selection-from-a-call, negative/register-class-as-operand-type-is-named, negative/name-left-out-after-a-dot-is-written-there, negative/match-subject-left-unfinished-is-reported-there, negative/value-left-out-before-a-multiline-statement-is-written-there and negative/binding-missing-its-name-is-reported-on-its-line, negative/addr-of-a-call-result-is-refused-there, negative/addr-of-a-literal-is-refused-there, negative/generic-formals-in-brackets-are-reported-once and negative/operand-with-no-block-text-is-refused-there, whose one report is recorded; negative/struct-closed-by-end-struct-is-given-its-name, whose repair the fixes suite compiles clean; positive/value-continued-at-any-indentation, which holds a continued value the grammar accepts to being accepted; server/repair-actions, which holds the preference an editor sees to the two levels; and server/formatting.

D264 — Hosted system identity selects libc records, independently of C transport

From [1500], [1550] and [1975].

The discrepancy: FreeBSD shares Linux's SysV AMD64 and standard AAPCS64 calling conventions, but its libc uses __error, BSD open flags and a 224-byte stat record on both architectures. The C transport fact cannot select that record without changing the meaning D256 gave it.

Chosen: freebsd-x86-64 and freebsd-arm64 are distinct LP64, little-endian target descriptions using the existing ELF backends, DWARF, 16-byte stack alignment and frame pointers. They share the existing C ABI facts and feature levels of their architectures, including arm64's unsigned plain char and reserved x18. compiler.os is a fixed configuration value in its own equality domain, with linux, darwin, freebsd and freestanding as compiler-owned values. It names the target's hosted system, never the compiler host, and is available only in fixed configuration. core/io/hosted uses it to select FreeBSD's native libc record; calling conventions remain selected by C ABI facts. The hosted bridge uses __error and O_WRONLY | O_CREAT | O_TRUNC = 0x601. The selected FreeBSD driver is Clang with an explicit FreeBSD sysroot and ELF linker; x86-64 assembly uses GNU as so the selected level constrains user assembly too. FreeBSD executable feature levels make no loader-refusal promise: the execution lane confirms the selected features before running higher-level code.

The alternatives: inferring libc record layout from the C calling convention, which reads and writes outside the actual record. Reusing the Darwin ABI fact because the errno spelling agrees, which misplaces variadic arguments. D256 declined an OS fact for C transport; the new fact serves the now demonstrated libc-record distinction and changes none of that transport. A backend copy would split instruction selection without changing the ABI.

Pinned by runtime/target-hosted-system-facts, negative/system-compared-with-architecture, negative/system-outside-configuration, abi/core-io-file-identity, targets/descriptions do not follow the host, targets/backends are stated per target, toolchain/a target names its toolchain, runtime/assembly-operands, the two backend register-verifier cases and compiler/tests/freebsd/check.py's recurring runtime, C peer and source-debugger sessions. FreeBSD's errno header, open flags and stat record state the libc contracts; the independent C peers check their selected headers.

D255 — A build assumes a CPU feature level, and a level changes no layout

From [1500] and [1550].

The discrepancy: [1500] selects declarations by architecture, and a target description named one processor: cortex-m0 was ARMv6-M, and the hosted targets emitted for the oldest processor of their architecture. A program could not be built for a processor with more, nor ask whether the one it was built for had something, so every instruction a newer core adds was out of reach without leaving the language for assembler.block.

Chosen: a build assumes one CPU feature level of its target's family, selected with --level=NAME and by the language server's level option. A level is a set of features; the levels and what each holds are:

familylevelfeatures
x86-64x86-64-v1, the defaultnone
x86-64-v2cmpxchg16b, lahf, popcnt, sse3, ssse3, sse4_1, sse4_2
x86-64-v3those, and avx, avx2, bmi1, bmi2, f16c, fma, lzcnt, movbe, xsave
x86-64-v4those, and avx512f, avx512bw, avx512cd, avx512dq, avx512vl
arm64armv8-a, the defaultnone
armv8.1-alse, crc32, rdm
M profilearmv6-m, the defaultnone
armv7-mthumb2, idiv
armv7e-mthumb2, idiv, dsp

The x86-64 levels are the x86-64 psABI's microarchitecture levels; the Arm ones are the architecture versions of the A-profile and M-profile manuals, in GCC's spelling. Synthetic-32 describes no processor and has no level. Each default is the level every backend emitted for before levels existed, so a build that selects none is the build it was. cortex_m0 names the M-profile backend's family, not its core: a build at armv7-m is still cortex-m0's description and ABI. Darwin's lowest processor, Apple's M1, has more than armv8-a; assuming less than a machine has is sound, so the default stays and a build for Apple silicon may select armv8.1-a.

A program reads its level as compiler.feature.NAME, a fixed bool fact [1500] that holds when the selected level has the feature NAME, spelled as in the table. A feature of another family is false rather than refused, so fixed if compiler.feature.lse then needs no architecture test before it, and a name no family has is L0305. compiler.feature is a member chain the grammar already derives; it adds no reserved word and no configuration atom, so no option name collides with one. Like every other fact it is read only in a fixed configuration expression.

A level changes which instructions the backend selects, which Cortex assembly text the checker admits, and which instructions the toolchain accepts, and nothing else. The Cortex text check uses the level so its default-only instruction allowlist does not refuse valid instructions of higher levels; type checking and IR do not depend on it. The assembler is held to the level at every level, the default included, so an assembler.block can use no instruction the build does not assume. At x86-64-v3 a variable shift of 32 or 64 bits is BMI2's shlx, shrx or sarx, which shifts by any register rather than by %cl; narrower shifts, which BMI2 has no form for, and every guard [0320] and [1950] ask of a shift are unchanged. At armv8.1-a an atomic add, exchange or compare-exchange is one LSE instruction, ldaddal, swpal or casal, rather than an exclusive-monitor retry loop; the acquire-release form inside the same full fences strengthens every ordering exactly as much as the loop does. At armv7-m a 32-bit quotient is sdiv or udiv and its remainder mls, after the same zero-divisor and minimum-over-minus-one guards, rather than a call to the runtime's __aeabi_idivmod; a 64-bit one still calls the runtime. Beyond that: every level of a family shares one layout, one calling convention and one C ABI, so code built at two levels of one family links together. A level is not a target. Comparing two descriptions still says which backend and which ABI, and type checking and the target-neutral IR do not depend on a level. A name that is no level of the selected family is L0009. A build at a level the machine running it lacks is not detected by the program; on Linux x86-64 the executable carries the level in its ISA note and the loader refuses it. Linux arm64 emits no ISA-level note and has no such loader-refusal protection. Selecting a supported level for its execution environment remains the caller's responsibility.

The alternatives: a target per level, --target=x86-64-v3, which multiplies every operating system by every level and makes comparing two descriptions answer a question about the processor when every caller asks which backend. A level in the target description, which is the same thing inside the compiler. Ordering levels and comparing them, compiler.level >= v3: the psABI's levels nest, but ARMv8-M's baseline lacks what ARMv7-M has and RISC-V's extensions combine freely, so a set is what a level is. Taking Apple's floor as Darwin's default, which changes the code every existing Darwin build emits.

Pinned by targets/levels are stated per family, targets/names select their descriptions, driver/a level is selected within its family, positive/feature-level-selects-declarations, negative/feature-unknown-name, negative/feature-outside-configuration, negative/feature-compared-with-architecture, end-to-end/feature-level-default-lacks-bmi2, end-to-end/feature-level-x86-64-v3-has-bmi2, end-to-end/feature-level-armv8-1-a-has-lse, end-to-end/feature-level-linux-arm64-default-lacks-lse, end-to-end/feature-level-linux-arm64-armv8-a-selects-without-lse, end-to-end/feature-level-linux-arm64-armv8-1-a-selects-lse, end-to-end/feature-level-armv6-m-lacks-idiv, end-to-end/feature-level-armv7-m-has-idiv, end-to-end/feature-level-of-another-family, x86 opt/a level selects its shifts, fixtures/profiles are explicit, backend/a level selects its instructions, driver/the arm64 default is armv8-a, fixture execution/an assembly block is held to its level, runtime/variable-shifts-at-every-width, which executes at x86-64-v3 too, runtime/r630-memory-scalars, which the Linux arm64 and Darwin lanes execute at armv8.1-a too, runtime/assembly-block-at-its-level, which selects a BMI2 assembly block by compiler.feature.bmi2 and runs at both x86-64 levels, runtime/assembly-block-at-its-arm64-level, which selects an LSE block by compiler.feature.lse and runs at both arm64 levels, and runtime/division-by-arguments-at-every-width, runtime/a-zero-divisor-traps and runtime/signed-division-overflow-traps, which the Cortex-M corpus executes at armv7-m on QEMU's Cortex-M3.

D256 — Linux arm64 is the standard AAPCS64, a third C ABI with unsigned plain char

From [1500], [1580] and [1975].

The discrepancy: [1975] selected two hosted C ABIs, both with signed plain char, and core/c made c_char an i8. Linux on arm64 uses the standard Procedure Call Standard for the Arm 64-bit Architecture, which is neither: Apple's variant puts every unnamed argument on the stack and packs named stack scalars at their natural size, the standard does neither, and its plain char is unsigned. A second arm64 description could not reuse compiler.c_darwin_lp64 without making that fact mean "arm64".

Chosen: linux-arm64 selects the standard AAPCS64 LP64, whose fixed bool is compiler.c_aapcs64_lp64. It is false on every other target, and compiler.c_darwin_lp64 is false on linux-arm64, so each C fact still names exactly one ABI and compiler.arch == arm64 is what the two arm64 targets share. [1975] states the transport: Darwin's banks, homogeneous floating aggregates, sixteen-byte indirect bound and x8 result, with unnamed arguments assigned as named ones are and every stack argument in whole eight-byte slots. core/c's c_char is the selected ABI's plain char, u8 under compiler.c_aapcs64_lp64 and i8 otherwise, chosen by a fixed if on that fact. x18 stays reserved, so one register rule, and one rule for assembly blocks, holds for compiler.arch == arm64. Both arm64 targets share D255's arm64 levels, so compiler.feature.lse means the same on each.

The alternatives: reusing compiler.c_darwin_lp64 for both arm64 targets, which misplaces variadic and stack arguments on Linux. One fact true on both with a separate Apple fact beside it, which changes what an existing fact means to every program that already reads it. A compiler.os fact, when the transport is decided by the ABI and FreeBSD's arm64 shares this one. Keeping c_char an i8, which disagrees with every header compiled for the target. Allocating x18 on Linux, which AAPCS64 permits and which would make an assembly block's register rules depend on the operating system.

Pinned by targets/descriptions do not follow the host, targets/backends are stated per target, targets/target contracts, targets/levels are stated per family, toolchain/file operands keep their identity, driver/fixed facts come from the target, and end-to-end/refine-identity.

D257 — A build targets the compiler's own host, and another target is named

From [1500] and [1550].

The discrepancy: [1550] says Landin relies on the assembler and linker of the platform, and says nothing of which platform a build that names none is for. The driver and the language server answered linux-x86-64 everywhere, so a plain refine --emit=exe on a Mac or on Linux arm64 compiled for a machine it was not running on and handed that assembly to a driver that could not finish it: a cross-compilation nobody had asked for.

Chosen: a build that names no --target=, and a language server whose editor names no target, is for the compiler's own host, and every other target is named. The host is the triplet the compiler itself was built for, which the Ada compiler fixes when it builds refine: an x86_64 Linux build defaults to linux-x86-64, an aarch64 Linux build to linux-arm64, and an aarch64 Darwin build to darwin-arm64. A compiler built for any other host has no default: a compilation that names no target is L0004, and a server there checks for synthetic-32, which emits nothing, and asks for a target. A request that compiles nothing, --identify or --help, needs none. refine --identify lists what is described, not the default, so its text is the same on every host. Nothing asks the running machine: a compiler built for x86-64 still defaults to linux-x86-64 under an emulator on an arm64 host, which is the compiler's host as its build says.

The alternatives: keeping linux-x86-64 as the default everywhere, which makes every native build off x86-64 Linux a silent cross-compilation. Asking the operating system at run time, uname or its equivalents, which is the host detection Landin.Targets exists to keep out of the compiler and which answers differently under emulation than the compiler's own build does. Refusing every build that names no target, which makes the common native build longer to write and gives cross-compilation no distinction.

Pinned by targets/names select their descriptions, driver/targets have a default, which reaches every host's default through the driver and the refusal of a host with none, and compiler/tests/test_default_target.py, which every gate host runs against its own refine.

DECISIONS: THE CORE LIBRARY AND THE DERIVED PROGRAMS

These were taken while writing core and the derived programs, and most bind those modules rather than any program the compiler accepts. D199 is the exception: its conversion matrix and its checked and trapping edges are language rules the compiler enforces in every program, and they sit here because writing the text layer is what forced them.

D151 — Raw storage is a private library state machine

The tour said that slice_from lies by describing uninitialized bytes as []mut T [0510]. The allocator and container pressure case derived the necessary transitions with a non-zeroable pointer element, but deliberately proposed no spelling.

Chosen: the repository-owned core/mem module declares a private parameterized nominal raw(item) with an allocation state (a byte pointer or no storage), capacity and an initialized slice witness. The witness length is the initialized count. D150 permits public routines to carry that private identity, so callers hold it through inferred bindings without being able to name its type or select its fields. The parser-support core adds the public parameterized alias storage(item) so another core module may name the same identity in a field or signature without exposing its representation. D135's alias introduces no second nominal identity. Cross-module field selection through such a value is L0202, related to the private type declaration. Code in the defining module retains ordinary field access; no field-visibility syntax or special raw type kind is introduced.

reserve records a supplied byte pointer and capacity with an empty witness. admit and transfer each construct a local ptr mut [1]item to name the first destination; constructing it is not a read or publication of an initialized array. capacity and initialized expose capacity and witness length. admit checks for raw_full before a complete typed store. For the first item it then takes the genuine singleton slice; for later items a narrow unchecked block stores at the old length before extending the witness by one. Neither step publishes spare capacity. get and replace check for uninitialized before their typed read or write; replace, like admit, declares the inserted value escaping. used returns only the initialized witness, with mutable element permission and from storage. release checks for raw_empty, saves the typed former tail and then shortens the witness. clear shortens the witness to zero in one transition, retaining capacity and backing without reading the discarded values; callers still manage any resources those values refer to. dispose checks for raw_not_empty, returns the original byte pointer and clears the allocation state, witness and capacity. The caller saves the capacity-derived byte extent before disposal; allocator ownership remains the container's composition rather than state stored in raw.

Growth is transactional by composition: a replacement begins empty; reads of the old prefix and admissions to the private replacement may be rolled back by tail release without changing the old value. Only after the full copy succeeds does the caller drain and dispose the old value and publish the replacement by assignment. transfer performs the copy as one initialized-source to next-destination transition, so a reference-valued item is not exposed as a borrow between the two raw values. Its private destination address uses [0470]'s explicit integer-to-pointer boundary for both first and later slots; the complete typed store precedes publication of the extended witness. This manual raw-storage responsibility does not exempt ordinary stores from [1910]'s origin checks, and unchecked still removes only D187's named edges. raw never yields a slice over capacity and never gives spare storage a T image. The public checks are declared atom outcomes, not traps, because these are foreseeable container conditions [0940].

The state machine does not validate the allocation behind its byte pointer. Supplying insufficient, misaligned, stale or otherwise invalid storage remains the unsafe pointer operation [0430]/[1720] says it is. Returned pointer-valued items and initialized views retain the conservative local from storage origin, so a caller ends that view before mutating the raw value again [0800]. No integer reconstruction is used to return the witness or read a transferred item. unchecked suppresses the append's dynamic bound check; it does not change reference permission or cut origin tracking. A writable view still has [0860]'s shallow alias limitation: inserting a reference through one alias is not generally propagated back to every other descriptor for that storage.

Initialized allocation composes with this state machine using ordinary library routines. new accepts an escaping complete initial value, allocates its target extent and alignment, stores it and then returns the pointer; delete consumes one pointer binding and frees that original extent. The byte-specific new_bytes returns a private byte_buffer containing the full allocation extent and an initialized byte prefix. Zero count makes no provider call; nonzero count publishes a view only after every byte is initialized. bytes derives its mutable view from the owner. drop_bytes empties the byte witness with clear, then dispose clears the descriptor before drop_bytes frees the saved original base and extent; a shortened borrowed slice is never used as allocation identity. These routines introduce no ownership, implicit destruction or exemption from shallow origin analysis.

The alternatives: a built-in raw-storage kind would add syntax, type-table and backend machinery for an invariant a private module can express. A public record would let callers forge counts. Reintroducing slice_from would make the original false value claim. Requiring zeroable would reject the pointer element that derived the contract. Trapping invalid transitions would turn foreseeable container state into process termination. All were declined.

Pinned by negative/core-mem-private-representation, runtime/core-mem-raw-storage, the rooted fixture execution path, and the raw.prefix and raw.backing guarantee rows.

D152 — The parser-support core is raw-backed and byte-oriented

The prototypes said that parser support needs allocator-threaded vectors, arena allocation and text positions, while Z3, Z9 and Z10 left their exact minimum unresolved. The allocator pressure case and D151 established the honest raw-storage boundary, but did not compose it into the modules the derived parser can use.

Chosen: core/mem.allocator(provider) has alloc, grow and free entries. grow may extend the same block from an old byte extent to a larger one; it returns false without changing the block or provider when it cannot. Callers fall back to allocation, transfer and free after a refusal. This addition lets a monotonic arena extend its current top allocation without spending the old extent again; other providers may always refuse. Allocation reports the declared out_of_memory atom. arena_over builds a monotonic allocator over a caller-supplied pointer and byte extent, aligning each successful result and refusing a result that does not fit. fail_over adds a successful-allocation budget and public counters so exhaustion and cleanup paths have deterministic executable evidence. Both returned allocator handles retain from base; returning one over frame storage is L0314. Freeing does not reclaim monotonic space. The pointer and extent remain unsafe caller-supplied backing under [0430], [0470] and [1720]. This ordinary library allocator is the explicit-authority replacement for [0820]'s formerly promised builtin forms. Its checked constructors require retainable backing and its private representations prevent direct construction; arena_over_unchecked and fail_over_unchecked mark a local-backing lifetime opt-out. D212 withdraws both builtin forms after D191 and D196 exposed the missing backing and escape semantics; the named refusals now report that disposition.

core/vec.list(item) contains one D151 mem.storage(item). It threads an allocator through reserve, push and release, while length, capacity, get and pop expose only initialized values. Growth first offers the provider an in-place extension. If refused, it allocates an empty replacement, iteratively transfers the complete initialized prefix, rolls back that replacement on failure, and publishes it only after draining and freeing the old storage. D194 replaces the original recursive traversal with ordinary loops for positive-sized items and bulk witness transitions for zero-sized items, and checks capacity arithmetic before allocation. A failing reserve leaves the old list and its values unchanged. Pointer elements are valid inputs; no zeroable constraint is introduced. get and pop translate raw bounds/empty results to out_of_bounds and empty; D194 distinguishes foreseeable capacity failures from the retained fallbacks for impossible internal raw-state failures.

core/text supplies an opaque nominal byte position, traversal, bounded byte access with past_end, and a half-open subslice whose result is from source. Positions are byte offsets because the parser consumes source bytes. This is not the complete [0600] text design: D161 subsequently adds the read-only []u8 literal view, while the other literal contexts, UTF-8 scalar decoding, codepoint indexing and the permanent text/string boundary were later text work.

The composition exposed four language rules needed by ordinary modules. D135 aliases may normalize to a nominal aggregate, selected calls are statement calls under [1810], a qualified declaration reference may appear in a declared error set, and origin inference follows selected calls and distinguishes a slice of a by-value fixed-array parameter from a retained slice parameter or inout storage. These are general language rules rather than privileges for core/*.

The derived parser did not require maps and trees. The hosted core library slice supplies those libraries, the typed initialized-prefix slice witness and core/small.small(item, N). The vector has a public wrapper with one private nominal storage field. Its explicit uninit inline array has a readable prefix bounded by count; its separate core/vec.list(item) descriptor owns spilled storage and reuses that list's transactional growth. The written zeroable constraint remains on the public alias and operations, but no longer causes eager inline clearing. small.push declares its inout container escaping so an aggregate copied from the initialized inline prefix may be retained in the fresh list during first spill; a plain non-escaping inout source is refused by L0314. Pop and release shorten the readable prefix without clearing unused slots; release disposes a spill and resets only metadata. Ordinary traversal and sorting use vec.used; D180's source-free iterable item does not replace that retained-origin view. Allocator acquisition and ownership remain outside the compiler; the modules thread an allocator supplied by their caller on allocating/freeing operations.

uninit is a contextual initializer only for an explicitly labelled fixed-array field in a private compact nominal construction inside its defining module. It emits no store for that field and is refused for module static images, public representations, packed layouts, scalar fields and stand-alone arrays. Construction establishes the containing value for transport, but it does not create readable item images in the array. The defining module is responsible for writing an item before every typed read and for restricting public access to the initialized prefix. Existing aggregate transport still copies the complete padded extent, including unspecified bytes; only written fields and prefix elements have value meaning. This is a deliberately narrow raw-storage responsibility like D151's pointer-backed prefix. It does not change ordinary zeroed, D19/D22 definite assignment for arrays, or D76 variant selection.

The alternatives: expose raw-backed vector capacity as []mut item, require zeroable, publish a partially copied replacement, store an allocator in each container, treat parser text as codepoints now, or implement the prototype's map and tree before a workload needs them. The first two repeat the false raw storage model D151 rejected; the third breaks failure atomicity; the fourth confuses capability threading with ownership; and the last two settle wider library design without parser evidence. All were declined.

Pinned by runtime/core-mem-allocators, runtime/core-vec-pointer-storage, runtime/r420-small-vector, runtime/r420-small-vector-providers, runtime/core-text-byte-positions, negative/core-arena-frame-escape, negative/core-small-live-view, negative/core-small-frame-view, negative/core-small-pointer-item, negative/core-text-frame-slice-escape, negative/core-text-private-position, and the allocation.failure, allocation.backing, raw.prefix, origins.escape and modules.visibility guarantee rows.

D153 — Hosted I/O is a libc-backed capability over a scalar import seam

D203--D208 supersede the narrow C signature limit and complete [1975]'s selected-boundary contract. D208 refines this decision's original executable- owned argument capture into the shared Landin- or C-owned startup contract. The original bridge decision below remains the basis of the hosted authority path, not today's complete C admissibility rule.

The tour and prototypes said that hosted arguments begin in C argc and argv form [1650], that the entry is where a root capability is minted [1660], that world access is passed as an ordinary argument [1680], and that core/io.world admits real and in-memory providers. They did not choose how the first backend reaches Linux services or how much of [1570]/[1580]'s foreign surface must become executable before the complete C work.

Chosen: D153 is exactly [1975]. The compiler implements bodyless extern(c) declarations for fixed scalar/pointer signatures and carries them as signature-only IR routines. The Linux backend captures entry argc and argv, then emits a small fixed bridge whose implementations tail-call libc for argument length, read-only and write-create-truncate open, file read/write/close and errno. One bridge entry publishes argv + 1; the private system provider stores that actual table capability and max(argc - 1, 0). The capability-aware indexed lookup has a distinct symbol, receives the stored table explicitly and returns its pointer from that table; the existing one-index helper remains unchanged for earlier foreign-boundary fixtures. The world.argument entry in turn returns its public pointer-and-length descriptor from self. Thus an in-memory provider may return caller backing under the same contract, while the system provider does not disguise a source-free global pointer with a false origin annotation.

Every world entry has D146's exact first self pointer. Open, identity comparison, close, read, write and write_some use ptr mut provider; standard streams, argument count and argument lookup use ptr provider. The system provider is ordinary composed conformance evidence and may be erased behind any world; generic wrappers retain the same operations for statically known providers. A read-only provider pointer cannot construct an erased world containing the mutable entries. The opaque file value remains one scalar descriptor whose interpretation belongs to its provider; sink on close consumes only the named handle place, so an earlier copy can still attempt a second close.

The bridge uses libc rather than direct syscalls because the hosted executable already uses the C runtime and libc supplies the smallest stable host contract for this workload. File descriptors remain private library representation. Arguments exclude argv[0]; a runtime fixture's new run_args metadata pins the distinction. Reads expose EOF as count zero and host failure as io_failed. world.write completes the whole slice by iterating over the remaining suffix; zero progress, the host failure sentinel, or a count larger than the offered remainder is io_failed. A failed write can leave an accepted prefix. world.write_some instead returns the positive accepted count of one nonempty attempt, including a short success. An interrupted host attempt with no transfer is retried with the same offer; a terminal failed attempt returns io_failed and transfers no bytes. Both operations accept an empty slice without a host call; write_some returns zero for it. open_read and open_write map Linux libc ENOENT to not_found, EPERM, EACCES or EROFS to no_access, and every other failure to io_failed. open_write supplies O_WRONLY | O_CREAT | O_TRUNC and mode 0666, subject to the process umask.

The required world.same_file(left, right) entry compares filesystem identity without opening or truncating either path. The input left must exist and be inspectable; any failure inspecting it is io_failed. An absent right returns false; every other failure inspecting it is io_failed. The hosted provider follows symlinks and compares the full native device and inode fields through a target-selected libc stat binding. Its private records are checked against native C headers on each supported host. The memory provider compares the first matching file-table indices under the same missing-input and missing-output contract. Identity lookup does not require opening a memory file or change its contents, cursor or counters. Neither provider promises an atomic check-and-open operation: callers relying on the result must ensure that names are not concurrently replaced. Every world provider supplies both same_file and write_some; existing implementations must add these entries to their conformance evidence.

The pointer-path entries require an already NUL-terminated path. The ordinary dynamic adapters take a byte view plus caller-owned writable scratch, reject an empty view, an embedded NUL, or scratch without one extra terminator byte in that order, and copy nothing before all three checks pass. No path is silently truncated and no hidden allocator is consulted. Public open_read_text and open_write_text obtain that byte view through core/text and use the same byte adapters and termination helper. Close maps a nonzero libc result to io_failed. On an otherwise successful path that failure is observable; when close is a reached undo while another declared failure is already propagating, D133 preserves the primary atom and cleanup cannot replace it.

The core/io module contains the target-neutral world concept, adapters and caller-backed memory provider. The libc-backed system provider and its extern(c) bridge live in core/io/hosted; hosted roots import that module explicitly and call hosted.host(). Selecting core/io alone does not select foreign declarations, so the same world API can be used by Cortex-M0 consumers. The hosted provider still conforms to io.world, and the bridge and errno contract above remain unchanged.

The bounded core/io.memory provider implements the same capability from caller-supplied file descriptors, content buffers, argument descriptors and standard-output/error buffers. It makes no host calls and allocates no storage. memory_world retains those four supplied slices through its result's from clause. Files are existing-only, selected by the first matching name; opening resets the cursor, and opening for writing truncates only after permission, open-state and capacity checks. Construction preserves the supplied file state. A file-table index is a provider-local handle, with no generation or ownership identity: a copied stale handle can address a reopened slot.

A positive read_limit bounds each read. Zero progress with unread data and a nonempty destination reports io_failed, so it cannot masquerade as EOF. write_limit bounds each write_some attempt; zero reports io_failed for a nonempty write. A successful attempt returns a positive count, possibly short, and a failed attempt transfers nothing. write repeatedly calls that operation to complete its slice; a later failed attempt preserves the exact completed prefix. Empty reads and writes are unconditional no-ops, even for closed handles, and do not advance failure counters; an empty write_some returns zero. Other operations validate the handle. Failure schedules name one-based read, write-chunk and close counts; zero disables injection. A valid close clears the open state before its injected failure, allowing ordinary manual cleanup to consume the handle once.

The memory representation is public composition. Clients preserve initialized lengths and capacities, leave headroom for checked operation-counter increments, and keep both descriptor tables and all nested file-name, content and argument backing valid. Transfer source and destination ranges must not overlap. These are caller obligations, not ownership or transitive alias guarantees. Argument lists exclude the executable name; argument returns a view from self. written and written_errors take the memory provider inout and return only the initialized output prefix from that provider, retaining the ordinary local frame-escape and live-view checks.

An argument deliberately remains the foreign-shaped ptr u8 plus byte length used by both providers; it is neither a cstring nor a fabricated slice. Ordinary core/io.copy_argument first checks that caller-owned scratch has at least the exact argument length, then copies the bytes and returns the genuine initialized prefix from scratch. Insufficient capacity changes no byte, and an empty argument returns an empty scratch-derived slice. The caller keeps the complete source extent readable during the copy, ensures that its addresses are representable, and does not overlap scratch. The copied view may then be validated by core/text.from_bytes; no pointer-to-cstring conversion, hidden allocation or pointer-to-slice operation is introduced. Both provider argument sequences contain only user arguments and exclude argv[0].

The backend's calls to strlen, open, read, write, close and __errno_location are private runtime dependencies, not names reserved from Landin source. A non-external Landin declaration with one of those spellings is therefore given a deterministic whole-program assembler name, just as two reached module declarations with the same short name are. The selected hosted entry and an extern(c) declaration retain their required ABI spellings. This prevents a public Landin open from interposing on the bridge while preserving the explicit foreign-symbol contract.

The alternatives: direct Linux syscalls would couple the first hosted library to kernel numbers and conventions without reducing the already-linked C boundary. Enabling aggregate returns, unions, variadics, callbacks, foreign allocation ownership or generated header bindings would pre-empt the complete C boundary. Making I/O a compiler intrinsic or global singleton would defeat [1660]'s replaceable capability. Passing C-shaped parameters to Landin main would reverse [1650]'s chosen ordinary no-argument entry.

This selects the bootstrap provider, not permanent compiler ownership of I/O. The hosted modules and the C boundary retain both direct libc declarations with explicit library linkage and target-specific core providers built over inline assembly or separately linked syscall wrappers. Either may implement the same world capability without changing its callers.

Pinned by positive/external-scalar-c-boundary, negative/external-aggregate-boundary, negative/core-io-world-readonly-receiver, negative/core-io-file-use-after-close, runtime/hosted-io-reads-parser-input, runtime/core-io-erased-system, runtime/derived-parser, runtime/derived-hosted-memory, abi/r440-errno-interposition, the rooted fixture execution path, and the host.io, host.io-failure and extern.c-boundary guarantee rows.

D258 — Hosted capability parameters select providers without excluding new roots

The tour and prototype 4 said that the entry normally mints host roots [1660] and that ordinary routines receive capabilities as arguments [1680]. They also expose public, zero-argument host constructors. The original W1 resolution called the argument list enforcement below a root, but an ordinary helper can mint another root below that call.

Chosen: keep the constructors public and permit ordinary hosted routines to call them. A capability parameter promises that the caller can supply a provider for uses of that parameter; it does not promise that the routine or its callees have no other route to host I/O or allocation. Passing an in-memory world or bounded allocator makes code that uses those providers substitutable and testable. For a whole call tree, that claim requires inspecting its calls and imports, not reading its signature. The derived hosted-memory fixture even mints a heap root inside a parameterless helper. This is an explicit limit of the current capability model for trusted code as well as untrusted code.

The alternative: restrict root construction to an entry module or add an effect or authority rule checked through calls. Either would improve the checkability of host exclusion for code below that boundary, but would add a privileged module or whole-call-graph rule to ordinary function checking. Entry-module restriction alone would still leave direct foreign calls and freestanding address literals as independent authority paths. Without an actual need for a static exclusion guarantee, the added machinery and incomplete boundary do not earn their cost for a systems language. The roadmap's language-evolution record reopens this choice when trusted code needs that guarantee or when untrusted code must be run, and requires the proposed boundary to account for those other authority paths.

Pinned by runtime/derived-hosted-memory, whose long_lines helper calls heap.host() without an allocator parameter, runtime/core-io-erased-system for provider substitution, and the capabilities.host-root-exclusion guarantee row. These demonstrate the current behavior; they do not prove that an arbitrary call tree uses only supplied providers.

D154 — Diagnostics separate retention from delivery failure

The tour and prototype 2 said that a diagnostic sink is an ordinary capability [0950] [1680], that a parser reports foreseeable syntax mistakes and continues, and that bounded and streaming sinks must be interchangeable. They did not say whether bounded overflow or a failed hosted write belongs to the parser's error channel, how a retained message keeps its origin, or whether the two implementations use the same dynamic call path.

Chosen: core/diag.log(logger) is an object-safe concept with note and failed. note receives a mutable self pointer, core/text.position, a u8-represented warning/error severity and a call-scoped []u8 message, and declares core/io.io_failed. failed reports whether any error-severity note has been received. A producer accepts any diag.log and invokes both entries through D147's ordinary erased evidence table; it neither names nor branches on the concrete logger.

bounded(capacity) is a parameterized private nominal implementation. It copies up to message_capacity (256) bytes into each retained entry, so a producer may pass a frame-backed message through the shared concept. It retains fitting notes in order until capacity entries have been stored; every note that arrives after the entry limit or exceeds the byte limit increments dropped. Error severity is counted even when that note is dropped. Overflow returns normally and never raises io_failed. Entry and logger representation stay private; checked accessors report out_of_bounds rather than exposing unused storage. A returned entry owns its copied bytes and remains valid after the producer's frame ends. Its inline note array is explicitly uninit at construction; each owned entry is written before stored grows, and note_at checks that prefix.

streaming retains a pointer to an erased core/io.world and a borrowed file, not a system-provider pointer. Its construction result derives from both stored addresses, so neither frame-local world-pair storage nor frame-local stream storage may escape through it. It writes W: or E:, the decimal byte position, :, and the message bytes as the note arrives through ordinary dynamic world dispatch. Each write propagates io_failed; the error count is updated before delivery is attempted, so failed describes what the logger received rather than what the selected provider accepted. Both logger implementations receive the same ordered calls in the executable evidence.

The implementation pressure also closes two existing representation seams. A fixed formal used in a generic routine body is D138's per-instance constant and has no ABI position. An aggregate place reached through pointer .val uses the same target-neutral runtime-address storage path as a computed aggregate index; .val is not encoded as a fictitious field zero.

The alternatives: treating bounded overflow as failure would make a parser stop because its reporting policy is intentionally finite. Ignoring a failed stream write would claim delivery that did not happen. Giving each logger a different producer interface would erase the capability abstraction, while specializing the producer would make optimization the semantic basis contrary to [1310]. Retaining arbitrary frame bytes behind an origin-erasing address was also declined. The bounded implementation uses a finite copy budget and reports an oversized note in dropped instead.

Pinned by runtime/diagnostic-loggers-dispatch, negative/core-diag-frame-message-escape, negative/core-diag-frame-world-escape, the parameterized and erased conformance registers, the diagnostics.retention, diagnostics.delivery-failure, origins.escape and host.io-failure guarantee rows, and the rooted fixture execution path's recorded merged output.

D155 — The derived parser is ordinary composition, not a privileged stage

Prototype 2 said that a useful parser retains positioned bad input, reports foreseeable syntax faults through a replaceable sink, recovers and keeps valid nodes, while allocation, nesting and delivery failures take explicit paths. It used loops and the future text surface, and therefore did not settle what the enabled kernel of the time could honestly execute.

Chosen: the derived lexer and parser are ordinary rooted Landin modules. The lexer classifies an intentionally ASCII configuration grammar over core/text byte positions and emits bad-character and unterminated-string tokens rather than dropping bytes. The recursive-descent parser stores a recursive variant tree as arena-allocated value nodes reached through core/vec.list(ptr mut value). Syntax mistakes call an erased any core/diag.log, recover at a newline, brace or end boundary, and do not enter the public error set. Excess nesting is reported and recovered internally. Only core/mem.out_of_memory and core/io.io_failed leave parse_file.

The same parser body runs with bounded and streaming D154 providers. No specialized parser copy is emitted or required. When loops and the complete UTF-8 text model were not yet enabled, scanner, recovery and sequence walks used recursion over core/text's byte positions as an implementation substitution, not a second parser design. Now that loops are enabled, recovery skips malformed-line tokens in a loop: the recursive walk could exhaust the process stack before reaching a boundary. Scanner and sequence walks remain recursive, and recovery still leaves newline, brace and end tokens for its caller.

The program also pins general compilation rules already implied by the language. A try call followed by another statement is the statement form of [1810], not an expression consuming the rest of the body. A pointer to an ordinary nominal needs the target's identity without forcing its value layout, including when nested in a parameterized wrapper; only by-value recursion is L0313 under D137. A concrete call's named recovery binding and body are checked even when result inference first reaches the call. Stored aggregate results from calls or control expressions are produced in caller-owned temporary storage before being copied into a nested or runtime-addressed destination. None is a parser-only exception.

The alternatives: implementing the workload inside the Ada frontend would test the wrong language; stopping at the first syntax fault or putting each one in the declared error channel would reverse Y1 and [0950]; waiting for loops, UTF-8 text or specialization would make the first major compiler milestone depend on later surface or optimization work. Adding special AST allocation, diagnostic or parsing intrinsics would duplicate the ordinary allocator, container and evidence mechanisms. All were declined.

Pinned by runtime/derived-parser, positive/try-statement-before-return, its DERIVATION.md, the prototype derivation register, and the complete rooted fixture path.

D191 — The region and the derivation cut are core's; the arena block is refused by name

D196 carries this increment's unresolved arena questions forward; D212 now settles them by withdrawing both builtin forms. The original rationale below records why the compiler first added the named refusals.

The tour said that arena is built in, both as a block and as the type a parameter is written with at [0780] [0820], and that derivation stops at the three primitives of [0500] — offset, base_of and slice_from — which "yield a reference independent of what went in, and core answers for that" [0810]. Neither paragraph says what the block's name is a value of, where its bytes come from, or what any of the three primitives costs the compiler. Between them they name one operation this repository has already refused to have and two that do not exist.

Chosen: all three constructs belong to core and to the allocator surface, not to this kernel. [0500] and [0810] describe library functions with no compiler privilege, and the hosted core library slice owns them because it would add them. [0820] is language syntax, and it is recognized and refused by name here rather than enabled: the parser reports L0010 on the arena of arena name do and swallows the block's own end name, and the checker reports L0304 on a written arena type. At this increment both notes name [0820] and the hosted core library slice. The construct applicability register moves all three rows to that later hosted work, the shape [1430] and [1440] already have.

The pointer half is settled by evidence rather than by scheduling. [0810] says the three primitives are the cut that lets an allocator hand out storage pointing into itself without the storage borrowing it. core/mem's arena_alloc does exactly that today and reaches none of them: it computes usize(state.base) + offset and converts the sum back with ptr, which is [0470]'s integer-to-pointer conversion. That conversion is already the cut, already classified — the pointer.integer-origin guarantee row calls it a non-guarantee with four fixtures behind it — and already in the open, written in the library where a reader can audit it. slice_from is not deferred at all: D151 rejected it for [0510]'s reason and the repository will not have it. offset and base_of are the library spellings of a cut the compiler already makes, so making either a compiler intrinsic would put a core name in the frontend against [0490] and buy nothing. [0810] is amended to say this; the example keeps its spelling, because changing it would assert an operation the language does not have.

The block half is refused because four questions decide it and neither document answers one of them. Which type the block name has, and how it meets [1360]'s allocator contract without the frontend depending on core/mem. Where the region's bytes come from and how many, on a host and on a 32 KB part, given that [0820]'s own promise is that the extent is exact rather than guessed. Whether exhaustion is out_of_memory or a trap. And how "everything from it has frame origin, and allocated once the arena is passed on" is expressed at all, when [0790] says an allocator's result carries no from clause and therefore borrows nothing. That last one is why the obvious shortcut is unsound rather than merely incomplete: lowering the block to mem.arena_over over a hidden frame buffer would make every allocation out of it an independent origin free to be returned, which is the precise opposite of "nothing from it may leave the block". Shipping that would be worse than the refusal.

The refusal is complete because [0820] has two faces. Refusing only the block would leave (a: arena) reported as a name declared nowhere, which is a true sentence about the wrong thing, and the second half of the paragraph would go unmentioned. So the parser owns one face and the checker owns the other, for the reason the two tables are separate: the parser refuses a shape it can read off the tokens, and the checker refuses a name it had to resolve first.

arena is not added to [1760]'s keyword rule, and that is the price paid for the shape gate. core/mem declares public arena: type = arena_value over a private representation; examples/config_parser threads a parameter spelled arena through six functions, and [1760] promises that a program avoiding a construct never trips over its keyword. So the parser recognizes three tokens — arena, a name, do — and nothing else. arena = x, arena(x), arena: loop do and mem.arena are all untouched, and runtime/arena-is-an-ordinary-name pins that from the other side.

The alternatives: lowering the block to mem.arena_over over a frame buffer the compiler supplies was declined above — it guesses the extent [0820] says is exact and inverts the frame/allocated rule the paragraph turns on. Reserving arena as a keyword was declined because it deletes the library arena's spelling, breaks negative/core-arena-frame-escape and runtime/derived-parser, and breaks [1760]'s stated promise. Making mem.offset and mem.base_of compiler intrinsics was declined because [0490] puts pointer policy in core and [0470] already supplies the cut. Reopening slice_from was declined: D151 closed it and no new evidence argues otherwise. Leaving the block to the ordinary parse error was declined against [1830] — a program written against the whole tour must meet a named diagnostic and not a four-report cascade, and before this decision it met the cascade. Keeping the three rows as work already done on the hosted path, with a refusal naming the hosted construct work, was declined because that work cannot close over a refusal that names it, which is a rule check.py enforced.

Pinned by negative/arena-block-not-enabled, negative/arena-type-not-enabled, runtime/arena-is-an-ordinary-name, and the pointer.integer-origin guarantee row. D196 completes the [0500]/[0810] disposition and transfers both [0820] refusals and all four questions to the derived hosted application; the compiler still grants no privilege to a core name.

D193 — Arena requests align absolute addresses and fail atomically at arithmetic boundaries

The tour and prototypes said that an allocator receives a byte size and alignment and reports only out_of_memory [1360], that a caller-backed arena advances a monotonic offset, and that its backing pointer and extent remain an unsafe caller assertion [0430] [1720]. The first core/mem implementation aligned only that offset. A base at address n + 1 could therefore return the same misaligned address for an alignment of eight. Its rounding addition and later base, padding, and size additions could also trap for usize overflow instead of taking the allocator's declared failure channel.

Chosen: core/mem.arena and core/mem.failing align the numerical absolute address usize(base) + used. Every positive alignment is its ordinary numeric address multiple; zero has the same byte-aligned meaning as one. The contract does not require power-of-two alignment, although every alignment produced by alignof for an enabled type is one. A size of zero is a valid request. It returns the aligned point and consumes any padding required to reach it, but no payload bytes. In failing, it is still one successful allocation and consumes one unit of allocation budget, just as the provider's existing counter contract says.

Before forming each sum, the providers prove that base + used, its aligned address, the aligned offset, and the exclusive allocation end fit usize, and that the aligned request fits the stated extent. An impossible operation reports out_of_memory; it does not reach [0300]'s overflow trap. Extent or budget exhaustion has the same failure atomicity. No failed allocation changes used, remaining, allocations, or any other provider field. Exact positive exhaustion succeeds, a further positive byte fails, and a zero-byte request at that same end succeeds exactly when its aligned point still fits. The last representable address is consequently a valid aligned point for a zero-byte request, but not the beginning of a one-byte request whose exclusive end would be unrepresentable.

These checks validate the provider's arithmetic, not the caller's assertion that the backing storage is live and covers the stated extent. The latter remains the allocation.backing non-guarantee. Frees continue to reclaim no storage, the failing provider continues to count each free call, and the arena and failing-provider construction, origin, counters and ordinary allocation semantics are otherwise unchanged.

The alternatives: aligning only used relies on an unstated prealignment of caller storage and was the defect repaired here. Requiring a power of two or rejecting zero alignment would add an invalid_alignment policy [1360] does not expose and would change the provider's existing alignment <= 1 behavior. Rejecting zero size would likewise add a new error condition and make empty generic extents special. Letting checked arithmetic trap would bypass the one foreseeable allocation-failure channel the concept deliberately fixes. All were declined.

Pinned by runtime/core-mem-allocators, which retains the original monotonic and budget behavior, and runtime/core-mem-arena-boundaries, which uses misaligned caller storage, zero requests, exact exhaustion and maximum-usize size, alignment, address and end calculations.

D194 — Vector capacity arithmetic is checked before allocation and transfer uses bounded stack

The tour and prototypes said that allocation reports out_of_memory [1360], raw storage exposes only initialized items [0510], and vector growth preserves the old list until replacement succeeds. D152 implemented that composition, but want * sizeof item and geometric doubling could overflow before reaching the provider. Its copy and drain helpers also recursed once per initialized item, although ordinary loops are now enabled.

Chosen: for a positive-sized item, reserve checks want <= maximum_usize / sizeof item before multiplying or calling the provider. An unrepresentable byte extent reports mem.out_of_memory with no provider call and no change to the old capacity, initialized count or contents. The largest representable extent reaches the provider unchanged; the provider still decides whether it can supply that request. A request no larger than the current capacity remains a no-op.

An enabled zero-sized item, such as [0]u8, retains logical capacity and an initialized count. Its byte extent is zero without division. Every successful increase to a nonzero capacity performs one zero-byte allocation, later paired with one zero-byte free using the returned pointer. Admission, transfer and release change the logical count without copying payload bytes. Growth establishes the replacement's initialized witness with one complete typed store through the returned pointer, then extends that witness to the old logical count in one step. It does not require a zeroable item or invent backing when the provider returns an invalid pointer. Releasing or replacing zero-sized storage shortens its witness in one step before disposal. These bulk transitions check the old initialized count, replacement capacity and allocation token; failed allocation still leaves the old list untouched. Even maximum_usize is a representable reserve capacity for this item. Capacity zero acquires no allocation; releasing an empty-capacity list, including a second release, makes no provider call. No zeroable constraint is added.

The current geometric policy starts at eight slots and doubles thereafter. Doubling a capacity greater than maximum_usize / 2 fails before multiplication or a provider call; push reports mem.out_of_memory. The private arithmetic helper is tested directly at that boundary through ordinary same-module source composition. It is not a public test API or a promise that a particular growth factor is part of the list's public interface.

Positive-sized copy and drain use loops with stack usage independent of list length; zero-sized copy and drain take constant work. Only the old initialized prefix is transferred. A positive-byte vector may instead extend its existing allocation when the provider confirms that the same block owns the larger extent. Its initialized prefix and pointer stay in place; only its private capacity changes. A refusal changes neither provider nor vector state and proceeds to the ordinary replacement allocation. Zero-byte items always use the replacement path and retain their exact allocation/free counts. For replacement, the fresh list remains private until that copy succeeds and the old initialized values have been drained and their allocation freed with its original exact byte extent. Publication is last. Failed allocation leaves pointer values and the list shape intact, and a retry uses those same initialized values. No spare-capacity typed view is formed.

D151's private raw counters make transfer failure impossible for a valid vector and a larger fresh allocation. The inherited defensive path still drains and frees the replacement and returns the vector's existing out_of_memory result if that invariant fails; this fallback is not evidence of provider exhaustion. The inherited drain/dispose rejection paths return early without manufacturing an allocation error. These are internal invariant failures, not new recoverable raw-state guarantees. Admission after a successful growth or spare-slot check retains the same defensive out_of_memory fallback if its supposedly available slot is rejected. The public list shape and unsafe raw reserve operation do not validate caller-forged backing or storage states. Arithmetic checks do not strengthen allocation.backing.

Positive zero-sized coverage exposed a missing implementation path for enabled fixed-array whole stores through pointer .val. Such stores and copies use the ordinary runtime-address representation, retaining nested variant payload steps. The destination is evaluated once, before the source; if its evaluation leaves the block, no address instruction, RHS or store follows. Nonzero arrays pin actual copies as well as zero-byte execution. The large-list case also requires generic discovery to type traversal headers before deducing calls whose arguments include the range variable, preserving [1150] and D138's exact argument descriptors before the error graph closes.

The alternatives: wrapping byte products or letting checked arithmetic trap bypasses the declared allocation error channel. Rejecting enabled zero-sized items or adding zeroable would narrow the existing generic contract to avoid a compiler defect. Recursing per item consumes unbounded stack for a valid large list. Publishing before copy completion exposes a partial replacement. All were declined.

Pinned by runtime/r420-vec-capacity-boundaries, runtime/r420-vec-growth-boundary, runtime/r420-vec-growth-transaction, runtime/r420-vec-large-list, runtime/r420-fixed-array-pointer-whole-copy, and runtime/core-vec-pointer-storage.

D195 — The hosted heap over-allocates through a fixed libc shim

The tour and prototype said that one allocator concept serves heap, arena and fixed-buffer providers [1360], that an allocator result is an independent origin [0790], and that cleanup errors hidden by a monotonic arena need a real reclaiming provider. They did not give the hosted provider an alignment or zero-size contract, or choose the libc operation behind it.

Chosen: core/heap is a hosted module separate from the freestanding core/mem protocol and caller-backed providers. Its system type conforms to mem.allocator, and host() mints the otherwise stateless capability. The module declares only two [1975] runtime routines: (usize, usize) -> allocation allocation, where allocation: type = no_allocation | ptr mut u8 and no_allocation is an atom, and ptr mut u8 -> none release. The no_allocation arm maps to mem.out_of_memory; the pointer arm carries a non-null allocation. No foreign error or ownership type crosses the seam.

Every usize alignment is accepted. Zero and one request no stricter than byte alignment; every greater value returns an address whose integer value is an exact multiple of that value. A successful zero-byte request returns a distinct non-null token that may be released but not dereferenced. The Linux x86-64 shim asks malloc for the requested size plus one pointer word and at most alignment - 1 padding bytes, aligns within that allocation, and records the original libc pointer in the preceding word. Release recovers that pointer and passes it to free; the allocator contract's size remains available to wrappers and is not required by libc.

The shim checks both additions and refuses a total above PTRDIFF_MAX before calling malloc. This makes the maximum admitted request depend on alignment: size + sizeof(ptr) + alignment - 1 must be representable and no greater than the host's PTRDIFF_MAX. A null malloc result becomes no_allocation in the bridge and takes the declared out_of_memory path. Pointer-word width, the PTRDIFF_MAX test and hidden header layout are selected-backend facts in the runtime shim, not constants or structures in target-neutral IR. The public module therefore contains no host pointer-width arithmetic and creates no general C ABI, foreign-ownership, nullable-pointer or syscall surface.

The alternatives: aligned_alloc and posix_memalign were considered. Both restrict alignment to powers of two, posix_memalign additionally needs a pointer-to-pointer carrier, and their zero-size result can be null. Adopting those contracts would narrow [1360] for a provider when a small over-allocation shim can retain every admitted alignment and deterministic empty allocations. Calling malloc(0) directly was declined because its portable result is not deterministic. Putting the heap in core/mem was declined because merely importing the freestanding protocol must not import hosted authority. Direct syscalls, a general C binding, and storing the allocator in a container remain outside this slice.

Pinned by runtime/hosted-heap-provider, the backend case a hosted heap shim checks before libc, and the allocation.failure guarantee row. The runtime audit sees two differently aligned live blocks, exact requested extents, a non-null empty allocation, the old and replacement allocations coexisting during vec.list(ptr node) growth, and no live block after release.

D196 — The library omits pointer conveniences and transfers lexical arena to the hosted application

D212 now discharges the arena handoff below with explicit-authority library semantics and permanent withdrawal of both builtin forms. The pointer convenience dispositions remain unchanged.

The hosted core library slice inherited D191's [0500], [0810] and [0820] dispositions. Its scope explicitly permitted recording the two pointer conveniences as unneeded and naming the work that inherits the lexical block. The working caller-backed allocator does not implement the block's promised region semantics.

Chosen: offset and base_of are unnecessary for this library slice. The allocator uses ordinary [0470] conversions; slice consumers check for nonempty storage before taking an element address. Neither operation is an enabled API or a privileged compiler name. [0810] now states the actual integer-to-pointer derivation cut, and [0580]'s empty-base representation no longer implies that an omitted accessor exists. D151's rejection of an arbitrary-pointer slice_from remains in force.

Both arena name do and the builtin arena parameter type remain refused by name, now against the derived hosted application. That work owns the first complete program using prototype 4's W7 helper-returned configuration, and precedes the hosted parity gate. It inherits all four D191 questions: builtin type and ordinary allocator conformance without frontend dependence on core/mem; authority, backing and capacity on hosted and constrained targets; exhaustion behavior; and the relationship between direct frame-origin allocations and independent results of ordinary allocator calls. The library slice gains no dependency on the application.

The last question has a concrete counterexample to W7's historical argument. A helper passed the allocator can allocate through its no-from signature and store that independent pointer in module storage as a side effect. The reference never returns through the lexical block's boundary. Even an ordinary helper return carries no signature fact reconnecting its allocation to that block. Merely checking the block's returned value therefore does not establish its promise. The application must implement the promised checks with explicit semantics or amend the promise on evidence before claiming the complete application. It must cover direct, helper-returned and helper-side-effect escapes, including aggregates, slices and any, while allowing simultaneous allocations and helper results used inside the block. Explicit unsafe pointer conversion remains a documented non-guarantee.

The alternatives: a hidden frame buffer guesses capacity and returns independent pointers, so it still fails D191. Adding from allocator revives prototype 3's rejected Z5 behavior: a live allocation borrows the allocator and prevents another allocation. Neither is a region implementation. Sending the questions to an unspecified future library would leave the complete hosted prototype and the hosted gate without an owner. Leaving the three-primitives claim above a contradictory caveat would retain a false rule. All are declined.

Pinned by negative/arena-block-not-enabled, negative/arena-type-not-enabled, negative/arena-block-names-owner, negative/arena-type-names-owner, runtime/arena-is-an-ordinary-name, runtime/core-mem-allocators, runtime/core-mem-arena-boundaries, and the pointer.integer-origin guarantee row. The refusal transcripts then named the hosted application; the working allocator fixtures provide no claim about lexical arena escapes.

D197 — Fixed slots use caller metadata and failure injection wraps a provider

The tour and prototype said that one allocator concept serves a fixed buffer as well as a heap or arena [1360], that allocators are threaded rather than stored in containers, and that deterministic allocation failure exposes transactional bugs. They did not say how a reclaiming fixed provider stores its finite free-state or how a generic failing provider retains and audits its inner allocator.

Chosen: core/pool is a caller-backed reclaiming provider distinct from the monotonic core/mem.arena and hosted core/heap. Construction receives an explicit byte pointer and exact extent, a positive uniform slot size, a finite slot count, a slot alignment, and a caller-supplied initialized []mut pool.slot. Each record holds the live request extent or vacancy sentinel, and one free-index heap entry; the heap uses the same caller-supplied slice and no other storage. The slice length is the explicit finite bookkeeping capacity and the requested slot count may not exceed it. Construction initializes the active records only after every configuration check succeeds. The caller reserves those records for the provider while it is in use. Its result's from base, bookkeeping clause retains both when the actuals have tracked origins, and a local metadata slice cannot escape beside a named backing parameter. The module imports no heap and has no fallback.

Each pool.slot stores a usize requested size and a usize free-heap index. The maximum requested size marks an unoccupied slot, removing the old Boolean field and its padding. Cortex-M0 bookkeeping shrinks from twelve to eight bytes per slot; hosted 64-bit bookkeeping shrinks from twenty-four to sixteen bytes. The free-index heap retains lowest-index reuse. A positive pool refuses a slot size equal to that marker. Such a slot would require a base address of zero to fit in the target address space, and [1975] forbids constructing a non-null pointer there. Zero-slot pools may still use that size. A zero-size request stores zero and still occupies a slot. The single caller slice and the from base, bookkeeping origin clause remain the same.

The existing whole-value origin algebra still applies: Untracked is an OR. If one constituent is deliberately made untracked, such as a base produced by ptr(integer), the complete provider is untracked and the checker does not independently enforce the other constituent's tracked metadata origin. This is the mixed tracked/untracked non-guarantee, not evidence that metadata was dropped from over's declared sources. The caller remains responsible for both storages; no field-sensitive origin or provenance mechanism is added.

Zero and one configuration alignment mean byte alignment. For every other usize value, construction uses D193's checked absolute-address algorithm to find the first aligned address, rounds the uniform stride with checked arithmetic, and proves that every complete slot fits both the declared extent and the target address space before publishing the provider. An allocation accepts a size no greater than the slot size and alignment zero or one, or an alignment that divides the configured slot alignment. It consumes the lowest free slot, including for a zero-size request, and records the exact requested extent. A free reclaims only an occupied exact slot address with that recorded extent. A wrong address, a wrong size, or an address whose slot is currently unoccupied is rejected and counted. After the same slot is freed and reused for the same extent, a stale pointer is indistinguishable from the current allocation and remains [0430]'s pointer-validity non-guarantee; the pool adds no generation identity. The free-index min heap selects the lowest free slot in logarithmic time. Free derives a candidate index from the address and fixed stride before checking occupancy and extent; a valid free updates the heap in logarithmic time, while an invalid free leaves it unchanged. Allocation, valid-free, live and rejected-free counts are observable audit evidence.

The uniform domain is deliberate. A vector or map chooses a slot size at least as large as its greatest planned extent and supplies one metadata record for each allocation that may be live simultaneously. In particular, a transactional map rehash that holds three old and three replacement extents uses six records. The implementation has no unrolled boolean ceiling and the capacity is not an arbitrary library constant.

core/failing.counted(A) is a separate generic wrapper for any mutable A is mem.allocator. count_down takes an ordinary nonescaping ptr mut A and returns counted(A) from inner: the returned value retains the actual's origin without [1880] requiring that actual itself to have an origin independent of the call. The wrapper therefore accepts local heap and pool providers for local use, while returning such a wrapper past the inner provider's frame remains L0314. An immutable provider pointer is L0340.

The budget counts future allocation calls allowed to reach the inner provider. It is consumed before delegation, so an inner failure consumes one attempt; after it reaches zero, an injected out_of_memory does not invoke the inner provider. Resetting the budget preserves cumulative attempts, delegations, successes, injected failures and inner failures. Every free is delegated once with its original pointer and extent. Because the allocator entry returns no free result, wrapper frees and live are valid-free accounting: malformed or duplicate frees are still delegated, and an inner rejection cannot be learned or reflected in the live count.

The parameterized conformance (A: type is mem.allocator) counted(A) is mem.allocator is ordinary evidence. Neither provider changes mem.allocator, stores a provider in a container, adds an ownership type, or creates a new ABI.

The alternatives: four unrolled occupancy booleans, a larger magic slot limit, hidden heap bookkeeping, and heap fallback were declined because each either fails a known six-live allocation transaction or makes an explicitly finite provider silently unbounded. A fixed generic capacity was possible, but the admitted initialized mutable slice already exposes caller storage, runtime count and capacity without generating a family of provider types. Layering deterministic refusal into the monotonic arena was declined because it cannot provide real reclamation or wrap heap behavior. Marking the inner pointer escaping was declined because [1880] would unnecessarily exclude a local actual even when only the returned wrapper retains it.

Pinned by runtime/r420-pool-provider, runtime/r420-failing-providers, negative/core-pool-frame-escape, negative/core-pool-bookkeeping-frame-escape, negative/core-failing-needs-mutable-inner, negative/core-failing-frame-escape, and the allocation.failure, allocation.backing, allocation.reclamation and origins.escape guarantee rows. Runtime evidence covers zero and one delegation budgets, finite exhaustion, six simultaneous live slots, exact-alignment writes, exact free/reuse, inner and injected failure counts, and failed pointer-vector growth followed by retry and complete release.

D198 — Map buckets are initialized records over dense key and value prefixes

The tour and prototype said that map(K is hashable, V) uses open addressing without a null or sentinel key, that hash reduction occurs before a possibly narrower usize conversion, that tombstones contribute to growth pressure, and that rehash makes three fallible acquisitions. The prototype's parallel slices nevertheless claimed every sparse K and V slot was initialized, left probes unbounded, and inserted into the first tombstone before proving an equal key did not occur later in the chain.

Chosen: core/map.map(K, V) owns three mem.storage allocations. The first is a completely initialized array of bucket records whose module-private type contains a scalar free/used/dead tag, a dense index and previous/next live-bucket links. The map stores the head and tail; capacity is the link's end marker. The other two are equally long initialized prefixes of K and V. A bucket that has never held an entry has no dense index in use. First occupation appends one actual K and V before marking the bucket used. Removal marks the bucket dead without reading, zeroing or releasing either value. Reuse replaces the K and V at that bucket's existing dense index. Rehash transfers only used positions and final release drains all initialized positions, including dead ones. No K or V zero image, destructor or implicit resource ownership is introduced.

equatable(K) and hashable(K) is equatable are public map concepts. A concrete key supplies both explicit conformances under [1340]; the child table does not synthesize its parent. Insert retains K and V through escaping parameters, and get returns V from map. Construction, insert, get, remove, length, capacity, entry enumeration and release comprise this bounded public surface; the growth and rehash operations remain private. entries() starts a cursor; next_entry receives the map and an inout cursor and returns an entry(K, V) from map, or reports end_of_entries. It follows only used bucket links in insertion order, at most length links across an unchanged map's complete walk, and never visits free or dead positions. Removing an entry unlinks it; reusing a tombstone appends it; rehash preserves the order. An empty or exhausted walk reports end_of_entries without reading a key or value. Reference-bearing entry fields retain the map origin; copying an entry does not detach its references. Scalar copies retain no reference origin [1910].

A cursor is a manually managed live-bucket position, not a checked association with one map or generation. Start a new cursor after mutation and do not transfer an in-progress walk to another map. Mutation invalidates the walk even when capacity does not change. The compiler's local reference checks remain in force, but do not enforce this cursor protocol.

map itself is a public struct composition. Its three storages, two counters and live-bucket head/tail are public fields. A module-private bucket identity and mem.storage's opaque raw representation do not encapsulate those fields: callers can use mem to reach the typed initialized K/V prefixes, including removed dense entries, and an inferred bucket view can copy or overwrite whole bucket values without naming their type. A caller that composes at this level must manually preserve equal capacities, a fully initialized bucket array, equal K/V prefix lengths, exactly one used or dead bucket with an in-range dense index for each prefix position, count/tombstone totals equal to the used/dead records, and a finite doubly linked walk through exactly the used records. The compiler neither enforces those map invariants nor supplies a deep-safety guarantee.

The semantic conformance contract, also not compiler-proved, requires eq to be reflexive, symmetric and transitive. Equal keys produce the same hash. Equality and hash results for every stored key remain stable until removal, including when the key contains a pointer or reference: mutation of anything reached through it must not change either result while the key is stored.

The starting capacity is eight. An absent-key insertion into a table with tombstones reuses the first dead bucket in its probe chain, or a free bucket when reached first. Even when every bucket has been occupied, at least one dead bucket is available and the bounded probe finds it. This uses no new extent and keeps the three initialized prefixes within capacity. A tombstone-free table doubles on insertion pressure after a checked maximum bound. Lookup, removal and placement each probe at most capacity records and wrap without adding one to the final index. Placement records the first dead bucket until a free bucket or the probe bound is reached. Migration follows live links and probes the replacement at most capacity times per entry. Insert first performs a bounded search for an equal used key, remembering the first dead bucket and the first free bucket reached. If found, it replaces that dense value and returns before load pressure or any allocator call; if absent, it has changed no map state. Without a rebuild it inserts at the remembered bucket without probing again. When pressure requires a rebuild, it rehashes before probing the replacement table for placement. Thus an update after a preceding tombstone changes one value without changing length, duplicating the key or depending on allocation availability, and malformed full or all-dead records still terminate. Bucket selection reduces the u64 hash by the capacity before conversion to usize. For power-of-two capacities, a u64(capacity - 1) mask gives the same result as hash(K) % u64(capacity); other capacities use the remainder.

For a tombstone-free table, growth pressure has the meaning (length + 1) * 4 > capacity * 3, but computes the occupied count only after proving both additions against capacity and computes the three-quarter threshold from quotient and remainder. Neither side can overflow. Before the first provider effect, rehash checks the bucket, K and V byte products. It then acquires initialized buckets, empty K storage and empty V storage in that order, registering failure-only cleanup after each acquisition. All migration remains private. Any failure releases every acquired replacement and leaves the old map untouched. After migration, only infallible drain, exact free and field publication steps remain. The success path frees each old extent once; release frees each current extent once and resets the map to its empty shape. Growth retains all three refusal and rollback positions. The live links add two usize fields per bucket and a head/tail pair per map. Insert appends and remove unlinks in constant time after finding the bucket; a complete unchanged walk follows exactly the live count, including when removal leaves most buckets dead. Bucket-position order was dropped because maintaining that order in a linked walk would require searching the live list on insertion.

Why dense prefixes: they use D151's existing honest raw-storage state machine without pretending sparse K/V slots contain values. A dead bucket's still-initialized K/V entry follows the language's manual element-resource contract, and its stable dense index makes tombstone reuse infallible after the ordinary invariant checks. The entry is exposed by the public composition; it is not claimed to be private. Three independent extents preserve Z19's actual failure pressure and D197's six-live-slot allocator case. Reusing dead buckets keeps capacity and metadata bounded under churn without repeatedly acquiring replacement extents. A table may retain dead entries until growth or release; absent lookups still probe at most capacity buckets. Growth retains the three-acquisition transaction and its failure atomicity. Enumeration uses one position rather than a snapshot allocation or per-map generation metadata.

The alternatives: sparse initialized K/V slices recreate Z8's false type claim and would require K and V to be zeroable. One allocation evades rather than answers the three-stage rollback case and complicates independent generic alignment. Stopping at the first tombstone duplicates a later equal key. Unbounded loops rely on load policy to hide corrupt/full termination. Wrapping load-factor products and narrowing the hash before modulo make valid behavior target-accidental. All are declined.

Pinned by runtime/r420-map-operations, runtime/r420-map-failure-rollback, runtime/derived-containers, negative/r470-container-entry-live-map, negative/r470-container-entry-wrong-from, negative/core-map-missing-parent-conformance, negative/core-map-key-frame-escape, and negative/core-map-value-frame-escape. Runtime evidence includes pointer K/V, collision wrap, churn, rehash, full and all-dead bounded probes, failure at acquisitions one/two/three with zero/one/two rollback frees, reclaiming-provider retry, exact old/new frees and final zero live allocations. At six-of-eight pressure, an existing-key replacement under a zero allocation budget leaves provider attempts and map length unchanged. Repeated remove/insert churn on an arena leaves its used byte count unchanged. The complete derivative additionally pins dead-bucket reuse without arena growth, all three growth allocation refusals and retries, and live-only scalar and pointer entry walks, including empty and repeatedly exhausted cursors. The two entry negatives preserve live-map and exact-source refusals.

D199 — Text conversion preserves carriers and validation has checked and trapping edges

The tour and prototypes said that [0600] gives utf8, utf16 and cstring identities distinct from their representations, that [0310] ordinary explicit conversion traps when a runtime value cannot be converted, and that foreseeable data faults use declared errors. Prototype 4 needs runtime file and C text, exact equality, substring matching, decimal parsing and bounded output. They did not say which representation conversions exist, where UTF-8 is validated, whether C text is already valid by construction, or what happens to empty-view origins and partially written output.

Chosen: ordinary explicit conversion admits exactly these four source-derived reference conversions:

SourceDestinationRuntime work
immutable ordinary []u8utf8validate shortest-form UTF-8
utf8immutable ordinary []u8none
cstringimmutable ordinary []u8scan to the first NUL
cstringutf8validate while measuring to the first NUL

Each result retains the source base, the source-derived origin and immutable permission. A length-bearing result retains the source length or the measured pre-NUL length. In particular, converting an empty non-null slice or an empty C string keeps that actual base and origin; it does not substitute the canonical empty-slice datum. The matrix is descriptor-exact: a mutable byte view is not itself a conversion source or result, though ordinary call argument weakening may pass it to a library parameter declared []u8. A one-atom optional cstring is a pointer union rather than a cstring source; it must be matched, after which the present ptr binding retains the exact C-text view and may be converted. There is no conversion involving utf16, no byte- or UTF-8-to-C conversion, and no pointer-to-cstring conversion. An ordinary pointer supplies neither a first-NUL promise nor an extent.

The byte-to-utf8 edges accept ASCII, embedded U+0000 and shortest-form two-, three- and four-byte sequences. They reject stray continuations, truncation, C0/C1 overlong leaders, overlong E0/F0 sequences, UTF-16 surrogates, values above U+10FFFF and leaders above F4. Direct conversion traps synchronously through the existing checked runtime mechanism, including inside unchecked; it declares no atom error. Conversion evaluates its source exactly once and introduces no copy, allocation, mutable alias, backend opcode or core-module privilege. If evaluating that source leaves the enclosing control flow, no carrier load, store, scan or validation follows.

A cstring is the read-only byte carrier published by a foreign C-text boundary. Its pointer must have accessible backing through a first NUL byte, but its pre-NUL bytes are not thereby promised to be valid UTF-8. Scanning to ordinary bytes does not decode them. Direct cstring to utf8 conversion validates each sequence while measuring the prefix: a NUL ends the text only between sequences, and a NUL in place of a continuation makes the sequence truncated. Thus C2 00 yields a one-byte ordinary view but traps when converted to utf8; bytes after the first NUL are unobserved. Literal pooling remains stronger: D181 constructs valid encoded bytes and appends its own terminator. D184 traversal validates foreign C text before each scalar decode and traps on malformed encoding, even in unchecked, without reading beyond the first NUL. Inaccessible storage or a missing terminator remains [0430]'s pointer validity non-guarantee.

core/text.from_bytes and core/text.from_c are ordinary source routines which validate first and report the declared invalid_text atom instead of entering the trapping conversion on malformed input. Their successful utf8 from source results retain the actual input origin. from_c first uses the ordinary scan conversion and then the same byte validator. core/text.bytes is the infallible utf8 representation view. eq and contains compare exact encoded bytes without normalization, locale or grapheme policy; contains considers the empty sequence present. Shortest-form validity makes exact byte equality equivalent to equality of the represented scalar sequence. contains uses a Two-Way byte search: critical-factorization preprocessing and matching take worst-case time proportional to the combined byte lengths of source and sought, with constant scratch storage and no allocation.

to_u32 accepts one or more ASCII decimal digits, including zero and 4294967295. Empty input and a nondigit report invalid_number; a value above the u32 maximum reports number_overflow before multiplication or addition could trap. write_byte and write_u32 write into a caller-supplied initialized []mut u8 and return the next usize offset. They report no_space; the complete capacity check precedes the first mutation, so a refusal preserves both the caller's bytes and its separate used count. written returns the bounded immutable prefix from its source. No helper allocates or silently truncates.

Prototype 4's config.build therefore recovers or propagates every fallible from_c call. Its escaping args parameter and config from args result remain necessary because successful adapters preserve argument origins. match_keep applies from_bytes to arbitrary file bytes and treats invalid_text as no match; it does not invoke a trapping conversion. Malformed --every encoding is handled separately from a valid UTF-8 value which is not an accepted decimal.

The alternatives: representation inheritance would erase exact text identity and admit mutable or wrong-element views. Treating every cstring as prevalidated would make a foreign boundary silently promise what from_c is meant to diagnose; validating before publication would instead move that recoverable policy into every host adapter. Pointer conversion would invent an unbounded scan contract. Literal-only helpers would not serve runtime input. Returning a copied or canonical empty value would lose origin, and a backend text opcode or core-name exception would make ordinary conversion depend on library spelling. All were declined.

Pinned by runtime/text-ordinary-conversions, runtime/cstring-first-nul-validation, runtime/cstring-traversal-invalid-traps, runtime/text-conversion-invalid-traps, runtime/text-conversion-overlong-traps, runtime/text-conversion-out-of-range-traps, runtime/text-conversion-truncated-traps, runtime/text-conversion-operand-exit, runtime/core-text-runtime-helpers, negative/text-conversion-exact-identities, negative/text-conversion-mutable-source, negative/text-conversion-optional-cstring, negative/pointer-to-cstring-conversion, the retained hosted text, range, indexing and traversal fixtures, and the text.conversion guarantee row. The C fixture publishes its argument through an ordinary external cstring result, then uses the existing explicitly unsafe integer-pointer round trip to install C2 00 and a later ignored byte; it does not add a pointer-to-cstring conversion.