Skip to content

Release 0.2

Incan 0.2 introduces namespaced stdlib imports and namespaced decorators under the std.* module tree (RFC 022). This is a breaking change to import syntax — all stdlib imports and decorators must now use their fully qualified paths.

This release lays the groundwork for a cleaner stdlib architecture where the compiler knows less about domain-specific modules (web, testing, async) and the stdlib can grow without polluting the global namespace.

Migrating from 0.1

Use this checklist when moving a 0.1 codebase to 0.2.

Import paths

All stdlib imports move from bare module names to the std.* namespace:

# Before (0.1)
from web import App, Response, Json
from testing import assert_eq, assert_ne

# After (0.2)
from std.web import App, Response, Json
from std.testing import assert_eq, assert_ne

This also applies to async modules:

# Before (0.1)
from async.time import sleep

# After (0.2)
from std.async.time import sleep

Decorators

Decorators are now resolved by their fully qualified module path. Use an explicit import or a canonical path:

# Import and use short name (preferred)
from std.web.routing import route

@route("/hello")
async def hello() -> str:
    return "Hello!"
# Canonical path (also works)
@std.web.routing.route("/hello")
async def hello() -> str:
    return "Hello!"

Testing decorators follow the same rule:

# Canonical path
@std.testing.skip("not implemented")
def test_future() -> None:
    pass

Or with an alias:

import std.web.routing as routing

@routing.route("/hello")
async def hello() -> str:
    return "Hello!"

and:

import std.testing as testing

@testing.skip("not implemented")
def test_future() -> None:
    pass

Soft keyword activation

async/await keywords are activated per file through stdlib imports.

If a file uses async syntax, import std.async (or a submodule like std.async.time) in that same file.

Stdlib types require explicit imports

Types like App, Response, Html, Json, and Query are no longer globally available — import them from std.web. The compiler will suggest the correct import if you use a stdlib type without importing it.

Testing markers are runner metadata

@skip, @xfail, @slow, @fixture, and @parametrize are consumed by incan test from std.testing metadata. They are not intended as runtime function calls.

Reserved names

std and rust are now reserved at the module level and cannot be used as declaration names.

Features and Enhancements

  • Compiler: Namespaced stdlib imports under std.* — all stdlib modules use qualified paths (RFC 022).
  • Parser/formatter: Parenthesized multi-line import lists are supported for both from module import (...) and from rust::crate import (...), with optional per-item aliases and formatter-aware wrapping (#116).
  • Compiler: Import-activated soft keywords — async and await are identifiers by default and become reserved only when import std.async (or from std.async...) is present. Forgetting the import produces a targeted diagnostic with a fix suggestion. Similarly, std.testing activates the assert statement syntax (RFC 023).
  • Compiler: Surface Semantics Engine — soft keywords (assert, async, await) and decorator semantics are routed through a registry-driven dispatch system (SurfaceSemanticsPack). The parser emits generic Surface AST nodes keyed by SurfaceFeatureKey; downstream stages dispatch on that key rather than per-keyword AST variants. Adding a new soft keyword requires no parser, AST, or IR changes — only a keyword descriptor and a semantics-pack handler (RFC 023).
  • Compiler: incan-vocab establishes a standalone, registry-driven keyword/manifest/desugaring contract for future library vocabulary extensions, and core tooling consumers now read keyword surface data through that shared registry path (RFC 027).
  • Compiler: Namespaced decorator resolution — decorators resolved by module path (e.g., from std.web.routing import route enables @route(...)) with alias support (RFC 022).
  • Compiler: @rust.extern marker for Rust-backed function stubs, replacing the internal @std.builtin decorator (RFC 022, RFC 023).
  • Compiler: @staticmethod decorator for type-scoped methods with no self receiver, available on class, model, and newtype declarations. Required for @rust.extern methods on types (instance delegation is not supported).
  • Testing: std.testing is Incan-first — user-facing API and assertion behavior are defined in crates/incan_stdlib/stdlib/testing.incn, with Rust limited to explicit @rust.extern host boundaries (for example fail and fail_t) (RFC 023).
  • Compiler: Stdlib namespace registry (STDLIB_NAMESPACES) replaces the flat stdlib-module list — convention-based submodule discovery, registry-driven unknown-module diagnostics, and soft-keyword activation metadata.
  • Compiler: Reserved root namespaces — std and rust cannot be used as user declaration names.
  • Compiler: Stdlib types require explicit imports with actionable error messages when used without import.
  • Compiler: from rust import <crate> syntax for importing Rust crates — the compiler validates imports against [dependencies] in incan.toml and emits the correct use statements in generated Rust (RFC 013).
  • Compiler: Rust crate dependency management with inline version annotations, manifest-based configuration, version validation (semver), and lock files for reproducible builds (RFC 013).
  • Compiler: Convention-based source root resolution — the compiler and test runner resolve user module imports against src/ (or an explicit [build] source-root) so imports are uniform across source and test files (RFC 015).
  • Web: Compiler-to-stdlib routing handoff via incan_stdlib macros (RFC 022).
  • Web: Web-free compiler — all web-specific knowledge (route registration, extractor types, response builders) lives in std.web stdlib modules and the incan_web_macros proc-macro crate. The compiler uses generic decorator passthrough (@rust.extern + rust.module()) and derive passthrough (@derive(X) from rust.module() traits) with no domain-specific web logic in the compiler core (RFC 023).
  • Web: Import-driven web feature activation — importing std.web automatically enables axum, incan_web_macros, and inventory dependencies in the generated project (RFC 023).
  • Runtime: incan_stdlib::r#async now provides the narrow Rust runtime leaves behind the source-declared std.async modules, rather than exposing the async surface as a raw Tokio re-export facade.
  • Tooling: incan init scaffolds a full project: src/main.incn, tests/test_main.incn, and incan.toml with [project.scripts] main set (RFC 015).
  • Tooling: incan lock generates incan.lock for reproducible builds; --locked and --frozen flags enforce lock freshness in CI (RFC 013).
  • Tooling: Test runner resolves imports against the project source root, enabling tests to import directly from source modules (e.g., from greet import greet) without duplication (RFC 015).
  • Tooling: Test marker semantics (@skip, @xfail, @slow, @fixture, @parametrize) are derived from std.testing metadata in crates/incan_stdlib/stdlib/testing.incn instead of brittle string/path hardcoding (RFC 023).
  • Parser: async is allowed as a module path segment in imports (e.g., from std.async.time import sleep).
  • Diagnostics: Clearer error messages for unknown decorators and reserved namespace violations.
  • Diagnostics: Enhanced lock-out-of-date error with expected vs actual fingerprint for easier debugging.
  • Compiler: rust::core and rust::alloc are now rejected at the typechecker level with a targeted diagnostic pointing users to rust::std::... instead (reserved for future no_std/target work) (RFC 005).
  • Diagnostics: Rust interop dependency errors now include the import site path and a hint to verify the crate/module/item path or add version/features in incan.toml (RFC 005, RFC 013).
  • Docs: "Your first Incan project" tutorial covering incan init, modules, and testing.
  • Docs: Contributor docs now describe the registry-driven keyword path, including incan-vocab, parser Ident keyword handling, and generated VS Code grammar synchronization (RFC 027).
  • Codegen: String literals passed to external Rust type methods now emit .into() instead of .to_string(), letting the Rust compiler resolve custom string types (e.g. Polars' PlSmallStr) via the Into trait.
  • Compiler: MSRV bumped from 1.85 to 1.88 (required by time crate v0.3.47).

Bugfixes

  • Diagnostics: Unknown symbol errors in f-string interpolations now point to the precise {expr} span (including nested interpolation expressions) instead of the full f-string (RFC 011, #71).
  • Compiler: Fixed project root resolving to empty string when running incan run src/main.incn from the project directory, causing "No such file or directory" errors.
  • Docs: Web tutorial examples updated to std.web imports and namespaced decorators.
  • Docs: Derives and traits explanation updated to use @rust.extern.

Known limitations (0.2)

  • Web route handlers and their request models must be declared pub for cross-module wrapper generation (#117).
  • Rust macro syntax (e.g., serde_json::json!(...)) is not supported in Incan source — use Rust crate functions and types directly instead.

RFCs implemented

  • Namespaced stdlib modules and compiler-to-stdlib handoff: RFC 022
  • Compilable stdlib and Rust module binding (web-free compiler): RFC 023
  • Rust crate dependency management: RFC 013
  • Hatch-like tooling (partial — incan init, project discovery, source root resolution): RFC 015
  • Rust interop surface (rust:: imports, type mapping, string borrow adaptation, curated derives): RFC 005
  • Precise f-string interpolation diagnostics: RFC 011