Skip to content

v0.28.0

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Jun 16:25
· 2 commits to main since this release
9329bbc

By a wide margin, the fastest Acton to date! Massive compilation speedups,
mostly from optimized data structures (HashMaps, IntSets etc) rather than
linear list searches, concurrent type checking and concurrent parsing etc -
which makes the compiler over 5000x for a particularly large test module
(~300MB .act file). A new back pass compilation technique, which we call
Deferred Back Passes (DBP), selects only the interesting parts of a module for
compilation, providing another massive speedup.

Compiler & Build

  • Add concurrent top-level type checking for total statements, allowing the
    compiler to check independent top-level definitions in parallel while keeping
    source-order semantics for non-total statements. [#2773, #2782]
    • Verbose and timing builds now report inferred signatures for non-total
      statements, making it easier to add explicit signatures and unlock more
      concurrent checking.
    • Type errors from independent total statements are collected into multiple
      diagnostics instead of stopping at the first failing statement.
    • Use a fixed worker pool with bounded lookahead, improving memory behavior
      and performance for modules with many independent top-level definitions.
  • Parse modules in parallel by splitting top-level statement chunks across
    parser workers, reducing parser latency for large source files while
    preserving source-order results. [#2787]
    • --parse-serial keeps the whole-file parser available for debugging and
      fallback comparisons.
    • Module-suite validation now uses a set-based duplicate check, avoiding
      quadratic validation time in large projects.
  • Report parser progress percentages during builds, giving useful feedback for
    very large files before type checking starts. [#2784]
  • Report hashing as its own front-pass progress phase in CLI and LSP builds, so
    large modules show source, implementation, interface, and dependency hashing
    work instead of appearing stuck after type checking. [#2905]
    • Type-checking and hashing progress updates are paced to keep detailed
      progress reporting from slowing large-module builds through excessive UI
      churn.
  • Report active back-pass progress for normalize, deactorize, CPS, lambda
    lifting, boxing, code generation, render, and write steps, so CLI and LSP
    builds show which generated-code phase is currently running. [#2808, #2853]
  • Generate unboxed code for bounded integer and float values through the boxing
    and code-generation passes, a major reduction in wrapper allocation and
    box/unbox traffic for numeric Acton programs. Fewer boxes also means less
    memory traffic and less garbage for the runtime to collect, so numeric-heavy
    code can improve both by doing faster primitive work and by putting less
    pressure on the memory subsystem and garbage collector. [#2824, #2890]
    • Builtin, base, and standard-library C implementations now use raw C values
      for unboxed integer and float operations where the Acton type is known.
    • Cached module interfaces from older boxed-primitive compiler versions are
      treated as stale and rebuilt instead of being reused across the
      representation change.
    • As one example, the existing examples/sumto.act benchmark at 30 million
      integer additions dropped from about 960 MB of GC heap allocation to about
      54 KB, with reported GC time falling from about 2.05 seconds to 0 ms and
      wall time from about 1.47 seconds to about 0.12 seconds.
    • In a standalone run of the DCT performance fixture at size 2,000, GC heap
      allocation dropped from about 768 MB to about 384 MB, reported GC time from
      about 1.58 seconds to about 0.79 seconds, and wall time from about 1.14
      seconds to about 0.65 seconds.
  • Preserve each module's import context in cached module interfaces, so builds,
    acton sig, documentation, and completion can reuse cached interfaces without
    losing imported class and protocol information. [#2779]
  • Store cached module interfaces in LMDB-backed .tydb directories instead of
    monolithic .ty files, keeping corrupt or version-mismatched entries as safe
    cache misses while adding keyed records for headers, imports, names, hashes,
    dependency hashes, and typed statements. [#2819, #2855, #2858, #2889, #2896,
    #2907]
    • Full reads reconstruct source-order environments from explicit order keys,
      and cache copy and cleanup paths now handle directory artifacts.
    • Cache values are encoded with persist, improving .tydb write and read
      time for large generated interfaces while treating older binary-encoded
      caches as stale rebuilds.
    • Dependency hashes are indexed by provider module and name, so stale-cache
      checks can skip unchanged modules cheaply and only inspect the dependency
      names a cached module actually used when an upstream module changed.
    • Preparing .tydb entries for names, hashes, extensions, and typed
      statements now happens in strict concurrent chunks before the LMDB write
      transaction, and CLI progress distinguishes preparation from writing.
    • Read transactions retry transient LMDB lock-table setup errors with a fresh
      environment and a longer backoff window, matching the existing retry path
      for environment opens.
    • Build and statically link LMDB from a pinned bundled dependency so compiler
      builds do not depend on the host LMDB installation.
  • Run front-output writes asynchronously after front passes, so cached
    interface writes, .tydb copies, and documentation rendering can overlap with
    downstream work while watch and LSP builds discard stale-generation writes.
    [#2851]
  • Add deferred back passes for very large modules, letting the compiler run the
    normal front passes first and then generate code only for declarations that
    are reachable from the program, similar to tree shaking, dead-code
    elimination, or link-time optimization for generated Acton modules. [#2843,
    #2884]
    • Automatic selection starts at modules with at least 1,000 top-level names;
      --dbp MOD[:NAME,...] can force focused experiments, and --no-dbp
      disables both heuristic and forced selection.
    • Deferred back passes prune typed modules to interested names, root actors,
      local dependency closures, and class/protocol extension dependencies before
      running the existing back-pass chain.
    • Modules at explicit Build.act library boundaries compile normally so
      declared library outputs keep their full generated surface.
  • Skip build-time HTML documentation pages for modules with more than 10,000
    top-level names while keeping compilation and cached interfaces intact. The
    generated project documentation index still lists those modules without
    linking to missing pages, and explicit acton doc FILE.act requests still
    render the requested source file. [#2884]
  • Fix concurrent .tydb reads so shared interface caches retry transient LMDB
    lock-file setup races and propagate environmental errors with their real
    cause instead of reporting a missing interface. [#2841]
  • Speed up compiler environment lookups, scans, module-environment rewrites,
    attribute queries, solver candidate enumeration, substitutions, and witness
    resolution in large modules by indexing active names, signature and
    definition locations, state-variable and type-variable names, solver
    candidate sets, term substitutions, and type witnesses; separating closed
    imports and finalized top-level names from live local bindings; avoiding
    temporary inherited-attribute lists for single-attribute queries; reading
    substitution state once per traversal; narrowing used-substitution tracking to
    active entries; and deduplicating reserved names with a hash index while
    preserving source-order semantics. [#2789, #2796, #2797, #2799, #2800, #2816,
    #2833, #2837, #2839, #2840, #2924]
  • Speed up documentation rendering and generated-name hashing by indexing
    documentation type lookups and hashing internal/generated names without
    rendering prefix strings. [#2830, #2831]
  • Report more detailed front-pass timing for type reconstruction, result
    forcing, hash computation, cached interface writes, and documentation output,
    and speed up signature validation by checking bindings through a set. [#2848]
    • Build progress output now keeps long five-digit second durations aligned
      with shorter timings, using the same width for active progress lines and
      completed timing logs. [#2901, #2908]
    • Multi-line type-check result blocks, including timing details and inferred
      signatures, are emitted atomically so concurrent module builds cannot
      interleave another module's progress between detail lines. [#2925]
    • Build progress labels avoid repeating the project prefix when module names
      are already project-qualified, keeping dependency build output shorter and
      easier to scan. [#2929]
  • Speed up back-end work on large modules by indexing code-generation name
    membership and boxed variable lookups, and by tracking boxing-pass witness
    names with a hash set, reducing repeated scans during boxing and generated
    C/H rendering. [#2806, #2810, #2895]
  • Hash implementation fragments and normalized source/implementation AST
    fragments through direct byte and structural streams, making cached change
    detection cheaper while preserving per-name build hashes and ignoring
    location-only source changes. [#2811, #2897, #2900]
  • Hash per-name source/implementation and interface fragments in parallel, and
    deduplicate dependency lists before unaliasing or writing .tydb
    dependency-user rows, speeding the hash phase and large generated interface
    writes while preserving stable cache contents. [#2921]
  • Fix quantified type-variable scope cleanup so leaving an inner quantifier only
    drops witnesses associated with the removed variables, preserving unrelated
    witnesses for later type checking. [#2802]
  • Fix actor state-variable inference so unannotated var fields keep their
    inferred type when actor assumptions are matched instead of being widened to
    value after ordinary assignments. [#2894]
  • Fix generated C declarations so parameters, return values, and local
    declarations all keep volatile when the compiler environment marks the
    variable as volatile. [#2898]
  • Fix generated protocol witness method tables so inherited abstract slots are
    filled through forwarding wrappers only from concrete ancestor witness
    classes, avoiding both empty slots across multiple protocol inheritance paths
    and unrelated classes that merely share a method name and ABI. [#2887,
    #2927]
  • Bump the GHC toolchain to 9.8.4 (Stackage lts-23.28), fixing a rare arm64
    segfault in the compiler. GHC 9.6.6's runtime could crash in the garbage
    collector by following a NULL closure pointer (GHC #24791, black holes in
    large objects); the static LMDB interface cache shifted the binary layout
    enough to expose it, producing intermittent SIGSEGVs on arm64 (Linux and
    macOS) during pkg operations and when compiling some programs. 9.6.7
    reduced the crash rate and 9.8.4 eliminates it (0 crashes across thousands of
    builds that reproduced it on 9.6.x). [#2832, #2834]

CLI & Project Workflow

  • Resolve project modules under their Build.act project name, so dependency
    modules are imported through the name declared in the dependencies table.
    For example, a dependency listed as "analytics": (...) is imported with
    import analytics.events, while local project modules still support
    unprefixed imports. [#2914]
    • Importing a dependency name resolves to that dependency's lib.act, so
      import analytics works for the dependency root module and
      import analytics.events works for other dependency modules.
    • acton sig, root actor selection, --modules, deferred-back-pass module
      selectors, library outputs, generated file paths, and incremental rebuild
      traces understand project-qualified module names.
    • Projects now reject source trees whose first module path segment overlaps a
      declared dependency name, avoiding ambiguous imports between local source
      modules and dependency projects.
  • Add acton repl, a live interactive Acton shell for trying code, inspecting
    values, and getting immediate feedback as you explore. [#2842]
    • It uses the normal compiler pipeline inside a scratch REPL directory, so
      inputs are parsed, type checked, code generated, and run like ordinary
      Acton code; session and evaluation modules are compiled as dynamic
      libraries so most evaluations avoid the long runner relink step.
    • Because each interaction produces and reruns a normal executable, the REPL
      does not keep a live interpreted runtime. Retained imports, declarations,
      and setup assignments are replayed for each evaluation, unlike REPLs that
      keep an interpreted process alive between inputs.
    • The REPL retains imports, declarations, and setup assignments as session
      source, prints non-None expression results, supports multi-line blocks,
      and provides :show, :reset, :dep, and :quit commands.
  • It is now possible to customize project library output in Build.act by
    declaring selected modules as named static or dynamic libraries that
    executables can link against. [#2809]
    • Dynamic libraries are installed in the normal output layout with executable
      rpaths, so a project can rebuild a library module and keep running an
      existing executable against the updated shared library.
    • Incremental builds keep every module in a declared library together, so
      library artifacts stay complete even when only one member module changed.
  • Use the canonical acton binary in Makefile build, test, distribution, and
    release recipes while keeping actonc as a compatibility symlink and install
    alias. [#2882]
  • Let Build.act Zig dependency options refer to the compiler toolchain's
    bundled dependency directory with the {sysdeps} sentinel, written as
    "{{sysdeps}}" in Acton strings, so project wrappers can use bundled headers
    and libraries without hardcoding the installed dist path. [#2915, #2917]
    • Commands that rewrite Build.act, such as acton pkg add, now re-escape
      literal braces in strings so sentinel values and other brace-containing
      names, descriptions, dependency keys, and option values round-trip safely.
    • Unescaped interpolation in Zig dependency option values now reports a clear
      project error naming the dependency and option instead of silently dropping
      the option from the generated Zig build.

Runtime & Standard Library

  • Add an RTS sync-pause primitive for worker threads, allowing a worker to
    cooperatively park the rest of the worker pool around synchronized runtime
    operations such as dynamic library code reload. [#2815]
  • Expose standard library modules through a bundled std project and namespace,
    so applications can import modules such as std.json, std.argparse, and
    std.xml without declaring an external dependency. [#2817]
    • Project builds add an implicit std dependency unless one is declared, and
      compiler lookups include bundled std interfaces alongside base.
    • The distribution builds and ships dist/std separately from dist/base,
      keeping base focused on builtins and runtime support.
  • Fix XML decoding so comments between text/CDATA nodes and child elements are
    ignored while preserving the surrounding text and tail content. [#2886]
  • Fix macOS crash handling so the RTS can print a backtrace without relying on
    Linux /proc/self/exe, then restore the platform crash handler before
    re-raising the original signal. [#2909]
  • Move TLS and DNS native I/O allocations to explicit ownership, keeping
    mbedtls and tlsuv state off the GC heap while preserving GC roots for libuv
    handles. TLS listeners and connections now close native streams through
    explicit close paths with actor cleanup as a safety net, queued TLS writes
    keep their payloads alive until completion, and immediate TLS connect setup
    errors are reported to callbacks instead of being ignored. [#2911]
    • TLSListener now exposes close(), accepted TLS connections can outlive
      the listener actor, and accepted connections stay pinned to the worker
      thread that owns their libuv stream.
  • Fix list.index on empty lists so it raises KeyError for a missing element
    instead of rejecting the default stop position. [#2801]

Packages & Distribution

  • Change x86_64 Linux builds from statically linked GNU libc to dynamically
    linked GNU libc while keeping other libraries statically linked. [#2774,
    #2781]
    • The x86_64 Linux release job and Debian package builds run on Debian 11 to
      provide a glibc 2.31 floor.
    • Nightly CI still covers Debian 11, 12, and 13 on x86_64.
    • CI now validates the dynamic library set and maximum required GLIBC version
      for acton, lsp-server-acton, and actondb.
  • Build the compiler's host-linked C libraries with bundled Zig projects
    instead of host static archives, so release builds can link zlib, gmp, and
    tinfo, and LMDB against the selected platform target. [#2819, #2822,
    #2827]
    • Linux compiler links prefer the bundled static archives and Zig's libc++ /
      libunwind over host libraries, preserving the chosen glibc target.
    • macOS compiler links can use the same bundled static archive path for zlib,
      with Mach-O archive alignment and a stable macOS deployment target.
  • Vendor the diagnose compiler diagnostic library from upstream after
    diagnose removed its stale text <=2.0 dependency, so compiler builds can
    use the resolver's text package instead of pinning text-2.0 just for
    diagnostics. [#2783]
  • Keep Acton-owned Zig build files for bundled dependencies in this repository
    and overlay them during dependency extraction, making Zig build glue easier to
    update while allowing dependencies without source changes to use upstream
    source archives. [#2805]
  • Port Acton and bundled dependency build files to Zig 0.16, including remote
    dependency fetching and cache archive extraction for acton pkg add,
    acton fetch, and project builds with remote dependencies. [#2807]
  • Fix release tarball naming to use the stamped VERSION_INFO directly, so
    make release keeps the tarball version aligned with the compiler version
    and tagged releases keep plain version numbers. [#2928]
  • Fix Windows Acton program execution by building the vendored libuv Windows C
    sources without Zig/Clang's null sanitizer, avoiding a sanitizer trap in
    libuv's async wakeup path. [#2902]

Documentation

  • Document when and how to use the Acton container image, including
    copy-pastable Docker commands for checking the compiler version and building
    the current project. [#2767]
  • Document dependency import prefixes across the user and developer guides,
    including Build.act dependency-name examples, dependency src/lib.act
    imports through the dependency name, and other dependency modules under the
    same prefix. [#2932]

Testing & CI

  • Add make targets for accepting compiler golden outputs, including separate
    targets for Sydtest goldens, Acton Tasty goldens, and the combined compiler
    golden workflow documented in the developer guide. [#2821]
  • Assert incremental rebuild behavior directly in compiler tests, checking
    stale and fresh modules, type checking, code generation, public-hash
    propagation, doc-only edits, and codegen-only stale outputs instead of
    comparing fragile concurrent progress-output goldens. [#2923, #2926]
  • Add dedicated compiler benchmark drivers for performance work. [#2794, #2813]
    • The type-checking benchmark reports parse, environment, kind-checking, and
      type-checking timings, with optional RTS allocation and GC statistics.
    • The compiler pipeline benchmark can stop after parsing, kind checking, type
      checking, front passes, documentation-aware front passes, or the full
      front/back pipeline.
  • Refresh Acton compile-cache snapshots from nightly and manual workflow runs,
    while pull request and push builds restore those snapshots without saving new
    cache entries. [#2823, #2826]
    • Haskell dependency caches are keyed separately from the Acton/Zig compile
      cache, and cache saves require successful build and release steps so failed
      builds cannot publish partial snapshots.
    • The Acton/Zig compile cache uses one stable per-platform key refreshed by
      producer runs, with stale entries evicted before saving so CI does not keep
      a week of duplicate snapshots.
    • The nightly producer workflow now runs at 02:00 UTC. [#2931]
  • Run cross-compilation checks in a dedicated CI job after Debian packages are
    built, covering macOS, Windows, GNU/Linux, and musl targets without bloating
    the default test job's compile cache. [#2850, #2852, #2902]
    • Windows cross-compilation uses --no-threads, matching the supported
      Windows target mode, and nightly/manual runs refresh a separate
      cross-compilation cache.
    • Cross-compiled Windows hello.exe artifacts are preserved and run on
      matching x86_64 and arm64 Windows runners.
    • Linux container jobs free host disk before restoring compile caches, and
      release, container, apt, and Homebrew publishing jobs now wait for the
      cross-compilation job.
    • The cross-compile job installs the freshly built Debian package with
      dpkg -i, avoiding unrelated hosted-runner apt repository failures while
      still testing the produced artifact. [#2904]
  • Keep CI cache restores clean after Stack/GHC changes by removing broad Stack
    restore-key fallbacks, and make the standard-library time test tolerate slow
    CI startup while still catching gross clock errors. [#2836, #2838]
  • Cache downloaded source archives in source-build and Debian package-build CI
    jobs with keys based on dependency build inputs, so transient archive download
    failures are less likely to break unchanged release builds. [#2856]
  • Retry network-bound package-manager installs and flaky distributed-database
    test binaries in CI, and print Linux container disk usage around cache restore
    and test execution to make out-of-space failures easier to diagnose. [#2846]
  • Run REPL command tests against the normal persistent scratch path and add
    in-process renderer checks, while keeping explicit --tempdir coverage for
    scratch-directory isolation behavior. [#2881]
  • Avoid running the compiler standard-library test groups twice in make test
    by leaving those checks to test-stdlib. [#2870]
  • Switch external application CI coverage from the old Orchestron repository to
    StratoWeave while keeping the reusable app-test workflow. [#2888]
  • Add a generated class-heavy type-checking fixture to exercise concurrent
    type-checking scheduler performance on large recursive class structures. [#2777]

Compatibility Notes

  • Projects that import dependency modules by bare source module names may need
    to qualify those imports with the dependency name from Build.act;
    dependency lib.act modules can be imported as that dependency name itself.
    [#2914]
  • C extension bindings that implement functions taking or returning Acton
    numeric primitive types may need to follow the new unboxed C signatures for
    bounded integers and floats instead of passing boxed wrapper pointers. [#2824]