5.0.0 — Technical Summary

Mica is a systems programming language with clean, structured syntax and explicit low-level control, compiled from scratch — in pure Go, with no external dependencies — to native Linux x86-64 and ARM64 ELF binaries with full DWARF v5 debug information, using the GNU assembler and linker as the only external tools. It is the work of a single engineer with AI assistance, built quietly over around three years.

5.0.0 is the largest release in the project’s history and the first prepared for a public audience. It adds the two capabilities a systems language is ultimately measured by — a heap and a real optimizing backend — and it does the first of those in a way that is, as far as we know, distinctive: heap memory safety is proven at compile time by flow analysis, with no garbage collector, no borrow checker, and no lifetime annotations.

Structured clarity. C control. Born for AI.


At a glance

ImplementationPure Go, zero external dependencies
Compiler source107,642 gross lines of Go across 594 files; ≈ 35 packages
Whole project≈ 268,000 gross lines (Go + Mica + C runtime + contracts)
History2,799 commits since 2023
TargetsLinux x86-64 (System V AMD64) and ARM64 (AAPCS64)
OutputELF executables, static archives (.a), shared objects (.so)
Debug infoDWARF v5, with a registered DW_LANG_Mica language code
External toolchainGNU as + ld only
Heap safetyProven at compile time by flow analysis
AllocatorsThree plug-ins behind one seam: hosted, region, fixed-arena
Standard libraryA single 1,149-line C23 runtime
VerificationOver 4,500 test cases across more than 740 test programs (over 150,000 lines)

1 · The language

Mica reads like structured intent. Its design rests on a precise, expressive type system rather than on runtime machinery.

  • Structured coreprogram/library, const/type/var, nested functions and procedures (to 16 levels), and a small, complete statement set: if, while, for (to/downto), repeat … until, case, leave. and/or short-circuit.
  • Fixed-width numeric typesint8/16/32/64, uint8/16/32/64, float32/64, bool, unicode (a 32-bit code point), and string (a length-prefixed descriptor, UTF-32 by default).
  • The ordinal type system — enumerations, subranges, and the integer/char/bool types are all ordinals with computable domain bounds the compiler uses everywhere: array index domains (with lower bounds that mean something — array[1900..2100], array[Jan..Dec]), set cardinalities, for-loop ranges, and case label validation. Domain meaning lives in the type, not in the programmer’s head.
  • Explicit memory — pointers are spelled in words (pointer T, address x, value p), with a typed, zero-cost auto-dereference for pointer-to-record field access.
  • First-class nil and recursive typesnil is an assignable, comparable pointer value, and a record may contain a pointer to its own type, enabling linked lists, trees, and graphs.
  • Checked arithmetic on demand — under the checked profile the compiler weaves overflow detection into every signed arithmetic site; under debug/release the hardware wrap semantics apply.
  • Compile-time generics — monomorphized: a gen block parameterizes a procedure or function over a type constrained by capabilities (ordered, numeric, equality, …); type arguments are inferred at the call, and one specialization is generated per concrete type set. No boxing, no runtime cost.
  • Strings — a length-prefixed descriptor, UTF-32 or UTF-8 per target from one source; chained concatenation is fused into a single allocation with no intermediate temporaries, and format strings are validated at compile time.

2 · Memory safety by flow

This is the heart of 5.0.0. Every heap allocation creates an obligation that the compiler must see discharged on every control-flow path. There are exactly three ways to discharge one: a dominating dispose, registration with an owner (defer dispose p, or new T until F / until program), or transfer by returning the pointer. Each allocation site is then classified into one of four lifetime classesowner-bound, transferred, manual-verified, or manual-unverified — and the compiler can narrate that decision, in source order, naming the owner and the allocator it scheduled.

The proof is a dataflow analysis: a forward may-analysis over the intermediate code and control-flow graph, run in every compilation mode. It is the same kind of reasoning a backend uses to schedule registers, turned onto lifetimes. The result is a guarantee that reads simply: a leak of a fully-tracked allocation does not compile. Where a pointer’s flow exceeds what the analysis can follow precisely, the site is reported as manual-unverified and narrated — never silently miscompiled, and never a rejected correct program.

What makes this concrete is that the contract reasons about every path, not about whether a dispose appears somewhere in the text.

The simplest case — allocate and never release

A dispose that runs on only one branch still leaves a path that leaks. The compiler finds it and names the way out:

 1  program LeakOnePath;
 2  imp
 3      WriteLn : std;
 4
 5  procedure Handle(flag : int64);
 6  var
 7      p : pointer int64;
 8
 9  begin
10      p := new int64;
11      value p := 42;
12
13      if flag = 1 then
14          dispose p;
15
16      WriteLn("handled");
17  end;
18
19  begin
20      Handle(1);
21  end.
    10: p := new int64;
             ^ obligation error 13102 [10,10]: heap cell is not released on every path:
               last use at line 14, the path leaving at line 17 releases nothing —
               dispose it, defer the dispose, return it, or bind it to an owner with 'until'

Across loop iterations

The analysis reasons about loops too. Each turn here overwrites p, abandoning the cell the previous turn allocated:

 1  program LeakInLoop;
 2  imp
 3      WriteLn : std;
 4
 5  procedure Fill(n : int64);
 6  var
 7      i : int64;
 8      p : pointer int64;
 9
10  begin
11      for i := 1 to n do
12      begin
13          p := new int64;
14          value p := i;
15      end;
16  end;
17
18  begin
19      Fill(3);
20  end.
    13: p := new int64;
             ^ obligation error 13103 [13,14]: heap cell is allocated again while the
               previous cell is still owed — dispose the previous cell before the
               allocation repeats, or bind it to an owner with 'until'

Every message names the way out — dispose it, defer the dispose, return it, or bind it to an owner with until — and a program that takes any of them compiles. Moving the dispose in Handle so it runs on both paths builds and runs cleanly. The contract is against silent leaks, never against correct code: it tells you exactly where the obligation escapes, and how to close it.


3 · The heap runtime

Proving a lifetime is half the work; serving it is the other half. Mica’s intermediate code never names malloc — it emits allocator intrinsics, and the compiler chooses which allocator serves each site from the lifetime class it proved. Allocator selection is instruction selection.

AllocatorBehaviourChosen for
Hosted (default)calloc/free over the C allocator; transparent to valgrind and AddressSanitizermanual, transferred, and unverified sites
Regionper-owner arena — bump-allocate, reclaim the whole region in bulk at the owner’s exitowner-bound sites (until F / until program)
Fixed-arenaone statically-budgeted byte array with no operating-system heap behind it — for freestanding deploymentevery site, when linked as that deployment class

defer, owners, and regions all ride one small runtime data structure — a per-owner cleanup list drained last-in-first-out at the owner’s exit. The deployment class (hosted or fixed-arena) is a per-program link decision, never a source change, because code generation is byte-identical across classes. The allocator is a genuine plug-in: a third-party archive that honours the heap symbol contract links and runs with no change to the compiler.


4 · The optimizing backend

5.0.0 introduces a full SSA-based middle and back end, the largest subsystem in the compiler.

  • Inlining — a pure IL→IL pass (body budget 256 instructions) that runs before the graph is built, so later passes tidy the substituted code.
  • Control-flow graph — basic blocks via the leader algorithm, with explicit edges.
  • SSA — pruned φ-placement at the iterated dominance frontier, renaming over the dominator tree, and a suite of passes over the form: constant folding and constant-branch (dead-code) elimination, store/load forwarding, value-range analysis, loop rotation and invariant motion, interference checking, and a verifier.
  • Dataflow — liveness (backward) and reaching definitions (forward), solved by worklist to a fixed point.
  • Register allocation — a whole-function linear scan with loop-weighted spill costs by default, plus an optional Chaitin–Briggs graph-colouring allocator; debug builds keep every value on the stack for predictability, register homing is a release-mode optimization.
  • Two architectures, mirrored — x86-64 (System V) and ARM64 (AAPCS64) lowering backends behind one shared seam, written shape-for-shape, with every divergence a named ISA constraint. A per-architecture peephole optimizer runs over a shared dispatch engine.

5 · Code generation and debugging

  • ELF output — executables, static archives, and shared objects, with correct section layout.
  • DWARF v5, architecture-agnostic and shared by both backends. A registered DW_LANG_Mica language code means GDB reports the source language as Mica; arrays carry their real declared bounds (an array[1900..2100] is not shown zero-based), and enumerations print by name.
  • ABI fidelity — one ABI classification of every type feeds the call emitter, the register allocator, and the DWARF generator alike, so a value is passed, returned, and described to the debugger the same way the platform ABI specifies.
  • An inspectable pipeline — the token stream, AST, Spectra IL, SSA form, assembly for both AMD64 (Intel or AT&T syntax) and ARM64, and the binary can each be exported and read; the compiler will also narrate its memory decisions and report per-pass optimization statistics, so every transformation is measurable.

6 · The platform

Mica’s standard library grows by surfacing what already exists rather than rebuilding it. Every C library that follows a stable ABI is reachable through a JSON contract with full compile-time type and format-string checking, and Mica binaries link with C as equal citizens — in both directions.

  • Contracts ship for standard I/O, process arguments, numeric limits, the C standard library, and libm (math, linked with -lm).
  • No separate I/O runtime — console I/O is resolved, per the target’s string encoding, onto the C standard I/O layer; the encoding boundary lives in the contracts, not in programs, so the same source serves UTF-32 and UTF-8 targets.
  • Type fingerprinting catches ABI mismatches between compilation units at compile time.
  • Cross-compilation between Linux/AMD64 and Linux/AArch64 works on one host.

7 · Performance

Performance is measured with the deterministic retired-instruction count (Ir) as the primary metric and wall-clock time as an advisory second, on x86-64 and ARM64 development machines, reproducible from committed benchmark scripts. (Ratios are Mica ÷ gcc -O2; below 1.00× means Mica executes fewer instructions.)

  • The heap is additive. A heap runtime call is emitted only in a function that uses new, dispose, defer, or until. Non-allocating compute kernels are byte-identical to their pre-heap baseline.
  • Scalar kernels are competitive. On the Computer Language Benchmarks Game kernels, Mica runs within roughly 0.94×–1.42× of gcc -O2; Mandelbrot executes fewer instructions than gcc -O2 on both architectures.
  • On an allocation-bound workload, the region allocator wins on instruction count. Repeated waves of small cells run at 0.80× of gcc -O2’s retired instructions on x86-64 — the compiler-scheduled region (bump-allocate, reclaim in bulk) executing fewer instructions than glibc malloc/free. On wall-clock, glibc’s low per-call latency keeps it ahead; on the deterministic instruction count the region leads. Safety analysis and allocation strategy are the same engine here: the programmer wrote until F, and the speed followed from the proof.
  • Compile speed. A 100,000-line program compiles, with full optimization, in about 5.5 seconds, on a lock-free, file-parallel driver.

8 · Engineering discipline

No feature lands without coverage in the manifest-driven harness — over 4,500 test cases running on more than 740 test programs (over 150,000 lines), across execution, error, IL, debug, and export categories. Tests run under multiple compiler configurations from one source, and an internal quality-gate layer checks the compiler’s own transformations. The compiler is pure Go, with no dependencies to resolve and nothing beyond a standard Go toolchain required to build it.


9 · How Mica stands against GCC 15

GCC 15.1 (April 2025) is a roughly 38-year-old, ~15-million-line toolchain with about 48 CPU back ends and ten front ends. Mica is young and small, with one language and two targets. The map below marks where each is distinct.

DimensionMica 5.0.0GCC 15
Compile-time memory-safety proofFlow analysis proves heap discharge on every path; a fully-tracked leak does not compile-fanalyzer is, by its own documentation, “neither sound nor complete … a bug-finding tool, rather than a tool for proving program correctness,” and C-only
Allocation-bound performanceRegion allocator at 0.80× of gcc -O2 retired instructions on one workloadThe baseline (lower wall-clock latency via glibc)
Scalar performanceWithin ~0.94×–1.42× of gcc -O2; ahead on MandelbrotThe mature reference, decades of tuning
Optimization breadthA new SSA backend with the core passesFull IPA, LTO, PGO, polyhedral and vectorization machinery
Target architecturesx86-64 and ARM64, Linux~48 CPU back ends, many operating systems, GPUs
LanguagesOne structured systems languageC (C23 default), C++, Fortran, Ada, D, Go, Modula-2, COBOL, and more
Debug infoDWARF v5 on both targets, custom Mica language codeDWARF 5 by default
External dependenciesPure Go; GNU as + ld onlyA large self-contained toolchain
TransparencyEvery stage exportable; memory decisions narratedInternal IRs (GIMPLE/RTL) exist but are large and internal
Maturity & ecosystemMonths–years; single developer + AI~38 years; hundreds of contributors; a vast ecosystem

Two distinctions are Mica’s own: a different category of guarantee — heap safety proven at compile time, where GCC offers runtime hardening and a best-effort analyzer — and deliberate minimalism and transparency. On nearly everything else, GCC’s maturity and breadth lead, and that is the honest shape of a young compiler beside a foundational one.


10 · Direction

The road ahead is consistent: Mica grows new capability out of the foundation it already has. Through the rest of the 5.x line, a modern text and string runtime, broader standard-library coverage with compiler-emitted contracts, first POSIX and Linux API access, and a supported editor experience. Then the track that gives the language its tagline — built-in fixed-shape vector and matrix types with compile-time shape checking, grown directly out of the ordinal type system; mixed-precision numerics; SIMD and accelerator lowering; and structured concurrency. These are the stated direction, not present capability — but the foundation they build on is the one described above.


Mica is being built in the open because compilers deserve to be understood, not just used. If it is useful to you — as a language, as a study in compiler construction, or as a glimpse of where structured systems programming can go — that is exactly what it is for.

License: MCL-1.0 — free for personal learning, private projects, academic research, and teaching; commercial use by separate agreement. Contact: info@mica-dev.com · Full detail in the Technical Portrait.

GCC 15 facts are drawn from gcc.gnu.org (release notes; optimization, debugging, and static-analyzer documentation). Mica figures are reproducible measurements from the project’s committed benchmark scripts on the author’s x86-64 and ARM64 development machines, gated on retired-instruction count. All figures are a snapshot of 5.0.0 in active development.