Nocter v0.13.0
Status: Phases 0 through 6 complete. No later phase is active.
v0.13.0 completes source-defined collection capabilities and gives each audited standard-library operation one public declaration identity. Its phases cover structural indexing, standard built-in source authority, value-producing recovery, expansion-based iteration, source-defined ordering, canonical library surfaces, and instance-owned borrow coercions with structural generic evidence.
The published v0.12.0 language, tag, archive, download instructions, and qualification record are immutable. v0.13.0 work must not alter or relabel that release.
Phase 0: Source-Defined Indexing
Problem
The language can state readonly and readwrite index requirements:
where (&C[K]): &V
where (&+C[K]): &+V
Concrete programs can currently satisfy them only through arrays, views, or one visible borrow coercion to an indexable built-in view. A user type cannot declare the operation directly. This makes the generic capability language more expressive than the declaration language and forces a collection either to expose a representation coercion or to abandon index syntax.
Phase 0 closes that asymmetry. It does not introduce a second index expression, a named indexing interface, compiler recognition of collection names, or arbitrary operator overloading.
Public Declaration Forms
An instance may own readonly and readwrite index declarations:
instance Buffer<T> {
pub operator (&self[index: usize]): &T {
return &self.values[index]
}
pub operator (&+self[index: usize]): &+T {
return &+self.values[index]
}
}
The receiver token, index binding, index type, and borrowed element type are authored source. Readonly indexing must return &V; readwrite indexing must return &+V. This is deliberately a place-producing capability: assignment, loan tracking, and result provenance all retain one meaning for container[index]. A partial lookup belongs in an ordinary method such as get(key): &V?; Phase 0 does not overload index syntax with a second value-producing operation.
Phase 0 accepts exactly one index operand. Readonly declarations start with &self; readwrite declarations start with &+self. An owned self, unnamed index operand, missing parameter type, multiple indices, equality token, or bodyless declaration is invalid. Ordinary pub, pub(path), declaration type-pattern, and declaration-wide where rules apply unchanged.
The result provenance follows the existing callable contract rules. Compiler-inferable origins remain omitted from normal source. A declaration must use an explicit from clause only when the public result origin cannot be inferred unambiguously by the common provenance service.
Selection and Requirements
Index selection preserves one deterministic order:
- 1. Direct compiler-owned array or view indexing on the original receiver remains the primitive leaf operation.
- An accessible declaration on the original nominal receiver is selected before considering a receiver coercion.
- If neither direct indexing nor an original-owner declaration applies, each accessible one-step borrow coercion is considered. The target may provide a primitive index operation or a declared index operator.
- Coercions do not chain and have no implicit ranking. Multiple viable targets are ambiguous.
- The index expression must satisfy the selected declaration or structural requirement using ordinary contextual typing rather than a collection-specific conversion rule.
A lexical where (&C[K]): R requirement is evidence for an unknown generic receiver. At concrete specialization, the same selector proves the substituted operation through a primitive leaf, declared operator, or one-step receiver coercion. Requirement checking and ordinary expression selection must not use separate algorithms.
Readonly and readwrite declarations are independent capabilities. Assignment through container[index] requires a selected readwrite result compatible with the assigned place. A readonly declaration cannot be upgraded because the source binding happens to be mutable.
Compiler Architecture
The authored declaration is an IndexOperatorDecl; equality and index declarations form an explicit operator-member enum inside instance rather than parallel optional lists. Each index declaration exposes one compiler-private callable view so signature qualification, body joining, visibility, generics, provenance summaries, specialization, reachability, and static calls reuse ordinary method infrastructure.
TypecheckIndexPlan remains the only post-typecheck authority. Its selected operation records one of:
- a primitive array or view projection;
- a lexical generic requirement;
- a source index declaration and its resolved callable identity.
Receiver and index adjustments, concrete input and result types, access capability, zero or one coercion, and owner provenance travel with that plan. Ownership, place checking, specialization, buildability, IR, diagnostics, and editor analysis consume it without repeating declaration lookup or reconstructing an operation from source spelling.
Declared operator calls lower through the shared static-call boundary. Primitive array and view indexing remain checked projections and do not become synthetic source functions. A declaration that implements its body by indexing another value receives that nested expression's independent plan; recursive selection cycles fail deterministically before lowering.
Ownership and Native Semantics
Receiver and index expressions evaluate once, from left to right. Any deferred scalar index value is stabilized before the selected call can reuse backend scratch state. A declared operator borrows its receiver according to the authored capability and never consumes an owned receiver.
A returned borrow retains the provenance of the callable result contract, normally the receiver. Owner move, destruction, replacement, and conflicting mutable access remain rejected while that borrow is live. Readwrite results support mutation only when the receiver and declaration both provide readwrite capability. The index operand itself uses the ordinary call argument and cleanup paths; the result remains a borrow-place rather than an owned call result.
The operator body owns bounds policy. A direct array or view keeps the existing checked trap; source declarations may return none, return an error, or call another checked projection. The compiler must not insert a second bounds check or translate a user failure into a trap.
Diagnostics and Editor Contract
Malformed declarations receive focused parser or type diagnostics on the receiver, bracket, binding, index type, or result type. Duplicate and overlapping declaration patterns use the common instance-member overlap service. Missing, inaccessible, unsatisfied, cyclic, and ambiguous selection remain distinct errors and include candidate declaration or coercion notes.
Hover presents the normalized source declaration and selected concrete specialization. Definition, references, and rename use the operator bracket/declaration identity and the index binding's own parameter identity. Completion inside an instance offers readonly and readwrite index templates only when their structural patterns do not overlap an existing declaration. Semantic tokens color self and the index binding as parameters, not types. LSP code must consume semantic plans and shared presentation services; it must not search for operator, brackets, type names, or method spelling independently.
Implementation Sequence
- 1. Add the authored index declaration and operator-member enum to parser, AST, formatting, AST JSON, visitors, and recovery tests.
- Generalize instance collection, type-pattern overlap, callable views, body joining, qualification, visibility, and source-backed identity for both operator kinds.
- Extend the common index selector and
TypecheckIndexPlanwith declared candidates and exact requirement satisfaction. - Route signature checking, provenance inference, ownership, place capability, specialization, reachability, and buildability through the selected callable plan.
- Lower declared readonly/readwrite calls through the ordinary ABI while preserving primitive projection leaves, evaluation order, cleanup, and owner loans.
- Add diagnostics and complete hover, completion, semantic-token, definition, references, rename, and signature-presentation coverage.
- Add unit, CLI build/run, installed-home, source-corpus, and public-example coverage; then update the public specification, implementation document, generated website, and completion record.
Completion Definition
Phase 0 is complete only when readonly and readwrite index declarations parse, format, serialize, resolve, specialize, and execute for local, imported, generic, and refined instance patterns; structural requirements are satisfied by the same selector; direct and one-step-coerced calls retain deterministic precedence and ambiguity behavior; indexed assignment preserves capability, evaluation order, provenance, and exactly-once index-operand cleanup; invalid result shapes and cyclic selection have exact diagnostics; all editor operations use semantic declaration identity; no collection-name recognition, compatibility grammar, textual fallback, duplicate selector, or required TODO remains; and the complete repository, distributed-home, public-example, source-corpus, documentation, formatting, warnings-denied Clippy, and diff verification gates pass.
Completion Record
Phase 0 completed on 2026-08-12.
IndexOperatorDecland the common instance operator-member model carry source syntax through parsing, formatting, AST JSON, resolution, overlap checking, callable qualification, and body analysis without a compatibility grammar or collection-specific declaration path.- One index selector and immutable
TypecheckIndexPlanserve direct projections, lexical generic requirements, source declarations, and one-step coercions. Analysis and lowering share the same cross-resolver specialization service and exact callable identity. - Readonly and readwrite declarations execute through the ordinary static borrow-return ABI. Scalar and aggregate reads, assignment, dynamic fixed-array element borrows, owner loans, capability checks, bounds policy, and exactly-once evaluation use common lowering primitives.
Vec<T>declares both index capabilities in source. Direct, coerced, generic, move-only, installed-home, and bounds behavior run without compiler recognition ofVecor its storage layout.- Hover, completion, semantic tokens, definition, references, rename, and normalized presentation use semantic declaration ranges and hide compiler-private callable names.
- All 3,534 repository tests passed across compiler units, CLI boundaries, the distributed home, public examples, and the source corpus. Formatting, warnings-denied Clippy, documentation generation, and diff verification also passed.
Non-goals
Phase 0 does not add multiple index operands, ranges as index syntax, owned-receiver indexing, value- or optional-producing index operators, index-move places, automatic bounds policy, compound assignment operators, arithmetic or ordering operator declarations, operator precedence declarations, transitive coercion, coercion ranking, runtime dispatch, mutable iteration, hashing, maps, Unicode scalar types, source-level lifetime parameters, or another native target.
Phase 1: Canonical Built-in Surfaces and Core Prelude
Problem
The built-in failure payload has one runtime identity but two public spellings. Lowercase error is the language type while Error is a standard-library alias used only to own Error.new. ErrorCode is another alias for &str without additional static distinction. This leaves source, hover, completion, and documentation presenting a nominal-looking API that does not denote a nominal type.
The same architectural boundary is incomplete elsewhere. Built-in str and [T] have source-owned instance surfaces, while bool and integers may own conformances but are explicitly barred from inherent source APIs, and error is absent from the common built-in owner registry. Construction, inherent behavior, conformance, authority, and editor identity therefore do not yet share one model for compiler-owned type identities.
Finally, catch requires a named error even when the failure is intentionally ignored, and the synthetic prelude exports the obsolete aliases while omitting the owning collection and iterator contracts needed for ordinary method-chain code.
Canonical Error Surface
error becomes the only public failure type spelling. The exact standard-library std/error module owns its source construction surface, backed by the existing package-visible primitive:
construct error {
pub default func new(code: &str, message: &str): Self from code | message {
return new_error(code, message)
}
}
User and standard-library code constructs failures as error.new(code, message). Error, ErrorCode, their prelude exports, and all use std/error.Error imports are removed without a compatibility alias or compiler rewrite. The ABI, T! representation, direct code and message fields, copy behavior, and provenance remain unchanged.
The compiler must not recognize the spelling error.new. It resolves the construct error member from the validated built-in surface and reaches new_error only through the existing primitive registry.
Discarding a Caught Failure
catch _ explicitly handles a failure without binding its payload:
operation() catch _ {
return fallback()
}
Named and discarded catch targets use an explicit binding-pattern enum rather than storing _ as an identifier or an optional string. The discard form creates no local symbol, storage slot, hover, semantic token, definition, reference, rename target, or provenance root. It still executes the same terminating catch block and cleanup path. Bare catch { ... } remains invalid because discarding a recoverable failure must be visible in source.
Common Built-in Source Authority
One registry entry per built-in owner records its canonical syntax, source authority, and allowed surface capabilities. Frontend loading, resolver collection, authority diagnostics, method and construction lookup, type checking, buildability, lowering, and editor analysis consume that registry. Phase 1 adds error, removes the str/slice-only instance gate, and permits validated source instance or construction surfaces for scalar built-ins without inserting synthetic nominal types into the symbol table.
The registry must support multiple built-in owners in one responsibility module, such as integer owners in std/num, without duplicating module loading or authority checks. Source behavior is added only where an actual public API exists; Phase 1 does not create empty instances merely to enumerate every primitive type.
Core Prelude
The synthetic user prelude becomes:
pub use std/string.String
pub use std/vec.Vec
pub use std/iter.{Iterator, Iterable, IntoIterator}
String and Vec are the ordinary owning text and sequence types. The three iterator contracts make .iter(), .into_iter(), and iterator default-method chains available without repetitive imports. Format remains loaded for interpolation conformance discovery but is not re-exported.
Prelude exports are namespace fallbacks rather than authored declarations. An explicit module declaration or import, parameter, local binding, or block import takes precedence. This prevents a future prelude addition from invalidating existing source while preserving ordinary duplicate-name diagnostics between authored names.
I/O functions and types, allocation APIs, Format, Sequence, ExactSizeIterator, process APIs, and pointer APIs remain explicit imports. Prelude expansion is limited to ubiquitous owning values and the contracts required to use their normal iteration surface.
Implementation Sequence
- 1. Replace fixed built-in instance-owner/module tables with one capability-bearing authority registry and add construction collection for built-in surfaces.
- Add the validated
construct errorsource surface and route associated lookup, specialization, primitive reachability, presentation, completion, and navigation through it. - Replace
Error.newacross the standard library, examples, fixtures, and specification; removeErrorandErrorCodedeclarations and exports completely. - Add the named/discard catch binding AST, parser recovery, formatting, AST JSON, resolution, type/provenance/ownership analysis, IR lowering, and editor behavior.
- Rebuild the prelude around
String,Vec,Iterator,Iterable, andIntoIterator; verify collision behavior, standard-home exclusion, method availability, and package invalidation. - Audit built-in owners and document which behavior is source-defined, primitive, or deliberately absent; add focused local, imported, installed-home, LSP, source-corpus, and public-example tests.
- Update public and contributor documentation, rebuild the website, run every verification gate, record completion, and stop before Phase 2 or publication.
Completion Definition
Phase 1 is complete only when error is the sole current public failure type spelling; error.new resolves through a source-backed built-in construction identity; no Error, ErrorCode, compatibility alias, spelling rewrite, or name-based lowering remains; catch _ creates no binding at every compiler and editor layer; all built-in surface authority and loading uses one registry; the core prelude exposes exactly the adopted owning types and iterator contracts; standard and user sources work without obsolete imports; and the complete repository, distributed-home, public-example, source-corpus, documentation, formatting, warnings-denied Clippy, and diff verification gates pass.
Completion Record
Phase 1 completed on 2026-08-12.
- One capability-bearing
BuiltinTypeOwnerregistry now owns canonical spelling, inherent-source module, instance and construction permissions, package conformance authority, and implicit loading forstr, slices,error,bool, and every integer type. - Built-in surfaces live outside the nominal symbol table while reusing common construction, method, conformance, qualification, specialization, buildability, lowering, occurrence, and presentation services. The former instance-only frontend and resolver modules were replaced by source-surface modules.
std/errordefines the only public failure spelling and itsconstruct errorsurface in source.error.newresolves to that declaration; native failure lowering uses resolved identity and ABI shape rather than the member spelling.ErrorandErrorCodeare absent without aliases or rewrites.catch _is represented as a discard pattern through AST, parsing, formatting, JSON, analysis, ownership, provenance, lowering, and editor services. It executes normal failure cleanup while creating no symbol or storage.- The prelude exports
String,Vec,Iterator,Iterable, andIntoIterator. Prelude exports are fallback names, so explicit module names and lexical bindings remain stable as the prelude evolves;Formatremains loaded but is not exported. - All 3,544 repository tests passed across compiler units, CLI boundaries, the distributed home, public examples, and the source corpus. Formatting, warnings-denied Clippy, documentation generation, and diff verification also passed.
Non-goals
Phase 1 does not add typed failure variants, user-selected failure payloads, throw, exception unwinding, fallible pattern matching, implicit catch, map_error, optional/fallible instance combinators, new numeric algorithms merely to populate instances, source-defined primitive arithmetic, broad I/O prelude exports, hashing, maps, Unicode scalar types, another native target, release identity changes, packaging, tagging, or publication.
Phase 2: Value-Producing Catch
Problem
otherwise can recover an optional expression with a block result, while catch requires its block to leave the enclosing control path. That difference is not inherent to optional and fallible values. Both operators remove one outcome layer and select either the payload or an explicit fallback.
The terminal-only rule forces local error recovery to return from an enclosing function or move into a helper merely to continue with a value. Adding a recover method would encode the missing control-flow capability as a library alias and would leave catch less composable than the body model used everywhere else.
Phase 2 makes a catch block an ordinary value-producing body. It does not add exception handling, implicit failure conversion, a second catch form, or outcome combinator names.
Public Semantics
For an expression operation: T!, both forms are valid:
let value = operation catch failure {
report(failure)
fallback
}
let value = operation catch failure {
return replace(failure)
}
On success, the catch expression evaluates to the original T. On failure, the binding receives the error payload and the block runs. A reachable block end must produce a value assignable to T; that value becomes the catch expression result. A block may instead terminate with return, break, continue, or never as permitted by its surrounding context.
When T is void, a block with no result expression recovers with void. A non-void block with neither a compatible result nor guaranteed control exit is invalid. A trailing T! is not implicitly flattened and a trailing error does not implicitly re-fail: propagation uses ?, and replacing the enclosing function's failure uses an explicit return error_value.
catch _ has the same value rules while creating no binding. catch unwraps only the outer fallible layer of T?!; its success and fallback type is T?. Nested outcome handling remains explicit and follows the existing postfix grouping rules.
Semantic and Lowering Model
The catch expression type remains the operand's fallible success type. Type checking validates the fallback body against that type with the same block-result assignability service used by otherwise, if, and match. Return statements inside the fallback retain the enclosing callable's return context; the block result belongs only to the catch expression.
Successful and recovered paths join through one destination selected by the surrounding expression consumer. The failure handler may either initialize that destination and continue or execute a terminal path. Scalar values, borrows, views, direct and indirect aggregates, fields, arguments, assignments, returns, and stored fallible values must use the same recovery abstraction rather than separate catch-specific algorithms.
The backend continues to receive an explicit outcome failure mode. A value-producing catch records the error destinations and recovery instructions that initialize the already selected success destination. It does not synthesize a return, copy a backend return register opportunistically, or re-evaluate the operand. The operand evaluates exactly once before the selected handler.
Ownership and Provenance
The success payload and fallback result are mutually exclusive initializers of one result. A move-only payload or fallback transfers exactly one obligation into the destination. Failure drops no uninitialized success payload; success creates no error binding. Catch-local values are dropped after the fallback result has moved out, in reverse initialization order, before control rejoins.
Borrow provenance joins the operand success branch with the fallback result branch. A fallback borrow may originate from outer inputs or the caught error's code and message; its resolved origin must survive the join, while a borrow of catch-local owned storage cannot escape. Mutable loan, region escape, initialization-state, and path-sensitive ownership analysis consume the same reachable-branch facts as other value-producing control flow.
Diagnostics and Editor Contract
An incompatible fallback result receives a focused diagnostic on the result expression and reports both the catch success type and actual fallback type. A missing non-void result reports that the block must produce the success type or leave the control path. Existing diagnostics for a non-fallible operand, invalid binding, invalid propagation, and invalid surrounding loop control remain distinct.
Formatting, AST JSON, semantic tokens, hover, definition, references, rename, visible locals, and completion retain the existing catch syntax and binding identity. Editor analysis must traverse a fallback result as an ordinary expression and must not classify a value-producing block as an error solely because it can fall through.
Implementation Sequence
- 1. Specify value-producing catch and replace terminal-only diagnostics with common block-result validation against the operand success type.
- Join return, ownership, initialization, allocation, and borrow-provenance state from reachable success and fallback paths.
- Generalize the outcome failure-mode builder so named and discarded catch handlers can either initialize a caller-selected destination or terminate.
- Reuse the existing scalar, borrow, view, aggregate, field, argument, assignment, return, stored
outcome, and composed-outcome destination lowering used by value-producing
otherwise. - Verify exact evaluation order, move-only cleanup, caught-error lifetime, nested blocks, loop
control, and
voidrecovery in native execution. - Complete diagnostics and editor coverage, then update the public specification, implementation documents, source corpus, and generated website.
- Run every repository and distributed verification gate, record completion, and stop before outcome combinators, Phase 3, release preparation, or publication.
Completion Definition
Phase 2 is complete only when a catch fallback can produce every currently buildable success shape and continue in every supported expression destination; terminal fallback behavior remains valid; type, provenance, ownership, initialization, cleanup, and allocation joins are path-correct for named and discarded bindings, direct calls and stored fallible values, move-only aggregates, borrows, void, and composed outcomes; diagnostics and editor behavior consume common semantic facts; no catch spelling, method-name workaround, terminal-only buildability gate, duplicated destination selector, compatibility path, or required TODO remains; and the complete repository, distributed home, public examples, source corpus, documentation, formatting, warnings-denied Clippy, and diff verification gates pass.
Non-goals
Phase 2 does not add recover, unwrap, expect, map, and_then, map_error, optional or fallible instance surfaces, implicit catch, implicit flattening, typed failure variants, user-selected failure payloads, throw, exception unwinding, fallible pattern matching, hashing, maps, sorting, Unicode scalar types, another native target, release identity changes, packaging, tagging, or publication.
Completion Record
Phase 2 completed on 2026-08-12. A reachable catch fallback now produces the operand success type and rejoins its expression consumer, while terminal handlers and empty void recovery retain their distinct control-flow behavior. One fallback-result model is shared with otherwise across scalar values, borrows, views, aggregates, fields, arguments, assignments, returns, direct calls, stored outcomes, and composed T?! outcomes.
Type checking, return analysis, provenance, borrow checking, initialization, ownership, buildability, IR lowering, native execution, diagnostics, formatting, AST JSON, and editor analysis consume the same reachable-fallback semantics. Aggregate destinations carry explicit runtime liveness: failed calls never destroy an uninitialized success destination, recovered values become live exactly once, and values moved from a recovered aggregate are marked dead before cleanup. Caught error fields remain available to recovery expressions without allowing catch-local owned storage to escape.
The compiler and CLI suites cover named and discarded handlers, scalar and move-only aggregate recovery, stored fallible values, void, borrows, result destinations, terminal handlers, and composed optional/fallible outcomes. ./scripts/verify.sh passes cargo check, all 3,555 tests, formatting, and warnings-denied Clippy. Documentation generation and diff verification also pass. Phase 2 did not add outcome combinators, define Phase 3, change release identity, package, tag, or publish.
Phase 3: Expansion Operators and Mutable Iteration
Problem
Collection iteration currently uses the Iterable and IntoIterator interfaces only to select one conversion method, while sequence spread independently assigns meaning to the ... token. The two interfaces describe syntax-directed conversions rather than multi-operation behavioral contracts. Adding mutable iteration as a third conversion interface would duplicate that model and leave for and sequence spread with separate selection vocabularies.
Phase 3 makes expansion a source-defined operator owned by the source type. Readonly, readwrite, and consuming receiver forms select an iterator value; collection for and typed-sequence spread consume the same immutable expansion plan. The readwrite form supplies safe mutable element iteration without making mutable spread or multiple outstanding mutable elements implicit.
Public Declaration Forms
An instance may own any applicable expansion form:
instance Buffer<T> {
pub operator (...&self): BufferIter<T> {
return BufferIter.from_view(self.view())
}
pub operator (...&+self): BufferIterMut<T> {
return BufferIterMut.from_view(self.view_mut())
}
pub operator (...self): BufferIntoIter<T> {
return BufferIntoIter.from_buffer(move self)
}
}
Each declaration has exactly one receiver and no ordinary parameters. Its result must satisfy the validated Iterator contract. The three receiver capabilities are distinct operator identities; a type may implement any subset. Visibility, declaration type patterns, where clauses, result provenance, and ordinary method-body checking apply unchanged.
Structural generic requirements use the existing operator-predicate grammar:
where (...&C): I
where (...&+C): I
where (...C): I
The requirement proves only the conversion and exact result type. A generic consumer states I: Iterator and associated-item equalities separately. Expansion does not become a general prefix expression; outside a collection for source or typed-sequence spread segment, ...value remains invalid.
Iteration Semantics
The collection forms select expansion by receiver capability:
for item in &values { ... } // (...&self)
for item in &+values { ... } // (...&+self)
for item in move values { ... } // (...self)
for item in iterator { ... } // direct Iterator, unchanged
The source expression evaluates exactly once. Expansion constructs one iterator and the existing Iterator.next contract drives the loop. Iterable and IntoIterator are removed rather than retained as aliases; there is one conversion authority and no type-name or method-name fallback.
A readwrite expansion normally returns an iterator whose Item is &+T. Its iterator owns the exclusive loan of the collection for the loop lifetime. Each iteration transfers one element loan to the loop binding. The next step is permitted only after the preceding binding's loan ends; ordinary last-use and scope cleanup determine that boundary. The source cannot be accessed or borrowed independently while the iterator remains live.
break, continue, return, propagation, and terminal or recovering outcome control flow end the current element loan before cleaning or advancing the iterator. Escaping a yielded mutable borrow remains subject to the common region and provenance rules. Phase 3 does not invent an iterator-specific alias analysis or runtime borrow token.
Sequence Spread
Typed-sequence spelling is unchanged:
Vec [...values, ...&borrowed, ...move owned]
Bare and explicit-readonly segments select (...&self); bare spread copies each readonly yielded referent and therefore retains its copy requirement, while ...&source contributes readonly borrows. Consuming spread selects (...self) or accepts a direct owning iterator as before. Every selected iterator must also satisfy ExactSizeIterator because literal-pack length is fixed before the body executes.
...&+source and mutable sequence spread are rejected in Phase 3. A literal pack may retain all of its elements simultaneously, so accepting mutable yielded borrows would require a separate proof of pairwise-disjoint element provenance. Mutable collection for consumes one element loan at a time and does not imply that stronger capability.
Semantic Architecture
Parser and AST represent expansion declarations and requirements beside equality and index operators. Resolution indexes them by owner identity, receiver capability, visibility, declaration pattern, and lexical requirement evidence. One TypecheckExpansionPlan records the selected primitive generic evidence or source declaration, concrete source and iterator types, callable target, receiver mode, result provenance, and source spans.
Collection for, sequence spread, ownership, provenance, buildability, specialization, IR, native lowering, and editor analysis consume that plan. They do not resolve iter, iter_mut, into_iter, Iterable, IntoIterator, Vec, slice, or iterator names. Direct iterator sources remain a separate explicit plan kind because no conversion call occurs.
The standard library owns expansion declarations for Vec<T> and any other supported collection. Readonly and consuming iterator implementations keep their existing behavior. A focused mutable view iterator retains &+[T], yields &+T? in forward order, and reports exact remaining length without allocation.
Diagnostics and Editor Contract
Diagnostics distinguish missing readonly, readwrite, and consuming expansion; inaccessible and ambiguous declarations; a non-iterator result; malformed generic evidence; an active source loan; and unsupported mutable sequence spread. They describe the authored expansion spelling rather than removed interface or method names.
Formatting, AST JSON, hover, completion, semantic tokens, definition, references, rename, and signature presentation use exact operator spans and declaration identity. Hover on an implicit collection conversion names the selected authored operator and concrete iterator/item types. Compiler-private callable names never appear.
Implementation Sequence
- 1. Add expansion operator declarations and structural requirements to the common operator AST, parser, formatter, JSON, resolution, presentation, and validation services.
- Build one declaration- and requirement-aware expansion selector and immutable typecheck fact; cover receiver capability, visibility, specialization, provenance, ambiguity, and diagnostics.
- Move collection
forand sequence spread conversion onto the selector, retain direct iterator plans, and remove trustedIterable/IntoIteratorroles and every compatibility fallback. - Add mutable loop planning and integrate exclusive source loans, yielded-element provenance, last-use, path-sensitive ownership, cleanup, buildability, IR, and native execution.
- Replace standard conversion conformances with expansion declarations; add the mutable view
iterator and exercise
Vec<T>readonly, readwrite, and consuming forms through source code. - Complete LSP, diagnostics, formatter, JSON, source-corpus, public examples, specification, compiler documentation, prelude, and distributed-home coverage.
- Run every repository and distributed verification gate, record completion, and stop before source-defined ordering, mutable sequence spread, sorting APIs, release preparation, or publication.
Completion Definition
Phase 3 is complete when source-defined expansion is the sole collection-to-iterator conversion authority; readonly, readwrite, consuming, direct, generic, imported, and visibility-constrained iteration select one shared semantic plan; for item in &+source safely yields mutable element borrows with path-correct loans and cleanup; sequence spread uses the same readonly and consuming selection while rejecting mutable spread; Iterable and IntoIterator plus their trusted roles, prelude exports, name-based paths, and compatibility behavior are absent; diagnostics and editor features preserve exact source identity; no required TODO remains; and the complete repository, distributed home, public examples, source corpus, documentation, formatting, warnings-denied Clippy, and diff verification gates pass.
Completion Record
Phase 3 completed on 2026-08-12.
- Expansion declarations and structural requirements preserve the authored readonly, readwrite, or consuming receiver through parsing, formatting, AST JSON, resolution, visibility, overlap checking, generic inference, specialization, and normalized source presentation.
- One expansion selector and immutable
TypecheckExpansionPlannow govern collectionforand typed-sequence spread. Direct iterators retain an explicit no-conversion plan; no downstream stage searches for conversion method, interface, or collection type names. IterableandIntoIteratorwere removed from trusted roles, the synthetic prelude, and the standard library.Vec<T>owns its readonly, readwrite, and consuming expansion behavior in source, while its named iterator methods remain ordinary explicit APIs.for item in &+sourceholds one exclusive source loan, transfers one mutable element borrow per step, ends it through the common control-flow and cleanup machinery, and supports direct mutation of aggregate elements. A shared aggregate-location borrow operation supplies the IR and native backend capability rather than an iterator-specific mutation path.- Sequence spread selects the same readonly or consuming expansion evidence, preserves its copy, provenance, exact-size, and exactly-once consumption rules, and rejects mutable expansion because a literal pack retains multiple elements simultaneously.
- Hover, completion, semantic tokens, definition, references, rename, and signature presentation consume semantic operator identity and canonical module presentation without exposing synthetic callable names.
- The complete verification script passed
cargo check, all 3,563 tests, formatting, and warnings-denied Clippy. Documentation generation and diff verification also passed.
Non-goals
Phase 3 does not add mutable sequence spread, multiple simultaneously retained mutable element borrows, source-defined < or other ordering operators, arithmetic operators, ranges over custom types, sorting, comparator APIs, hashing, maps, parallel or asynchronous iteration, generators, dynamic dispatch, erased iterators, source-level lifetime parameters, release identity changes, packaging, tagging, or publication.
Phase 4: Source-Defined Strict Ordering
Problem
Ordering expressions remain closed compiler operations over matching integer types. Generic source cannot require ordering, str and String cannot expose lexical comparison through their existing coercion relationship, and collection algorithms cannot state the capability needed by minimum, maximum, sorting, or binary search. Implementing all four ordering tokens independently would also permit contradictory definitions and duplicate selection, specialization, lowering, and editor models.
Phase 4 makes strict less-than the single source-owned ordering primitive. The other three surface comparisons derive from the same selected operation. It establishes the semantic foundation for later ordering APIs without adding those APIs in this phase.
Public Declaration and Requirement
An instance may declare one strict-order operation:
instance Text {
pub operator (&self < other: &Self): bool {
// strict total ordering
}
}
The receiver is exactly readonly &self, the right operand is a named readonly &Self, and the result is exactly bool. Visibility, declaration type patterns, declaration-wide where clauses, body checking, and ordinary callable provenance rules apply unchanged. Duplicate or overlapping declarations use the common instance-member overlap service.
Generic code states the same structural capability:
where (&T < &T): bool
The declaration contract is a strict total order: it is irreflexive, transitive, and orders every pair consistently. These algebraic properties are semantic obligations of the implementation and are not dynamically checked by the compiler.
Derived Surface Comparisons
Exactly one strict-order selection defines all four ordering expressions:
left < right => less(left, right)
left > right => less(right, left)
left <= right => !less(right, left)
left >= right => !less(left, right)
Derived comparison does not require equality and never evaluates strict ordering twice. The source operands always evaluate exactly once from left to right before a reversed call is prepared. The result inversion is a boolean operation after the selected call. Owned operands are implicitly borrowed and remain usable.
Primitive matching integers retain direct backend comparison leaves. Their four token spellings use the same normalization rules but do not become synthetic source calls.
Selection and Semantic Plan
Equality and ordering share one fixed binary-comparison selector. Selection first considers an accessible declaration on the semantic left owner, then accessible one-step readonly borrow coercions. The right operand must satisfy the selected &Self parameter exactly or through one readonly coercion. Coercions do not chain or rank; distinct viable targets are ambiguous.
For > and <=, the semantic left owner is the source right operand because those spellings reverse the strict-order call. Evaluation order remains source order and is independent of selection orientation. Generic requirement evidence is matched in the same orientation and concrete specialization reruns the same selector after substitution.
One immutable TypecheckComparisonPlan records the authored token and spans, source-order operand types, semantic operand orientation, selected primitive, lexical requirement, or authored callable, both operand adjustments, whether the boolean result is inverted, and exact declaration identity. Ownership, buildability, specialization, IR, native lowering, diagnostics, and editor analysis consume this plan without resolving an operator again.
Standard-Library Surface
str owns bytewise lexical strict ordering in source. String reaches it through the existing readonly coercion to str, supporting every readonly str/String pairing without duplicate implementations or compiler recognition of String.
[T] owns lexicographic strict ordering under where (&T < &T): bool. It compares corresponding elements and then length, using the same structural requirement for nested element comparisons. Vec<T> reaches that declaration through its readonly slice coercion. The selected standard package remains the only source authority permitted to attach behavior to built-in str and slice owners.
Diagnostics and Editor Contract
Diagnostics distinguish malformed declaration shape, missing strict ordering, inaccessible and ambiguous declarations, unsatisfied generic evidence, and invalid result type. Messages name the authored comparison token and selected strict-order declaration; they do not expose the compiler-private callable name.
Formatting, AST JSON, hover, completion, semantic tokens, definition, references, rename, and signature presentation preserve the exact < declaration span and identity. Navigation from any of <, >, <=, or >= reaches the selected < declaration. Hover may explain a derived orientation but must present normalized source syntax rather than a synthetic method call.
Implementation Sequence
- 1. Generalize the fixed comparison declaration, operator requirement, callable identity, formatter, AST JSON, visitors, and parser validation to represent equality and strict order.
- Replace equality-only selection facts with one kind-aware comparison selector and immutable plan while retaining primitive equality and integer ordering leaves.
- Normalize all four ordering expressions through strict order, preserving source evaluation order, exactly-once evaluation, borrow capability, cleanup, specialization, and result inversion.
- Add source strict ordering for
strand slices; proveStringandVecbehavior exclusively through existing readonly coercions. - Complete focused diagnostics and all editor features through semantic plans and declaration identities.
- Add unit, CLI build/run, distributed-home, source-corpus, and public-example coverage; update public specification, compiler documentation, and generated website.
- Run every verification gate, record completion, and stop before ordering algorithms, interface refinement, release preparation, packaging, tagging, or publication.
Completion Definition
Phase 4 is complete when < declarations parse, format, serialize, resolve, specialize, and execute for local, imported, generic, visibility-constrained, and refined instance patterns; one comparison selector serves equality and ordering without compatibility lookup; >, <=, and >= derive from one strict-order call while retaining left-to-right exactly-once source evaluation; integer primitive leaves and source declarations share one downstream plan; str, String, slice, and Vec lexical ordering run without standard-type recognition; generic requirements use the same concrete selector; diagnostics and editor features preserve source declaration identity; no required TODO remains; and the complete repository, distributed home, public examples, source corpus, documentation, formatting, warnings-denied Clippy, and diff verification gates pass.
Completion Record
Phase 4 completed on 2026-08-12.
ComparisonOperatorDecl,ComparisonOperatorKind, and the kind-aware structural requirement replace the equality-only declaration shape. Equality and strict ordering share callable, visibility, declaration-pattern, overlap, qualification, formatting, AST JSON, and editor infrastructure while retaining independent generic evidence.- One selector and immutable
TypecheckComparisonPlanserve equality plus all ordering tokens. The plan records semantic orientation and result inversion, and concrete generic specialization reruns the same selector without a method-name, token, or standard-type fallback. <,>,<=, and>=execute through one authored strict-order declaration. Runtime lowering evaluates source operands exactly once from left to right, stabilizes them through ordinary call argument machinery, and swaps completed ABI arguments only for reversed semantic orientation.strowns bytewise lexical ordering and[T]owns lexicographic ordering underwhere (&T < &T): bool.StringandVec<T>use the existing readonly coercions; compiler and nominal standard source contain no duplicate comparison algorithm or type-name recognition.- Hover, completion, semantic tokens, definition, references, rename, and normalized presentation
use the selected
<declaration identity for every derived token and never expose the compiler-private callable name. - Unit, native CLI, imported visibility, generic specialization, coercion, source evaluation order,
distributed-home, public-example, and source-corpus coverage agree with the specification. The
complete verification script passed
cargo check, all 3,577 tests, formatting, and warnings-denied Clippy; documentation generation produced 141 pages and diff verification passed.
Non-goals
Phase 4 does not add sorting, minimum or maximum APIs, binary search, comparator callbacks, three-way comparison values, partial ordering, floating-point types, independently authored >, <=, or >=, arithmetic operators, compound assignment operators, interface refinement, mutable sequence spread, hashing, maps, parallel or asynchronous iteration, source-level lifetime parameters, release identity changes, packaging, tagging, or publication.
Phase 5: Canonical Standard-Library Surfaces
Problem
Source-defined construction, instances, operators, coercions, and structural operator requirements now express capabilities that older standard-library APIs represented through forwarding free functions or nominal interfaces. Keeping both declarations public gives one operation multiple documentation, completion, hover, import, and compatibility identities. Sequence<T> is the most visible example: it repeats readonly length and optional indexed access for Vec<T> even though slice behavior and the existing Vec<T> borrow coercions provide the natural common owner.
Phase 5 makes each semantic operation have exactly one public declaration. It removes obsolete surface rather than adding aliases or deprecation shims. Implementations may retain private or package-visible helpers when representation access crosses a standard-library module boundary.
Canonical Surface Rules
- construction is public through
construct Type; an exact free-function forwarding wrapper is not also public; - behavior with one principal receiver is public through
instance Type; an exact forwarding free function remains internal; - checked syntax is public through an operator; a nominal owner does not redeclare an identical operator already available through one unambiguous coercion;
- borrowed observation belongs to the borrowed view type; owners obtain it through coercion;
- an interface remains public only when generic dispatch needs a contract not already expressed by a structural operator requirement or canonical borrowed view;
- a free function remains public when it has no principal receiver, constructs an otherwise unnamed source, or represents a genuinely symmetric operation rather than a forwarding alias.
Different failure or ownership contracts are not duplicates. Trapping value[index] and optional value.get(index) both remain. Explicit iter, iter_mut, and into_iter methods remain because expansion syntax is not a general expression and therefore cannot construct a method chain by itself. Iterator, ExactSizeIterator, Format, Reader, and Writer remain generic contracts.
Slice and Owner Consolidation
[T] becomes the sole public owner of contiguous readonly and readwrite observation:
instance [T] {
pub method &self.get(index: usize): &T?
pub method &+self.get_mut(index: usize): &+T?
pub method &self.first(): &T?
}
Vec<T> reaches these methods and primitive slice indexing through its existing readonly and readwrite coercions. Its duplicate index declarations, inherent get_mut, Sequence<T> conformance, the std/sequence module, and std/sequence.first are removed. The optional methods retain the source owner's storage provenance and bounds absence remains none rather than a trap.
Readonly and readwrite expansion declarations on Vec<T> remain direct. Expansion selection does not use receiver coercion and named iterator methods remain necessary for explicit lazy chains.
Forwarding Surface Consolidation
Exact public forwarding functions in std/vec, std/string, std/iter, std/path, std/mem, std/io, and std/fmt become private or pub(/) implementation helpers when their construct, instance, or interface member is the canonical user API. Distinct constructors, source functions, and failure contracts remain public. String copy construction uses one name rather than parallel from_str and copy aliases; borrowed text algorithms are presented on str and become available to String through readonly coercion. File construction belongs to construct File, path inputs reuse the Utf8Path coercion, and nonfallible scalar formatting belongs to Format.format_into; recoverable try_append_* operations remain distinct.
std/testing replaces scalar- and text-specific equality assertions with one generic assertion whose where (&T == &T): bool requirement uses the source-defined equality selector. The generic operation borrows its operands, reports the same assertion error, and does not introduce a nominal equality interface.
Tooling and Documentation Contract
Completion, hover, definition, references, and rename expose only the canonical public declaration. Coerced members retain the target declaration identity and show the specialized receiver surface; removed module exports fail as ordinary missing imports without a compatibility suggestion. Specification examples use construct and instance syntax and name the borrowed view as the owner of observation behavior.
Implementation Sequence
- 1. Record the public-surface rules and inventory exact forwarding aliases versus intentionally distinct failure, ownership, and expression contracts.
- Add optional slice access, migrate Vec access through coercion, and remove
Sequence<T>plus duplicate Vec index declarations. - Restrict exact construct and instance forwarding helpers to standard-library implementation visibility; remove duplicate String construction aliases and redundant iterator free functions.
- Replace specialized testing equality functions with one structural generic assertion.
- Migrate standard source, fixtures, public specification, examples, and editor expectations to canonical declarations and add rejection coverage for removed exports.
- Run every verification gate, record completion, and stop before ordered algorithms, element relocation, sorting, release preparation, packaging, tagging, or publication.
Completion Definition
Phase 5 is complete when every audited semantic operation has one public construct, instance, operator, coercion, interface, or free-function identity; Vec observation and indexing reuse slice behavior through existing coercions; Sequence<T> and exact forwarding aliases are absent without compatibility paths; optional and trapping access remain distinct; generic equality assertion uses the structural operator requirement; standard source and editor analysis resolve canonical declarations; no required TODO remains; and the complete repository, distributed home, public examples, source corpus, documentation generation, formatting, warnings-denied Clippy, and diff verification gates pass.
Completion Record
Phase 5 is complete.
[T]owns optional access and primitive indexing;Vec<T>reaches both through readonly or readwrite coercion without duplicate index declarations or a nominalSequence<T>contract.- construction, receiver behavior, file I/O, and nonfallible formatting have one public construct, instance, interface, operator, coercion, or free-function identity; helpers are private or package-visible.
- different optional, trapping, fallible, recoverable-allocation, ownership, and expansion contracts remain separate rather than being collapsed by name similarity.
std/testing.assert_equses the structural equality requirement, and obsolete specialized or forwarding exports fail through ordinary visibility and import diagnostics without aliases.- standard source, distributed fixtures, LSP expectations, specification, examples, and generated website content use the canonical declarations.
- the complete verification script passed
cargo check, all 3,577 tests, formatting, and warnings-denied Clippy; documentation generation produced 140 pages and diff verification passed.
Non-goals
Phase 5 does not remove interfaces that carry independent generic semantics, make expansion syntax a general expression, merge operations with different failure or ownership behavior, add ordered query algorithms, sorting, element relocation, comparator callbacks, interface refinement, a compatibility namespace, release identity changes, packaging, tagging, or publication.
Phase 6: Instance-Owned Coercions and Structural Requirements
Problem
Borrow coercions are behavior of an existing borrowed instance, but their surface is owned by a separate top-level coerce Type declaration. The compiler then adapts every coercion block into a synthetic InstanceDecl so callable-body validation, ownership, provenance, specialization, and lowering can process it. This repeats the owner type and generic pattern in source and preserves a parallel declaration traversal throughout the compiler.
Generic source also cannot state that a borrowed type must coerce to a particular borrowed view. Concrete contextual, explicit, receiver, comparison, and indexing selection already share one coercion model, but generic algorithms must name a nominal interface or expose a representation instead of requiring that structural conversion directly.
Instance Member Syntax
coerce becomes an instance member beside methods and operators:
instance String {
pub coerce &self as &str {
return view(self)
}
}
instance Vec<T> {
pub coerce &self as &[T] { return view(self) }
pub coerce &+self as &+[T] { return view_mut(self) }
}
The grammar is visibility? coerce receiver as target (from self)? block. The receiver remains exactly &self or &+self, the target remains borrowed, and result provenance is inferred from the receiver unless the author writes the only valid explicit clause, from self. Coercion entries share their instance declaration's owner generics and where clause. Their coherence key remains source nominal identity, receiver capability, and canonical target type across every instance block and source file in the module.
The standalone coerce Type { ... } declaration is removed. No parser fallback, deprecated AST node, resolver rewrite, alias, or diagnostic compatibility path remains. The source type's module remains the only authority allowed to add a coercion entry.
Structural Coercion Requirement
A where clause may require one ordinary one-step borrow coercion:
func view<T>(value: &T): &str
where &T as &str
{
return value
}
The left side is exactly &T or &+T for a visible generic parameter. The right side is a borrowed type or view. It may mention visible generic parameters and associated projections. The target is already the result type, so the predicate has neither parentheses nor a trailing : Result.
The predicate means that ordinary conversion selection from the left capability to the exact right type succeeds. It does not require an entry with textually identical receiver capability: a readwrite source may weaken to a readonly receiver, while a readwrite target still requires a readwrite result. Coercions do not chain, infer unconstrained target arguments, insert a borrow, consume a value, or bypass visibility.
Evidence and Specialization
Generic-body checking records a structural coercion requirement as delayed static evidence. Every contextual, explicit, receiver, comparison, and indexing use invokes the existing conversion selector; a matching requirement produces the same immutable conversion-plan shape with a requirement authority rather than an invented declaration.
At concrete specialization, the substituted source and target are resolved in the concrete type's source context. The ordinary selector must find one accessible declaration, and the specialized plan replaces requirement authority with that declaration identity before call specialization, ownership, provenance, analysis, or lowering consumes it. No runtime witness, interface object, coercion table, type-name rule, or second compatibility algorithm is introduced.
Compiler Responsibility Boundaries
InstanceDeclowns methods, operators, and coercion entries;Item::CoerceandCoerceDeclare removed.CoercionEntryremains a distinct member node because receiver/target syntax, coherence, and presentation differ from named methods.- a dedicated coercion-requirement AST node owns source,
as, target, and exact spans;WherePredicatedoes not encode it as an operator or type equality. - resolver coercion collection traverses instance members and preserves module/type authority and visibility on the entry.
TypeEnvironmentowns authored generic coercion evidence; conversion selection is the only consumer allowed to match it.- immutable conversion plans distinguish declaration and requirement authority until generic substitution specializes the latter through the ordinary selector.
- formatter, AST JSON, diagnostics, semantic occurrences, hover, completion, definition, references, rename, and signature presentation consume AST or resolved identities rather than scanning source text.
Implementation Sequence
- 1. Record the surface, requirement semantics, delayed-evidence model, and migration boundary.
- Add coercion members to
InstanceDecl, migrate compiler traversals and standard source, then remove the standalone AST item and parser production. - Add the authored coercion-requirement node, parsing, formatting, AST JSON, validation, qualification, and type-environment representation.
- Extend the common selector and immutable plan with requirement authority and concrete specialization across source contexts.
- Prove contextual, explicit, method-receiver, comparison, and indexing uses in generic bodies; preserve capability weakening, visibility, provenance, ambiguity, and one-step limits.
- Migrate fixtures, examples, specification, implementation documents, and editor expectations; add focused rejection coverage for standalone declarations and unsatisfied requirements.
- Run every verification gate, record completion, and stop before release preparation or new standard-library algorithms.
Completion Definition
Phase 6 is complete when coercions exist only as instance members; no standalone declaration or synthetic instance adapter remains; generic where Source as Target evidence uses the ordinary one-step coercion selector and specializes to an accessible concrete declaration; every contextual, explicit, receiver, comparison, and indexing consumer shares the same plan; provenance and capability rules remain unchanged; formatter, AST JSON, diagnostics, editor features, standard source, fixtures, examples, and documentation agree; obsolete syntax is rejected without a compatibility path; no required TODO remains; and the complete repository, distributed home, public examples, source corpus, documentation generation, formatting, warnings-denied Clippy, and diff verification gates pass.
Completion Record
Phase 6 completed on 2026-08-12.
instanceis the sole owner of methods, operators, and coercions. The standalone coercion item, its AST declaration, and its synthetic instance adapter were removed rather than retained as a compatibility layer.- A dedicated
where Source as Targetpredicate carries exact source ranges and generic evidence through parsing, formatting, AST JSON, resolution, type environments, diagnostics, and editor presentation without encoding coercion as equality or an operator. - Contextual conversion, explicit
as, receiver fallback, comparison, and indexing all use the common one-step selector. Generic evidence is replaced by the accessible concrete declaration through the same selector before call specialization and lowering. - Coercion entries remain distinct instance members, so named-method lookup cannot expose them as callable members while signature validation, ownership, provenance, reachability, and lowering reuse the common callable-body boundary.
- Standard
String,Vec<T>, andPathsources, fixtures, normalized LSP presentation, public specification, compiler architecture documents, and the generated website agree on the new declaration and requirement syntax. - All 3,584 repository tests passed across compiler units, CLI boundaries, the distributed home, public examples, and the source corpus. Formatting, warnings-denied Clippy, 141-page documentation generation, and diff verification also passed.
Non-goals
Phase 6 does not add owned conversions, fallible conversions, coercion chaining or ranking, automatic borrowing outside method receivers, runtime coercion witnesses, interface refinement, arbitrary conversion operators, ordered algorithms, sorting, element relocation, release identity changes, packaging, tagging, or publication.