Programming Language

Nocter

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

/development/milestones/v0.11.0.md

Nocter v0.11.0 Milestone

Status: Phase 0, Phase 1, Phase 2, Phase 3, and Phase 4 complete.

Phase 0 completed the authored/resolved requirement split, intrinsic copy contracts, callable requirements for inherited parameters, generic-body and concrete-substitution checking, conditional conformance filtering, standard-library migration, and compiler-backed editor presentation. Qualification evidence is recorded in the completion gate below.

Purpose

v0.11.0 removes language-expression gaps that force ordinary standard-library contracts to rely on implementation-time rejection. Phase 0 starts with the smallest existing contract defect: generic source can perform a copy only after concrete specialization proves that the type is copyable, but a declaration cannot require that property in its generic signature. Construction members expose a second part of the same defect: a member cannot add a requirement to an owner parameter without constraining the type's entire construction surface.

The current Vec.from_slice<T> and Vec.try_from_slice<T> implementations copy elements from a readonly slice. Their public signatures cannot state that T must be copyable. The compiler eventually rejects a non-copy specialization, but callers, generic forwarding functions, editor tooling, and API documentation cannot observe the requirement at the declaration boundary.

Phase 0 introduces one identity-independent intrinsic generic requirement and a shared semantic requirement model. It does not encode the rule as a standard-library interface, infer a hidden requirement from a function body, or special-case Vec, a callable name, or a source path.

Phase 0: Resolved Generic Requirements and Copy Contracts

Source Contract

The copy keyword is a prefix requirement on a generic parameter:

func duplicate<copy T>(value: T): T {
    return value
}

func inspect<copy T: Printable>(value: T): void {
    value.print()
    return
}

A callable may add requirements to generic parameters already in its lexical scope:

construct Vec<T> {
    pub func from_slice(values: &[T]): Self where copy T {
        ...
    }
}

The callable where clause is necessary because placing copy on construct Vec<T> would also constrain Vec.empty, Vec.with_capacity, and every other construction entry that works for non-copy element types. It is not an alternate spelling that hides an ordinary local bound: directly declared generic parameters use inline bounds by canonical style, while where allows a callable to refine an owner parameter inherited from construct, impl, or interface scope.

GenericParameter    = ["copy"] Name [":" Bound ("+" Bound)*]
CallableWhereClause = "where" Requirement ("," Requirement)*
Requirement         = "copy" Name [":" Bound ("+" Bound)*]
                    | Name ":" Bound ("+" Bound)*

The clause follows result provenance and precedes the body or bodyless declaration terminator:

func project<T>(value: &T): &T from value where T: Inspectable {
    return value
}

copy never modifies a value type. Forms such as &[copy T], &copy T, and Vec<copy T> are invalid. A copy requirement belongs to the generic declaration or callable contract, so [T], &[T], and Vec<T> retain one type identity regardless of whether the surrounding callable can copy T.

copy in a bound names the compiler-owned copyability property. It is not a type, interface, prelude declaration, importable symbol, or user-implementable contract. Existing copy struct syntax remains unchanged.

Rules:

  • bound order is formatting information and has no semantic effect
  • a parameter may contain at most one prefix copy requirement
  • prefix copy may be combined with nominal interface bounds and one callable contract
  • a callable where clause may constrain its own parameters and inherited owner parameters
  • an inline bound and where requirement for the same parameter merge into one set and follow the same duplicate and multiple-callable rules
  • every where target must resolve to a generic parameter in that callable's lexical scope
  • a concrete type satisfies copy exactly when the ownership model classifies that concrete type as copyable
  • a generic parameter satisfies another callable's copy requirement only when its own declared requirement set contains copy
  • the compiler does not infer or publish a missing copy requirement from body operations
  • aliases preserve the copyability of their resolved target and cannot manufacture copyability
  • no impl, import, declaration name, or package can grant the intrinsic property
  • the requirement introduces no runtime metadata, dictionary, witness value, or ABI field

Copyability remains structural where the existing ownership rules already make it structural. A concrete instantiation of a generic copy struct is copyable only when all of its stored fields are copyable. copy T allows generic body checking to rely on that property before specialization; specialization still validates the concrete substitution and lowering still consumes the ordinary resolved type capability.

Semantic Requirement Model

Phase 0 replaces the current convention in which every bound is transported as an unresolved TypeExpr and repeatedly reclassified by consumers. Syntax and semantic requirements have separate representations:

authored generic bound
    -> resolver-owned requirement identity
        -> typecheck requirement environment
            -> call/conformance validation, ownership, analysis, and lowering

The semantic model distinguishes exactly these existing and new kinds:

  • a specialized nominal interface identity
  • a structural callable contract
  • the intrinsic copy property

The model has one canonical equality and duplicate rule. Interface member lookup consumes only interface requirements. Callable conversion and invocation consume only the callable requirement. Ownership copy decisions consume the intrinsic requirement. Consumers must not recover a requirement kind from formatted source, a declaration spelling, or an unresolved type expression.

The AST retains authored inline-bound and where spans for formatting, diagnostics, and editor focus. Resolver output owns canonical interface identities, lexical parameter identities, and the intrinsic kind. Typecheck environments and callable signatures carry the merged resolved requirement set rather than parallel Vec<TypeExpr> conventions. Concrete substitution checks use the same copyability classifier already used by ownership, buildability, and native value capabilities.

Ownership and Generic Bodies

Inside a generic body, an unconstrained owned T remains non-copy by default. With copy T, the following operations use ordinary copy semantics:

  • reading an owned parameter or local without move
  • returning or passing the value without consuming its source binding
  • readonly array and slice element reads
  • readonly sequence spread when the yielded element type is that parameter
  • construction and assignment of aggregates whose concrete copyability follows from the bound

The requirement does not weaken borrow conflicts, make an unsized value sized, suppress drop for a non-copy concrete type, or permit byte copying of a type that the ownership classifier rejects. Contradictory internal facts are compiler errors, not a fallback to unchecked copying.

Generic forwarding must be declaration-stable:

func inner<copy T>(value: T): T {
    return value
}

func valid<copy T>(value: T): T {
    return inner(value)
}

func invalid<T>(value: T): T {
    return inner(move value) // error: T does not promise copy
}

Conditional conformances and method-local generics use the same requirement environment. No second check may exist only in buildability or IR lowering.

Standard-Library Migration

Phase 0 updates every public standard-library declaration whose implementation copies a generic value from a borrow. At minimum, the owned vector constructors become:

construct Vec<T> {
    pub func from_slice(values: &[T]): Self where copy T

    pub func try_from_slice(
        allocator: &+TryAllocator,
        values: &[T],
    ): Self! from allocator | values where copy T
}

Top-level forwarding functions declare their own <copy T> inline. The migration audit also covers readonly spread, collection builders, numeric/text helpers, and package-visible helpers so no copying precondition remains only in an implementation comment or late buildability path.

Existing valid copy instantiations keep their behavior and ABI. A non-copy call is rejected during semantic call checking at the concrete type argument, with a note pointing to the copy bound. There is no compatibility path that accepts the call and waits for buildability or code generation to fail.

Diagnostics and Editor Contract

  • malformed, misplaced, unknown-target, and duplicate copy or where requirements receive source-backed diagnostics
  • a non-copy concrete argument reports the actual type, the intrinsic requirement, and the declaration span that introduced it
  • forwarding an unconstrained generic parameter reports the missing requirement at the call and suggests adding prefix copy or where copy T when that preserves the function's intent
  • hover, completion detail, signature help, and normalized declaration presentation render the authored copy bound through the shared requirement model
  • completion offers copy only in a generic-bound position where it is not already present
  • semantic tokens classify copy as a keyword; it has no go-to-definition target
  • rename, references, and auto-import never treat copy as a source symbol
  • AST JSON preserves the intrinsic bound kind, callable requirement clause, and exact source spans
  • the formatter emits one canonical spacing, + layout, and callable where placement

Editor features must consume resolver/typechecker requirements. They may not scan declaration text or recognize copy by a presentation string after semantic analysis.

Implementation Order

  1. 1. Introduce explicit authored-bound and resolved-requirement types, then migrate existing interface and callable consumers without changing accepted source.
  2. Add copy bounds and callable where clauses to parsing, recovery, AST JSON, formatting, and canonical source notation.
  3. Resolve and merge inline and callable requirements, then make generic environments, call checking, conformance, ownership, sequence copying, and specialization consume the shared model.
  4. Remove late or name-based copying assumptions that the semantic requirement now replaces.
  5. Migrate Vec.from_slice, Vec.try_from_slice, their forwarding APIs, and every other audited standard-library copying contract.
  6. Integrate diagnostics, hover, completion, signature help, semantic tokens, navigation, and source edits with the same semantic requirement identity.
  7. Update the public specification and focused contributor design, regenerate the documentation site, and run the complete qualification gate.

Structural migration of the generic-requirement model should be committed separately from the source-language behavior when practical. Each later step must use the new model rather than temporarily maintaining old and new semantic paths.

Completion Gate

Phase 0 is complete only when all of the following hold:

  • <copy T> is accepted in every generic declaration position supported for existing bounds, including functions, methods, nominal types, interfaces, construction members, and impls
  • callable where clauses constrain local and inherited parameters consistently in functions, methods, interface members, impl members, construction functions, and literal members
  • generic body checking permits copy operations only with a declared intrinsic requirement or an independently concrete copyable type
  • concrete calls, generic forwarding, conditional conformance, aliases, nested copy aggregates, arrays, slices, sequence spread, optional/fallible values, and callable specialization share one requirement-satisfaction path
  • non-copy String, Vec<T>, and user-owned aggregates fail at semantic call checking when passed to a copy-bounded API; references, integers, booleans, and valid copy aggregates succeed
  • resolver and typecheck signatures no longer expose an undifferentiated bound collection that every downstream consumer must reinterpret
  • no compiler rule identifies Vec, from_slice, std, a file path, or a presentation spelling to authorize copying
  • distributed Vec.from_slice and try_from_slice signatures state their copy requirement, and their former implementation-only limitation comment is removed
  • check, build, run, native tests, installed-home tests, and single-file mode agree on acceptance, diagnostics, ownership, cleanup, and execution
  • parser recovery and all LSP surfaces remain stable for incomplete inline bounds, callable requirement clauses, and mixed requirement sets
  • the public specification, contributor design, generated website, and packaged standard library contain one current contract
  • development/compiler/scripts/verify.sh, warnings-denied Clippy, cargo fmt --check, public examples, source corpus, documentation generation, and git diff --check pass

No required Phase 0 TODO, compatibility grammar, duplicated semantic path, or deferred implementation marker may remain at completion.

Qualification completed with the compiler verification script, warnings-denied Clippy, public examples, source corpus, installed-home checks, documentation generation, formatter stability, and the complete library suite. The focused contract suite covers inline and callable requirements, unknown and duplicate targets, generic forwarding, concrete rejection, enclosing construction parameters, normalized presentation, AST JSON, and semantic keyword identity.

Non-goals

Phase 0 does not add:

  • associated types, type projections, associated-type equality requirements, general predicate clauses on non-callable declarations, or generic associated types
  • const generics, compile-time evaluation, or source constant declarations
  • a user-implementable Copy or Clone interface
  • inferred public generic requirements
  • negative requirements, specialization, or overlap ranking
  • operator overloading, interface inheritance, interface objects, or dynamic dispatch
  • new copyability rules, unsafe memory copying, runtime type metadata, or ABI changes
  • Unicode scalar values, floating-point types, or a formatting protocol
  • another native target or a v0.11.0 release artifact

Phase 1 builds associated type identity on the qualified requirement model. It remains separate from Phase 0 so the generic requirement foundation and its qualification stay independently reviewable.

Phase 1: Required Associated Types and Projections

Purpose

Phase 1 gives an interface a named type slot whose identity is selected by each conformance. This removes the need to carry a result type through every generic use of an interface and establishes the projection identity needed by later standard-library protocol work.

The phase deliberately separates that identity model from associated-type equality predicates. Migrating adapters such as ChainIter safely requires a constraint such as R.Item = L.Item; accepting the syntax without a general equality solver would merely move the current redundant type parameter into an unchecked convention. Equality requirements and the complete iterator migration therefore follow Phase 1 rather than weakening its contract.

Source Contract

An interface declares a required associated type as a public member. A conformance binds every required type exactly once:

pub interface Source {
    pub type Item

    pub method &+self.next(): Self.Item?
}

conform<T> Source for BufferSource<T> {
    type Item = T

    method &+self.next(): T? {
        ...
    }
}

pub func next<S: Source>(source: &+S): S.Item? {
    return source.next()
}
AssociatedTypeDeclaration = "pub" "type" Name
AssociatedTypeBinding     = "type" Name "=" Type
ProjectedType             = TypeAtom "." Name

Rules:

  • associated types may be declared only by interfaces
  • every declaration is pub because it is part of the interface contract
  • an interface conformance must bind every required associated type exactly once
  • a binding is inherited from the interface and cannot carry pub
  • inherent impl blocks cannot declare associated types
  • declaration and binding names occupy an associated-type namespace separate from method names
  • Self.Name inside an interface resolves only to an associated type declared by that interface
  • T.Name requires T to have one unambiguous interface requirement declaring Name
  • a concrete projection resolves through one applicable conformance and its specialized binding
  • unresolved, unknown, missing, duplicate, extra, and ambiguous projections are diagnosed at the authored member name rather than degrading to an unknown type
  • projection normalization is semantic; consumers never recover it by splitting formatted text

Required associated types have no defaults or bounds in Phase 1. A binding may contain any type expression already valid in the impl's generic scope. The resulting type participates in ordinary sizing, ownership, copyability, provenance, specialization, and ABI checks after normalization.

Semantic Model

The AST records declarations, bindings, and projections with independent focus spans. Resolver symbols give declarations a canonical interface-owned identity and attach authored bindings to the corresponding conformance. Type checking represents an unresolved generic projection as the pair (base type, associated identity) and normalizes it only when a unique concrete conformance selects a binding.

The same resolver-owned identity drives conformance checking, method-signature substitution, generic bodies, call specialization, normalized source presentation, hover, navigation, rename, references, semantic tokens, and AST JSON. No subsystem may identify an associated type from a method return spelling, declaration text, Iterator, Item, std, or a source path.

Diagnostics and Editor Contract

  • missing and extra bindings name the interface and target conformance
  • duplicate declarations and bindings point to both authored spans
  • a projection diagnostic distinguishes an unknown member, a missing interface requirement, and ambiguous interfaces that declare the same member
  • hover on a declaration shows associated type Interface.Name
  • hover on a binding shows type Interface.Name = ConcreteType
  • hover and normalized callable presentation preserve Self.Item and T.Item until a concrete specialization is selected
  • go-to-definition from a projection or binding targets the interface declaration; references and rename use that semantic identity
  • completion after Self. or a bounded parameter offers only associated types available from the resolved interface requirements
  • semantic tokens classify declaration, binding, and projection member names as types while retaining keyword tokens for pub and type

Implementation Order

  1. 1. Add declaration, binding, and projection nodes with spans to the AST, parser, formatter, JSON, qualification, and canonical type notation.
  2. Add resolver-owned associated identities and conformance bindings without changing method lookup or reconstructing identities from strings.
  3. Add a projection type and one normalization service shared by generic checking, concrete specialization, interface method compatibility, ownership, sizing, and lowering.
  4. Enforce complete and exact conformance bindings, then add focused generic, concrete, imported, nested, alias, copyability, and failure tests.
  5. Connect presentation, hover, completion, signature help, semantic tokens, navigation, rename, references, and source edits to resolver identities.
  6. Update the language specification and contributor design, regenerate the website, and run the complete qualification gate.

Completion Gate

Phase 1 is complete only when:

  • interface declarations, conformances, and callable signatures accept the source contract above
  • projections work for Self, bounded parameters, concrete generic and non-generic targets, imported interfaces, aliases, and nested type constructors
  • every conformance has exactly one binding for each declaration and no undeclared binding
  • interface method compatibility substitutes associated bindings rather than accepting a textual match or rejecting a valid concrete spelling
  • generic forwarding preserves projection identity and concrete calls normalize it before ownership, sizing, buildability, and lowering decisions
  • invalid and incomplete source receives deterministic diagnostics and parser recovery
  • formatter output is stable and AST JSON preserves all declaration, binding, and projection spans
  • all editor surfaces consume the same declaration identity used by semantic checking
  • existing generic interfaces and standard-library APIs remain source compatible
  • the public specification, contributor documentation, generated website, source corpus, examples, installed-home checks, complete compiler suite, warnings-denied Clippy, formatting, and diff checks pass

No required Phase 1 TODO, name-based protocol rule, duplicate projection resolver, compatibility grammar, or deferred implementation marker may remain at completion.

Qualification completed with focused parser, formatter, semantic, conformance, projection, imported-identity, editor, and native execution tests; the complete compiler verification script; warnings-denied Clippy; public examples and source corpus; documentation generation; formatter stability; and diff checks. Associated type declarations, bindings, and projections now share one interface-owned identity and one normalization service across semantic checking, ownership, buildability, lowering, and editor analysis.

Phase 1 Non-goals

Phase 1 does not add associated-type defaults or bounds, equality or inequality predicates, generic associated types, inherent associated types, associated constants, interface inheritance, interface objects, or dynamic dispatch. It does not migrate Iterator<T>, Iterable<T, I>, or IntoIterator<T, I>; that migration requires associated-type equality requirements and receives a separate plan after this foundation is qualified.

Phase 2: Associated-Type Constraints and Iterator Migration

Purpose

Phase 2 removes generic parameters that exist only to transport an interface-selected result type. It adds the two missing semantic relations needed to express the iterator contracts without hidden compiler knowledge: an associated type may promise capabilities, and a generic declaration may require two projected types to be equal.

Equality alone is insufficient. Iterable.Iter must promise that its selected type is an Iterator; otherwise generic code can obtain the iterator but cannot call next. Conversely, an associated type bound alone cannot express that both inputs of chain yield the same type. Both relations therefore share one phase and one resolved predicate environment.

Source Contract

Associated type declarations may carry ordinary interface or callable bounds:

pub interface Iterable {
    pub type Iter: Iterator

    pub method &self.iter(): Self.Iter
}

A where clause may contain a type equality. Callable clauses keep their existing placement after result provenance. An impl clause appears after the target and before its body:

pub method self.chain<R: Iterator>(
    right: R,
): ChainIter<Self, R> from self | right where R.Item = Self.Item

conform<L: Iterator, R: Iterator> Iterator for ChainIter<L, R>
where R.Item = L.Item {
    type Item = L.Item
    ...
}
AssociatedTypeDeclaration = "pub" "type" Name [":" Bound ("+" Bound)*]
WhereClause               = "where" Predicate ("," Predicate)*
Predicate                 = GenericRequirement | TypeEquality
TypeEquality              = Type "=" Type

Rules:

  • at least one side of a type equality must contain an associated type projection
  • equality is symmetric and transitive; authored direction and predicate order have no meaning
  • equality checking expands aliases and recursively compares existing type constructors
  • a generic body may use an equality only when its lexical predicate environment entails it
  • concrete specialization substitutes arguments, normalizes projections, and proves both sides
  • an equality cycle that cannot produce a finite type is invalid
  • an associated binding must satisfy every bound declared by its interface-owned associated type
  • capability lookup on a projected type uses the declaration's resolved bounds
  • callable and impl predicates use one AST, resolver, validation, substitution, and presentation model; protocol code cannot maintain a second equality path
  • intrinsic copy is not an associated type bound in Phase 2

Type equality is a compile-time relation. It introduces no witness value, runtime metadata, dictionary, vtable, ABI field, or dynamic dispatch.

Resolved Predicate Model

The existing callable-only requirement container becomes a shared authored where clause whose predicates retain exact source spans. Resolution separates parameter requirements from type equalities while preserving one clause identity. A type equality owns resolved left and right type terms; consumers never compare canonical presentation strings.

Type environments carry a finite equality relation beside generic parameter requirements. The relation provides deterministic equivalence and entailment for projections beneath optional, fallible, borrow, pointer, view, array, callable, and nominal generic types. Concrete projection normalization remains owned by the Phase 1 associated-type service. Equality augments comparison; it does not create a second projection resolver.

Associated type bounds reuse the Phase 0 resolved requirement representation. Binding validation, generic projected-type lookup, method selection, call specialization, conditional conformance, ownership, sizing, buildability, and lowering all query the same requirement and equality environment.

Standard-Library Migration

The iterator surface becomes:

pub interface Iterator {
    pub type Item
    pub method &+self.next(): Self.Item?
}

pub interface ExactSizeIterator {
    pub method &self.remaining_len(): usize
}

pub interface Iterable {
    pub type Iter: Iterator
    pub method &self.iter(): Self.Iter
}

pub interface IntoIterator {
    pub type Iter: Iterator
    pub method self.into_iter(): Self.Iter
}

Iterable and IntoIterator do not duplicate an Item associated type. Their yielded type is Self.Iter.Item, so no equality contract is needed between two stored declarations. ExactSizeIterator describes only cardinality and does not redeclare Item; APIs that need both capabilities require I: Iterator + ExactSizeIterator and obtain the item from Iterator.

Adapter state removes parameters used only as type couriers:

  • MapIter<I, F> replaces MapIter<T, U, I, F>
  • FilterIter<I, F> replaces FilterIter<T, I, F>
  • TakeIter<I> and SkipIter<I> replace their two-parameter forms
  • ChainIter<L, R> replaces ChainIter<T, L, R> and declares item equality where needed
  • EnumerateIter<I> replaces EnumerateIter<T, I>

Every iterator conformance binds type Item. Default methods and forwarding functions use Self.Item or I.Item; callback contracts and return types retain ordinary static specialization. The migration is direct. The old generic interface spellings are not compatibility aliases and no temporary duplicate standard-library surface remains.

Trusted Iteration and Editor Contract

Trusted iteration roles record associated declaration identities and resolved associated bounds, not generic argument positions. Collection for, sequence spread, exact-size planning, cleanup, and provenance consume specialized bindings through the same projection service as ordinary code. No rule identifies Iterator, Item, std, an adapter name, or a source path after trusted role validation.

Formatting and normalized presentation emit associated bounds and equality predicates in authored order with canonical spacing. Hover and signature help retain generic projections. Completion after a projection uses associated bounds. Definition, references, rename, and semantic tokens preserve the Phase 1 declaration identity on both equality operands. Incomplete where T.Item = source may recover a right operand for editor queries but cannot invent an equality or capability.

Implementation Order

  1. 1. Replace the callable-only authored requirement container with shared where-clause predicates, preserving existing copy and nominal/callable behavior.
  2. Add associated type bounds and equality syntax to AST, parser recovery, formatter, AST JSON, qualification, substitution, and normalized presentation.
  3. Add one resolved equality environment and entailment service, then connect generic checking, concrete specialization, impl applicability, method compatibility, and projected capability lookup.
  4. Migrate the four iterator interfaces, adapter state, implementations, forwarding APIs, and all downstream standard-library consumers without compatibility declarations.
  5. Migrate trusted iteration roles, collection for, sequence spread, cleanup, provenance, LSP, source corpus, examples, and installed-home fixtures.
  6. Update the public specification and contributor design, regenerate the website, and run the complete qualification gate.

Completion Gate

Phase 2 is complete only when:

  • associated type interface and callable bounds validate every concrete binding and are usable for projected-type method lookup in generic bodies
  • callable and impl where clauses accept projection equality with symmetric, transitive, alias-aware, nested, generic-forwarding, and concrete-specialization behavior
  • missing, false, cyclic, unresolved, duplicate, and non-projection equalities receive stable source-backed diagnostics
  • every equality-sensitive consumer uses the resolved predicate environment rather than formatted strings or a local projection map
  • the public iterator interfaces have no generic item or iterator courier parameters
  • adapter structs have no redundant item/result type parameters, and chain is guarded by an explicit item equality
  • collection for, sequence spread, readonly and owned iteration, all default methods and adapters, exact-size behavior, provenance, move/drop cleanup, and native execution retain their qualified behavior
  • trusted roles derive yielded and iterator types from associated identities rather than generic argument positions
  • formatter, AST JSON, diagnostics, hover, completion, signature help, navigation, references, rename, semantic tokens, and recovery use the shared predicate and associated identity models
  • the public specification, contributor documentation, generated website, source corpus, examples, installed-home checks, complete compiler suite, warnings-denied Clippy, formatting, and diff checks pass

No old Iterator<T>, ExactSizeIterator<T>, Iterable<T, I>, or IntoIterator<T, I> public contract, compatibility grammar, iterator-name equality rule, duplicate solver, or required Phase 2 TODO may remain at completion.

Phase 2 Completion Record

Phase 2 completed on 2026-08-10.

  • one authored and resolved predicate model now owns associated capability bounds and projection equality for callables and conformances
  • specialization resolves projection substitutions in the declaration's source context and shares them across call analysis, buildability, ABI/drop discovery, and IR lowering
  • trusted iteration preserves both interface and associated declaration identities, so Iterable.Iter and IntoIterator.Iter never collapse into a name-only projection
  • the standard iterator surface uses Iterator.Item, bounded conversion results, and explicit item equality without compatibility declarations or courier parameters
  • the generated website contains 116 pages; no old generic standard iterator contract remains in active source, tests, specification, or compiler design documentation
  • development/compiler/scripts/verify.sh passed all 3,471 tests, including 225 distributed-home tests, public examples, and the source corpus, followed by formatting and warnings-denied Clippy; git diff --check also passed

Phase 2 Non-goals

Phase 2 does not add associated type defaults, intrinsic-copy associated bounds, generic associated types, inherent associated types, associated constants, interface inheritance, negative predicates, inequality predicates, specialization ranking, interface objects, runtime type metadata, or dynamic dispatch. It does not turn type equality into a general theorem prover or add new iterator operations unrelated to the contract migration.

Phase 3: One Generic Constraint Grammar

Purpose

Phase 3 removes the second spelling of generic constraints. A generic parameter list declares names and arity. A where clause declares every capability or equality relation required of those parameters. This keeps declaration identity separate from predicates and gives parser recovery, semantic checking, normalized presentation, and future constraints one extensible surface.

The change is intentionally direct. Inline interface bounds, inline callable contracts, and inline copy parameters are removed rather than retained as compatibility grammar. The distinct where copy T predicate remains the only intrinsic-copy spelling.

Source Contract

Generic parameter lists contain names only:

pub func from_slice<T>(values: &[T]): Vec<T> where copy T

pub func filter<I, F>(source: I, predicate: F): FilterIter<I, F>
where I: Iterator, F: &+func(&I.Item): bool

pub struct Cache<K, V> where K: Hashable + Equatable {
    ...
}
GenericParameterList = "<" Name ("," Name)* [","] ">"
WhereClause          = "where" Predicate ("," Predicate)*
Predicate            = Name ":" Capability ("+" Capability)*
                     | "copy" Name
                     | Type "=" Type
Capability           = InterfaceType | CallableType

The predicate spelling reflects semantic kind. T: Interface states interface or structural callable conformance, copy T states the compiler-owned intrinsic property, and Left = Right states type equality. copy is not a type or interface and is unavailable after : or in ordinary type positions. Duplicate predicates and more than one callable capability for the same parameter remain errors under the shared resolved requirement rules.

Canonical clause placement is:

  • after a callable's result provenance and before its body or terminator
  • after an impl target and before its body
  • after a struct, enum, or interface generic parameter list and before its body
  • after a type alias target

Associated type declaration bounds remain inline:

pub interface Iterable {
    pub type Iter: Iterator
}

This is not a second generic-parameter syntax. The bound constrains the type selected for the associated member itself; it does not constrain a named parameter from a generic parameter list.

Old forms are invalid:

func duplicate<copy T>(value: T): T
func inspect<T: Printable>(value: T): void
func refine<T>(value: T): void where T: copy

Diagnostics identify the obsolete constraint location and show the equivalent name-only parameter and the corresponding where copy T or where T: Interface contract. The formatter and editor never silently preserve or emit an obsolete form.

Semantic and AST Invariants

An authored generic parameter owns only its name and source span. It cannot carry requirements. Every declaration kind with generic parameters owns an optional shared where clause. Resolution maps predicates to lexical parameter identities and constructs the same resolved requirement and equality environment introduced by Phases 0 and 2.

Nominal type declarations publish their resolved predicates as part of their type symbol. Those predicates are available while checking fields and members and are revalidated whenever a concrete specialization is formed. A constrained nominal type therefore cannot become well-formed merely because one consumer omitted a late buildability check.

Formatting, AST JSON, qualification, substitution, diagnostics, source edits, hover, completion, signature help, and normalized declarations consume the clause node or resolved predicates. No consumer reconstructs a constraint from a parameter presentation string or maintains an inline fallback.

Migration

The compiler, standard library, examples, source corpus, fixtures, specification, and contributor documentation migrate in one phase:

  • <copy T> becomes <T> plus where copy T
  • <T: A + B> becomes <T> plus where T: A + B
  • <copy T: A> becomes <T> plus where copy T, T: A
  • existing clauses merge migrated predicates without changing their resolved meaning

No source rewriter is shipped as a language compatibility layer. Repository migration may use a one-time mechanical tool, but the completed parser, formatter, AST, and semantic model contain only the new grammar.

Implementation Order

  1. 1. Define the name-only generic parameter and declaration-wide clause invariants in AST, parser, formatter, AST JSON, qualification, recovery, and diagnostics.
  2. Give nominal declarations the shared predicate environment and enforce it in declaration checking, concrete specialization, conformance selection, and method lookup.
  3. Migrate resolver, typechecker, ownership, buildability, lowering, and analysis consumers so every requirement originates in a resolved where predicate.
  4. Rebuild normalized presentation, hover, completion, signature help, semantic tokens, and source edits on the new authored and resolved invariants.
  5. Migrate all distributed source and documentation, remove obsolete grammar and tests, regenerate the website, and run the complete qualification gate.

Completion Gate

Phase 3 is complete only when:

  • every generic parameter list accepted by the parser contains names only
  • functions, methods, literals, nominal types, interfaces, aliases, impls, construction members, and default methods express parameter constraints through the shared where clause
  • copy, nominal, callable, mixed, inherited, projection-equality, and multiple-predicate clauses preserve the qualified behavior from Phases 0 through 2
  • nominal declaration predicates are enforced both inside the declaration and at every concrete specialization boundary
  • malformed and obsolete inline or prefix forms receive stable source-backed diagnostics and recover without manufacturing a semantic requirement
  • AST JSON cannot encode a requirement as part of a generic parameter node
  • formatter and normalized presentation emit only the canonical grammar
  • all editor surfaces use parameter identities and resolved predicates rather than parsing display text or consulting obsolete inline fields
  • active standard-library, example, fixture, specification, and contributor source contains no inline generic constraint or colon-delimited copy spelling
  • the complete compiler verification script, installed-home tests, public examples, source corpus, warnings-denied Clippy, formatter stability, documentation generation, and diff checks pass

No compatibility grammar, duplicated requirement path, declaration-kind exception, required Phase 3 TODO, or deferred migration marker may remain at completion.

Phase 3 Completion Record

Phase 3 completed on 2026-08-10.

  • generic parameter AST nodes now contain only a name and span; one declaration-wide clause owns intrinsic copy, interface/callable capability, and associated-type equality predicates
  • functions, methods, literals, nominal declarations, aliases, impls, construction members, and interface defaults resolve constraints through the same requirement environment
  • nominal requirements are checked in declaration bodies and at every specialized type-use boundary, including forwarded generic, nested, copy, interface, callable, and equality cases
  • <copy T>, <T: Interface>, and where T: copy are rejected directly; where copy T remains distinct from the colon-delimited interface/callable capability grammar
  • normalized AST, symbol, hover, completion, and signature presentation share one predicate renderer; incomplete where recovery offers copy only at predicate starts
  • the standard library, integration fixtures, specification, contributor documentation, and generated 116-page website use the canonical grammar; obsolete forms remain only in explicit rejection tests and historical phase records
  • development/compiler/scripts/verify.sh passed all 3,479 tests, formatting, and warnings-denied Clippy; documentation generation and git diff --check passed

Phase 3 Non-goals

Phase 3 does not add new requirement kinds, associated type defaults, intrinsic-copy associated bounds, generic associated types, inheritance, negative predicates, inequality predicates, specialization ranking, interface objects, dynamic dispatch, runtime metadata, or ABI changes.

Phase 4: Instance Behavior and Explicit Conformance

Purpose

Phase 4 removes the overloaded impl declaration. Nocter already assigns construction to construct, associated functions to qualified top-level func, and contracts to interface. The two responsibilities left in impl are semantically different: inherent behavior and destruction for an existing instance, and proof that a type conforms to an interface. Giving them separate declarations makes those responsibilities visible in source and unrepresentable as one optional AST state.

Source Contract

An instance declaration owns methods and at most one destructor for an existing value:

instance<T> Vec<T> {
    pub method &self.len(): usize {
        ...
    }

    drop &+self {
        ...
    }
}

A conform declaration proves one interface contract for one target type:

conform<I> Iterator for TakeIter<I> where I: Iterator {
    type Item = I.Item

    method &+self.next(): I.Item? {
        ...
    }
}
InstanceDeclaration    = "instance" GenericParameters? Type WhereClause? InstanceBody
InstanceMember         = MethodDeclaration | DropDeclaration
ConformanceDeclaration = "conform" GenericParameters? Type "for" Type WhereClause? ConformanceBody
ConformanceMember      = AssociatedTypeBinding | MethodDeclaration

The interface-first conform Interface for Type order is retained so declarations group and scan by contract and the existing target/bound ordering remains stable. instance and conform blocks are not marked pub; member visibility and interface visibility retain their existing rules. Self, generic constraints, method compatibility, associated bindings, drop semantics, and ABI behavior do not change.

The old forms are removed:

impl File { ... }
impl Iterator for File { ... }

At a declaration start, impl receives a focused diagnostic showing either instance Type or conform Interface for Type. It is not accepted as compatibility grammar, emitted by the formatter, or offered by completion.

AST and Semantic Invariants

The AST has separate InstanceDecl and ConformanceDecl item variants. InstanceDecl cannot store an associated type or interface target. ConformanceDecl always stores an interface and a target, cannot store drop, and uses a distinct conformance-member enum. No consumer branches on an optional interface field to discover which declaration it received.

Resolver symbols continue to call the semantic relation an interface conformance. Inherent method collection consumes only instance declarations; conformance collection consumes only conform declarations. Type checking, ownership, drop discovery, specialization, buildability, lowering, documentation attachment, and editor analysis follow the same split. Internal identifiers use instance for inherent declarations and conformance for contract implementations; stale impl_*, ImplDecl, and ImplMember terminology is removed from language-model code.

Formatting, AST JSON, document symbols, hover, semantic tokens, completion, definition, references, rename, and source edits expose the authored declaration kind. AST JSON emits instance_decl and conformance_decl, never a generic implementation node with an optional child.

Migration

  • impl Type { ... } becomes instance Type { ... }
  • impl Interface for Type { ... } becomes conform Interface for Type { ... }
  • standard-library declarations, compiler fixtures, public examples, specification examples, and contributor documents migrate directly
  • historical release records remain immutable; the active milestone identifies Phase 4 as the current syntax

No source rewriter, parser fallback, duplicate AST representation, or transitional standard API is shipped.

Implementation Order

  1. 1. Split tokens, parser entry points, AST declarations and member enums, JSON, and formatting.
  2. Route inherent method/drop collection and interface conformance collection through their exact declaration types.
  3. Migrate type checking, ownership, lowering, call specialization, diagnostics, and all editor queries; remove optional-interface branching and obsolete internal names.
  4. Migrate the standard library, tests, fixtures, specification, and contributor documentation; regenerate the website.
  5. Audit removed syntax and internal terminology, then run the complete qualification gate.

Completion Gate

Phase 4 is complete only when:

  • the parser accepts instance Type only for inherent methods/drop and conform Interface for Type only for associated bindings/interface methods
  • the AST cannot represent a declaration that mixes inherent and conformance-only members
  • resolver, typechecker, ownership, drop discovery, specialization, buildability, lowering, and LSP consume the exact declaration kind without optional-interface discrimination
  • formatter, AST JSON, diagnostics, hover, completion, document symbols, navigation, references, rename, semantic tokens, and source edits use the new source vocabulary
  • active standard-library, example, fixture, specification, and contributor source contains no accepted impl declaration
  • obsolete impl source receives a focused removal diagnostic and has no compatibility path
  • the complete compiler verification script, installed-home tests, public examples, source corpus, warnings-denied Clippy, formatter stability, documentation generation, and diff checks pass

No generic implementation AST node, ImplDecl, ImplMember, optional interface discriminator, accepted impl grammar, required Phase 4 TODO, or deferred migration marker may remain at completion.

Phase 4 Implementation Result

Phase 4 completed the declaration split without a compatibility AST or parser fallback:

  • the lexer reserves instance and conform; impl is an ordinary identifier and receives one directional declaration-start diagnostic
  • parser responsibilities live in separate instance, conformance, interface, and method modules
  • InstanceDecl with InstanceMember::{Method, Drop} and ConformanceDecl with ConformanceMember::{AssociatedType, Method} make mixed declaration state unrepresentable
  • a read-only MethodOwnerDecl view shares method-body analysis without merging the declaration models; drop and associated-type consumers still require their exact declaration type
  • resolver collection, conformance validation, ownership, provenance, drop discovery, specialization, buildability, IR lowering, callable-body identity, and editor analysis consume the split declarations
  • formatting emits authored instance and conform source; AST JSON emits instance_decl and conformance_decl; document symbols, hover, completion, navigation, semantic analysis, and source edits preserve the authored declaration kind
  • the distributed standard library, compiler fixtures, active specification, contributor documentation, and generated website use the new source contract
  • explicit tests reject associated bindings in instance, reject drop in conform, and prove that obsolete impl has no accepted compatibility path
  • development/compiler/scripts/verify.sh passed all 3,482 tests, formatting, and warnings-denied Clippy; documentation generation produced 116 pages and git diff --check passed

Phase 4 Non-goals

Phase 4 does not change method lookup, conformance overlap, orphan rules, interface defaults, associated type semantics, construction, destruction order, visibility, generic constraints, runtime dispatch, ABI, or code generation behavior. It does not add extension declarations, interface objects, conformance synthesis, or automatic delegation.

Phase 5: Declaration Type Patterns

Purpose

Phase 5 removes the redundant generic binder list from instance and conform. These declarations already expose every declaration parameter in their interface or target type. Their headers now form one type pattern: a name in a pattern slot introduces a binder, and every later occurrence reuses that binder.

The change is semantic rather than parser shorthand. One shared pattern model owns binder discovery, refinement, applicability, diagnostics, coherence, formatting, and editor identity.

Source Contract

instance Vec<T> {
    pub method &self.len(): usize { ... }
}

conform Iterator for TakeIter<I> where I: Iterator {
    type Item = I.Item
    method &+self.next(): I.Item? { ... }
}

instance<T> Vec<T> and conform<I> Iterator for TakeIter<I> are removed. A declaration pattern slot accepts a bare binder name only. Concrete or nested arguments are introduced through a directed refinement predicate:

instance Vec<T> where T = i32 { ... }
conform Printable for Pair<L, R> where L = String, R = Vec<String> { ... }

where T = Type is a binder refinement. Its left operand must be one binder introduced by the same declaration header, its right operand must not contain that binder, and a binder may be refined at most once. It is distinct from the symmetric associated projection equality used by ordinary generic declarations:

func zip<L, R>(left: L, right: R): void
where L: Iterator, R: Iterator, R.Item = L.Item { ... }

Refinement is available only on instance and conform; other declarations continue to reject a projection-free type equality. func and method generic parameters remain explicit because their signature positions are uses rather than an exhaustive declaration pattern.

Pattern and Coherence Invariants

  • target and interface generic arguments, and a built-in slice element, are declaration pattern slots; each slot contains one bare binder reference
  • binders are ordered by first source occurrence across the interface and target patterns and retain that occurrence as their declaration identity
  • a repeated name denotes the same binder and imposes equality between those positions
  • refinements are normalized before method applicability, conformance selection, associated-type substitution, body checking, ownership, buildability, and lowering
  • destruction remains uniform for a nominal type family: an instance containing drop must use every distinct target binder exactly once and cannot carry a where predicate; specialized method-only instances remain valid
  • two conformances overlap when some substitution satisfies both normalized interface and target patterns; two inherent declarations overlap when their normalized targets share a method name or both define drop
  • overlapping declarations are rejected; source order and a more-concrete pattern never create an implicit specialization ranking
  • old prefix binder lists have no compatibility grammar or second AST representation

Implementation Order

  1. 1. Add a declaration-pattern parser and AST validation boundary that discovers binders and records directed refinements separately from associated projection equality.
  2. Normalize pattern substitutions in one semantic service and route method, conformance, associated-type, drop, ownership, buildability, and lowering applicability through it.
  3. Add structural overlap checking for renamed binders, repeated binders, refinements, and nested refinement values; reject ambiguous inherent and conformance surfaces.
  4. Rebuild formatter, AST JSON, hover, completion, signature help, occurrences, semantic tokens, and diagnostics from binder identities and normalized predicates.
  5. Migrate the standard library, tests, fixtures, specification, and contributor documentation; regenerate the website and run the full qualification gate.

Completion Gate

Phase 5 is complete only when:

  • every accepted instance and conform discovers its binders from the declaration pattern and rejects an explicit prefix binder list
  • pattern arguments reject concrete and nested source types with a diagnostic directing them to where Binder = Type
  • binder refinement is directed, occurs-checked, duplicate-checked, declaration-local, and kept distinct from associated projection equality in AST JSON and semantic consumers
  • repeated binders and refinements affect method, conformance, and associated-type applicability in checked and executable code; conditional destruction is rejected explicitly
  • overlapping conformances and overlapping inherent member/drop surfaces are diagnosed without source-order or concreteness ranking
  • formatting and all editor surfaces preserve the canonical header, exact binder spans, and refinement spelling
  • active source and documentation contain no accepted prefix binder list on instance or conform
  • the complete compiler verification script, installed-home tests, public examples, source corpus, warnings-denied Clippy, formatter stability, documentation generation, and diff checks pass

No compatibility grammar, parser-only binder inference, unranked ambiguity, duplicated pattern matcher, required Phase 5 TODO, or deferred migration marker may remain at completion.

Phase 5 Completion Record

Phase 5 completed on 2026-08-10.

  • instance and conform derive ordered, source-backed binder identities from first occurrences in their interface and target patterns; the parser rejects the removed prefix binder list and concrete or nested pattern arguments
  • BinderRefinementPredicate keeps directed where Binder = Type refinements structurally separate from symmetric associated projection equality in the AST, JSON, formatter, qualification, diagnostics, presentation, and occurrence model
  • refinement validation rejects duplicates, direct and mutual cycles, Self recursion, and reserved type spellings; one shared structural unifier handles alpha-renamed binders, repeated positions, nested refinement values, and canonical resolved type identities
  • method lookup, call specialization, conformance selection, associated-type normalization, conformance member checking, body environments, buildability, and lowering consume refined substitutions rather than source text or concreteness ranking
  • overlapping inherent method surfaces and conformances are rejected, while disjoint refinements select the exact receiver or interface application independently of declaration order
  • destruction remains a uniform nominal-family property: conditional or repeated-slot drop patterns receive a focused diagnostic instead of introducing conditional ownership or ABI behavior
  • the standard library, compiler fixtures, active specification, contributor documentation, and generated 117-page website use canonical declaration patterns; old prefix forms remain only in explicit rejection tests and historical phase records
  • development/compiler/scripts/verify.sh passed all 3,491 tests, formatting, and warnings-denied Clippy; documentation generation and git diff --check passed

Phase 5 Non-goals

Phase 5 does not add specialization ranking, negative predicates, inequality predicates, orphan rules, generic associated types, interface objects, dynamic dispatch, blanket conformance synthesis, or runtime type matching. It does not change explicit generic parameter lists on any other declaration kind.

Phase 6: Explicit Destruction Declarations

Purpose

Phase 6 removes destruction from instance. An instance defines callable behavior on an existing value; destruction is a unique ownership property of an entire nominal type family. Keeping both in one member enum makes every method-oriented consumer branch around a non-method and incorrectly suggests that a destructor may participate in instance refinement or specialization.

Destruction therefore has one top-level declaration form:

destruct File(&+self) {
    os.close(self.fd)
}

destruct Box<T>(&+self) {
    drop self.value
}

The &+self receiver remains explicit because a destructor mutates the value while consuming its ownership state. destruct is a reserved declaration keyword. The contextual drop value statement remains the explicit operation that starts the same compiler-owned destruction path.

Source and Semantic Contract

  • instance contains methods only; drop &+self { ... } is removed without compatibility grammar
  • destruct TypePattern(&+self) { ... } is private, unique, non-callable, and cannot carry visibility, target, generic-prefix, or where modifiers
  • the target must name one nominal struct or enum family and cover every declared generic slot exactly once with a distinct declaration-pattern binder
  • one nominal family has at most one destructor across its package graph; imports, source-file composition, and declaration order do not change that rule
  • copy structs cannot declare destruction
  • automatic scope cleanup, field cleanup, explicit drop value, error cleanup, and native drop glue resolve the same DestructDecl identity
  • destructor body checking receives exactly one read-write borrowed self: &+Self binding and the target pattern's generic environment
  • destruction order, partial-move accounting, recursion guards, and ABI behavior do not change

No conditional, specialized, repeated-slot, interface, visible, inherited, or directly callable destructor is representable. If conditional destruction becomes necessary later, it requires a separate ownership-model phase rather than an instance-selection shortcut.

Implementation Order

  1. 1. Add DestructDecl as a top-level AST item and parser responsibility; simplify InstanceDecl to a method list and remove the drop-member variant.
  2. Give resolver collection, duplicate detection, body resolution, type checking, ownership, return checking, sizing, facts, buildability, and IR lowering explicit destructor traversal.
  3. Preserve one canonical DestructSignature per nominal type while sourcing it solely from the destructor declaration and its declaration-pattern substitution.
  4. Rebuild formatting, AST JSON, document symbols, hover, completion context, occurrences, semantic tokens, call-site analysis, and source ranges around the authored declaration.
  5. Migrate the standard library, fixtures, specification, contributor documentation, and generated website; retain the old member syntax only in focused removal diagnostics.
  6. Run the full compiler, installed-home, examples, source-corpus, formatting, warnings-denied Clippy, documentation-generation, and diff qualification gates.

Completion Gate

Phase 6 is complete only when:

  • accepted source has exactly one destruction syntax, destruct TypePattern(&+self) { ... }
  • AST and semantic consumers contain no instance drop-member variant or optional drop accessor on the shared method-owner abstraction
  • instance refinement and overlap concern methods only, while destructor uniqueness and uniform family coverage are validated by a destructor-specific service
  • every checked and executable cleanup path resolves the independent declaration with exact generic substitution and source identity
  • editor and JSON surfaces expose destruct with exact keyword, target, receiver, and body ranges
  • the standard library and active source corpus use independent destructor declarations
  • public specification and contributor documentation define one consistent ownership model
  • the complete qualification matrix passes and no required Phase 6 TODO or migration marker remains

Phase 6 Non-goals

Phase 6 does not add conditional destruction, destructor interfaces, manual destructor calls, visibility, specialization ranking, asynchronous cleanup, unwinding, a Dispose convention, or a change to field destruction order, partial-move rules, explicit drop, layout, or ABI.

Phase 6 Completion Record

Completed on 2026-08-10.

  • destruct TypePattern(&+self) { ... } is the sole accepted destructor declaration. instance stores methods only, and the removed member form survives only in a directional parser test.
  • DestructDecl owns exact keyword, target, receiver, and body spans. One DestructSignature on each eligible nominal type symbol supplies the canonical cleanup identity without creating an inherent callable member.
  • resolver collection enforces package-graph uniqueness. Type checking rejects aliases, views, copy structs, non-uniform patterns, repeated binders, and non-&+self receivers; the parser rejects visibility, target, generic-prefix, and where modifiers.
  • body resolution, generic substitution, return checking, ownership, region and provenance facts, buildability, specialization, automatic and explicit cleanup, and native IR drop glue consume the independent declaration directly while retaining the existing destruction order and ABI.
  • formatter and AST JSON expose the authored declaration. Hover, document symbols, semantic tokens, occurrences, completion context, visible locals, and call-site analysis use exact source ranges and present destruct Type(&+self) with the visible type name.
  • File, RawBuffer, Vec<T>, and VecIntoIter<T>, all active compiler fixtures, the public specification, contributor architecture documents, and the generated website use the new model.
  • development/compiler/scripts/verify.sh passed the full compiler, CLI, installed-home, public example, source-corpus, formatting, and warnings-denied Clippy matrix. The final inventory is 3,497 passing tests; documentation generation produced 118 pages and git diff --check passed.

Phase 7: Path-Sensitive Aggregate Cleanup

Purpose

Phase 7 removes the native backend's remaining aggregate control-flow exception. Ownership checking already accepts programs in which a non-copy aggregate is moved, explicitly dropped, or reinitialized on one reachable path. Native lowering still represents each local with one static drop obligation, so it cannot preserve a path-dependent live state after an if, match, or loop edge. Buildability consequently rejects otherwise valid programs before IR lowering.

The phase introduces one runtime drop-state model at the aggregate-local boundary. It is not a new source feature: the ownership checker remains responsible for whether a use is legal, while lowering records whether cleanup is required on the path that actually executes. The same state must drive automatic cleanup, explicit drop, move arguments, move bindings and assignments, reinitialization, condition evaluation, loop control, and early exits.

Compiler Contract

  • an aggregate local has a static drop obligation and may additionally have one promoted runtime live flag; no control-flow lowering subsystem owns an independent liveness model
  • promotion occurs before the first path-sensitive operation and initializes the flag from the local's current obligation; straight-line aggregates pay no runtime-state cost
  • completed initialization and reinitialization set the flag; whole-value move and completed explicit destruction clear it at the exact evaluation point
  • every cleanup path consumes the same pending-drop representation and guards destruction with the promoted flag when one exists
  • cloned branch contexts share the same IR flag location; compile-time branch-local obligations remain local to lowering and are not treated as a join result
  • condition moves are recorded by expression lowering at their evaluation point, including within short-circuit expressions; a condition-wide postlude may not clear a value that was not evaluated
  • loops use the same state transitions on each executed edge; ownership analysis, not lowering, decides whether a later iteration may legally read the value
  • copy aggregates and aggregates without destruction do not acquire cleanup flags merely because they occur in control flow

The design and lowering responsibilities are owned by Path-Sensitive Aggregate Cleanup.

Implementation Order

  1. 1. Extend aggregate-local and pending-drop state with an optional runtime live location, plus one promotion operation that reserves and initializes the flag.
  2. Guard complete and partial aggregate cleanup through the pending-drop boundary so function returns, branch exits, loop exits, error paths, and normal scope exits cannot diverge.
  3. Centralize move/drop/initialization state transitions beside the IR operations that complete them; make call-argument and short-circuit lowering preserve exact evaluation order.
  4. Promote affected outer locals before lowering non-terminal if, match, while, loop, and value control flow; remove the static-context rejection paths.
  5. Replace buildability rejection tests with IR and native execution coverage for taken and untaken branches, compound conditions, loops, match arms, reinitialization, early exits, imported aliases, and exactly-once destruction.
  6. Update implementation documentation and qualification state, then run the complete compiler, installed-home, examples, source-corpus, formatting, warnings-denied Clippy, documentation-generation, and diff gates.

Completion Gate

Phase 7 is complete only when:

  • every ownership-valid whole-aggregate move, explicit drop, and reinitialization in supported control flow reaches native lowering without an aggregate-specific E0435 buildability diagnostic
  • condition moves work at their actual evaluation point and short-circuit paths never suppress or duplicate cleanup
  • taken, untaken, repeated, break, continue, and return paths destroy each live non-copy value exactly once and never destroy a moved value
  • the common pending-drop path, rather than syntax-specific cleanup copies, owns flag guarding
  • straight-line aggregate IR remains free of unnecessary runtime live flags
  • focused IR tests expose promotion and transition placement, native tests observe destructor counts, and imported aliases resolve through semantic type identity
  • no aggregate control-flow compatibility diagnostic, required TODO, or deferred migration marker remains, and the complete qualification matrix passes

Phase 7 Non-goals

Phase 7 does not add partial field or index moves, conditional destruction declarations, destructor failure or unwinding, exception handling, borrow lifetime syntax, a general SSA conversion, runtime ownership checks, or new source syntax. It does not promote unrelated native gaps such as temporary read-write borrows or opaque generic layout.

Phase 7 Completion Record

Completed on 2026-08-10.

  • destructor-bearing move-only aggregate locals gain one optional runtime live flag only when a path-sensitive whole-value operation requires it; promotion is idempotent and straight-line IR retains its prior zero-cost static cleanup model
  • PendingAggregateDrop carries the flag into the existing complete and partial cleanup programs, so normal exits, early exits, propagation, loop control, and replacement cannot grow independent guarded-destruction implementations
  • one lowering-owned transition pass records whole-value call transfers, aggregate copies, initialization, reinitialization, and explicit destruction at their executed IR positions; it recurses into short-circuit and value-control instructions without clearing skipped moves
  • parent contexts promote affected outer locals before non-terminal if, match, while, and loop lowering. Branch clones share the same runtime location instead of attempting to merge cloned static DropObligation values
  • aggregate-specific buildability modules for control-flow conditions, outer moves, explicit drops, and binding restrictions were deleted. Ownership remains the source of legality and native lowering now represents every accepted whole-aggregate case in this phase's scope
  • focused IR tests cover promotion, transition order, guarded cleanup, idempotence, aliases, value control flow, short-circuit evaluation, and the absence of flags from straight-line aggregates; native tests observe exactly-once destruction across taken, untaken, zero-iteration, transfer, explicit-drop, match, loop, and value-branch paths
  • development/compiler/scripts/verify.sh passed the full compiler, CLI, installed-home, public example, source-corpus, formatting, and warnings-denied Clippy matrix. The final inventory is 3,502 passing tests; documentation generation produced 119 pages and git diff --check passed

Phase 8: Static Opaque Result Types

Purpose

Phase 8 lets a body-bearing callable publish an interface result without making its concrete implementation type part of the source contract. some Interface denotes one statically selected concrete witness per callable declaration and generic specialization. It is not an interface object: calls remain statically dispatched, layout and destruction remain compile-time facts, and no vtable, boxing, metadata field, or implicit allocation is introduced.

The immediate standard-library use is implementation-independent iterator results. An API may return an internal adapter while exposing only Iterator and selected associated-type bindings. Concrete adapters remain available where users need a nameable field or construction type; opaque results are an API option, not mandatory type erasure.

Source Contract

pub func lines(text: &str): some Iterator<Item = &str> from text {
    return LinesIter.new(text)
}
  • some is a contextual keyword only at the start of a type atom; ordinary value identifiers named some remain valid
  • the initial form contains one accessible nominal interface and zero or more named associated-type bindings: some Interface or some Interface<Name = Type, ...>
  • an opaque type is accepted only as the result payload of a body-bearing function, associated function, inherent method, or body-bearing interface default method
  • parameters, fields, aliases, callable value types, construction entries, primitives, bodyless interface requirements, and conformance method contracts cannot introduce opaque types
  • ? and ! wrap the opaque success payload using ordinary outcome precedence; from remains an independent result-storage contract
  • every reachable value return and body result must normalize to the same concrete witness; aliases do not create distinct witnesses and different branch result types are rejected
  • the witness must satisfy the advertised interface and every named associated binding
  • callers may use only the advertised interface surface. Two opaque declarations remain distinct even when they select the same witness and advertise the same interface
  • opaque results are conservatively move-only at the public contract boundary in Phase 8; hidden copyability is not an observable capability

The compiler architecture is owned by Static Opaque Result Types.

Compiler Contract

  • one OpaqueResultIdentity is derived from callable declaration identity and survives imports, re-exports, same-module implementation sources, aliases, and generic specialization
  • source AST retains the authored interface contract; an elaboration fact attaches the inferred concrete witness without replacing the public type
  • associated projection normalisation selects advertised bindings from the opaque contract and never discovers them by rendering a type or inspecting a witness name
  • type checking exposes only the interface contract, while sizing, ABI classification, cleanup, specialization, and IR lowering consume the attached witness through one explicit lowering view
  • the defining body is checked against the witness and contract in two steps: all result paths agree on one witness, then that witness proves the interface and associated bindings
  • provenance summaries describe the opaque result shape and authored from contract without exposing the witness; existing aggregate provenance and region escape checks inspect the lowering view where storage capability matters
  • formatter, AST JSON, hover, completion, signature help, semantic tokens, definition, references, and rename preserve some Interface<...> and never display the hidden witness to callers

Implementation Order

  1. 1. Add the opaque type atom, associated binding syntax, source ranges, formatter, AST JSON, and focused parser/recovery diagnostics.
  2. Add declaration-scoped opaque identity and one witness-elaboration pass before ordinary body validation; reject unsupported positions and inconsistent or missing witnesses.
  3. Extend interface conformance and associated projection services to answer opaque contracts without exposing witnesses to ordinary member lookup.
  4. Route copyability, ownership, provenance, sizing, buildability, specialization, ABI, drop glue, and native lowering through a shared opaque lowering-view service.
  5. Add editor occurrences and presentations, then migrate a focused iterator-producing public API whose concrete adapter need not be named by its callers.
  6. Run the complete compiler, CLI, installed-home, public examples, source-corpus, formatting, warnings-denied Clippy, documentation-generation, and diff gates.

Completion Gate

Phase 8 is complete only when:

  • valid local, imported, generic, optional, fallible, provenance-carrying, and method-chain opaque results check, build, and run through static dispatch
  • inconsistent branch witnesses, non-conforming witnesses, wrong associated bindings, unsupported positions, declarations without bodies, and attempts to use witness-only members receive focused diagnostics
  • move, return, argument transfer, scope cleanup, and path-sensitive cleanup destroy the hidden aggregate exactly once without exposing or boxing it
  • associated method results and projections use declaration identities and normalized bindings
  • LSP hover, completion, signature help, navigation, rename, and semantic tokens present only the authored opaque contract
  • at least one distributed standard-library API uses an opaque iterator result while concrete adapters that remain useful as nameable state keep their public declarations
  • no compatibility grammar, witness-name recognition, required TODO, or deferred Phase 8 migration marker remains, and the complete qualification matrix passes

Phase 8 Non-goals

Phase 8 does not add runtime interface objects, any Interface, dynamic dispatch, heterogeneous containers, named opaque aliases, opaque fields or parameters, multiple advertised interfaces, interface inheritance, generic associated types, intrinsic-copy opaque contracts, binary-stable separate compilation, reflection, or user-visible witness inspection.

Phase 8 Completion Record

Completed on 2026-08-10.

  • some Interface<Name = Type> is a contextual, return-only type atom with exact source ranges, canonical formatting, stable public AST JSON, and diagnostics for unsupported positions, bodyless declarations, missing or inconsistent witnesses, conformance failures, and invalid associated bindings
  • witness elaboration runs on a private analysis copy after initial resolution; authored interface identity, declaration-scoped opaque identity, and concrete lowering witness remain independent facts, and public serialization and notation cannot expose the witness
  • ordinary type checking exposes only advertised interface methods and associated projections; generic specialization, optional and fallible results, imported calls, and default methods retain the opaque identity while dispatching statically through the proven witness
  • one explicit type-level lowering view supplies layout, ABI, ownership, provenance, buildability, cleanup, and IR consumers. Native results remain unboxed and move-only at the public boundary, including exact-once destruction of hidden aggregates
  • hover, completion, inlay hints, signature help, semantic tokens, definition, references, and rename present the authored opaque contract and share associated declaration identities without offering witness-only members
  • distributed str.lines() now returns some Iterator<Item = &str>; native execution proves static method dispatch and distributed provenance tests prove that the opaque iterator retains the source loan
  • implementation commits 9b80a74d, 60875152, and b4111788 establish the plan, representation, and semantic integration respectively
  • development/compiler/scripts/verify.sh passed the full compiler, CLI, installed-home, public example, source-corpus, formatting, and warnings-denied Clippy matrix. The final inventory is 3,527 passing tests; documentation generation produced 120 pages and git diff --check passed