Nocter v0.9.0 Milestone
Status: Phases 0, 1, 2, and 3 completed on 2026-08-08. Feature development is inactive; release stabilization and qualification follow the separate ../releases/v0.9.0.md record.
Purpose
v0.9.0 returns development to practical standard-library outcomes after v0.8.0 completed the borrow-coercion foundation. Each phase must make a complete user program materially simpler while preserving the compiler-owned ownership, storage, and static-dispatch model. Compiler changes are permitted only when an ordinary source implementation exposes a general language defect.
The published baseline is v0.8.0. Its language, standard library, package model, LSP model, and arm64-darwin distribution remain the compatibility boundary for this milestone.
Phase 0: Whole-Stream I/O
Phase 0 makes reading an entire byte stream or UTF-8 text stream an ordinary operation on every Reader. Today a user must allocate and initialize a scratch Vec<u8>, repeat reads, track the initialized prefix, append bytes, detect end of file, and validate UTF-8. The existing examples/file-summary package exposes that machinery even though its application concern is only counting newline bytes.
The phase also separates portable I/O protocols from file-descriptor ownership. This boundary lets File, BufReader, and later readers share one source implementation without compiler-recognized type names or duplicated inherent methods.
Public Contract
std/io.Reader keeps its released import path and gains default methods equivalent to:
pub interface Reader {
pub method &+self.read(buffer: &+[u8]): usize!
pub method &+self.read_to_end(): Vec<u8>!
pub method &+self.read_to_string(): String!
}
read returns at most buffer.len() initialized bytes. Zero means end of stream. A reader that reports a larger count violates the protocol; the common collector returns a stable std.io.invalid_read_count error instead of indexing outside the supplied buffer.
read_to_end reads until the first zero count, preserves byte order, propagates the first read failure, and returns independently owned storage. It reuses one initialized scratch buffer rather than allocating a new chunk for every read. Normal growth follows the current aborting allocation policy; the result has no caller-managed external from origin.
read_to_string consumes the same common byte collector, validates the complete byte sequence as UTF-8, and returns an independently owned String. Invalid text reports the existing std.string.invalid_utf8 error.
std/io.Writer keeps its released import path and gains a default write_text method that exposes the UTF-8 bytes to the existing write contract. Concrete writers do not duplicate this adapter.
Architecture
- new
development/std/io/core.nctowns portableReaderandWritercontracts and their protocol-derived default operations development/std/io.nctcontinues to ownFile, descriptors, target primitives, error translation, and the stable re-exportsstd/io.Readerandstd/io.Writerdevelopment/std/io_buffer.nctcontinues to own buffered state and implements the re-exported protocols without forwarding copies of default methods- byte collection is ordinary Nocter source; no trusted primitive, compiler name table, or special provenance rule is added
- the root
std/ioAPI remains source-compatible for existing imports and method calls
User Outcome
The public file-summary example must read its input as owned text and focus on the application loop:
var file = open_path(&path)?
let text = file.read_to_string()?
The example must no longer construct a scratch collection or orchestrate buffered reads. It must still check, build, and produce the same newline count for valid UTF-8 input.
Verification Gate
- source-shape tests prove the stable
std/ioimports, generic default methods, andBufWritertext method all resolve without concrete forwarding methods - native distributed-home tests cover empty input, input larger than one scratch chunk, multiple
partial reads, UTF-8 across chunk boundaries, invalid UTF-8, underlying read failure, and an
impossible count returned by a user-defined
Reader - native tests cover
FileandBufReadercollection plusBufWriter.write_text - LSP protocol coverage proves hover and member completion present the concrete receiver while navigation retains the shared interface declaration identity
- the updated public example passes package check and native execution with the distributed home
- public specification and implementation documentation describe the same ownership, EOF, error, and protocol-boundary rules
development/compiler/scripts/verify.sh,cargo fmt --check, warnings-denied Clippy, documentation generation, andgit diff --checkpass
Phase 0 is complete only when every gate above passes and no implementation TODO remains in its scope. Completion does not bump release identity, create a candidate archive, tag, push, or publish v0.9.0.
Non-goals
Phase 0 does not add asynchronous I/O, seek, directory traversal, file metadata, standard input, line or Unicode-scalar iterators, borrowed substrings, zero-copy Vec<u8> to String transfer, read-size limits, recoverable collection allocation, another operating-system target, or new source syntax. Those require separate API and ownership contracts.
Phase 0 Completion Record
Phase 0 completed the public contract and every verification gate above:
std/io/core.nctowns the portableReaderandWritercontracts, including sharedread_to_end,read_to_string, andwrite_textdefault methods;std/io.nctre-exports the interfaces while retaining descriptor ownership and target primitives- the byte collector uses one initialized 8 KiB scratch vector, preserves byte order across
partial reads, recognizes zero as EOF, rejects impossible read counts with
std.io.invalid_read_count, propagates reader failures, and delegates complete-text validation toString.from_utf8 File,BufReader, user-defined readers, andBufWriterconsume the shared protocol defaults; the file-summary example now expresses its actual task throughfile.read_to_string()- imported interface-default specialization now records a canonical requested-target alias to the actual concrete implementation target, so a generic default body can dispatch to an imported implementation without an I/O-specific forwarding method
- LSP hover, completion, and definition preserve the concrete receiver presentation and navigate to the shared source declaration
- the standard-library contract audit assigns every imported module a path-derived alias, avoiding
false name collisions between modules such as
std/io/coreandstd/iter/core
The final clean development/compiler/scripts/verify.sh run passed 3,351 tests: 2,317 library tests, 296 build CLI tests, 7 formatter CLI tests, 27 LSP CLI tests, 18 package CLI tests, 452 run CLI tests, 11 native-test CLI tests, 214 distributed-home tests, 2 public-example tests, and 7 source-corpus tests. Formatting, warnings-denied Clippy, documentation tests, generated public documentation, and git diff --check also passed.
No implementation TODO remains in Phase 0 scope. The compiler version remains v0.8.0; Phase 0 did not create a v0.9.0 archive, tag, push, or release.
Phase 1: Result Origin Elision
Phase 1 makes from exceptional syntax. The compiler already computes exact, identity-based result provenance for bodies and trusted declarations. Source signatures should repeat that fact only when omitting it would hide a choice that callers need to understand.
Source Rule
An omitted from has these meanings:
- a storage-independent, fresh-current-context, or static result needs no caller-managed origin
- one eligible receiver, parameter, allocator, or literal-pack origin is inferred
- a body-backed callable with multiple eligible inputs may omit
fromonly when its result retains none of them - a storage-carrying bodyless declaration with multiple eligible inputs is ambiguous and must name the retained upper bound explicitly
Static storage never makes a clause necessary because callers preserve no source place for it. An explicit clause remains an allowed upper bound and may document or pin a deliberately broader abstraction. It is not inferred editor text.
func view(text: &String): &str
method &self.get(index: usize): &T?
func version(): &str
func choose(left: &str, right: &str, first: bool): &str from left | right
Elision is declaration-stable: candidate origins come from the resolved signature, nominal result shape, and trusted declaration role. A concrete body supplies the exact retained subset and is validated against that boundary. Adding a second caller-managed result origin to an elided public body therefore produces a diagnostic instead of silently widening its API.
Shared Semantic Boundary
A new provenance-elision component owns candidate collection and produces one of three semantic states: no caller-managed origin, one inferred origin, or an ambiguous origin set. Contract validation, bodyless summaries, callable-value invocation, interface conformance, diagnostics, and analysis consume that result. No layer reconstructs elision from parameter names or formatted text.
AST and JSON preserve only clauses actually written by the author. Formatter, hover, completion, and signature help present source notation and never synthesize from self, from parameter, or from static. Ownership and call analysis continue to consume the expanded semantic contract.
Standard-Library Migration
The distributed standard library removes clauses that name only the receiver, one parameter, one allocator capability, one literal pack, or static storage. Clauses that distinguish multiple eligible inputs remain. This migration is semantic, not a compatibility alias layer; every removed clause must retain the same call-site loans and region-escape behavior.
Verification Gate
- public functions, methods, constructors, literals, coercions, interface defaults, and interface requirements infer one unambiguous origin without written syntax
- ambiguous bodyless declarations and body-backed declarations retaining one of multiple eligible inputs receive a focused diagnostic and explicit-clause help
- static and fresh results do not require a clause
- interface implementations may elide a required unique origin, still reject wider results, and may narrow to independent or static storage
- callable types apply the same zero/one/ambiguous rule and instantiate only their expanded origin set at calls
- generic, aggregate, outcome, callback, iterator, allocator, literal-pack, and imported-call provenance remains sound under elision
- LSP signatures stay source-normalized while definition, completion, rename, semantic tokens, and diagnostics retain declaration identity
- the distributed standard library contains no redundant single-origin or static clauses
- specification, implementation documentation, formatter fixtures, AST JSON fixtures, public examples, and generated documentation agree with the new rule
development/compiler/scripts/verify.sh, documentation generation, andgit diff --checkpass
Phase 1 is complete only when every gate passes and no migration TODO remains. It does not add borrowed text views, lifetime parameters, a public provenance-inspection syntax, a lint framework, or a v0.9.0 release artifact.
Phase 1 Completion Record
Phase 1 completed the source rule, shared semantic boundary, standard-library migration, and every verification gate above:
typecheck/provenance/elision.rsis the sole zero/one/ambiguous classifier for resolved declarations and callable signatures; validation, abstract summaries, callable invocation, interface conformance, coercions, and analysis consume its semantic result- authored AST and JSON retain only explicit clauses, while hover, completion, signature help,
coercion presentation, and inlay hints never synthesize an inferred
from - body-backed declarations retain exact body summaries; only a typed sequence literal's semantic element-pack boundary supplies an omitted unique capture fallback, so fresh copies are not falsely tied to ordinary inputs
- fallible contracts constrain the successful result only; compiler-owned error storage remains available to escape analysis without becoming public origin syntax
- bodyless declarations accept zero or one eligible origin and diagnose ambiguous sets; public bodies diagnose only a retained origin outside the elided boundary
- trusted static process views use an explicit semantic role instead of declaration names, and
coercions may omit their uniquely determined
from selfcontract - the distributed standard library contains no redundant single-origin or static clauses; its remaining clauses distinguish genuine choices such as allocator versus input storage
- region-escape coverage proves that borrowed elements transferred through an elided sequence literal pack remain tied to their source region, while whole-stream I/O and owned text copies remain independent of their input lifetimes
The final verification passed 3,359 tests: 2,325 library tests, 296 build CLI tests, 7 formatter CLI tests, 27 LSP CLI tests, 18 package CLI tests, 452 run CLI tests, 11 native-test CLI tests, 214 distributed-home tests, 2 public-example tests, and 7 source-corpus tests. Formatting, warnings-denied Clippy, documentation tests, generated public documentation, and git diff --check also passed.
No implementation TODO remains in Phase 1 scope. The compiler version remains v0.8.0; Phase 1 did not create a v0.9.0 archive, tag, push, or release.
Phase 2: Borrowed Text Views
Phase 2 turns the result-origin foundation into allocation-free text processing. Current search returns byte offsets and split copies every component into a new String. Users need a safe way to project UTF-8 ranges and iterate borrowed components without reconstructing views from raw pointers or allocating intermediate collections.
Phase 2 originally closed the planned feature work. The later Phase 3 plan reopens the milestone to replace compiler-recognized view method names and duplicated owning-type methods with one source-declared type surface.
Public Contract
std/string keeps its released surface and re-exports focused borrowed-view declarations equivalent to:
pub func get_range(text: &str, start: usize, end: usize): &str?
pub func strip_prefix(text: &str, prefix: &str): &str? from text
pub func strip_suffix(text: &str, suffix: &str): &str? from text
pub func split_views(
text: &str,
separator: &str,
): SplitIter! from text | separator
pub func lines(text: &str): LinesIter
All indices are UTF-8 byte offsets. get_range returns none when start > end, either endpoint is outside the text, or either endpoint divides a UTF-8 scalar encoding. Empty valid ranges are allowed. strip_prefix and strip_suffix return a view into text, never prefix or suffix.
split_views is allocation-free and matches the existing owned split component boundaries, including empty components between adjacent separators and after a trailing separator. An empty separator reports std.string.empty_separator. SplitIter retains both text and separator because both are read during iteration; each yielded &str retains the text storage through the iterator.
lines recognizes LF and CRLF. It omits the terminator, strips the CR only when it is immediately before LF, yields no item for empty input, and does not synthesize an extra empty item after a final terminator. Other carriage returns remain text. LinesIter retains only its input text.
The existing allocating split(value, separator): Vec<String>! remains available and unchanged. Phase 2 adds a borrowed alternative rather than silently changing ownership or failure behavior.
Typed Projection Boundary
Subview creation must be expressed as a validated typed projection from an input &str. The standard implementation may use restricted pointer operations behind that boundary, but public and ordinary standard-library code must not claim provenance by converting an integer address back into a view.
One compiler-owned semantic role records a borrowed projection and its source parameter by index. The role is attached only to the exact restricted helper declaration shape in its owning standard module. Borrow-return analysis instantiates the source argument's existing provenance; it does not search for a helper name or infer lifetime from pointer arithmetic. Allocation analysis treats the role as allocation-free.
development/std/string_views.nct owns range validation, the restricted projection helper, SplitIter, LinesIter, and their iterator implementations. development/std/string.nct remains the stable std/string facade and re-exports the new public declarations. The new file is a responsibility boundary, not an alternate public module users must discover.
Verification Gate
- range tests cover empty, full, prefix, suffix, out-of-bounds, reversed, ASCII, two-, three-, and four-byte UTF-8 boundaries
- strip tests prove exact match, mismatch, empty affixes, and that returned provenance comes only from the text input
- split-view tests cover empty text, absent, adjacent, leading, trailing, and multi-byte separators
and prove output parity with owned
split - line tests cover empty input, LF, CRLF, bare CR, consecutive terminators, and final terminators
- native tests prove both iterators are allocation-free and preserve source order through ordinary
Iterator<&str>dispatch and adapter chains - ownership tests keep source loans active while a view or iterator can still be used, reject mutation, move, drop, and region escape, and allow static text to escape
- trusted-role tests reject the right name in the wrong module and every near-miss signature
- LSP hover, completion, signature help, definition, and semantic tokens use normalized declarations, hide inferred unique origins, and retain explicit multi-origin clauses
- the existing owned string APIs, public examples, and distributed standard-library audit remain unchanged and passing
- specification, compiler-development documentation, generated documentation, formatter fixtures, and AST JSON agree with the public contract
development/compiler/scripts/verify.sh, documentation generation, andgit diff --checkpass
Phase 2 is complete only when every gate passes and no implementation TODO remains in scope. It does not add char, Unicode scalar or grapheme iteration, range syntax, mutable string views, regular expressions, zero-copy Vec<u8> to String transfer, standard input, filesystem metadata, another target, a version bump, or a release artifact.
Phase 2 Completion Record
Phase 2 completed on 2026-08-08. std/string now exposes validated UTF-8 ranges, exact affix removal, allocation-free split views, and allocation-free line iteration while retaining the existing owned split behavior. std/string_views owns validation and cursor state; std/string_search owns the byte-search loop shared by owned and borrowed algorithms.
The compiler recognizes only the exact restricted subview primitive in its owning standard module. Its BorrowedProjection { source: 0 } role flows through provenance and allocation analysis into a typed SetStrSubview IR instruction. Native lowering adjusts a validated view pair without reconstructing provenance from an integer address. Near-miss declarations and the same spelling in another module receive no role.
The implementation audit also closed two general native-lowering defects exposed by the new API: comparison operands whose materialization needs scratch registers are now stored before the final comparison, and a generic adapter specialized to a borrowed byte view can lower its already-checked move marker. These are common expression boundaries rather than iterator-specific exceptions.
The acceptance matrix covers every UTF-8 width, invalid and empty ranges, exact and missing affixes, owned-split parity, empty/absent/adjacent/leading/trailing/multibyte separators, LF, CRLF, bare CR, consecutive and final terminators, ordinary iterator adapters, and an allocator sentinel that aborts if either borrowed iterator reaches allocation. Ownership tests cover text and separator loans, mutation, move, drop, static escape, exact affix provenance, and region escape. Framed installed-home LSP tests cover normalized hover, completion, signature help, definition, and semantic tokens through the std/string re-export.
The final development/compiler/scripts/verify.sh run passed 3,370 tests: 2,327 library tests, 296 build tests, 7 formatter CLI tests, 27 LSP CLI tests, 18 package CLI tests, 452 native run tests, 11 native test-command tests, 223 distributed-home tests, 2 public-example tests, and 7 source-corpus tests. cargo check, cargo fmt --check, warnings-denied Clippy, documentation tests, git diff --check, and generation of 127 documentation pages also passed.
No Phase 2 implementation TODO remains. The compiler version remains v0.8.0. Phase 2 did not prepare an archive, tag, push, or publish v0.9.0. At that checkpoint, further feature work required a new plan; Phase 3 below now provides it.
Phase 3: Source-Owned View Methods
Phase 3 makes str and [T] own their public observation methods in standard-library source. It also extends the existing one-step borrow-coercion machinery to method receivers, allowing owning types to expose their borrowed view API without repeating it.
Today len() and is_empty() on &str, &[T], and &+[T] are recognized by member spelling in type checking and IR lowering. String consequently repeats len, is_empty, byte access, search, splitting, and iteration methods even though &String already coerces to &str. This creates two authorities for one API and forces editor analysis to understand compiler-invented methods. Phase 3 removes that boundary rather than adding more recognized member names.
Public Contract
The borrowed types own observation and projection. The exact source declarations are equivalent to:
impl str {
pub method &self.len(): usize
pub method &self.is_empty(): bool
pub method &self.ptr(): *u8
pub method &self.bytes(): &[u8]
pub method &self.is_char_boundary(index: usize): bool
pub method &self.get_range(start: usize, end: usize): &str?
pub method &self.find_from(needle: &str, start: usize): usize?
pub method &self.find(needle: &str): usize?
pub method &self.contains(needle: &str): bool
pub method &self.starts_with(prefix: &str): bool
pub method &self.ends_with(suffix: &str): bool
pub method &self.strip_prefix(prefix: &str): &str? from self
pub method &self.strip_suffix(suffix: &str): &str? from self
pub method &self.split(separator: &str): Vec<String>!
pub method &self.split_views(separator: &str): SplitIter! from self | separator
pub method &self.lines(): LinesIter
pub method &self.bytes_iter(): ViewIter<u8>
}
impl<T> [T] {
pub method &self.len(): usize
pub method &self.is_empty(): bool
pub method &self.ptr(): *T
}
impl str, not impl &str, owns text methods. Receiver capability supplies the borrow, as it does for every nominal inherent method. Likewise [T] owns slice methods; &self is &[T], and a readwrite slice may weaken to that receiver without a second declaration. Neither unsized type may be constructed, consumed by self, or own drop.
String keeps only operations whose semantics depend on owned string storage:
impl String {
pub method &self.capacity(): usize
pub method &+self.reserve(additional: usize): void
pub method &+self.try_reserve(additional: usize): void!
pub method &+self.clear(): void
pub method &+self.push_str(value: &str): void
pub method &+self.try_push_str(value: &str): void!
}
Construction remains in construct String; borrowed access remains in its existing coerce declaration. Calls such as text.len(), text.find("part"), and text.lines() keep their source spelling but select the str declaration through &String as &str. The redundant String.view() method is removed; an explicit conversion is written &text as &str.
The same ownership rule applies to Vec<T>. Slice observation belongs to [T]; allocation, capacity, mutation, and ownership transfer remain on Vec<T>. A method required by an explicit interface conformance, such as Sequence<T>.len, remains because it satisfies that contract rather than acting as a duplicate inherent API. Existing public functional entry points that accept &str or slices may remain, but their algorithms and the methods must share one implementation. Phase 3 does not retain duplicate owning-type methods solely as compatibility aliases.
Built-in Type Declaration Authority
The resolver gains one declaration-identity model for method owners. It represents both ordinary nominal declarations and compiler built-in unsized types without inventing a fake struct symbol. The active Nocter home supplies the exclusive source implementation unit for each built-in owner. Loading that unit makes inherent methods available to user and standard-library modules without injecting value names or pretending that str and [T] come from the synthetic prelude.
Only the registered standard implementation unit may declare inherent implementations for a built-in type. A project cannot add competing impl str or impl<T> [T] blocks. Duplicate method identities are rejected before type checking, independently of source order. The registry owns type identity, declaration authority, and implementation-unit loading; parser, resolver, type checker, IR, and LSP code must not carry separate module-path or method-name tests.
Operations that ordinary Nocter cannot express, such as extracting a view length or data pointer, remain narrow typed pub(nocter) primitive declarations below the public methods. Compiler support therefore recognizes a resolved primitive role, not a call named len, ptr, or bytes. is_empty and the higher text operations are ordinary source bodies.
Receiver Coercion Selection
Receiver coercion extends the existing ConversionPlan; it does not create a second conversion engine. One immutable resolved call plan records receiver evaluation, automatic borrow or capability weakening, at most one declared borrow coercion, the selected method declaration, and generic substitution.
Lookup follows this order:
- 1. Collect accessible methods on the original receiver through the existing inherent, conformance, and interface-default rules.
- If one candidate is selected, use it without consulting coercions. If the original lookup is ambiguous, report that ambiguity.
- Only when the original receiver has no accessible candidate, form its normal automatic method borrow and consider each accessible one-step borrow coercion.
- Look up the requested method on each exact coercion target. Select the result only when one coercion and one target method remain; otherwise report a receiver-coercion ambiguity.
An original-type method therefore shadows a view method deterministically. Declaration order is irrelevant. Lookup does not chain coercions, infer an unconstrained generic argument from a coercion target, rank conversions, or fall back from an original candidate whose receiver capability is invalid.
The receiver expression is evaluated once. Borrow checking treats the automatic source borrow, coercion call, and target method as one call boundary. A result derived from target self retains the original owning value's loan, including through optional, fallible, aggregate, iterator, and generic results. Lowering consumes the recorded call plan and never repeats lookup from types or member text.
Standard-Library Responsibility Split
- a new focused standard-library source file owns built-in
strdeclarations and the narrow primitives needed to inspect its runtime view representation - a separate focused source file owns generic
[T]declarations and slice representation primitives std/string_viewscontinues to own UTF-8 validation and borrowed iterator state;std/string_searchcontinues to own byte searchstd/stringownsStringconstruction, allocation, mutation, and theStringcoercion, and remains the stable facade for existing public function imports and named iterator types- standard-library internals call typed primitives or shared private algorithms at dependency boundaries; they do not depend on compiler-recognized public method spellings
The final file names are chosen during implementation after the module-dependency audit, but each responsibility above must have one source authority. A cyclic import or a second implementation of an algorithm is not an acceptable migration mechanism.
Work Order
- 1. Freeze positive and negative fixtures for current
str, slice,String, andVec<T>calls; inventory every compiler branch that recognizes a collection member by text. - Introduce built-in method-owner identities, exclusive standard implementation authority, and implementation-unit loading without changing method behavior.
- Permit validated
impl strandimpl<T> [T]declarations, reject every unsupported built-in target, receiver form, user-owned declaration, and duplicate. - Add typed representation primitives and source method bodies, then delete name-based
len,is_empty,ptr, and byte-view typing/lowering paths. - Extend ordinary method selection with one nested borrow-coercion plan and make type checking, ownership, provenance, region checking, mutation effects, and IR consume that plan.
- Move text and slice observation methods to their borrowed owners; narrow
StringandVec<T>inherent surfaces and migrate standard-library callers without forwarding copies. - Drive hover, completion, signature help, definition, semantic tokens, references, and rename from selected source declarations and the recorded receiver plan.
- Update the public specification, compiler architecture documentation, examples, source corpus, and release migration notes; run the complete repository and installed-home qualification gate.
Each architectural step should be committed only after its focused tests and repository formatting checks pass. The final completion commit records the complete verification counts and leaves no temporary compatibility table or dual lookup path.
Verification Gate
- string literals, readonly text views, readonly slices, and readwrite slices select source-backed methods without importing a value name
- owned and borrowed
Stringvalues reach everystrobservation method through exactly one receiver coercion;Vec<T>reaches slice-only observation methods through its declared coercion - direct original-type methods and explicit interface conformances win before coercion, while multiple viable coercion targets receive stable ambiguity diagnostics
- invalid receiver capability does not silently choose a coerced alternative; coercions never chain and never drive unrelated generic inference
- receiver side effects execute once in check and native execution paths
- a view returned by a coerced method preserves the owning source loan and prevents mutation, move, drop, or region escape until its last use
- generic, optional, fallible, aggregate, iterator, callback, and static results preserve the same origin and allocation facts as direct calls
- no type-checking, ownership, IR, or analysis branch recognizes public view behavior from the
strings
len,is_empty,ptr, orbytes - hover and completion show the canonical
stror[T]declaration rather than a syntheticStringorVec<T>copy; definition and references use the exact source identity - standard-library source contains no redundant
Stringobservation methods orVec<T>inherent view methods, and distributed-home tests exercise the source declarations - malformed and incomplete built-in impls and receiver-coercion calls produce diagnostics without panics or unstable LSP ranges
- specification, implementation documentation, formatter and AST JSON fixtures, generated pages, public examples, and migration notes agree with the implemented surface
development/compiler/scripts/verify.sh,cargo fmt --check, warnings-denied Clippy, documentation generation, andgit diff --checkpass
Phase 3 is complete only when every gate passes and no implementation TODO remains in scope. Completion returns v0.9.0 to an inactive feature state; release stabilization and qualification still require a separate explicit plan.
Phase 3 Completion Record
Phase 3 completed on 2026-08-08. std/str.nct and std/slice.nct are now the exclusive source authorities for inherent methods on the built-in str and [T] type identities. The frontend loads those implementation units without injecting value names, validates their complete generic and receiver shapes, and rejects competing project implementations. Built-in surface collection uses a deterministic source order, so diagnostics and selected declarations do not depend on hash iteration.
Public view behavior is source-backed. Only four exact pub(nocter) representation primitives retain compiler roles for extracting string or slice length and pointer data. Type checking, ownership, provenance, analysis, and lowering consume resolved method and primitive identities; they do not recognize public len, is_empty, ptr, or bytes behavior from member spelling. Semantic expression type facts now drive string and slice indexing, collection byte handling, assignment, and native lowering, including expressions whose explicit conversion changes the view element type.
Method selection extends the existing conversion plan with one receiver-coercion step. Original methods and explicit interface conformances retain priority; minimum-capability paths to the same declaration collapse; distinct targets remain ambiguous. Hidden signature dependencies preserve canonical imported type identities for built-in methods whose results contain standard-library types. Returned views retain the original owner's loan through optional, aggregate, iterator, and generic results, while receiver evaluation still occurs exactly once.
String now owns construction, capacity, allocation, and mutation while observation, search, projection, splitting, and iteration resolve through its declared readonly coercion to str. Vec<T> similarly delegates view-only observation to [T] while keeping capacity, mutation, ownership transfer, and required interface implementations. Hover, completion, signature help, definition, references, rename, and semantic tokens use the selected source declaration and show canonical &str, &[T], or &+[T] receivers without synthetic owning-type copies.
The final verification matrix passed 3,389 tests: 2,346 library tests, 296 build CLI tests, 7 formatter CLI tests, 27 LSP CLI tests, 18 package CLI tests, 452 native run tests, 11 native test-command tests, 223 distributed-home tests, 2 public-example tests, and 7 source-corpus tests. cargo check, cargo fmt --check, warnings-denied Clippy, documentation tests, generated public documentation, and git diff --check also passed.
No Phase 3 implementation TODO remains. The compiler version remains v0.8.0. Phase 3 did not bump the version, prepare an archive, tag, push, or publish v0.9.0. The next change must begin with a separate stabilization or release-qualification plan.
Non-goals
Phase 3 does not add user extension methods on foreign or built-in types, transitive coercion, owned-value coercion, implicit borrow insertion outside method receivers, coercion-based operator or literal selection, overload ranking, dynamic dispatch, new collection representations, mutable UTF-8 views, Unicode scalar or grapheme APIs, range syntax, another target, a version bump, an archive, a tag, a push, or publication.