Skip to content

Release 0.5

Incan 0.5 is the backend-foundation and Hees.ai proof-lane release. It starts the transition away from treating generated Rust source as the compiler's semantic path, while keeping the 0.4 install, project, check, build, test, and inspect surfaces usable for early 0.5 development.

Features and Enhancements

  • Compiler foundation: The 0.5 backend-foundation lane now has a behavior inventory, generated-Rust deprecation policy, stable semantic identity scaffolding, typed compiler facts, initial HIR structures, and a Hees.ai dependency inventory so backend migration work has a shared review surface (#646, #647, #648, #649, #650, #651).
  • Compiler foundation: Executable builds, generated-Rust inspection, codegraph export, and ordinary test batches now share CompilationSession analysis. Checked lowering inputs, source-backed stdlib metadata, and SemanticModuleSnapshot facts are produced together, so codegraph no longer independently reconstructs source-target facts and the legacy backend no longer rechecks those critical CLI paths (#224, #225).
  • Stdlib: std.checksum adds CRC32 value, digest-byte, and incremental helpers for compatibility and accidental-corruption checks, separate from std.hash security and hashing contracts (#709).
  • Stdlib: std.hash exposes Sha256Hasher, a storable incremental SHA-256 handle that models and classes can update across methods without retaining source chunks for final replay (#969).
  • Stdlib: std.environ adds redacted, read-only Unicode environment access through required, optional, and defaulted string reads, plus typed reads for primitives, explicit TryFrom[str] adopters, and validated newtypes (RFC 089, #557).
  • Stdlib: std.fs adds same-filesystem atomic publication, explicit directory synchronization, and OS-backed shared/exclusive advisory locks for crash-safe local state (RFC 112, #829).
  • Stdlib: Iterator.sum() is now ordinary source-owned Incan behavior through Sum[int] and Sum[float], including supported validated numeric newtypes, rather than a Rust-source backend special case (#510).
  • Language and stdlib: FallibleIterator[T, E] adds explicit for item in stream?: polling, lazy map, filter, list-returning flat_map, take, inspect, map_err, and inspect_err adapters, plus fallible collect and fold terminals. Adapter callback bounds accept matching functions, capturing closures, enum variant constructors, and explicit Callable1 / Callable2 adopters. Setup failures remain separate from polling failures, and retry remains explicitly owned by domain sources rather than loop syntax. BinaryReader.chunks(size) provides the first Incan-authored FallibleIterator[bytes, IoError], ends cleanly at EOF, and now powers reader-backed std.hash helpers through the generic map_err adapter (RFC 115, #579).
  • Compiled providers, SDK components, and package features: Checked Incan libraries and official SDK artifacts now enter compilation through one session-owned provider plan. The standard library ships as nine independently addressable components with minimal, default, and full profiles; project manifests can refine the selected profile without changing stable std.* imports. Package-owned features resolve additively across optional Incan dependencies, support compile-time when feature(...) source projection, and remain distinct from private Cargo implementation features. incan inspect providers and incan inspect features explain the resolved graph, while canonical locks record the semantic component, feature, provider, and implementation-facet closure ([RFC 114], #544).
  • Libraries and tooling: Published libraries now preserve their checked source hierarchy as automatic pub::package.module namespaces without a pub module declaration. Public declarations remain visible through directory namespaces and exact nested imports, private declarations stay private, and sibling-name collisions require an exact child path. The checked API drives package consumers, test batches, and editor completion while the generated crate reproduces the same compiled module layout; codegraph records preserve the consumer's canonical nested import spelling. Existing flat src/lib.incn facades remain compatible (#948).
  • Compact offline SDK seed: Toolchain archives carry relocatable, integrity-checked provider payloads and one shared Cargo lock without provider source, mutable build targets, or repeated per-project caches. Installed compilers publish the selected profile into a shared content-addressed store with crash-safe coordination, and generated build and test projects reuse those compiled providers instead of materializing standard-library source (#544).
  • Stdlib/tooling: std.registry adds typed declaration catalogues that preserve one source authority across runtime loading and static tooling. Libraries define a domain-owned Registry[K, T], opt descriptor models into immutable structural snapshots with @derive(Descriptor), and attach functions or concrete methods with the non-wrapping @describe decorator; explicit entries cover compilation-unit and package facts without fake declarations. loaded_entries() exposes only entries initialized in the current process, while incan inspect registry returns the complete deterministic checked projection without executing modules. Public facts travel in .incnlib artifacts and feed LSP navigation, codegraph facade projections, and the generated feature inventory. Existing custom registries can migrate to this single authority when their entries are structurally knowable at compile time; dynamic-only registries remain runtime-only by design. Start with the typed-registry tutorial, use the migration and inspection how-to, and consult the std.registry reference for exact contracts (RFC 113, #575).

Tooling

  • Interop (experimental): from std.interop import c activates import-scoped binding declarations for checked C scalar functions, opaque resources, and scalar or owned-resource output positions. The compiler verifies explicit signatures, enum carriers, and listed plain layouts with Clang before generated Rust emits a private C ABI bridge. A declared c.Owned[T] resource has one native release operation and a last-resort release guard; c.Borrowed[T] and c.BorrowedMut[T] are inferred from the checked parameter contract; c.Out[T] and c.InOut[T] use compiler-managed slots and outcome-guarded reads. Direct calls remain inside explicit unsafe: blocks, and scalar conversions are range-checked. A package can separately declare target-specific headers, static or bundled artifacts, system capabilities, C/C++ shim sources, compatible toolchain or SDK requirements, and Android/iOS platform constraints under [oven.interop] in incan.toml; incan lock records the normalized requirements and content-derived identities of package-owned files without claiming that Oven has resolved a concrete local toolchain. incan check --interop-target <triple> verifies the same source declaration against one declared mobile ABI profile, including its API or deployment version and preprocessor definitions. incan inspect interop-plan --target <triple> emits the locked requirement projection that a later Gradle or Xcode adapter can consume without duplicating target, artifact, shim, or placement facts. C strings, spans, scoped views, Oven artifact resolution, shim compilation, cross-target generated-Rust builds, toolchain attestation, and mobile packaging remain separate RFC 116 work (#940, #941, #942, #944).

  • Interop tooling (experimental): incan inspect bindings provides deterministic human and JSON views of the compiler-checked C declaration descriptors, including source anchors, symbols, exact C types, enum constants, and plain structures. It runs the ordinary host-target C probe but intentionally reports declaration facts rather than a reusable verifier receipt; native artifact resolution, shim baking, bridge/façade classification, and editor support remain separate work (#943).

  • Codegraph: A runnable Incan-authored external importer example uses std.json.parse_jsonl to validate schema-v1 JSONL exports end to end while keeping compiler-owned facts authoritative and unknown future record kinds opaque (RFC 106, #776).

  • Diagnostics and codegraph: Machine-readable diagnostics now carry compiler origin, structured expected and actual values, and labeled related spans across incan check, LSP, and tolerant codegraph exports (#771).
  • Workspaces: RFC 077 adds explicit rooted and virtual project workspaces with deterministic member selection, explicit shared dependency and environment inheritance, one crash-safe root lock, incan workspace inspect, and member-scoped build/check/test/fmt reports (#405).
  • npm package: Installing the npm toolchain adapter no longer emits the package-manager install-script warning now that the release packaging no longer relies on that hook (#812).
  • Release tooling: Installer and packaging tests use lock-protected, named temporary staging, reclaim abandoned staging from interrupted runs, and surface cleanup failures instead of silently retaining release archives and package-manager fixtures (#864).
  • Bounded generated-build cache: Generated Cargo output reuses compatibility-scoped targets below INCAN_HOME by default instead of multiplying the same dependency graph across projects and worktrees; path-independent root identities prevent temporary paths from creating unbounded duplicate binaries, while per-root locks and project-local publication isolate concurrent final outputs. Active-use leases protect concurrent builds only through Cargo and project-local publication, then release before user code runs; interrupted domains are measured before idle reuse, and every completed lease prunes the newly idle set toward a 20 GiB soft limit. An idle domain that exceeds its configurable post-Cargo safety bound has only its rebuildable Cargo target discarded. incan cache inspect|prune exposes versioned human and JSON management surfaces with exact-identity cleanup and logical-usage reporting. The storage-model documentation records complete small and DataFusion-shaped cold/warm build, run, test, and library measurements plus cache-identical nested-Cargo throughput evidence (#876, #877, #925).

Bugfixes

  • Compiler: A nested source module no longer silently imports itself when a same-leaf bare import collides with the module name. Use crate::module_name for an intended project-root import (#976).
  • Language: F-string interpolation retains support for direct zero-argument function calls, such as f"enabled:{enabled()}"; parser and complete-CLI regression coverage now protect that form (#979).
  • Language: Built-in mutable Set[T] values now expose add(value) consistently with the documented collection surface. The operation typechecks as None, lowers to HashSet::insert, and preserves set deduplication (#963).
  • Compiler: Public computed properties on models and classes now travel through checked API metadata and .incnlib contracts, so consumers of a compiled library can typecheck property access using the published result type (#952).
  • SDK providers: Source SDK preparation now validates the catalog's declared compiler range before compiling any component. A stale compiler therefore reports the incompatible source-SDK requirement directly instead of emitting unrelated provider type errors later in preparation (#945).
  • SDK providers: Stdlib lowering now reuses one parsed module cache across direct imports, façade re-exports, recursively loaded submodules, and source-default lookup instead of reparsing the same stdlib tree for each call. On the measured cold-provider fixture, preparation fell from 416–422 seconds to 204 seconds without changing provider identities, generated code, or test coverage (#957).
  • Compiler: Type-only generic Rust declarations now retain their owner type parameters in inspection and compiled-library metadata, so associated constructors such as Fft.new[f32](...) validate their complete signature and emit a receiver turbofish while an expected Fft[f32] result can infer the same specialization without brackets. Const-generic receivers fail with a checked diagnostic instead of emitting a misplaced Rust argument. Generated applications, compiled-package consumers, and test batches share the checked receiver decision (#961).
  • Compiler: Derived source traits now retain their canonical declaring module when imported directly into another source module, so method calls across compiled-library boundaries emit provider-qualified Rust paths instead of depending on an unrelated local module alias. Multi-module JSON libraries can therefore define @derive(json) models separately from Serialize-using helpers and publish both through a package facade (#946).
  • Compiler: Canonical Iterator[T] values now retain their item type when used directly as for and comprehension sources. Source-owned adapters such as zip, take, and enumerate are polled through Iterator.__next__() without invalid Rust struct-literal loops or collection-only .iter() injection, including composed tuple-producing adapters. The builtin zip(left, right) now has the same lazy Iterator[tuple[T, U]] contract as left.iter().zip(right.iter()) instead of being typed as an eager list (#950, #953).
  • Compiler: set(values) and Set(values) now preserve the frontend's canonical collection-constructor decision through lowering and emit a typed Rust HashSet collection instead of an unresolved function call. A user-defined function named set continues to shadow the collection constructor normally (#951).
  • Lockfiles: Compiled providers now publish a digest of their authored manifest and selected Incan source inputs for canonical semantic identity, while generated Rust and host ABI metadata remain under the byte-exact physical artifact digest. Equivalent native provider builds therefore share one SDK inventory and dependency fingerprint across macOS and Linux without weakening strict locks or user-authored path dependency identity (#931).
  • Compiler: Published Rust ABI metadata now excludes traits introduced only by unrelated downstream crates in the loaded inspection graph, keeping SDK provider identities and workspace dependency fingerprints stable across cache state and host platforms (#924).
  • Compiler: Legacy read_file and write_file builtins now convert Rust filesystem errors into their declared owned Incan str error type, so string operations on Result errors compile through generated Rust (#874).
  • Web: Route handlers now retain concrete Query[T], Json[T], and typed Path[T] extractors in generated Rust, while source-level scalar path captures are grouped into the Axum 0.8 path extractor expected by the route. Routes preserve {capture} syntax, support multiple captures and methods, and let Axum return client errors for malformed typed request data (#867).
  • Tooling: Canonical lock publication now keeps its persistent cross-process guard under ignored compiler target state instead of leaving .incan.lock.incan.lock in the project root (#912).
  • SDK providers: Official stdlib component packages now preserve their source-owned Apache-2.0 license in generated Cargo metadata, so downstream dependency audits no longer classify synthesized provider crates as unlicensed (#920).
  • Stdlib: Cold SDK preparation now copies borrowed regex matches and capture names into owned std.regex values instead of calling an unavailable &str.to_string() method (#918).
  • SDK providers: Compiled library artifacts now rebind SDK path dependencies to the active content-addressed provider cache, including copied support crates, so semantically identical components cannot enter one Cargo graph through conflicting cache roots (#911).
  • Lockfiles: Canonical dependency fingerprints now use checked SDK provider identities instead of physical cache paths, rooted-workspace lock generation snapshots artifacts after preparation, and selected library builds re-root the aggregate Cargo resolution onto the member's exact dependency closure. Clean and relocated provider stores now converge on one lock, target-free strict member builds consume it directly, and an immediate relock stays byte-identical. Compatibility note: non-strict build and test commands still warn and leave a stale incan.lock untouched, but no longer use its embedded Cargo lock as authority; strict modes still reject it (#921).
  • Compiler: Published library Rust ABI metadata now performs complete Rust metadata extraction for the selected public ABI query paths instead of relying on the current rust-inspect prewarm cache, keeping cold and warm artifacts identical when earlier commands inspected only part of that selected surface (#922).
  • Compiler: Cold library and SDK-provider builds now preserve Rust functions returning String as Incan str expressions, so direct compound assignments use string-aware lowering without requiring an explicitly typed intermediate local (#896).
  • Toolchain: Prelude parsing, stdlib type metadata, testing markers, and compiled SDK-provider publication now resolve one canonical stdlib source tree. INCAN_STDLIB and INCAN_STDLIB_DIR are true overrides, preventing a compiler in a shared Cargo target from mixing its source checkout with an older executable-adjacent stdlib.
  • Workspaces: Rooted workspace library artifacts now retain the selected project's identity across Cargo package, Cargo library, and .incnlib metadata, while removing self-dependencies even with explicit output overrides so external consumers can compile the published package (#909).
  • Workspaces: Root library dependency preparation now targets exactly that project and leaves canonical lock publication to its parent command, preventing fresh rooted workspaces from recursively spawning incan build --lib until the machine is exhausted (#908).
  • Workspaces: Rooted-workspace entrypoints and tests now resolve through their deepest owning member, so selected member builds retain both direct and inherited Rust dependency versions (#907).
  • Workspaces: Canonical workspace locks now rebase nested package roots and feature edges into workspace-relative coordinates, keeping cross-member semantic state and fingerprints portable across checkout locations (#906).
  • Compiler: Batched test modules now keep transitive dependency imports out of each other's local scopes, so separate test files can legitimately import the same public package symbols while true duplicate bindings inside one module remain rejected (#898).
  • Compiler: Public types imported from compiled libraries now retain provider-qualified nominal identity across split imports, multiple local aliases, qualified module calls, nested generics, and generated test batches, without unifying same-named types from separate dependencies (#892).
  • Compiler: Generated Cargo packages now preserve the authored Incan project version and SPDX license for application and library builds, keeping library Cargo.toml versions aligned with their .incnlib manifests (#889).
  • Compiler: std::io::stdout() now retains its stable Stdout receiver type when sysroot metadata is unavailable, so fallible extension-trait calls such as crossterm's ExecutableCommand.execute(...) expose their native Result and support postfix ? (#888).
  • Compiler: Unbound names in source type annotations now receive an Incan diagnostic before code generation instead of reaching generated Rust as undeclared types; explicit generics, forward declarations, and transparent generic aliases remain valid (#902).
  • Compiler: JSON deserialization of validated newtypes now reconstructs through the canonical from_underlying hook or primitive constraints, including nested model and container fields, so invalid wire values return Err instead of creating invalid nominal values (#904).
  • Compiler: Class-field privacy now survives checked metadata and compiled package boundaries. Named construction through a compiled package uses an exact package-owned constructor bridge—including aliases, inherited fields, and provider-owned defaults—while later private member access receives an Incan diagnostic instead of a Rust privacy failure; older manifests without field visibility retain their compatible public behavior (#883).
  • Compiler: Public classes imported from ordinary source modules now construct through the exact declaring-provider bridge when they contain private fields. Direct imports, aliases, and multi-hop public facade re-exports preserve declared field order and defaults even when sibling modules export classes with the same name, while later private member access remains an Incan type error (#886).
  • Compiler: Consumer subclasses of classes imported from compiled libraries now lower the typechecker’s complete parent-first field layout into generated Rust, preserving inherited order, visibility, materializable defaults, exact Rust field types, and source-level reflection names across application builds and package test batches (#885).
  • Language: Fields on public models now follow the ordinary visibility rule: pub exposes a field, while an unmodified field is private to the declaring model. Privacy is preserved across access, construction, patterns, aliases, source facades, checked metadata, compiled libraries, generated Rust, and test batches; runtime reflection exposes public fields only, while serialization remains an explicitly adopted complete-data-shape behavior. Existing DTO-style pub model declarations must add pub to fields that remain part of their public surface (#884).
  • Compiler: Generated Rust libraries no longer expose public all-fields constructors for models with private inputs. Required private fields remain constructible only through Incan-authored factories, while default-backed private fields stay provider-owned behind a public-field bridge; all-public models and the distinct complete-constructor contract for classes remain unchanged (#964).
  • Compiler: Expected Result[T, E] contexts now select the exact repeated generic trait method by recursively comparing the complete result type, so typed std.io.BinaryRead[T] calls keep their requested integral or floating width through compiled providers, generated Rust, and package test batches while calls without enough context remain ambiguous (#955).
  • Compiler: Absolute sibling-module imports such as from crate.types import Decision now retain public model fields and enum variants across direct checks, generated builds, library builds, re-exports, and test batches (#882).
  • Stdlib: std.regex replacement and split operations now reconstruct strings with the regex engine's UTF-8 byte spans, preserving characters adjacent to non-ASCII matches while keeping public match offsets byte-based (#893).
  • Compiler: String literals returned from closures now materialize owned Incan str values, so Result.map_err and other closure consumers generate Rust String values instead of borrowed &str values (#880).
  • Compiler: Imported mutable Rust trait receivers now distinguish owned values from dereferenceable guards, so calls such as Read.by_ref(input) emit a valid direct borrow for Stdin while stdlib RefMut readers retain their required reborrow (#878).
  • Compiler: Rust interop method calls with inferred Into-bound generic parameters now keep string literals in an inferable shape instead of generating ambiguous .into() calls (#804).
  • Compiler: Rust boundary metadata now preserves pointer-sized integer identity, so usize and isize arguments are no longer reported as mismatches against themselves (#803).
  • Compiler: Expression-position vocab declarations now activate their declaration-owned clause keywords, keeping parser routing and downstream syntax ownership aligned (#813).
  • Compiler: Generic Index[K, V] adoptions now retain their key and output substitutions through lowering and generated Rust, including adopters whose trait arguments use Self (#815).
  • Compiler: Trait-typed receivers may call only methods available through the declared trait and its supertraits; methods belonging only to narrower subtraits now receive an Incan diagnostic (#817).
  • Compiler: Rust callback metadata now preserves borrowed slice parameters in FnMut bounds for imported functions and trait methods. Named callbacks can use borrowed list[T] parameters, while inline closures are contextually typed from the inspected Rust bound, allowing both forms to satisfy APIs that pass &[T] or &mut [T] values (#835).
  • Compiler: Incomplete explicit generic arguments on inspected Rust methods are rejected during Incan typechecking with the method's required arity, instead of failing later in generated Rust compilation (#834).
  • Compiler: Generic Rust function results can now be inferred from an annotated return or parameter context through Result.unwrap(), including generated package-test builds such as serde_json::from_str (#852).
  • Compiler: Rust interop now preserves callable bounds such as FnMut(&mut T, &U) when checking generic callback parameters, so by-value Incan callbacks are rejected at typecheck instead of reaching Rust codegen with an invalid borrowed callback shape (#805).
  • Compiler: Rust interop now preserves concrete &T and &mut T method parameters through complete metadata extraction and generated Rust; mutable Incan bindings are required for &mut T calls (#861).
  • Compiler: Generic value-reflection bounds are preserved for impl-method-owned type parameters, and direct dependency-module generation now typechecks before lowering so root Rust trait imports stay available in generated module tests (#819, #827).
  • Compiler: Rust interop now preserves inspected &dyn Trait and &mut dyn Trait parameter shapes through typechecking, lowering, and generated Rust, including a source-level diagnostic when an exclusive borrow requires an Incan mut binding (#832).
  • Compiler: Rust interop now preserves the diverging ! return type as an internal bottom type, so combining Rust and source-module imports no longer causes unrelated return-type mismatches in modules that call diverging Rust helpers (#381).