TYCHO Search

Search documentation

    ↑ ↓ to move · Enter to open · Esc to close

    Architecture & project status

    Where the project stands: how it's built, what each verification gate proves, what's shipped, and what's a decided non-goal.

    Tycho tests one claim: value semantics makes hierarchical arena allocation fully implicit, with no whole-program analysis. It transpiles to C and is MIT-licensed. For the argument itself see thesis.md; for a full accounting of where the model wins and loses see internals/value-semantics-limits.md.

    The pieces

    One compiler ships. compiler/ is 26,202 lines of Tycho across 13 files, built as tychoc1 and installed as tychoc. Six packages: lex, parse, ast, types, emit, driver. The spec is normative; the compiler is the reference implementation in practice, and every suite here defaults to it (tests/run.sh:175@TYCHOC).

    bootstrap/tycho_compiler.c is a generated cold-start artifact: the compiler source emitted as C by the last known-good compiler. It is not a second implementation and is not edited by hand. The historical C compiler, src/tychoc.c, has been deleted; its final source is at commit c7d46528ac6efcf9dc93359d14d98bedcb7ddbad in git history. Historical design and defect records still cite it, and scripts/check_citations.py resolves those citations against that revision. See the archive note.

    Which compiler is right

    The self-hosted compiler is the reference implementation; the spec is normative. The archived C compiler is not a second opinion and is never used to resolve a disagreement.

    Bootstrapping

    make tychoc1 builds in two stages (Makefile@tychoc1):

    ./bootstrap-tychoc  compiler/main.ty -o tychoc1-stage1
    ./tychoc1-stage1    compiler/main.ty -o tychoc1
    

    The first stage is built from the checked-in bootstrap C with cc; the shipped tychoc1 is emitted by a compiler written in Tycho, so a defect in its own code generation reaches the binary you run instead of hiding one generation back. make bootstrap-check proves the checked-in C builds and emits itself byte-for-byte.

    The fixpoint holds. Generating three further compilers from compiler/main.ty gives byte-identical C at every hop — gen2 == gen3 == gen4. The corelib is resolved relative to the running binary, so a generation built somewhere else must be run from the repo root or it cannot find core:strings.

    TYCHOC1_CFLAGS (Makefile@TYCHOC1_CFLAGS) links -static-pie, not -static: a plain static link leaves .eh_frame unsorted, so the first unwind runs classify_object_over_fdes over the whole table — 201,604 Ir on every compile regardless of input size.

    The fixpoint is gated rather than measured by hand: make fixpoint-check (scripts/fixpoint_check.sh) has tychoc1 emit the compiler's C, builds that one generation -O0 (it only has to run), has *it* emit the compiler again, and requires the two C files byte-identical — f(f(x)) == f(x). It compares the emitted C rather than binaries, so it is free of link-time noise. It is [1e/13] in make ci.

    The verification surface

    One class the lanes below do not cover, stated so it is not mistaken for covered: ASan sees addresses, UBSan undefined behaviour, LSan leaks, TSan races — none sees a read of memory that was never written. That gap was probed with valgrind memcheck over the fixtures, corelib packages, examples, and all tools driven through their gates — clean — with the instrument proved able to fire in both directions. The method is recorded in internals/probe-uninit-arena-2026-09-11.md and the controls in controls.md.

    make ci runs the whole gate locally — there is no hosted CI, by policy. What each step proves:

    GateProves
    make testgolden-output tests pass under ASan/UBSan/LSan; tests/reject/ must fail with a non-empty diagnostic; tests/abort/ must die with a tycho: message; tests/diag/ and tests/warn/ match their recorded stderr.
    make ilp32the same fixture suite rebuilt under gcc -m32, golden-compared: Tycho int stays 64-bit off LP64.
    make asan-selfthe checked-in compiler bootstrap built with ASan+UBSan, compiling the whole corpus (the compiler's *own* memory safety).
    make corelibevery corelib package + examples + the site dogfood vs recorded goldens.
    make raytrace / make mandelbrotfloat-heavy value-semantics dogfoods (a ray tracer, a 16-core parallel for reduction): tychoc == ASan (+ TSan), golden-locked.
    make concspawn / parallel-for / channels: native + ASan + TSan vs goldens; aborts fire, rejects are refused.
    make ffiextern FFI vs golden, ASan-clean; affine-handle misuse and library-name injection refused.
    make fuzzrandom valid programs: tychoc's native -O2 and ASan/UBSan builds must agree byte-for-byte and neither may fault.
    make fuzz-rejectmalformed input: tychoc must fail closed — never crash, and anything it accepts must emit valid C.
    make fuzz-leakLeakSanitizer: no arena / owner leaks.
    make tools-checkformatter idempotence + semantic preservation + LSP smoke.
    bench-guardtree-alloc wall: Tycho must beat C (perf-regression gate).
    make recursiondeep input fails closed (no stack-overflow DoS).
    make spec-checkthe spec's grammar matches the prose, its fixtures exist, and its examples produce the documented output.

    The make hooks pre-push gate runs the full deterministic lane set plus a fast fuzz smoke, so a red make ci can't reach main: a green make test is *not* a green tree.

    Shipped

    Decided non-goals

    These are settled — please don't propose them:

    Traits / typeclasses — reopened 2026-09-11, re-closed the same day

    Traits were first closed as "complete for the thesis", then reopened when that premise was retired — and closed again on new grounds: the *dynamic* form (trait objects held in fields or heterogeneous containers) is impossible under value semantics (thesis §5), while the *static* form is largely already present via post-substitution generics, leaving only overloading as the demand-gated gap (ROADMAP). The full argument is in internals/value-semantics-limits.md.

    Known limits

    Pointer-shaped, structurally-shared data (tries, graphs) costs ~1.55× C in RAM because children are stored by value, with no sharing. The recommended idiom (a flat index-pool) is documented but not presented as "the model." See internals/value-semantics-limits.md.