Incan 0.6 — in development¶
Development release note. Incan 0.6 has not shipped. This page records the release contract and the user-facing direction of the active development line; the tagged release note will distinguish delivered behavior from work that was deferred or explicitly migrated.
The release in one sentence¶
0.6 makes Incan's own compiler facts and Oven project model the normal authority for compilation, packages, build artifacts, and inspection—so generated Rust is an optional projection, not the semantic handoff.
Why this release exists¶
0.5 established compiler-owned foundations, checked project boundaries, and the first Oven Alpha evidence. It still retains generated Rust in the normal backend path and leaves Cargo-shaped build behavior too close to the centre of the system.
0.6 is the architectural cutover. Its purpose is not to rewrite every compiler component in Incan immediately. It is to put Incan in a position where large parts of its internals can begin moving into Incan source deliberately, while Rust stays a bounded host capability rather than a second semantic authority.
Features and enhancements — in development¶
The compiler owns source meaning end to end¶
The replacement backend will consume direct, compiler-owned lowering facts through Body IR. Backend selection and execution will be explicit and receipted, with no silent fallback to the legacy route. A corpus-based parity system will show which behavior is verified, which is intentionally migrated, and which is not yet acceptable.
- Packages: Library builds publish versioned executable content for covered public declarations. Replacement consumers execute supported calls through package aliases and facades without producer source, using the original declaring identities and selected public type context. Missing, incompatible and uncovered requirements refuse before output or a new execution receipt. Native linking remains available for packages without executable coverage. (#1339)
- Tooling:
incan inspect representationreports a published package's executable-representation version and the coverage it declares for each public declaration, with refusals carrying their stable reason. A package that publishes none, and a representation this build cannot interpret, are both reported rather than refused. (#1339) - Packages:
.incnlibmanifests carry anonymous union types in checked signatures, and declare manifest format 4. A reader without support for the new type reference refuses the manifest by format number rather than failing to parse it, so an artifact from a newer compiler names the reason it cannot be read. Comment- and order-preserving manifest editing is unaffected. (#1339, #1453) - Standard library:
std.tomlreads typed manifest values and declared models, reports source locations for parse and structural errors, and writes generated lock documents while retaining TOML date/time kinds. Comment- and order-preserving manifest editing remains deferred. (#1409) - Tooling: A direct-rustc store entry retains the complete receipt of the compilation that produced its bytes, admitted against the entry's own receipt, build unit and intent, and re-checked whenever a held payload is revalidated.
incan oven store inspectreports it, so a reused artifact can say what made it rather than only naming a receipt. (#1037) - Tooling: A consumer of an admitted Incan package no longer needs the producer's private Rust path sources to resolve it: the package is identified by its sealed artifact, never by walking the producer's private Cargo edges. An explicit bake of a consumer that declares no registry roots of its own composes the provider's sealed closure and links it once. The one shape that still refuses is a diamond over two sealed providers that each compiled the same shared registry unit: Oven names the crate and the collision at its own boundary, never falling back to Cargo, until #1241 reconciles shared units to one compiled artifact. (#1469)
- Tooling: A package diamond that names one provider under one alias from both sides links it once instead of refusing a duplicate extern. (#1459)
- Tooling: An explicit bake treats a cached output whose release Loaf the active toolchain no longer ships as a cache miss and rebakes; a consumer facing project extensions from two retained families selects the one whose base the toolchain still ships. (#1444)
- Tooling: A normal
incan build,run, ortestnever launches Cargo. The two remaining silent detours — an executable whose caller-owned provider resolved a shared registry package to a different compiled artifact than the project's own closure, and a library whose assembled closure rustc could not load — are now refusals. The first names the package and the provider artifact that pins it; the second names the library and rustc's crate-loading report, including aStableCrateIdcollision, which carries no error code. Both point at the Oven-native reconciliation still owed (#1241). (#1141) - Tooling: Two large interop projects can share one Oven home. An explicit bake reserves a 4 GiB staging floor before it runs, reclaiming inactive store entries oldest-first to reach it instead of failing with a demand to prune by hand, and prints a
note:naming what it reclaimed; entries under a live lease are never touched. The everyday store policy grows to 12 GiB aggregate and per-domain physical allocation so a Bevy-scale and an IncQL-scale project coexist instead of evicting each other. (#1230) - Tooling: Editing a baked project no longer stops
incan buildandincan runwith a demand to bake again. The sealed project output is set aside with one warning and the edit compiles from source against the dependency closure the bake published; reverting the edit picks the sealed output back up. (#1141) - Tooling: A no-change
incan buildon a starter project went from 529 ms to 357 ms on the reference machine, and a cold one from 721 ms to 582 ms: Loaf selection materializes only the candidate it picks instead of every compatible family, the compiler is probed once per process withrustc -vVinstead of twice, and a packaged provider's sealed digest is served from a tree-stamp memo.incan build --report jsonnow attributes every preparation step undertimings_ms. (#1111, #1556) - Tooling: A sealed closure's shape check is written down once. Every command that selected the standard-library Loaf re-checked its 9,500 files for presence, regularity and containment; the first command now records a closure proof beside the Loaf envelope (or the Oven store, for a leased project plan) and later ones read that record. Warm no-change build 357 → 277 ms, cold 582 → 416 ms on the reference machine.
incan inspect ovenstill rehashes what it audits. (#1546) - Tooling: Oven validates caller-owned native output bytes against the digest recorded after compilation before reusing them. Changed outputs and old or malformed reuse evidence trigger a rebuild. (#1463)
- Tooling: Native package imports read published Oven stores without changing access bookkeeping or cache files inside the package artifact. This keeps recorded dependency digests stable during import while retaining ordinary consumer-store reuse. (#1458)
- Compiler: Generated Rust accepts a released stdlib within the declared compatibility range, including a patch release after a prerelease requirement. A new major is rejected; before 1.0, a new minor is rejected, and
0.0.xkeeps its patch boundary. Linked prerelease stdlibs still require an exact match. (#1481) - Compiler: Source traits can inherit imported Rust trait bounds without synthesizing conflicting implementations of foreign parents. (#1427)
- Compiler: Qualified Rust enum patterns work through shared and mutable references without cloning the matched value. (#1448)
- Compiler: Checked SDK artifacts retain derive-provider membership, so
@derive(toml)remains available through compiled standard-library imports and re-exports. (#1449) - Compiler: Imported Rust generic trait bounds accept native scalars and collections, with the actual trait obligation checked by Rust during native compilation. Same-spelled Incan traits still require explicit adoption. (#1451)
- Tooling: Declared scripts that resolve to
src/lib.incnfail with a located manifest diagnostic naming the script and library path, before Oven generates executable code. (#1068) - Tooling: Experimental replacement execution admits compiler-selected
str,int, andfloatscalar conversions with receipt-bound normal output and classified parse failures. Source literals and runtime numeric strings share one language-owned underscore-separator policy. Malformed source literals produce compile-time diagnostics, while failed runtime conversions retain the original spelling in the canonicalValueError. #988 retains the broader numeric-operation and entrypoint profile. (#1249, #1278) - Tooling: Exact signed and unsigned widths,
f32,f64, aliases, and checked fixed-scale decimals now retain their compiler-selected carrier through literals, locals, lossless widening, source-local calls, direct entry arguments/results, Display output, receipts, the replacement JSON report'sresult_type, and bounded two-route comparison. Exactf32/f64carriers are finite-only: native exact arithmetic validates each result before it can be stored, returned, compared, or printed, and runtime exact-carrier boundaries use the same canonicalValueError; ordinaryfloatretains IEEE non-finite values until code attempts to cross into an exact carrier. The replacement profile still refuses arithmetic on these exact carriers, their unary and resize operations, Debug formatting, aggregates, matching, and decimal scalar casts before effects under #988; package/import execution remains under #989. (replacement-body-v0-029, #1279) - Tooling: The experimental direct replacement profile now executes its admitted selected entry through one session-owned package-feature projection and records matching semantic-module provenance in its JSON report and backend receipt. That initial profile did not admit package/public imports; published package coverage is described above, and broader unsupported source remains outside the profile. (#1254)
- Compiler: The experimental replacement profile executes source-local hashed set and dictionary membership with checked
int,bool,str, or unit keys, including typed-empty constructors. A same-source comparison covers exact program output and a separate boolean result; iteration, mutation and general collection parity remain outside this profile. (#1247) - Tooling: The experimental direct replacement profile recognizes compiler-selected global
enumerate(list)andzip(list, list)over retained structural list shapes, preserving zero-based enumeration and ordered shortest-side pairing. Receipt-backed comparisons cover the selected list cases; this does not grant general iterator support. (#1249) - Compiler: Native compilation materializes stored
enumerateresults as checked list values and preserves later-used values when introducing aliases, including the required genericClonebounds. (#1249) - Compiler: Generic callers now inherit implementation-only bounds from the exact checked trait implementation, including across compiled-library metadata, without imposing those bounds on every use of the owning type. The manifest retains the selected trait identity, arguments, associated types, bound origin, and implementation header; private same-program implementation details remain absent from the public artifact. (#1280)
- Compiler: Dependency-interface predeclaration preserves concrete public result types across cyclic and transitive local imports, so chained generic method calls no longer degrade to unknown placeholder types merely because their modules depend on each other. (#1280)
- Tooling: Experimental replacement execution delivers program output during execution and preserves accepted bytes if execution or receipt persistence later fails. JSON reports require a separate
--report-outputfile. The bounded named-function shadow comparison transports typed results separately from stdout/stderr and compares each program stream exactly; unavailable comparisons and diagnostic differences remain non-green. (#1249) - Compiler: Provider-aware replacement preparation checks missing hosts inside deferred computations and reachable same-module callees before program output or provider invocation. Host discovery uses retained compiler identities; invocation-time authority checks and operation receipts remain unchanged. (#1249)
- Compiler: Compiler-selected integer
absand builtinsumnow fail on overflow in every build profile. Replacement execution preserves the original call span and prior output, while generated Rust uses explicit checked operations instead of inheriting Rust debug/release overflow behavior. This does not yet define overflow for ordinary integer operators. (#1249) - Compiler: The experimental replacement profile executes the selected
upper,lower,strip,replace,join,split, andcontainsstring helpers through checked compiler identities and the shared runtime. A dedicated same-source comparison covers those helpers; arbitrary methods and general formatting parity remain outside this claim. (#1256) - Compiler: String
len(value)andvalue.len()count Unicode scalar values consistently in generated Rust and the experimental replacement profile. The replacement path keeps checked builtin/helper identity, and a dedicated same-source corpus row compares exact program streams and the returned result; otherLenoperand profiles remain bounded. (#1249) - Tooling: The experimental replacement profile executes compiler-selected
json_stringifyfor directly represented integers, booleans, strings, andNone, evaluating the operand once and preserving the shared runtime's exact JSON bytes. A same-spelled source declaration keeps its lexical identity; floats, collections, nominal values, and broader serialization remain explicit refusals. A dedicated same-source corpus row compares the exact returned bytes and empty program streams through independent receipts without claiming general JSON parity. (#1249) - Tooling: The experimental replacement profile executes compiler-selected
lenover its source-local hashed set/dict carriers, returning the distinct element/key count after duplicate collapse, including typed-empty constructors. A dedicated same-source comparison covers exact streams and the integer result; iteration, indexing, projection, mutation, equality, ordering, printing, and formatting of these containers remain outside this bounded claim. (#1249) - Tooling: The experimental replacement profile executes compiler-selected
boolfor its directly represented booleans, integers, strings, lists, sets, and dictionaries. Zero and empty values are false; nonzero and nonempty values are true. A same-spelled source declaration keeps its own identity, and floats, tuples, bytes, frozen collections, options/results, arbitrary objects, and custom truthiness remain outside this bounded claim. (#1249) - Compiler:
isinstance(value, Target)now retains the typechecker-resolved value and target types, any proven nominal target identity, and the target's exact source span in a dedicated Body IR operation. The experimental replacement profile executes the boundedint,bool,str, and ordinary binaryfloattarget set when the checked value type is one of those scalars or a nonempty union containing only them. Ambient and explicitstd.builtins.isinstance(...)calls consume the same compiler-owned identity, while a source declaration with that spelling remains an ordinary direct call. A same-source comparison covers true and false union-member branches, direct expression use, exact streams, and the typed boolean result. Unsupported value or target shapes refuse before effects; this does not add arbitrary runtime type values, general reflection, nominal execution, or package/import execution. Closed #1154 supplied the current direct nominal/value substrate; open #988 owns broader replacement execution, and #989 owns package/import execution. (#1281) - Tooling: The experimental replacement profile executes compiler-selected
sortedfor nonempty represented integer lists, returning a fresh ascending list while retaining negative values, duplicates, and the source list's original order. Empty lists and other accepted ordering domains remain explicit refusals until checked element-type/order facts reach this runtime seam. (#1249) - Tooling: Experimental replacement execution now runs calls that leave the entry module. A call into a sibling module executes against a graph spanning the session's reachable modules, resolving the callee by canonical identity rather than by a same-module span identity; a module-qualified call such as
helper.bump(41)executes as a direct call to the declaration its qualifier names, and a local sharing an imported module's name keeps its ordinary meaning. Refusals report against the module whose span they carry rather than the entrypoint, so a diagnostic names the file a reader has to open. That initial module-execution change left package (pub::) imports outside its scope; published package execution is described above. (#1260) - Tooling: A facade chain executes on the experimental replacement route with its direct, aliased, and re-exported bindings proven to resolve to one declaration. An alias is admitted as a binding to a declaration rather than a declaration of its own, so refusing it would refuse a name rather than any behavior. (#1261)
- Compiler: A Rust or Python interop boundary the replacement route cannot cross now refuses as a missing host rather than as a construct the profile has not reached, naming the crate a call would have entered. Previously
import rust::serde_jsonandimport std.ioreported the same text, which sent a reader to the language when the problem was a host. An ordinary standard-library import still reports as an unreached construct and never claims a missing interop host. (#1262) - Dependencies: The locked Wasmtime and Cranelift patch releases advance to the 36.0.14/0.123.14 family, clearing
RUSTSEC-2026-0269from the repository security gate without changing Incan's declared dependency range or public language surface.
Verified means verified by execution. A source profile counts as parity only when both routes actually ran over the same source and agreed on what the program did — the replacement backend executing Body IR directly, and the legacy backend building and running the program it emits through Oven, under a receipt that records which build authority produced the answer. The backend-selection receipt records that outcome explicitly as matched, diverged, or unavailable, and only a comparison that ran and agreed is green; a legacy program that merely compiled proves nothing about meaning. A comparison that could not run keeps whatever evidence the route that did run produced, so an unstaged environment stays distinguishable from a backend that cannot execute the source. Because an environment without a staged build authority is non-green everywhere, a dedicated CI job stages one and requires the comparison to run and agree, so "verified" always names evidence that was actually produced. See Backend selection & execution receipts.
Source identity is part of that contract. Imports, aliases, re-exports, locals, members, and generic binders should resolve to one canonical compiler identity across diagnostics, LSP features, graph tooling, and backend facts. This removes the backend-emitted Rust name as an accidental source of semantic truth.
Loaf and Oven become the opted-in project authority¶
For a project that adopts loaf.toml, Loaf expresses authored project intent and Oven owns resolution, targets, provider planning, cache identity, artifacts, receipts, and publication-facing build evidence. oven build and oven bake will provide the build and target-bound asset surfaces; in-Loaf incan run and incan test will use those same plans and receipts.
Cargo remains valid as a legacy format and explicit compatibility/adoption mode. It does not become invalid, and a Rust-only project can choose Oven without adding Incan source. But once a project is Loaf-native, Cargo cannot silently retake authority over its project graph or provider effects.
The authored project manifest is now loaf.toml. incan.toml is not read as a compatibility format — RFC 117 lists preserving it among its non-goals — so a directory holding one is reported as not being a project manifest, naming the file and saying to rename it once its tables satisfy the Loaf schema. Discovery stops at such a directory rather than walking past it to an ancestor project, because whoever put the file there meant it as a project root. [oven.interop] moves in the same transition to [interop.c], under an [interop] root that names each binding kind; its contents are unchanged.
The generated project lock is now oven.lock. It records the same resolved dependency, provider, and interop graph that incan.lock did, under the name RFC 117 gives it, and both authored and generated filenames are lowercase so a case-only difference never means one thing on Linux and another on macOS or Windows. incan.lock is not read: a project that still has one should run incan lock and delete the old file, which no longer contributes to any build. Committed example locks in this repository are renamed with it.
Incan-only, Rust-only, and mixed projects will have deliberate, non-overlapping source roots. Rust facets, direct rustc planning, build scripts, and proc macros remain supported through governed provider contracts. C and other foreign runtimes stay behind explicit interop boundaries rather than being inferred from a source directory.
- Tooling: The toolchain is three Cargo packages,
incan-cli(theincanbinary),incan-lsp(the language server) andoven-cli(anovenbinary over the same handlersincan oven …andincan lockrun; built, not yet shipped in the release archives); thelspCargo feature is gone. A source build installs each on its own —cargo install --git https://github.com/encero-systems/incan.git --locked incan-cli, and the same command withincan-lsp— and the prebuilt archives still ship both binaries. (#1478, #1481) - Compiler: Generated Rust links the standard library as one runtime crate per component —
incan_std_corealways, andincan_std_data,incan_std_async,incan_std_weborincan_std_testingwhen the program's namespaces reach them — in place of oneincan_stdlibcrate selected by Cargo features.incan inspect rustand build reports name those crates. (#1481)
Runtime effects become governed and inspectable¶
The runtime and embedded-language work in this release is there to make real programs and the new backend prove one another. Accepted embedded fragments have typed descriptors, diagnostics, LSP behavior, and a safe formatter contract: structured fragments format structurally; opaque fragments are preserved unchanged.
Authority declarations, grants, execution receipts, redaction, replay, and policy inspection make runtime effects explainable. Source and packages state requirements; Loaf applies project policy and target selection; Oven enforces and records the resulting execution. Source code cannot grant itself host authority.
- Stdlib:
std.hashadds keyed authentication withhmac_sha256, covering one-shot tags, an incremental signer, and constant-time verification. An unkeyed digest can only prove a value is self-consistent, since the hash formula is public source; a keyed MAC is what lets a process prove a value it received across an untrusted boundary was one it produced earlier. Verified against the RFC 4231 vectors (#1075). - Compiler: The nine reserved
host.*runtime capabilities are declared in the compiler's own bundledstd.runtimesource, using the samecapabilitydeclaration a package uses rather than a separate built-in list. Arequiresentry can now name one —from std.runtime import host, thenrequires = [host.fs.read]— and a misspelled host capability is an unresolved-symbol compile error instead of a runtime denial reported somewhere else. Granting and enforcing this authority is not wired yet; this is the declaration and reference half. (RFC 104, #1029) - Compiler:
@provider_operationcan name a host capability, so an operation declares the authority it needs the same way it declares a package capability. The decorator resolved its capability reference only through package dependencies, which cannot see the compiler's own bundledstd.runtime, so@provider_operation(host.fs.read)was unresolvable. (RFC 104, #1029) - Compiler: A
capabilitydeclaration no longer fails compilation. It declares authority rather than code, so it emits no Rust item, but lowering treated it as an unhandled declaration and failed any module containing one — which meantstd.runtimetypechecked while refusing to build. (RFC 104, #1029) - Tooling:
incan inspect codegraphpublishes RFC 104 capability declarations, including each one's description, typed scope dimensions, and the resolved identities of the capabilities it requires. A policy, CI job, editor, or agent can read what a package declares it can do without executing source or parsing acapabilityblock. (RFC 104, #1027)
Inspection becomes a first-class product surface¶
The CLI, LSP, Architect, MCP tools, and Rust/Oven views will consume the same source and build facts. They should agree about a symbol's identity and range, a package or artifact's provenance, the selected target and provider, and whether information is stale. Rust-aware inspection is deliberately bounded to the workspace, package, target, artifact, and explicit interop edges that Oven needs—it is not a separate compiler.
What must be true before 0.6 ships¶
- The replacement backend is the default only when the complete v0.6 matrix is verified or explicitly migrated.
- Every backend run records both the selected route and the route that actually executed; incompatible, unavailable, skipped, or failed parity comparisons are non-green.
- Generated Rust remains inspectable, but normal compilation, package contracts, and Oven do not rely on it as a semantic handoff. Reading it now takes a decoding step: every linker-visible Incan-origin declaration is emitted under a reversible
incan-v1identifier that encodes its canonical identity, and a private function carries no source-named alias at all. - Rust-only, Incan-only, and mixed Loaves can bake without Cargo acting as the project authority; Cargo compatibility remains explicit and well-described.
- Canonical source identities, provenance, source ranges, and stale-state behavior agree across compiler and inspection consumers.
Bugfixes¶
0.6 is not released yet, so this list carries only fixes that are merged, regression-tested, and part of the release branch's supported behavior.
- Tooling: SDK provider identities stay stable when a consumer uses only part of a compiled standard-library provider. Nested commands no longer reject a matching provider solely because its unused runtime facets were absent from the consumer's identity catalog. (#1481)
- Compiler: Native package consumers retain compiler macro dependencies used only in a provider's child modules, including function-only facades. (#1467)
- Compiler: Loops over nested literals such as
[[], ["x"]]infer the string element type without an extra caller annotation. (#1471) - Compiler:
import module::itemcompiles to the same canonical call asfrom module import item. The Rust-style spelling typechecked but native compilation named the item by its source name with no matching import in scope, so the generated crate did not compile. (#1441) - Compiler: A local function called inside a lambda that is passed to a Rust method now keeps its
incan-v1identity. The lambda body was skipped entirely while the Rust signature was pending, which discarded the resolved callee along with the diagnostics, and the bare source name reached the generated Rust as an undeclared symbol. (#1492) - Compiler:
Deque[str].from_iter(...)and every other type application keep their arguments on the receiver. The argument list was dropped at resolution, so the element type reached emission as unknown and a string literal appended to the result was emitted as&stragainst aStringparameter. (#1494) - Tooling: A command that has to wait for the SDK provider store lock says so, naming the store and the fact that another Incan process holds it, instead of blocking silently. A three-file
incan inspect codegraphthat sat inflockfor half an hour looked like a compiler hang. (#1514) - Tooling: A Loaf project that also holds a
Cargo.tomlbuilds with one warning naming the ignored file; a directory holding only the retiredincan.tomlstops project discovery with an error asking for the rename rather than being stepped over. (#1008) - Language:
{{and}}in an f-string render one literal brace, as in Python, sof"{{{name}}}"prints{x}; both characters were reaching the output. (#1562) - Tooling: A workspace member that carries a feature-selecting dependency edge can be baked inside its workspace. A command's
--featuresselection no longer rewrites the shared root lock, an explicit provider bake publishes the root lock with every member that can already resolve, and a member's sealed authority binds only its own lock entry, so baking providers leaf-first no longer invalidates each other. (#1414) - Compiler: Source-backed standard-library module imports retain the trait metadata required by their qualified codec functions. Models using
@derive(toml)satisfy TOML codec bounds with either module import spelling and with aliases. (#1473) - Compiler: Equality assertions accept inline model constructors on either side of the comparison without requiring an intermediate local binding. (#1470)
- Compiler: Reference-aware assignments preserve an existing borrow and materialize known borrowed values at owned destinations. Read-only nominal helpers and tree cursors can infer shared borrowing from complete local use and checked Rust receiver lifetimes, avoiding copies of ancestor subtrees. Crate-visible and inherent method entry points retain their callable ABI; mutation, escapes, overlapping call arguments, and unknown contracts keep owned behavior. (#1455)
- Language: Plain assignment inside a nested block now reassigns the nearest enclosing binding — requiring
mutand a compatible type — instead of silently creating a new block-local;letandmutremain the explicit shadowing forms, andmut name = valuenow declares a new binding over an active name rather than being rejected as mutation of an immutable one. This brings assignment behavior to the documented scoping contract. (#1072, #1248) - Language:
printandprintlnnow render every argument, space-separated. Previously every argument after the first was silently dropped in generated Rust, with no diagnostic. (#1248) - Language:
printandprintlnare protected builtin bindings: source declarations, imports, parameters, and local bindings cannot replace them. Fields and methods with these names remain valid. (#1249) - Language: Duplicate declarations and same-spelling imports are now rejected by one frontend binding registry instead of silently replacing whichever declaration was seen first. Imports are reported as ambiguous when their canonical targets differ or cannot be proven equal; an explicit alias resolves intentional conflicts. The immutable line-output spellings
printandprintlncannot be reused for ordinary lexical declarations or imports, while member names and ordinary builtin spellings such aslenremain available under their normal namespace rules. (#1042) - Compiler: Unreachable code after an unconditional return is reported. (#1117, #1134)
- Compiler: A package that calls between its own modules again projects the callee's emitted name. A package origin identifies which library declares a method; it does not make that method foreign to the build producing it, and reading it as foreign made a package decline to name a wrapper it was itself emitting. (#1174)
- Compiler: A
Result-returningmainretains ordinary runtime panic diagnostics and requestedimport thisoutput, matching the existing setup in other entrypoint forms. (#1249) - Language: A
matchwritten as a function's last statement now returns its value instead of being discarded, and every arm converts to the type thematchproduces. The documented spelling for pattern alternation previously emittedlet _ = match ...;, so a value-returning function built from it produced Rust that would not compile, andstrarms stayed borrowed where an ownedStringwas required. (#1386) - Tooling: A vocabulary companion may bind a helper to any callable spelling on its package's public surface, including a public partial and a reexport alias, and its own build now rejects a binding that resolves to something uncallable through a chain of aliases. The provider's build and every consumer's frontend read one export authority, so a helper the provider published can no longer be rejected as missing by the consumers that import it. (#1031)
- Editor integration: Signature help, scoped-symbol resolution, completion context, and call-site type arguments now reach inside an embedded fragment's expression holes. A hole is ordinary Incan that the compiler already typechecks, but the editor treated the whole fragment as opaque, so a call written inside one silently lost tooling that works everywhere else. One shared traversal now answers which expressions a fragment owns, for the compiler and its tooling alike. (RFC 081, #1022)
- Tooling:
incan fmtrenders an embedded fragment from its structured tree, and preserves the original source verbatim only when the claiming descriptor declares itself layout-sensitive. The formatter previously preserved every fragment verbatim regardless, which is the third fallback state RFC 081 rules out; a descriptor'slayout_sensitivedeclaration was recorded and never read. (RFC 081, #1022) - Editor integration: Hover and go-to-definition now stop at an embedded fragment's ownership boundary. Both resolved names by scanning source text, so a markup tag name or a style declaration property — perfectly good ASCII identifiers — resolved against ordinary Incan scope and answered with whatever unrelated local happened to share the spelling. DSL-owned syntax now reports which submode and which library own it; expression holes, being ordinary Incan, keep every tooling path they already had. (RFC 081, #1022)
- Tooling:
incan fmtno longer rewrites aRegexTemplatefragment into source that will not parse, and no longer grows a file by a blank line on every run. A template string's backticks and${...}delimiters are consumed while parsing, so reformatting`hello ${name}!`emittedhello {name}!— a shape the submode rejects outright. Separately, both modes that preserve a fragment's text verbatim also emitted the newline the enclosing block supplies, so formatting was never a fixed point. All six accepted submodes now round-trip. (RFC 081, #1022) - Editor integration: The language server now answers
textDocument/semanticTokens/full, so editors highlight Incan from the compiler's own reading of a file rather than from a regex grammar. Declarations take the kind of the thing they declare, type positions come from the parsed program instead of from capitalisation, member access separates a called method from a read property, and an f-string's interpolated expressions are highlighted as code rather than as string content. Embedded fragments are highlighted as their own submode, so a markup tag or a style selector never renders as an Incan local, while the expression holes inside a fragment do. A file that does not currently parse keeps its highlighting, losing only type positions and fragment ownership. (RFC 081, #1400) - Compiler:
import module::itemnow binds the item with its declared signature. The last path segment was registered as if it named a module, so the name resolved and nothing reported an error, but every call through it inferred an unknown type — the failure surfaced later and elsewhere, asexpected 'numeric', found '? + ?'on the first arithmetic using the result. Both import spellings now route through one symbol definition, so they cannot disagree about what an item is.examples/advanced/multifiletypechecks again. (#1407) - Tooling: A vocabulary companion no longer has to declare a helper binding for every helper it emits. An unbound helper key resolves directly against its package's checked public surface, the same surface an ordinary consumer imports through; an explicit binding remains the override for a key whose export spelling deliberately differs. A companion that listed its own package's export names was maintaining a second copy of that surface, kept honest only by a test. (#1032)
- Tooling:
incan fmtno longer rewrites valid source into different or broken source. Anenum'swith <Trait>adoption was dropped entirely, a byte literal's escaped quote and backslash were unescaped so the literal no longer terminated, and a guarded match arm was rewritten into an arrow form the parser rejects. Every committed example is now round-tripped by a property test that asserts the result still parses and is a fixed point. (#1401)
What this does not claim¶
0.6 makes self-hosting work possible; it does not claim that Incan has already rewritten its compiler wholesale. It also does not introduce a broad GPU API or a general foreign-interop plugin system. Those need real runtime consumers and separately governed follow-up work.
Follow the work¶
- #652 and #653: replacement-backend cutover and Body IR.
- #655 and #654: compatibility reporting and final removal of the Rust-source handoff.
- #1042: RFC 120 and canonical source identity.
- RFC 118 and #1010: Incan and Oven command surfaces.
- RFC 119: Rust facets, providers, and Cargo adoption.
- RFC 106 and #573: compiler-backed codegraph and inspection.
- 0.6 delivery map: delivery sequencing, slice evidence, and the current issue graphs.