Lyric v4.5.0

Changelog

This file starts at v1.0.0. Before it there was no compatibility promise to describe — neither for the language nor for the .lyrbc format — and a changelog written under those conditions records churn rather than change. The pre-1.0 releases carry their notes in their annotated tags.

Versions follow vMAJOR.MINOR.PATCH, as described in README. Each entry lists what changed for someone using the toolchain: the language, the standard library, the bytecode format, the command line and the embedding API. Compiler internals are in git log.


v4.5.0 — 2026-09-22

The project system. A compile is one of two named profiles and the default is debug; a build script names what it builds; a project builds, runs, packs, checks and tests without anybody naming a file; and lyric.json says what the project is called, what it depends on and which toolchain it needs.

Added

Changed

Fixed

v4.4.1 — 2026-09-04

Round 1 of the sweep after M36. Two findings, both older than the feature that surfaced them.

Fixed

v4.4.0 — 2026-09-04

Pattern matching becomes complete. Two forms the grammar always admitted, the checker always accepted, and the lowering never built. Both are additive: every program that compiled before compiles unchanged, and the bytecode format is untouched.

Added

v4.3.6 — 2026-09-04

Round 8 of the sweep. One finding, and it is a sentence I wrote in 4.3.5 that was not true.

Fixed

v4.3.5 — 2026-09-04

Round 7 of the sweep. Three findings: one is round 6's own, and two are the ownership rule of 4.3.0 meeting tools nobody had checked against it.

Fixed

v4.3.4 — 2026-09-04

Round 6 of the sweep, aimed at what round 5 built. Two findings in it, both mine, and one older one found while checking that round 5 had broken nothing.

Fixed

v4.3.2 — 2026-09-03

Round 5 of the sweep, aimed at 4.3's ownership rebuild and at the specification's own sentences. Four findings in the toolchain and two in the documents; the heaviest is again in what the release before it built.

Fixed

Documentation

v4.3.1 — 2026-08-27

Round 4 of the sweep, aimed at what 4.3.0 rebuilt. Two findings, and both are 4.3.0's own.

Fixed

v4.3.0 — 2026-08-27

A VM owns what its scripts open. The heaviest finding of the 4.2 sweep, fixed.

Added

Changed

Deliberately unchanged

v4.2.3 — 2026-08-27

Round 3 of the sweep. No behaviour changed: two gaps the earlier rounds named are now pinned by tests, one sentence of the 4.2.1 notes is corrected, and the heaviest finding is recorded rather than fixed.

Documentation

Testing

Known, not fixed

v4.2.2 — 2026-08-27

Round 2 of the sweep. One diagnostic fixed, one limit documented, and two language questions recorded rather than answered — deciding them is not a sweep's job.

Fixed

Documentation

Probed and clean

Round 1's own fix re-checked: the guard's panic is NOT catchable as an IoError, and a computed max walking down to exactly one still reads. Beyond that: a LineReader walked inside a coroutine that is itself pulled from a task — a chain in a chain, with the file read at the bottom yielding past the inner chain to the scheduler; the same walk through map and filter; one handle used across two separate run() calls; fifty queued writes all landing; and the time types carried through a coroutine by value.

v4.2.1 — 2026-08-27

The sweep after 4.1.0 and 4.2.0. Ten probe groups against what the two releases added; one real finding, fixed failing-test-first, and it turned out to be older and wider than the release that surfaced it.

Fixed

Probed and clean

Worth not re-running: two tasks sharing one handle (300 of 300 bytes, both finish); a 200 000-byte line and a CRLF pair split across the 64 KB refill boundary (exact); 2 000 open/close rounds with no descriptor leak; a directory opened as a file, and a write to a read-only handle, both refused with the twin naming why; close while a read is outstanding — the 4.0 sweep's crash class — which answers null rather than taking the process down; reads after EOF staying empty; create truncating; the time conformances at both ends of int, including sortList, Set and Map; the whole stdlib suite under LYRIC_JIT=1; and a packed executable.

v4.2.0 — 2026-08-27

Open files, read and written in pieces, inside tasks — and a scheduler bug the feature's own test exposed. Additive: nothing was deprecated or removed, and no existing program changes meaning.

Added

Fixed

v4.1.0 — 2026-08-27

Instant and Duration join the library's conformances. Additive: no existing program changes meaning, and nothing was deprecated or removed.

Added

v4.0.1 — 2026-08-27

The sweep after 4.0.0. Eight probes against what the major added; four real findings, all fixed failing-test-first. Nothing in the language or the format changed.

Fixed

v4.0.0 — 2026-08-27

The major (the basket is lyric#121, decided 2026-08-25 and delivered whole). One sentence carries it: yield works from any call depth, and everything the standard library waits for is built on that. Coroutines became stackful, std.task turned them into cooperative tasks, and TCP, UDP, child processes and Ctrl+C are all "a task yields a Wait" — no async syntax, no threads, no second mechanism. Every language rule landed spec-first (lyric-spec#26–#28); format 3.6 → 4.0; a 4.0 runtime runs every 3.x module unchanged, a 3.x runtime rejects 4.0 modules — which is the correct answer.

Added

Moved

Removed — the clocks came due

Fixed

v3.9.1 — 2026-08-25

The sweep after 3.9.0 (spec: lyric-spec#25). Twelve probes; two real findings and one recovery wart, all three fixed failing-test-first.

Fixed

v3.9.0 — 2026-08-25

Attributes: one value in parentheses, and the group spelling. The twin of lyric-spec#24. No format change — the row of a positional use is byte-identical to its braces twin, so nothing about the bytecode, its readers or a host changes.

Added

Changed

Documentation

v3.8.2 — 2026-08-25

The release 3.8.1 could not be. The v3.8.1 tag points at a tree whose README still said 3.8.0, and the release gate did its job: the version test failed on both platforms and no archives were published. This release is that tree with the README telling the truth — nothing else changed. There is no v3.8.1 download, and the tag stays as the record of why.

v3.8.1 — 2026-08-25

Tagged, never released — the gate refused it (see v3.8.2, which carries this content).

The sweep after 3.8.0. One finding, one cause, two faces: a global initializer was checked as if it stood in no module at all.

Fixed

v3.8.0 — 2026-08-25

Round 3: the opaque clock. opaque type has promised since 1.15 that "a script cannot forge one" — and any module that could see the alias could: 42 as Entity compiled anywhere. This release starts the clock that closes the hole, on the warn-then-error path LYR-SEM0074 took into 2.0. No format change; no correct program changes meaning today.

Added

Also in this release

Documentation

v3.7.0 — 2026-08-25

M35 — the reason. The gap std.io.file has carried since 2.14 — "a missing file and a permission denied look the same" — closes, and it closes as a LIBRARY DOCTRINE rather than a one-module patch (spec §9.0, lyric-spec#22): a value answers whether, a throw answers why. Everything is additive — no silent form changes, no format change (bytecode stays 3.6) — and every twin derives from the same implementation as its silent sibling, so the two can never drift.

Added

Deliberately unchanged

parseInt and parseFloat stay ?T alone — the reason of a five-character input is the input. std.os stays silent throughout: an unset variable, an unanswered hostName — null IS the whole truth there. Map.get, List and the option helpers keep absence as a value, and panics keep programming errors.

Fixed

Documentation

v3.6.1 — 2026-08-25

The sweep after 3.6.0, per the pipeline: adversarial probes against what the four changes make newly reachable. Two findings, both fixed with a failing test first; a second probe wave over the fixes found nothing.

Fixed

Noted, not changed

Three pre-existing edges the sweep recorded in STATUS.md rather than fixing, because each needs a decision before code: a transparent type alias is refused in a :: list although §3.5 says aliases serve everywhere; a fully substituted static method as a VALUE (let f = List<int>.empty;) is an LYR-IR0001 whose message names <?>; and a duplicate CONSTRAINT entry (<T :: [Ord, Ord]>) is silently deduplicated — the 3.6.0 list rule deliberately covers conformance and parent lists only.

v3.6.0 — 2026-08-25

The toolchain twin of the specification round lyric-spec#21: the inference rules are written down in spec §8.3, and the two places where the compiler silently chose or silently accepted now say so out loud. No format change — the bytecode stays 3.6 — and no correct, order-independent program changes meaning.

Fixed

Documentation

v3.5.0 — 2026-08-24

The standard library learns structured data: JSON in and out, and the binary-to-text encodings beside it. Both modules are written in Lyric; no language change, no format change — with one exception underneath, where std.string.parseFloat had to become native to make the numbers honest.

Added

Changed

Documentation

v3.4.1 — 2026-08-24

A ground-up bug sweep through the pipeline. Every fix carries a failing test written first, and none changes the behaviour of a correct, documented program — what they change is that malformed input, whether hand-written source or crafted bytecode, is now refused with a message instead of crashing, corrupting, or slipping through.

Fixed

Docs

Added

v3.3.0 — 2026-08-24

Fixed

Added

v3.2.0 — 2026-08-23

Added

v3.1.0 — 2026-08-23

Added

v3.0.2 — 2026-08-23

Fixed

v3.0.1 — 2026-08-23

The first sweep after the major, and the reason the pipeline now has one: four defects, none of which a test had asked about, all in what the new features do to EACH OTHER.

Fixed

Documentation

v3.0.0 — 2026-08-23

The major. Everything the 2.x line had deferred, in one release: heterogeneous arithmetic, throwability that survives being stored, overloading, and a compiler that turns hot functions into machine code. The .lyrbc format is unchanged at 3.6 — a 3.0.0 module loads in a 2.12 runtime and the other way round, as far as the language allows.

Migrating from 2.x, in the order the compiler will tell you:

  1. every Add<T> / Sub<T> / Mul<T> / Div<T> gains a second type argument, the RESULT: Add<Vec2, Vec2>. The compiler names the count (LYR-SEM0026);
  2. a coroutine whose body may throw is a different TYPE now — Coroutine<int> throws Exception — and a field or optional holding one says so;
  3. the eleven forms whose @Deprecated promised removal at 3.0 are gone: readText, readBytes, readLines and the eight free iterator adapters. Their replacements have been there since 2.14 and 2.17.

Nothing else in a 2.x program changes meaning.

Changed — breaking

Added


Fixed


v2.17.0 — 2026-08-22

M33 — iterator chaining. The last thing this project had written down as a documented No.

xs.iter().map<int>((n: int) => n * 2).filter((n: int) => n > 4).take(2)

Added

The two that stay free, and why

Fixed

v2.16.0 — 2026-08-22

An interface may declare several parents. The rule that said otherwise rested on a claim about the runtime, and the claim was wrong.

Added

Changed

v2.15.0 — 2026-08-22

Two small things off the list before v3, both of the same kind: something written in the source that the compiler looked past.

Fixed

Added

v2.14.0 — 2026-08-22

The second link of the patch train. std.io.file had three conventions for "it did not work", and one of them could not be told from success.

Added

The rule, written down

Two shapes, and each says what it is for:

A predicate (exists, isFile, isDirectory) answers bool as well, and there false is an answer rather than a failure.

What none of them carries is a REASON: a missing file and a permission denied look the same. That gap is real and left open deliberately — carrying reasons means an error type and a decision about throws, which is the larger question this release deliberately did not answer.

v2.13.0 — 2026-08-22

The first link of the train that runs ahead of v3.0.0: everything that does not need a major ships first, on its own, and deprecates what it replaces. This is the mechanism those deprecations will be written with.

Added

v2.12.0 — 2026-08-22

Bytecode format 3.6. The interpreter runs the same programs in a third of the instructions, and the release is about why that is the number that mattered.

The measurement it started from

An instruction on this VM costs ~6 ns — and costs it regardless of what it does. A br, an add f64 and an and i64 lie within twenty percent of each other. That is the normal price of a switch-dispatch stack machine, not a slow interpreter: the dispatch is the whole bill. So nothing that makes an instruction cheaper moves a program's time, and the only lever is executing fewer.

The loop test of every while in the language was four instructions, of which three existed to move a value onto the operand stack and off it again.

Added

Measured

Same harness, same machine, same session; the baseline is a build with selection switched off and the old nextInt. Two iteration counts differenced, so nothing that happens once is in the figure, and the instruction counts are read from an ExecutionBudget rather than counted by hand.

case instr ns/iter instr ns/iter
2.11 2.11 2.12 2.12
a counting loop 9 44.3 3 18.2 2.4×
an integer accumulator 13 59.2 4 27.6 2.1×
a float accumulator 13 68.7 4 24.8 2.8×
a masked accumulator 15 88.7 9 61.2 1.4×
a native call 14 82.4 8 56.9 1.4×
Random.nextFloat() 70 395.4 42 199.2 2.0×
an array read 19 91.6 13 65.8 1.4×

The time fell WITH the count rather than beside it, which is the claim the release rests on. What rose is the average price per instruction (≈4.9 → ≈6.3 ns), and that is the healthy direction: the instructions the fusion removed were the cheapest ones, the moves.

The rows that gain least say where the remaining work is: a nested expression keeps its intermediate on the stack, and neither fused form can reach a value that is not in a slot.

Format

3.6 against 3.5: four new opcodes. A producer may emit the unfused sequences instead, and one that never emits a fused form writes a module any 3.5 runtime accepts; a module that uses one needs a 3.6 runtime, named at load time.

The §Versioning rule was corrected in the same round. It read "a minor version may only add skippable sections", which 3.4 was not — the note beside that version said as much, so the document had contradicted itself since the day it shipped. It now states the compatibility the format has actually delivered: per MODULE, not per version.

v2.11.0 — 2026-08-22

Bytecode format 3.5. One new section, and the whole release is about a name that used to get lost.

Added

Format

v2.10.1 — 2026-08-22

One fix, reported the day 2.10.0 landed: the new enum argument was unusable in the shape an SDK actually writes.

Fixed

v2.10.0 — 2026-08-22

An attribute argument may name an enum variant. The bytecode format goes 3.3 → 3.4, and this is the first change to it that an older reader cannot ignore — see below.

Added

Changed

v2.9.0 — 2026-08-22

An editor can attach to a program a host is already running. The bytecode format stays 3.3 and the language gains nothing.

Added

v2.8.0 — 2026-08-22

Module constants initialize in dependency order, so a file compiles the same way whoever compiles it. The bytecode format stays 3.3; more programs compile than before and none fewer.

Fixed

v2.7.1 — 2026-08-22

One fix, to a request the debug adapter left unanswered.

Fixed

v2.7.0 — 2026-08-21

One overload, and with it the debugger reaches the shape an embedded script actually has. The bytecode format stays 3.3 and the language gains nothing.

Added

v2.6.0 — 2026-08-21

A compilation error tells an embedding host WHERE it happened, and a panic hands over its backtrace. Both were already known inside the toolchain and stopped at the boundary. The bytecode format stays 3.3 and the language gains nothing.

Added

Changed

v2.5.1 — 2026-08-21

One fix, to a promise the formatter's own chapter makes.

Fixed

v2.5.0 — 2026-08-21

One requirement from the embedder, and the documentation gap beside it. The bytecode format stays 3.3; nothing on the wire changes, which is the whole finding.

Fixed

Documentation

v2.4.0 — 2026-08-21

M31: two additive answers to what an embedder found in production. A host can bound how long foreign code runs, and an attribute argument may name its value instead of repeating it. The bytecode format stays 3.3, and a module compiled by 2.3 loads unchanged. Two conformance cases activate with this release (//! since: 2.4.0); the suite stands at 90.

Added

v2.3.1 — 2026-08-21

The post-2.3.0 audit's patch wave: four measured bugs, none of them reachable from a program that was doing anything unusual. The bytecode format stays 3.3, and the language gains nothing — three of the four were valid programs the toolchain mishandled. Three conformance cases activate with this release (//! since: 2.3.1); the suite stands at 88.

Fixed

v2.3.0 — 2026-08-20

M30: the toolchain learns to debug. Breakpoints, stepping, the call stack and the variables panel, in any editor that speaks the Debug Adapter Protocol — the VS Code extension wires it to F5. The bytecode format goes 3.2 → 3.3; the change is one strippable section, so a 3.2 runtime loads a 3.3 module unchanged, and every 2.x module keeps loading here.

Added

Fixed

v2.2.1 — 2026-08-20

One fix, found by the embedder the same day: the specification's §3.5 promises that an opaque alias resolves to its underlying in a native signature — without restricting where the alias was declared. The toolchain under-delivered.

Fixed

v2.2.0 — 2026-08-20

The A8 wave: both coroutine edges Erato's register filed after building its cutscene driver, plus one the fix uncovered. The bytecode format stays 3.2; a module that never calls next() loads on every 2.x runtime. Four conformance cases activate with this release (//! since: 2.2.0); the suite stands at 85.

Added

Fixed

v2.1.1 — 2026-08-20

One fix, found the day of 2.1.0 by the first embedder to re-pin: a compiler crash on a form the language always meant to allow.

Fixed

v2.1.0 — 2026-08-20

The ergonomics wave: two additive changes the audit measured the edges of. Four conformance cases activate with this release (//! since: 2.1.0); one 2.0 case pinning the old non-context rule retires with its sentence.

Added

v2.0.1 — 2026-08-20

The first harvest of the deep audit: seven bugs measured against the now-normative specification, fixed as one wave. Seven new conformance cases activate with this release (//! since: 2.0.1); the suite stands at 78.

Fixed

Improved

v2.0.0 — 2026-08-20

The specification is normative from this release on: lyriclang/lyric-spec defines the language, the toolchain implements it, and a divergence is a toolchain bug. The major cuts the SOURCE surface — everything the 1.x deprecation clocks announced — while the bytecode format stays 3.2 and bytecode compiled against 1.x keeps loading.

Removed — the 2.0 cut

Everything @Deprecated announced through 1.x is gone from the source surface. The registry still binds the old NATIVE names, so bytecode compiled against 1.x keeps loading; what the cut takes is the ability to write the old forms in new code.

Changed

v1.16.0 — 2026-08-19

The language has a specification: lyriclang/lyric-spec holds twelve chapters and a conformance suite, non-normative until 2.0 — and from this release on the semantics are FROZEN. Two toolchain fixes came out of writing it. The bytecode format stays 3.2.

Fixed

v1.15.0 — 2026-08-19

The freeze prep: the design leftovers settled before the spec freezes semantics. opaque type arrives, the string API becomes methods, iterator chaining gets its documented No — and a latent function-id collision in the lowering falls. The bytecode format stays 3.2.

Fixed

Added

v1.14.0 — 2026-08-19

The std polish, born from a line-by-line audit. The string module stops being quadratic, the print family collapses to one generic concept, the collections learn the operations daily use kept reaching for, arrays cross the native boundary as parameters for the first time — and two new modules arrive: std.random and std.time. The bytecode format stays 3.2.

Added

Fixed

v1.13.0 — 2026-08-19

The language gaps close. Interface inheritance arrives — one parent, implied through the whole chain — compound assignment reaches through the operator interfaces, block lambdas infer their return type, and std.core becomes the import-free root of the library. One question got its documented No: heterogeneous operator arithmetic. The bytecode format stays 3.2.

Added

Changed

Fixed

v1.12.0 — 2026-08-19

The standard library grows up. Every public item is documented, constructors live on the types, the first real deprecations start their clock, and the library tests itself — in Lyric. Two compiler fixes came out of the work. The bytecode format stays 3.2.

Added

Changed

v1.11.0 — 2026-08-19

Attributes stop being decoration. One is now read by the compiler — @Deprecated — and one by a new tool: lyric test runs every function marked @Test. The bytecode format stays 3.2, and no existing program changes meaning.

Added

Not in this release

v1.10.0 — 2026-08-19

The compiler learns to speak below "error". Four severities, warnings that matter, notes that point at places, and a CI gate. The language, the bytecode format (3.2) and the embedding API are unchanged; every program that compiled still compiles — some now hear about themselves.

Added

Changed

v1.9.1 — 2026-08-19

The formatter reaches the editor. textDocument/formatting is served by the language server — format on save works wherever the editor offers it, in VS Code and the JetBrains IDEs alike, with no client update needed.

The answer is one whole-document edit off the buffer as it stands, an empty list when the file already has the shape, and NO edits for a buffer that does not parse: the formatter never writes a guess over broken text, behind the editor's gesture either. The editor's tab settings are deliberately ignored — one shape is the tool's contract, in every surface it has.

The toolchain is otherwise unchanged.

v1.9.0 — 2026-08-19

Two tools. lyric pack turns a program into one standalone executable, and lyric fmt gives every Lyric file the one shape there is. The language, the standard library, the bytecode format and the embedding API are untouched; the format stays 3.2, and a .lyrbc built by 1.8.0 packs and runs unchanged.

Added

Changed

Not in this release

v1.8.1 — 2026-08-18

A one-line fix for the JetBrains plugin (now 1.2.1): the TextMate bundle provider was registered under an extension-point namespace that does not exist, so .lyr files rendered uncolored while everything the language server answers worked. The point is declared by the TextMate plugin but qualified under com.intellij; the registration moved there, and highlighting appears. The toolchain itself is unchanged.

v1.8.0 — 2026-08-18

The editors catch up with the compiler. No language change and no format change: the language server compiles the PROJECT instead of the open buffer, answers everything an editor asks, and two installable clients ship beside the toolchain — the VS Code extension as a .vsix, and a new JetBrains plugin.

Changed

Added

The interpreter stops allocating — and so does the native boundary. No language change and no format change: the same programs compile to faster, smaller modules, run with far fewer heap allocations, and a host SDK can now put Vec2 in a native signature. The numbers below come from tools/Bench (new in this release), Release, per operation, against v1.6.0.

Changed

Added

Not in this release

v1.6.0 — 2026-08-18

Attributes. A program can say things about itself that a tool outside it can read — which functions a host should call, what a script-declared type looks like, what a module is. The bytecode format goes 3.1 → 3.2; both new sections are skippable, so a 1.5.0 runtime loads a 1.6.0 module and runs it unchanged.

Added

Fixed

Changed

Not in this release

v1.5.0 — 2026-08-18

Operators on your types. Everything resolves through the one mechanism this language has for polymorphism — the interface a type declares — so there is no operator declaration syntax, no new opcode, and the .lyrbc format stays 3.1.

Added

Fixed

Not in this release

v1.4.0 — 2026-08-17

Completion, and a standard library that says what it does. The language, the command line, the embedding API and the .lyrbc format are untouched; the format stays 3.1.

Added

Fixed

Not in this release

v1.3.1 — 2026-08-17

Fixed

v1.3.0 — 2026-08-17

Everything in this release is the language server. The language, the standard library, the command line and the .lyrbc format are untouched; the format stays 3.1.

Added

Changed

Fixed

Not in this release

v1.2.0 — 2026-08-17

Changed

Added

v1.1.0 — 2026-08-15

Bytecode format 3.1. A minor of the format may only add skippable sections, so a 1.0 runtime reads a module built by this release and a 1.1 runtime reads one built by 1.0 — with one caveat below.

Added

Fixed

Not in this release

Both need a place where a project says what it consists of, and putting that on the command line would make a third place where the layout is written down.

v1.0.1 — 2026-08-14

Fixed

v1.0.0 — 2026-08-14

The first release with a compatibility promise. Everything below describes the state it ships, not a change against v0.9.0: there is no earlier entry to compare against.

From here on the .lyrbc format and the language carry the promise the versioning describes: a minor may add, a major may break.

Language

The whole grammar in docs/Grammar.md compiles and runs: functions, structs and classes, enums with match, interfaces with default methods and :: conformance, generics with constraints, optionals, exceptions with throws and defer, closures, coroutines, modules, and extend blocks on own and primitive types.

Fixed against v0.9.0, each of them a case that used to be refused or to fail late:

Toolchain

Documentation

Not in this release