Skip to content

Releases: promise-language/promise

Promise epoch 2026.9

Choose a tag to compare

@github-actions github-actions released this 16 Sep 11:09

Promise epoch-2026.9

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Promise epoch-2026.9 — 145 commits since epoch-2026.8.

The theme of this epoch is closing the memory-safety gap. unsafe and the
raw pointer type are gone from the language, the capability annotations that
gate native behaviour are declared in modules/std instead of hardcoded in
sema, and more than thirty ownership and codegen defects — leaks, double
frees, and use-after-free — were fixed at the root. Alongside that: the
compiler learned to cross-compile, HTTPS works end to end, net, io and os
grew the operations a real program needs, and macOS joined Windows and Linux in
building with no vendor toolchain at all.

unsafe (the annotation), unsafe { } (the block), and the raw pointer type
T* were removed from the language. Nothing in the standard library or the
catalog needed them, and leaving an escape hatch in a language whose premise is
that a single file tells you what it does was the wrong trade.

The capability annotations that remain are now honest about who may write them:

  • `interior requires `native (T1921) — a user type may not take
    the shared-borrow exemption.
  • `sendable / `sharable are native-only — asserting a
    concurrency capability on a Promise type is rejected at the declaration.
  • Type capabilities are declared once (T1413) — sema no longer carries
    hardcoded lists of "types that are Copy", "types that are sendable", and so
    on, re-enumerating what modules/std/*.pr already says. The annotation is
    the single source of truth, and `builtin(role) declares the compiler's
    dependence on a library type rather than sniffing for it by name.

The largest single category in this epoch. Most of these are silent — the
program keeps running and gives a wrong answer, or corrupts the heap.

  • Use after free — a go { } block capturing an owned droppable local took
    ownership without marking it moved, so the outer scope read freed memory
    (T1641); checkGoBlockCaptures missed three AST shapes codegen does walk, so
    a closure env could escape and non-sendable values could cross the spawn
    boundary (T1658); reading e.message in an untaken error handler inside a
    goroutine segfaulted after the first round (T1605). Borrows may now never
    cross a go spawn boundary at all (T1397, §17.4).
  • Heap corruptionChannel.send of a temporary closure corrupted the env,
    so the receiver read zeroed captures and then died in free (T1655);
    indexing two nested temporary arrays in one expression aborted with
    "invalid free" (T1711); boxing a MutexGuard[T] as Closer killed the
    process with no method call needed (T1887).
  • Leaks — failable unwrap (?^, ?!, bare auto-propagate) leaked native
    handles for Channel/Ref/Mutex/Task/Weak/MutexGuard (T1940);
    implicit error propagation never dropped the callee's heap return value
    (T1883); a heap user-type intermediate temp in a generator-call argument list
    (T1514) and a closure-env intermediate argument (T1515, which also
    double-freed through a generator call); assigning a heap string through a
    user-defined property setter (T1901); a typed error catch at a supertype
    dropped only the base's fields (T1702); dropping a polymorphic value by its
    static type leaked the subtype's fields, including through Ref[T] and
    Mutex[T] (T1706).
  • Double release — WebIDL bindgen emitted a handle-releasing drop on every
    resource wrapper, so seeding or rewrapping a handle released it twice
    (T1510); there is now a borrowed, non-owning handle.

Failable calls in expression and control positions were a systematic hole — a
bare failable call was never consulted for auto-propagation as an if/while/
for condition (T1873), a for-in subject (T1896), or a match scrutinee
(T1900), producing malformed IR or a silent segfault. Also fixed: a failable
[] getter read in expression position (T1416); an inline error handler on a
for-in iterable yielding a stream, which emitted an invalid phi or swallowed the
error (T1420); yield inside a go { } nested in a generator body (T1428).

Structural interfaces and generics: a declared is on an interface with default
methods left NULL vtable slots on a non-generic heap type (T1880); a synthesized
default method could not read a default getter through this (T1600);
as! from a structural value panicked codegen (T1884); a native requirement
called through a boxed view jumped to address 0 (T1885, T1905);
ImplementsInstance did not substitute a concrete type's own type parameters,
so Vector[int] could not be assigned to Stream[int] (T1772); for-in and
types.Implements disagreed on Stream satisfaction (T1735); for-in over a
subtype inheriting next() from its parent panicked (T1459).

Cross-module generic dispatch was restructured: a std generic monomorphized
during an earlier module's compile could not see a later module's method stubs,
so the declare and define sweeps are now separate passes over all modules
(T1458). A related Windows-only link failure — a generic native std type
instantiated only inside a module getting a typeinfo pointing at a .drop
nothing synthesized — is fixed (T1929).

Other miscompiles: a mut-ref (T ~p) generator parameter read garbage after the
first resume (T1516); a ~ lambda parameter silently discarded mutation and
passing a ~-borrowed vector to any closure segfaulted (T1661);
obj.field.push() re-evaluated the field owner, storing back to the wrong slot
for impure owners (T0990); a `factory method on a type that has a subtype
panicked with undefined variable "T" (T1749); a public factory taking a
structural-interface parameter could not be called from another module (T1740).

T0533 adds the cross-compile codegen backend: a --target flag,
triple-aware opt/llc/PAL selection, linker dispatch, and a target-keyed
cache. run, exec, test and stress share one dispatch path, and WASM
guest argv now reaches wasmtime instead of being dropped. A non-host native
target is a hard error until its link payload lands, and promise targets
answers identically on a warm and a cold cache.

  • HTTPS, client and server (T0079)Client.set_tls_config for custom CAs
    and mutual TLS, and Server.bind_tls for HTTPS serving. A TLS server sent
    only its leaf certificate on every backend, dropping the issuers in a
    fullchain.pem (T1612, with a separate Windows/SChannel fix for reading both
    certificate stores). A macOS TLS server handshake blocked forever on a
    non-TLS peer that stopped sending, where Linux and Windows rejected it
    immediately (T1769). SChannel's credential setup raced when one
    TlsServerConfig served concurrent handshakes (T1766). A malformed HTTP
    request now gets a 400 Bad Request instead of a silent close (T1670).
  • net: names and deadlines — DNS resolution and connect-by-hostname
    (T1518), and per-operation deadlines plus cancellation: connect timeout,
    read/write deadlines, CancelHandle (T1563). net.resolve("") raised on
    Linux but silently resolved on Windows and macOS — on Windows, to every local
    interface address (T1726).
  • io: durable writes (T1520) — atomic replace_content/replace_bytes
    via rename, whole-file advisory locking, and sync/Dir.sync, specified in
    docs/io.md so a durable write is not a per-platform guess. Slot ownership
    is keyed on file identity, and Windows locks no longer cover the data range
    (T1967, T1968).
  • os: child-process supervision (T1529) — graceful signals, process
    groups, and reaching a pid you did not spawn.
  • crypto: CSPRNG (T1571)random_bytes, the one native primitive.
  • Failable goroutinesgo! spawns a failable task; receiving with <-
    auto-propagates the goroutine's error, and an un-received failable task drops
    without leaking on either the value or the error path (T1403).

`structural(protocol: true) reserves protocol names and rejects near-miss
signatures at the declaration, so a type that almost satisfies Reader fails
where it is written rather than where it is used (T1731). A trigger table plus
on-demand declaration loading makes that work for unimported embedded modules
(T1732). Every protocol implementation in std and the catalog now declares is
explicitly, which exposed several near-misses (T1734). Value types may declare
`structural parents (T1730), and bindgen emits
`structural(protocol: false) on generated types (T1733).

Promise on macOS no longer consults Apple's SDK at all. Linking goes through a
bundled libSystem.tbd stub — the same zero-dependency stance already taken on
Windows, which generates its own import libraries from tracked .def files
(T0772), and on Linux, which vendors musl.

This started as a break rather than a feature. Xcode 27's SDK declares a new
architecture, arm64e.x1
, which the vendored LLD 22.1.0 cannot parse; it
rejects libSystem.tbd as malformed, and every libc and pthread symbol comes
out undefined. Any Mac that updated stopped being able to build at all. Pinning
an older SDK would only have deferred it to the next Apple release, so the host
SDK was removed as an input instead (T1609).

The bundled stub had been a rarely-taken fallback, and rarely-taken paths hide
things:

  • It was missing fourteen symbols, not the one the tracker had recorded for a
    month — including _memmove and ___sincos_stret, which are emitted by the
    backend rather than referenced in PAL source, so no source sweep would have
    found them. The regression test now links a representative set of programs
    against the stub rather than asserting a frozen list, so a future gap fails
    with the linker's own error on the change that introduces it.
  • Materializing it was not concurrency-safe: two promise processes sharing a
    `PROMISE_HOME...
Read more

Promise epoch-next (pre-release)

Pre-release

Choose a tag to compare

@github-actions github-actions released this 16 Sep 11:00

epoch-next pre-release at dbea3eb

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Changes since epoch-2026.8 (145 commits):

  • T2122: Windows trunk red: TestProgressRunDeadlineKillsTheChild asserts a killed child reports exit -1, but Windows has no signals — TerminateProcess yields exit 1, which also lets a timed-out child satisfy runProgressFailing
  • T2119: macOS trunk red: TestProgressFlagBeatsEnv fails under full bin/verify with empty child output — and the assertion discards the child's stderr and exit error, so the failure cannot be diagnosed
  • T2116: Windows trunk red: the T2108 "never consult PATH" rule was applied to product code but not to the tests — three TestRunReleaseWinlink* tests still gate on Which("llvm-dlltool") and fail on any host with LLVM installed; bin/verify also still reaches for ANTLR over the network
  • T2120: macOS bundled-SDK materialization is not concurrency-safe: two promise processes sharing a PROMISE_HOME race on the libSystem.tbd symlink and one aborts the compile with "file exists" — the T2119 failure, now with its stderr
  • T2108: Toolchain discovery must never consult the system PATH: findLLVMTool's Homebrew/PATH fallbacks make build results depend on incidental host state, and the docs present them as conveniences
  • T2107: darwin-arm64 CI red: four loopback TCP tests in modules/http/server_test.pr each block past their 10s budget, then wedge teardown — blocking the epoch-2026.9 cut
  • T1609: macOS red trunk: Xcode 27's SDK is unparseable by our lld (arm64e.x1) and the bundled stub omits _clock_gettime — on an Xcode 27 host there is NO working link path for promise test
  • T2094: Windows CI red — src_dir_test.go asserts cwd by spelling, and resolvedDir expands 8.3 short names that getcwd does not
  • T2102: integration gate never builds before measuring: builds/checked:go/tested:go/formatted:promise run against whatever build artifacts are on disk, so a change can pass integration against a stale build (or the gate aborts on a clone without them)
  • T2104: bin/vet (rename: bin/check) and checked:go must be one implementation in two modes — today they are two spellings that disagree, and the gate vets the generated parser bin/vet excludes
  • T2095, T2096: bin/clean --shared clears only ~/.promise/cache; clean tests pass on Windows
  • T2093: tested:go still skips the tools/build Go suite after T2084 landed — every integration run reports incomplete and no gate checks the tools tests bin/verify runs
  • T2084: tools/build/common tests act on machine-global state: TestRunVerify_AllKnownFlagsAreValid deletes ~/.promise when run outside bin/verify, and the clean tests run a real go clean -testcache that expires every cached Go test result (next bin/verify reruns all compiler Go tests, ~4 min)
  • T2087: bin/verify was red on windows-amd64 — a metric nothing judged on two targets, and an oracle that stopped discriminating
  • T2026: bin/gate speaks the gate contract — --list, --envelope, and bin/run as the judge
  • Untrack .workspace/project.json — per-clone state committed by accident
  • T1510: WebIDL bindgen: resource wrappers always emit a handle-releasing drop, so seeding/rewrapping a handle double-releases it (no borrowed/non-owning handle)
  • T1940: Failable unwrap (?^ / ?! / bare auto-propagate) leaks native handles — trackUnwrappedFailableTemp never got T0664's Channel/Ref/Mutex/Task/Weak/MutexGuard dispatch
  • T1521: promise run: expose a tool's own source directory (distinct from cwd; absent for exec)
  • T1514: Heap user-type INTERMEDIATE temp in a generator-call argument list leaks — for-in's T0088 blanket heap-temp flag clear frees nothing
  • T1416: Failable [] getter read in expression position is unchecked by sema → codegen panic (store {i1,T,i8*} into T*)
  • T1963: modules/io/io_test.pr uses fixed temp-file paths, so two concurrent runs on one machine corrupt each other — the failures look exactly like a real io defect and have already misled a bisect
  • T1420: for x in gen() ? e { ... } (inline error handler on a for-in iterable yielding a stream) generates invalid LLVM phi, or silently swallows the mid-stream error
  • T2003: Adopt the workspace check tools: hooks to tool-guard and precommit-guard, then delete the local guard and precommit twins
  • T1924: Define the reconciliation pass, then run it for annotations.md and normative.md
  • T2048: Windows red trunk — the guard resolved shell-absolute paths against cwd, and TestMakeCommands asserted IsAbs on a volume-less fixture
  • T1961: Flaky: TestKillChildrenKillsTheWholeTree (tools/build/common) — "KillChildren did not stop the child" under full-verify load
  • T1670: http.Server: a malformed request closes the connection silently instead of replying 400 Bad Request
  • T1813: guard's stale check resolves the repo root from cwd, so a scratch dir with a catalog.toml wedges every Bash call — including the ./make it tells you to run
  • T1428: yield inside a go { } block nested in a generator body is accepted by sema and emits invalid LLVM IR (use of undefined value '%yield_slot.addr')
  • T1516: Mut-ref (T ~p) parameter on a generator reads garbage after the first resume — the reference is not preserved across the coroutine suspend
  • T1734: cover the three protocol properties the sweep relied on but never tested
  • T1885, T1905: Calling a native requirement through a boxed structural view jumped to address 0; a same-named getter/setter pair emitted two view adapters under one symbol
  • annotationcheck: read docs/annotations.md with CRLF endings — a Windows checkout failed TestAnnotationCoverageReconcilesThisCheckout
  • Remove the commit, resolve and stress skills — cut-release is the one still in use
  • T1920: Normative annotation reference: docs/annotations.md as the single source of truth, plus a docscheck that reconciles it against the compiler's tables
  • T1632: Ban timing-based test synchronization — document the rule and sweep sleep-as-sync out of the test suite
  • T1515: Closure-env INTERMEDIATE argument (a lambda consumed by a nested borrowing call) leaks on the ordinary call path and double-frees through a generator call
  • T1513: promise update --force / --reinstall are unreachable — runUpdate switches on the un-normalized -- spelling, so the documented flag exits 1
  • T1962: bin/commitgate decides gate-value freshness from wall-clock age (10*time.Minute) instead of a worktree content hash — a clean verify goes "stale" while the tree is byte-identical, and this synchronizes on time, which the engineering guide forbids
  • T1612 on Windows: SChannel sent only the leaf and rejected a peer's chain — both stores it was handed are stores it never reads
  • T1887: Boxing a MutexGuard[T] as Closer kills the process — no method call needed
  • T1769: macOS/Secure Transport: TLS server handshake blocks forever on a non-TLS peer that stops sending — Linux and Windows reject it immediately
  • T0533: Cross-compile codegen backend: --target flag + triple-aware opt/llc/PAL + linker dispatch + target-keyed cache
  • T1612: A TLS server sent only its leaf certificate — every backend dropped the issuers in a fullchain.pem
  • T1667: codegen.resolveTypeRefToType duplicates sema's resolveType — both must be edited in lockstep for every type-syntax change
  • T1583: Codegen: fold the remaining ~18 inline IsStructural() && !IsValueType() spellings into isStructuralView / isNonValueStructuralType
  • T1458: Cross-module generic dispatch: a std generic monomorphized during an earlier module's compile cannot see a later module's method stubs
  • T1929: Windows link failure: a generic native std type instantiated only inside a module (MutexGuard[int]) gets a main-IR typeinfo whose drop pointer references a .drop that is never synthesized — lld-link: undefined symbol MutexGuard[int].drop
  • T1734: Declare is explicitly on every protocol implementation in std and the catalog; fix the near-misses it exposes
  • T1397: Enforce §17.4 — a borrow may never cross a go spawn boundary
  • T1967, T1968: replace_content loses to two open-to-lock races — slot ownership needs file identity, and Windows locks must not cover data
  • Two tests counted platform noise as signal, and were red on Windows for it
  • T1930: Windows cannot rename over an open file — MoveFileEx needs a POSIX-semantics fallback, not FILE_SHARE_DELETE
  • T1929: MutexGuard[T] instantiated only inside a module gets a drop stub nothing defines, and a typeinfo pointing at it
  • T1926: Map and Set are recovered by type identity in clone.go to answer a question their own structure determines — and any user-written container escapes the rule entirely
  • T1900: Bare failable call as a match scrutinee never auto-propagates — codegen crash, or a silent segfault for a heap scrutinee
  • gitignore .mcp.json, which workspace setup writes
  • T0990: obj.field.push() re-evaluates the field owner (double-eval) — wrong-slot store-back for impure owner expressions
  • T1459: for-in over a subtype that inherits next() from its parent panics: "codegen: undeclared method Child.next"
  • T1896: Bare failable call as a for-in subject crashes codegen — stmt_forin.go never consults AutoPropagateExprs
  • Vendor the org docs corpus at docs-2026.2 (#62)
  • archived are only superseded documents (#61)
  • Complete the `unsafe / T* removal: four references survived in packages the first sweep missed
  • Assertions are native-only: sendable / `sharable may not be written on a Promise type
  • Remove `unsafe (annotation), unsafe { } (block), and the raw pointer type T*
  • T1921: interior requires native — user types may not take the shared-borrow exemption
  • T1413: Eliminate the annotation/hardcode duality: type capabilities must be declared once in modules/std/*.pr, never re-enumerated as hardcoded lists in sema
  • docs: `builtin(role) — the compiler's dependence on a library type is declared, not sniffed by name
  • docs: memory-model.md — what may allocate, and why ever...
Read more

Promise epoch 2026.8

Choose a tag to compare

@github-actions github-actions released this 24 Aug 03:04

Promise epoch-2026.8

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Promise epoch-2026.8 — 90 commits since epoch-2026.7.

The theme of this epoch is the network stack: TLS lands on all three native
platforms, the HTTP client and server become production-shaped, and the
scheduler bug that made a concurrent server deadlock on a small machine is
fixed at the root.

  • New tls module (T0077) — TLS 1.2/1.3 over TCP. TlsConfig
    (create/insecure, custom CA, client certificate, minimum version),
    TlsStream (satisfies Reader/Writer), TlsListener (bind/accept),
    and TlsError/TlsErrorKind. One Promise-level API over three native
    backends: Linux links a vendored musl-static OpenSSL (T1596),
    macOS uses Secure Transport (T1599), Windows uses SChannel
    (T1598). WASM raises TlsError(kind: unsupported) rather than pretending.
  • HTTP client essentials (T0447) — redirect following, keep-alive
    connection reuse, and gzip response decoding.
  • Concurrent HTTP server (T1519) — one goroutine per connection with
    keep-alive and bounded concurrency (max_connections,
    max_keep_alive_requests) plus draining graceful shutdown.

T1685 was the most consequential bug in this epoch. Blocking operations
reached from ordinary library code — every function in modules/std and the
catalog modules — took the OS-thread-blocking path rather than parking the
goroutine, because that choice was made from a compile-time property that is
only true inside a go body. With the M pool fixed at num_cpus and no way to
grow, num_cpus concurrent blocking calls wedged the entire runtime: a
Promise HTTP server on a 4-core host deadlocked once four connections were
simultaneously in TcpStream.read.

The scheduler now tolerates blocked threads. Every library blocking wait
(channel send/recv, select, Mutex.lock, netpoll, for-in over a channel) hands
off its P around the wait, and the M pool grows on demandstartm either
reuses a pooled spare thread or creates one, capped at 10,000. Threads left
without a P park as spares and are rejoined deterministically at shutdown.

This also resolves T1636 (the http_test.pr hang) and explains why it only
ever reproduced on 4-vCPU CI runners and never on a developer machine. The
regression test derives its blocker count at runtime, so it fails on an
unfixed compiler on any host.

A broad sweep of ownership and codegen defects, most of them silent
miscompiles rather than crashes:

  • Double frees — returning a heap element out of a fixed-array (T1488) or
    Vector (T1491) parameter; a pre-coerced view element in a structural array
    literal (T1558); moving the same variable out on every loop iteration, which
    ownership accepted with no diagnostic (T1498).

  • Use after free — a heap-allocating parameter default passed to a
    generator was freed at statement end while the coroutine read it lazily
    (T1467), including the structural-view adapter variant (T1486).

  • Silently discarded writes — a value type read out of a vector index and
    passed to a ~ parameter dropped the mutation into a temp (T1585).

  • wasm32 silent miscompile — the emitted DataLayout disagreed with the
    toolchain's, so LLVM 22.1 relaid out every i128-bearing struct (T1544).

  • Codegen panics — value-type inheritance (T1527) and its optional-subject
    (T1552) and structural-parent upcast (T1550) variants; a value field whose
    type is imported from another module (T1542); string interpolation of a
    subtype inheriting format() (T1551); default getters inherited from a
    generic structural interface (T1559); lambdas capturing a mut-ref parameter
    (T1589); a value newtype's inherited ~this method (T1588).

  • use is file-scoped (T1686) — imports were module-scoped, so one file's
    use silently supplied aliases and anonymous-import symbols to every other
    file in the module. Directly contrary to the self-contained-readability goal:
    a file's imports are now visible in that file.

  • Callback-style APIs are writable (T1634, T1640) — void-returning lambdas
    emitted malformed IR, the ()-return and !(…) -> T function-type surface
    did not parse, and closures were unconditionally non-sendable.

  • Fixed-array repeat literal [x; n] (T1579) — bulk initializer for sized
    arrays.

  • New crypto module — SHA-256 in pure Promise (T1566, T1580) and
    constant_time_equal (T1565).

  • New encoding module — RFC 4648 hex (T1574).

  • linux-arm64 can link again (T1676)modules/tls failed with undefined
    LSE outline-atomics helpers. Promise now pins Alpine's compiler-rt builtins
    for both Linux arches and splices the archive onto every musl link line;
    neither the outline-atomics helpers (restricted register convention) nor
    binary128 soft-float can be honestly provided in IR. Both blobs are hosted
    rather than resolved from an ephemeral upstream URL (T1677).

  • Windowsbin/verify/bin/format/pre-commit exceeded the 32,767-char
    CreateProcess limit on the file list (T1582); tests split output on \n
    against \r\n (T1637) and hardcoded POSIX separators (T1696); gates
    bypassed the short-repo-dir helper (T1638) and silently scoped themselves
    out on a malformed tree (T1695).

  • wasm32-web — stdin reads reported EOF (T1586), plus bindgen and base PAL
    runtime glue fixes.

  • CLI diagnostics (T1604) — a typo'd --relase silently produced a debug
    build; unknown flags and stray positionals are now rejected.

  • promise run passes arguments (T1426) via the -- convention, and
    file-vs-project target resolution is unified across build/run/emit-ir
    (T1603).

  • Remote dependency in a repo subdirectory (T1524).

  • Test harness honesty (T1639) — a wedged test binary was neither timed
    out nor correctly reported: the per-test timeout never fired and the failure
    was mislabeled "compilation timeout", sending readers to the wrong
    subsystem. Timeouts now name the offending test.

  • No binaries in history (T1620) — pre-commit rejects any staged file with
    a NUL byte in its first 8 KB, or over 1 MB, unless explicitly declared binary
    in .gitattributes.

compiler-rt 21.1.2-r0 dependency blobs

Pre-release

Choose a tag to compare

@djabi djabi released this 23 Aug 16:20

Content-addressed dependency blobs for compiler-rt 21.1.2-r0. Verifiable via tools/build/blobs.json.

openssl 3.5.7-r0 dependency blobs

Pre-release

Choose a tag to compare

@djabi djabi released this 19 Aug 16:11

Content-addressed dependency blobs for openssl 3.5.7-r0. Verifiable via tools/build/blobs.json.

Promise epoch 2026.7

Choose a tag to compare

@github-actions github-actions released this 13 Aug 23:18

Promise epoch-2026.7

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Promise epoch-2026.7 — stable.

This release lands two major language features — fixed-width integers up to 512 bits and failable goroutines — promotes linux-arm64 to a supported platform, and fixes a broad set of memory-safety and correctness bugs.

Large integer types. i128/u128, i256/u256, and i512/u512 are now first-class (see docs/large-integers.md): full arithmetic, division/modulo, constant .rodata vectors, and use as map values. Includes correct lowering of the __udivti3/__umodti3/__divti3/__modti3 runtime builtins on both Linux and Windows. (T0587, T1399, T1414, T1418, T1419)

Failable goroutines. go! { } spawns a coroutine whose body may fail, yielding a linear (must-use) failable_task[T]; the failable receive <-t surfaces the error at the await site. Both expression and block forms are implemented, with value semantics, linearity, <- drain over a failable_task[T][], and cleanup fully specified (language-design §17.2.1). (T1379, T1384–T1393, T1381, T1427, T1434)

linux-arm64 is now a release-gated platform, alongside linux-amd64, darwin-arm64, and windows-amd64. The aarch64 musl CRT and LLVM 22.1.0 toolchain are catalogued and self-fetched by bin/build, and a latent aarch64 libc struct-layout bug in the PAL is fixed.

io.File gains explicit open_read / open_write factories with a proper write-only (O_WRONLY) mode, replacing the readonly: bool parameter. (T1275)

Memory safety

  • for e in v.iter() over a vector of heap elements (string / Vector / heap user type) no longer double-frees. (T1440)
  • Read-modify-write of an optional-valued map (map[K, heap?]) no longer double-frees. (T1432)
  • Boxing a value into a module-declared structural interface no longer corrupts the heap. (T1462)
  • Nested while let over an owned optional no longer moves out of the binding (use-after-free). (T1436)
  • Structural-view / default-parameter leaks and a fixed-array-literal-argument leak fixed. (T1460, T1466, T1427, T1395)

Correctness

  • Unsuffixed integer literals are now range-checked — u8 a = 300; is rejected instead of silently wrapping to 44. (T1483)

  • Structural-view method adapters are named per view, fixing duplicate-function invalid IR. (T1477, T1468)

  • Optional-chain getter access (opt?.getter) no longer crashes. (T1421)

  • Incompatible if/match value-arm types are rejected in sema instead of producing invalid phi IR. (T1393)

  • Install path fixed — the GitHub latest release pointer no longer resolves to a dependency-blob release, so curl … | install.sh and install.ps1 work again; a new install gate guards against regressions. (T1493)

  • promise test reports a batch process that dies mid-run as INCOMPLETE (non-zero) instead of a silent success. (T1415)

  • Compile/link drivers no longer os.Exit deep in the call graph — temp files are cleaned up and a single tool crash no longer aborts the whole test run. (T1470)

  • Release tooling unifies commit pinning under --commit across ci/cut, fixes pinned-CI checkout, and rejects a dispatch that would cancel an in-progress run. (T1489)

  • bin/build no longer requires GitHub credentials to fetch public blobs, and no longer hard-requires a preinstalled musl-dev. (#7, T0530)

  • Meta-annotation parameters are now validated (unknown/stray/misordered params rejected). (T1449)

musl 1.2.5-r23 dependency blobs

Pre-release

Choose a tag to compare

@djabi djabi released this 12 Aug 16:24

Content-addressed dependency blobs for musl 1.2.5-r23. Verifiable via tools/build/blobs.json.

Promise epoch 2026.6

Choose a tag to compare

@github-actions github-actions released this 04 Aug 14:38

Promise epoch-2026.6

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Changes since epoch-2026.5 (31 commits):

  • T1374: Inherited default combinator through a MODULE-defined generic structural interface view segfaults (null vtable slot); T0862 fix is main-file-only
  • gates: bump test-count baselines for T1257 (host 9345→9357, wasm 8747→8759)
  • gates: refresh test-count baselines (host 8260→9345, wasm 6739→8747)
  • ci: raise the job timeout to 75m — Windows exceeds the 40m cap
  • T1257: Single-owner handle declared in classic-for INIT and consumed in the loop CONDITION segfaults / deadlocks (works for while / body-declared handle)
  • T1082: Add Go IR-shape unit test for T0806 force-unwrap temp-tracking skip
  • T1061: maybeRegisterStructuralFree may over-register free for borrow-returning structural operators/methods
  • T1070: Verify suffix-~ (mut-ref) and & operator params are runtime-safe
  • T1063: Correct release.yml comment about PROMISE_LLVM and the forge prebuilts cache
  • T1064: Nested-vector push: captured slot can dangle if an argument reallocates the outer vector
  • T1370: push() on a method-returned (rvalue) Vector with droppable elements double-frees — "invalid free (bad header magic)"
  • T1065: Nested push on Map-valued vectors panics with a cryptic codegen message
  • T1067: time: implement WASI realtime via clock_time_get instead of returning 0
  • T1068: time: support fractional-second ISO-8601 in DateTime.parse/to_string
  • T1069: Collapse redundant --dry-run/--no-upload flags on bin/release publish-install
  • T1369: Binary/compound operator with suffix-~ (mut-ref) operand param miscompiles: value passed where pointer expected → segfault
  • T1072: Add timeout-minutes and a PR-cancel concurrency group to CI workflows
  • T1076: for-in over a Stream whose iter() returns a concrete iterator with drop() skips the user drop
  • T1077: Sweep orphan .tmp-* view-staging dirs during promise gc
  • T1079: Update stale file-level comment in gate_test_json.go
  • T1368: Non-optional as cast to T?: reading the subject before the optional result segfaults (borrow-view aliasing)
  • T1081: Ownership doesn't model the silent move of an Optional cast subject's inner
  • T1083: Add Arc/Weak member-source force-unwrap temp regression rows
  • T1088: Fix stale doc: winlink .lib are generated/gitignored, not committed under resources/winlink
  • T1345: `interior setter-receiver default doesn't apply to non-native types or enums (flag set after method resolution)
  • T1359: Value-type direct field assign through a non-addressable receiver (getter member) panics codegen instead of erroring/spilling (h.getter.x = v)
  • T1358: Value-type ~this method silently discards field/setter mutations (mutates a copy, not the caller's storage)
  • T1356: Value-type field mutation through a nested member / index receiver: direct assign panics codegen, setter silently no-ops (o.inner.x, vs[0].x, o.inner.prop=, vs[0].prop=)
  • T1343: Double-free: borrowed value pushed into a ~ mutable-borrow Vector is not rejected (Vector.push consume-check gap)
  • catalog: bump epoch to 2026.6 for ongoing development
  • T1341: Fixed-array read of an Optional structural-interface element double-frees the box (Showable?[N] → segfault)

Promise epoch 2026.5

Choose a tag to compare

@github-actions github-actions released this 30 Jul 12:47

Promise epoch-2026.5

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Changes since epoch-2026.4 (60 commits):

  • T1347: Fix residual HTTP serve() flake — tolerate benign shutdown-wake race; Content-Length-aware client read
  • T1353: Member/setter compound assignment double-evaluates a side-effecting receiver and orders RHS before target
  • T1354: Value-type property setter silently writes to a copy — mutation is lost (v.prop = x / v.prop += x no-op)
  • T1090: Align compound-assignment eval order between [:] and [] paths
  • T1348: Embedded-module cache extraction races under concurrent bin/promise invocations ("embedded_modules/net/promise.toml: no such file")
  • T1346: Numeric literal not adapted through an Optional element type in array/vector literals (f64?[] = [1,2], f64[2]?[] = [[1,2]])
  • T1349: Returning vec.iter() (or any structural iterator borrowing a local) that escapes its scope is not rejected — dangling borrow leaks/segfaults
  • T1350: Consuming a generator's .iter() result (Generator[T] upcast to Iterator[T]) segfaults — gen(n).iter().collect() / Iterator[int] it = gen(n).iter()
  • T1344: Mutating method through a shared borrow of a structural interface value bypasses the T1053 shared-borrow mutation check
  • T1336: Bare-statement if b {1} else {} (value arm + void arm, no value hint) emits malformed IR ("PHINode should have one entry for each predecessor")
  • T1342: Optional fixed-array element type not coerced element-wise in array/vector literals (int[2]?[] = [[1,2],[3,4]])
  • T1053: Decide whether RefNone implicit-this mutators should be blocked through & shared borrows
  • T1340: Codegen panic (slice bounds out of range) when a move-out enum-ctor var-decl is a leading statement in a block-value arm with a live sibling ctor temp
  • T1337: Inferred var decl (r :=) from a void-typed / diverge+void if/match panics codegen ("nil value for inferred var decl")
  • T1238: T1160 follow-up: unreachable peel arms + defensive nil guards in closureResultMayAliasCallInput
  • T1297: Fixed-array literal of vectors is not coerced element-wise to optional element type (int[]?[2] = [[1,2],[3,4]])
  • T1305: Discarded fresh-constructed structural return leaks when the call has a heap-typed argument (T1294 conservative fallback)
  • T1338: Inline enum-ctor temp buried as a by-value arg INSIDE a moved-out enum ctor's own arguments leaks its payload (wholesale enumCtorTemps clear)
  • T1339: Sibling by-value enum-ctor call-arg temp leaks when a LATER arg diverges via return/raise (T1331 analog)
  • T1326: Enum-ctor temp in one arm of a branch (match/if) moved out as the enum result leaks the by-value call-arg payload of a nested call
  • T1327: Discarded module-qualified free-function call returning a fresh structural value leaks the box (mod.fresh_return();)
  • T1335: Value-position if/match with one diverging arm and one void (non-diverging) arm panics codegen ("nil value for typed var decl")
  • T1332: if/match in value position where BOTH arms diverge (return/raise) panics codegen ("nil value for typed var decl")
  • T1334: Flaky WASM per-test timeout: tests/value_types/optional_test.pr exceeds 10s under full parallel wasm suite load
  • T1331: Block-value arm used as non-last call arg that diverges via break/continue leaks the enclosing call's sibling heap temp
  • T1330: if-expression with a diverging arm (return/raise) in value position produces nil/malformed IR (codegen panic) — match handles it correctly
  • T1329: Nested block-value body (if/match/? handler) with a leading statement drains the enclosing call's sibling heap temps mid-body → use-after-free
  • T1325: Sibling heap temp freed too early when a ? {} handler recovers-and-continues as a non-last call argument
  • T1322: Flaky: modules/http/http_test.pr test_server_serve — "panic: connection reset by peer"
  • T1323: Inline enum-ctor temp passed by value into a call whose RESULT is also an enum, bound with a var-decl (q := f(E.V(heapStr))), leaks the payload
  • T1272: Temporary (call result / constructor) passed into a ~ (MutRef) parameter leaks — temp is never dropped
  • T1317: Inline enum-constructor temp with a droppable payload, passed by value into a call that is directly returned, leaks the payload
  • T1321: Temporary structural-interface method receiver (getter/call result) leaks — stderr.write_line(...) leaks one allocation per call
  • T1273: Expose the standard streams: stdin / stdout / stderr getters in std (there is currently no way to write to stderr)
  • T1314: Unconsumed generator (stream[T]) passed as a function parameter leaks
  • T1316: Owned named string moved into a structural-interface struct field (Type(field: move s)) leaks — constructor field boxing clones instead of moving
  • T1282: Owned string boxed to a structural interface via a move position (return / move-param) leaks — dupString clones but the move-site cleared the source's drop flag, orphaning the original heap string
  • T1315: Storing a generator (stream[T]) value in a container element or struct field segfaults
  • T1313: Binding a generator to a local variable (s := gen(3);) segfaults
  • T1306: Discarded generator call leaks its box — gen(3); as a statement never frees the boxed iterator adapter
  • T1311: Discarded method call f.make(Counter(...)); segfaults — owned structural rvalue-temp ARG returned by value from a method, unbound result
  • T1310: Discarded method call f.make(s); double-frees — owned structural ARG returned by value from a method, unbound result
  • T1308: Method-call r := f.make(s) double-frees — owned structural ARG returned by value aliases caller, T1304 fix skips method calls
  • T1304: Binding-path r := pass_through(c) double-frees — owned structural param returned by value aliases the caller's still-owned argument
  • T1294: Discarded structural-interface-returning call leaks its box — show(1); as a statement never frees the boxed instance
  • T1303: Cross-module generic droppable type-param field escape (return this._v) double-frees — T1301 ownership check only sees same-unit instantiations
  • T1302: Borrow-returning getter that unwraps an Optional field (get val T& { return this._v!; }) leaks the field's box
  • T1301: Generic type-param field (V?/V) returned by value from a droppable owner double-frees when V is a drop-bearing heap-user type (sema skips via ContainsTypeParam, codegen doesn't clone)
  • T1299: Generic user-defined []= setter storing a structural-interface / Optional value segfaults (raw value passed to setter, no view-coercion)
  • T1300: Overwriting a populated Optional-structural-interface member field leaks the old view box (h.s = Counter(...) when s: Sink? already set)
  • T1298: Sema rejects implicit widening of a subtype to Optional-of-structural-interface (Sink? s = Counter(...))
  • T1279: Value/primitive coerced to a structural interface in a constructor-field or Vector.push argument is not view-coerced — codegen panic ("store operands are not compatible")
  • T1287: Vector[structural-interface] index-assign leaks the overwritten box — drop-old chain in genVectorIndexAssign has no structural branch
  • T1295: Mutating an inner container through a mutable optional-unwrap place on a Vector[Optional[Vector[T]]] element leaks (v[i]!.push(x))
  • T1291: Vector[structural-interface?] (optional-structural element) leaks its boxed elements — element drop skips __promise_structural_drop for the Optional-wrapped element type
  • T1292: Map[K, structural-interface] leaks its stored value boxes — map value drop never routes through __promise_structural_drop
  • T1289: Optional-unwrap binding leaks a structural-interface box when the source is an index-operator (if x := r[i]) or a getter (if x := r.slot) — isFreshOwnedStructuralRHS only recognizes Call/Unary/Binary
  • catalog: bump epoch to 2026.5 for ongoing development
  • T1288: Optional-unwrap binding (if x := opt) leaks a structural-interface box — unwrap-binding drop site has no __promise_structural_drop routing
  • T1284: Vector[structural-interface] leaks its heap-boxed elements — element drop never routes through __promise_structural_drop

Gate override reason: next already at b36126e

Promise epoch 2026.4

Choose a tag to compare

@github-actions github-actions released this 15 Jul 11:36

Promise epoch-2026.4

Install: https://github.com/promise-language/promise/blob/main/docs/installing.md

Changes since epoch-2026.3 (36 commits):

  • T1280: String coerced to a structural interface and bound to a local (via return) segfaults on drop — structural drop misreads the string instance's field 0 as a typeinfo header
  • T1276: Value type boxed as a structural interface and returned from a function is a use-after-return: dangling stack box → wrong field reads + fatal: invalid free
  • T1093: Add a regression test asserting heap-user-type narrowed enum field escape is sema-rejected
  • T1270: isDroppableOwner misses *types.Instance with *types.Enum origin — generic enum narrowed heap-user-type field escape not rejected
  • T1266: Segfault: fixed-size array element read of a value-copying container of closures (genArrayIndex path)
  • T1267: Bare failable call in a match expression arm bypasses auto-propagation — silent error swallow (void position), codegen panic (value position)
  • T1269: Return-alias safety net misses borrowed-param args: a borrow-derived call result moved into owned storage double-frees
  • T1268: sort() on a borrowed vector returns an aliasing buffer — moving the result into a struct field double-frees (fatal: invalid free)
  • T1265: Closure-aggregate borrow escapes via auto-move into a native consuming arg (Vector.push) → double-free/SEGV — ownership rejects index-assign/return/explicit-move but not last-use move into a by-value native param
  • T1234: T1160 sibling: discarded closure result of an optional-returning call (() -> int)? is never tracked → leaks env
  • T1242: T1160 follow-up: closureResultMayAliasCallInput's ParenExpr and AutoCloneExpr peel arms are unreachable dead code
  • T1160: Discarded closure-returning call result leaks its heap env (function-typed call results not tracked as env temps)
  • T1263: Segfault: bare Vector/struct-field direct read of a value-copying container of closures (native genVectorIndex / genFieldAccess paths)
  • T1264: Segfault: enum variant carrying a Vector/Map/Set of closures read from an aliasing container — dup zeroes the closure envs (T1262 sibling on the enum path)
  • T1259: Segfault: reading an enum-with-closure-variant value out of a by-value container (Vector/Map) and calling the closure — env corrupted
  • T1262: Segfault: a BARE Vector/Map/Set of closures read from an aliasing container (Map) — null-dup/dupVector zeroes the closure env
  • T1260: Segfault: struct holding a Vector-of-closures deep-copied on Map read — auto-dup clones the closure vector that direct .clone() correctly rejects
  • T1261: go-call form go recv.method(this.field) (viaBlock path) doesn't snapshot this → UAF/garbage read (T1219 sibling on the call path)
  • T1222: go-block this capture in a generic type's method mis-splits the .goroutine.N ramp → undefined-symbol link error (isolated) / UAF segfault (batched)
  • T1230: Segfault: reading a struct-with-closure-field value back from a Map (m[k]!.f()) — env pointer corrupted
  • T1258: Direct call on enum getter returning a function type panics in codegen (enum analog of T1253)
  • T1096: closureAggregateBorrowSource getter exclusion omits enum getters (codegen divergence)
  • T1127: promise version: gate commit SHA on the next channel only
  • T1132: Module-qualified enum destructure pattern rejects _ wildcard binding (parser)
  • T1133: Bare fieldless variant of a module-qualified enum not recognized in match exhaustiveness (sema)
  • T1256: T1255 residual: alias-handle reuse in a loop CONDITION / classic-for update / for-in iterable is a silent UAF (checked outside the loop frame)
  • T1255: T1137 residual: flow-insensitive reuse heuristic misses loop-reuse (silent UAF) and over-rejects mutually-exclusive branches
  • T1137: Generic identity over a single-owner handle (task/Mutex/MutexGuard) UAFs when the source is reused after the aliasing call
  • release: retry transient gh release download when fetching LLVM dep blobs
  • T1254: Generic user-defined operator returning a closure: lambda body mis-emitted in per-instance .bc → undefined-symbol link error (isolation) or lambda-number collision / silent miscompile (batch)
  • T1229: Discarded closure result from an operator call or ? e {} error-handler expr leaks its env (T1160's default branch)
  • T1241: Destructuring an owned tuple out of a getter / user-defined [] leaks its heap fields (srcOwned=false for Index/Member)
  • T1243: Windows 8.3 short-path: BuildGateOutput/buildInstallGateOutput "under base" check fails when temp path mangles (RUNNER~1 vs runneradmin)
  • T1250: Module-level getter returning a heap user type leaks when used as a bare temporary (lib.pt.x)
  • catalog: bump epoch to 2026.4 for ongoing development
  • T1252: Codegen panic: invoking an instance getter that returns a function type (obj.getter()) — no method / env leak