Releases: promise-language/promise
Release list
Promise epoch 2026.9
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:
`interiorrequires`native(T1921) — a user type may not take
the shared-borrow exemption.`sendable/`sharableare 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 whatmodules/std/*.pralready 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);checkGoBlockCapturesmissed three AST shapes codegen does walk, so
a closure env could escape and non-sendable values could cross the spawn
boundary (T1658); readinge.messagein an untaken error handler inside a
goroutine segfaulted after the first round (T1605). Borrows may now never
cross agospawn boundary at all (T1397, §17.4). - Heap corruption —
Channel.sendof a temporary closure corrupted the env,
so the receiver read zeroed captures and then died infree(T1655);
indexing two nested temporary arrays in one expression aborted with
"invalid free" (T1711); boxing aMutexGuard[T]asCloserkilled the
process with no method call needed (T1887). - Leaks — failable unwrap (
?^,?!, bare auto-propagate) leaked native
handles forChannel/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 throughRef[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_configfor custom CAs
and mutual TLS, andServer.bind_tlsfor 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
TlsServerConfigserved concurrent handshakes (T1766). A malformed HTTP
request now gets a400 Bad Requestinstead 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) — atomicreplace_content/replace_bytes
via rename, whole-file advisory locking, andsync/Dir.sync, specified in
docs/io.mdso 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 goroutines —
go!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_memmoveand___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
promiseprocesses sharing a
`PROMISE_HOME...
Promise epoch-next (pre-release)
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 -testcachethat 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 —trackUnwrappedFailableTempnever 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.pruses 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.mdandnormative.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
./makeit tells you to run - T1428:
yieldinside ago { }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
nativerequirement 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.mdas 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/--reinstallare unreachable — runUpdate switches on the un-normalized--spelling, so the documented flag exits 1 - T1962:
bin/commitgatedecides 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]asCloserkills 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
nativestd type instantiated only inside a module (MutexGuard[int]) gets a main-IR typeinfo whose drop pointer references a.dropthat is never synthesized — lld-link: undefined symbolMutexGuard[int].drop - T1734: Declare
isexplicitly 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
gospawn 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:
MapandSetare recovered by type identity inclone.goto answer a question their own structure determines — and any user-written container escapes the rule entirely - T1900: Bare failable call as a
matchscrutinee 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-insubject crashes codegen —stmt_forin.gonever 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 requiresnative — 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...
Promise epoch 2026.8
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
tlsmodule (T0077) — TLS 1.2/1.3 over TCP.TlsConfig
(create/insecure, custom CA, client certificate, minimum version),
TlsStream(satisfiesReader/Writer),TlsListener(bind/accept),
andTlsError/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 raisesTlsError(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 demand — startm 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 everyi128-bearing struct (T1544). -
Codegen panics — value-type inheritance (T1527) and its optional-subject
(T1552) and structural-parent upcast (T1550) variants; avaluefield whose
type is imported from another module (T1542); string interpolation of a
subtype inheritingformat()(T1551); default getters inherited from a
generic structural interface (T1559); lambdas capturing a mut-ref parameter
(T1589); a value newtype's inherited~thismethod (T1588). -
useis file-scoped (T1686) — imports were module-scoped, so one file's
usesilently 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!(…) -> Tfunction-type surface
did not parse, and closures were unconditionally non-sendable. -
Fixed-array repeat literal
[x; n](T1579) — bulk initializer for sized
arrays. -
New
cryptomodule — SHA-256 in pure Promise (T1566, T1580) and
constant_time_equal(T1565). -
New
encodingmodule — RFC 4648 hex (T1574). -
linux-arm64 can link again (T1676) —
modules/tlsfailed 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). -
Windows —
bin/verify/bin/format/pre-commit exceeded the 32,767-char
CreateProcesslimit 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
--relasesilently produced a debug
build; unknown flags and stray positionals are now rejected. -
promise runpasses arguments (T1426) via the--convention, and
file-vs-project target resolution is unified acrossbuild/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
Content-addressed dependency blobs for compiler-rt 21.1.2-r0. Verifiable via tools/build/blobs.json.
openssl 3.5.7-r0 dependency blobs
Content-addressed dependency blobs for openssl 3.5.7-r0. Verifiable via tools/build/blobs.json.
Promise epoch 2026.7
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 letover 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/matchvalue-arm types are rejected in sema instead of producing invalid phi IR. (T1393) -
Install path fixed — the GitHub
latestrelease pointer no longer resolves to a dependency-blob release, socurl … | install.shandinstall.ps1work again; a new install gate guards against regressions. (T1493) -
promise testreports a batch process that dies mid-run as INCOMPLETE (non-zero) instead of a silent success. (T1415) -
Compile/link drivers no longer
os.Exitdeep 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
--commitacrossci/cut, fixes pinned-CI checkout, and rejects a dispatch that would cancel an in-progress run. (T1489) -
bin/buildno 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
Content-addressed dependency blobs for musl 1.2.5-r23. Verifiable via tools/build/blobs.json.
Promise epoch 2026.6
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
ascast toT?: 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
~thismethod 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
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 += xno-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
structuralinterface 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-
thismutators 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+voidif/matchpanics 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/matchwith one diverging arm and one void (non-diverging) arm panics codegen ("nil value for typed var decl") - T1332:
if/matchin 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/continueleaks 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) —matchhandles 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/stderrgetters 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(...)whens: 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
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
matchexpression 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 snapshotthis→ UAF/garbage read (T1219 sibling on the call path) - T1222: go-block
thiscapture in a generic type's method mis-splits the.goroutine.Nramp → 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 downloadwhen 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'sdefaultbranch) - 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