Skip to content

Latest commit

 

History

History
113 lines (73 loc) · 13.4 KB

BETA.md

File metadata and controls

113 lines (73 loc) · 13.4 KB

Ion beta readiness contract

Ion is currently a 0.x language and toolchain. This document defines what the project means by a future beta release: a narrow, documented compatibility surface rather than a promise that every experimental feature is complete.

Beta compatibility window

For a beta tag, Ion should keep programs written against the stable beta subset compiling for the rest of the beta line unless a release note explicitly calls out a breaking change. Breaking changes require at least one of:

  • a new minor version while Ion remains 0.x;
  • a migration note in CHANGELOG.md;
  • an unstable-feature escape hatch documented in this file or ION_SPEC.md.

Stable beta subset

The stable beta subset is the part of Ion that examples, CI, and the standard library may rely on without an unstable marker:

  • ownership, moves, drops, no-escape &T / &mut T, and borrow conflicts;
  • functions, structs, enums, type aliases, modules, imports, and visibility;
  • primitive numeric and boolean types, arrays, slices, String, Vec<T>, Box<T>, and Result<T, E>;
  • if, while, for, loop, break, continue, match, select, guards, defer, scope, and postfix ? on Option/Result and on an owned enum with one success variant;
  • FFI through extern "C" and unsafe;
  • channels, try_send / try_recv, select, spawn / JoinHandle<T> / join, scope, protocol endpoints, and structural Send;
  • owned File streaming I/O and stdlib/fs.ion whole-file read;
  • ion-build projects with ion.toml fields documented in ION_SPEC.md.

0.1.24 is a breaking 0.x channel change: recv returns Option<T>, send returns SendResult<T>, clone_sender makes MPSC real, and channel<T>(cap) sets capacity. Last sender drop unblocks recv with None. See CHANGELOG 0.1.24.

0.2.0 is a breaking 0.x contract and language-surface change: wrapping arithmetic, abort panics, UTF-8 String, match ownership join, Vec::set as SetResult, joinable spawn, select, nested tuples, and owned File. See CHANGELOG 0.2.0.

0.2.2 tightens generic Send and extern checking: unbounded T is not Send without T: Send, and extern linkage other than "C" is a compile error. See CHANGELOG 0.2.2.

0.3.0 adds capabilities, Drop, const, richer patterns, lasting borrows, and stdlib option, string, hash, map, math, path, env, and time. A lasting borrow stays live until the last use of every binding that holds it, so a later borrow of that place is a compile error. A Drop value cannot be partially moved. See CHANGELOG 0.3.0.

0.3.1 lowers Vec::get and Vec::pop to a stack Option in generated C and removes ion_vec_get, ion_vec_pop, and ion_option_from_raw. Ion source is unchanged. C generated by 0.3.0 for those calls must be regenerated. See CHANGELOG 0.3.1.

0.3.2 lowers Vec::push to a typed store in generated C. Growth is ion_vec_reserve_one when len >= capacity. ion_vec_push is removed. Ion source is unchanged. C generated by 0.3.1 for Vec::push must be regenerated. See CHANGELOG 0.3.2.

0.3.4 claims a channel slot with atomics on the success path and waits with pthread only when the buffer is full, empty, or disconnected. HashMap probes and for_each borrow slots with Vec::get_ref. ion_box_alloc and ion_box_free are inline malloc and free. Ion source for channels and Box is unchanged. Programs that link the runtime must relink. Programs that import stdlib/map.ion must be recompiled. C that called ion_box_alloc or ion_box_free from ion_runtime.o must be recompiled against this header. See CHANGELOG 0.3.4.

0.4.0 stores an Allocator in Vec, String, and Box. ion_vec_t and ion_string_t start with ion_alloc_t. A box allocation is that header followed by the value, and the Ion pointer still addresses the value. join on JoinHandle<T> returns T. scope joins handles still owned in the block. A move closure is a struct value. endpoint<Name>() is two crossed channels of one generated message struct. Ion call sites for Vec::new, Box::new, String::new, and channel<T>() are unchanged. C generated by 0.3.4 for Vec, String, or Box, and any C that assumed ion_box_alloc was a bare malloc, must be regenerated. Programs that link the runtime must relink. See CHANGELOG 0.4.0.

0.4.1 rejects a move closure that takes a non-Copy binding while a & or &mut of that binding is still in scope, including a reference that is never read. That program is BorrowConflict. A use of the owner after the reference's last use, outside a closure, is unchanged. This is not an ABI change. Relink is not required. See CHANGELOG 0.4.1.

0.4.2 fixes Arena::get_ref and File read, write, and close when the value is a field of a struct reached through & or &mut. Generated C takes the address of that embedded value. A local arena, an &Arena or &File parameter, and every other program are unchanged. This is not an ABI change. Relink is not required. See CHANGELOG 0.4.2.

0.4.3 rejects a reference assignment whose owner dies before the binding. That program is ReferenceEscape, including a get_ref copied out of the vector's block and a match arm that yields a reference to a local declared in the arm. A use that stays inside the owner's block is allowed. Same-scope reassignment, including &mut, type-checks and frees the previous owner when no other carrier holds that loan. This is not an ABI change. Relink is not required. Generated C for other programs is unchanged. See CHANGELOG 0.4.3.

0.4.4 keeps each live Sender and Receiver holding the channel until that drop finishes waking waiters. The channel is freed only when the last hold reaches zero. Programs that link the runtime must relink. Ion source is unchanged. Disconnect, blocking, SendResult, and Option are unchanged. See CHANGELOG 0.4.4.

0.4.5 rejects a method get_ref while that Option<&T> loan is live and a later &mut covers the same place. handle::insert and handle::remove after arena.slots.get_ref, and Vec::push after v.get_ref, are BorrowConflict. A disjoint field, such as vm.stack during vm.code.get_ref, stays legal. This is not an ABI change. Relink is not required. See CHANGELOG 0.4.5.

0.4.6 rejects Vec::push and handle::insert inside an if or else while a get_ref loan is still used later in that arm, in an outer block, or anywhere in an enclosing loop. The same rule applies to any lasting borrow, not only get_ref. A binding used only before the branch, with no later use and not inside a loop, stays legal. A disjoint field stays legal. This is not an ABI change. Relink is not required. See CHANGELOG 0.4.6.

0.4.7 drops the previous owned value when a local, field, or array element is replaced. The right-hand side is evaluated first. An already-moved place is not dropped again, and assigning a place to itself does not drop. Vec::get and Vec::get_ref on a moved vector are UseAfterMove, including as a match scrutinee. Programs that reassign a Box, String, Vec, struct, enum, File, or channel must be regenerated. The runtime is unchanged. Relink is not required. See CHANGELOG 0.4.7.

0.4.8 does not drop a place that the right-hand side of an assignment already moved, and it clears a partial move before the aggregate drop. That clear is not written after the store. A let may reuse a name; the previous binding is dropped if it still owns a value. Qualified get_ref shared-borrows the place of the reference argument, so a disjoint field stays legal in that form too. Programs that replace a Box, String, Vec, struct, enum, array element, or field, and programs that use qualified get_ref on a field, must be regenerated. The runtime is unchanged. Relink is not required. See CHANGELOG 0.4.8.

0.4.9 writes a captured binding through the closure's field, and a nested closure copies that field. A second closure that moves the same non-Copy binding is UseAfterMove. Programs that assign a captured binding or nest a closure must be regenerated. The runtime is unchanged. Relink is not required. See CHANGELOG 0.4.9.

0.4.10 drops a closure value when it goes out of scope, including after a call that consumed it. A capture the body left in place, or stored back into the closure, is dropped with that value. A discarded Receiver can then release its channel. Programs that hold a non-Copy capture in a closure must be regenerated. The runtime is unchanged. Relink is not required. See CHANGELOG 0.4.10.

0.4.11 drops an owned temporary at the end of the full expression that created it, including a comparison, a borrow, a field or len projection, and a discarded statement. An owned String passed where &str is expected stays with the caller. Programs that compare, borrow, project, or discard an owned temporary, and programs that pass an owned String to String::push_str, must be regenerated. The runtime is unchanged. Relink is not required. See CHANGELOG 0.4.11.

0.4.12 rejects a reference into an owned temporary when that reference is stored, assigned, or matched. The diagnostic is ReferenceEscape. A borrow used only as a call argument stays on that call. A loan belongs to the binding that was borrowed, so a later let of the same name does not conflict with the previous loan. A function that returns [T; N] returns that array by value. A nested call and Box::unwrap of an array use that same return. Programs that return an array, pass that return into another call, or unwrap a boxed array must be regenerated. Relink is not required. Programs rejected by the type checker that still compile do not need to be regenerated. See CHANGELOG 0.4.12.

0.4.13 keeps a loan when any reachable path still holds it, so a partial reassignment after if, match, select, or a loop is BorrowConflict. A moved array place is cleared with memset. A returned array is copied from _data into a named array before an index, a call, a struct, tuple, or enum field, Vec::push, Box::new, Box::new_in, or for. Elements that index did not move are dropped. An owned enum match drops fields a wildcard or .. left behind. A move in an if or while condition is cleared before either branch. Programs that move an array, consume a returned array, match an owned enum, or use if or while must be regenerated. Relink is not required. Programs rejected by the loan join that still compile do not need to be regenerated for that check. See CHANGELOG 0.4.13.

0.4.14 copies an array expression that is not a durable place into a named array before a subscript, an address, a brace element, or a move-clear. A nested array literal copies each element into its slot. An inner array moved out of a nested array is copied from that named array. The source expression runs once, and the clear of a moved element names that array. Programs that index a returned array of a dropping element, build an array literal whose elements are arrays, or move an inner array out of a nested array must be regenerated. The runtime is unchanged, so relink is not required. See CHANGELOG 0.4.14.

0.4.15 copies an array literal into a named array before a subscript or an address. An owning argument that is not a durable place, including an array field of a call, is copied the same way. for copies a field or subscript of a call, and a subscript whose index calls, once before the loop. A local array, a field of a local, and a literal index of a local stay in place. Programs that index an array literal, pass an array field of a call, or iterate a field or subscript of a call must be regenerated. The runtime is unchanged, so relink is not required. See CHANGELOG 0.4.15.

0.4.16 ends a loan generation at its last read. Assigning the binding starts the next generation, including on every fall-through path before a loop back edge. A match arm promotes a loan only when the arm result holds that pointer. Vec::get_ref, Slice::get_ref, Arena::get_ref, and the method forms share that rule. & or &mut on a field that is already a reborrow keeps that pointer. This is not an ABI change. Relink is not required. See CHANGELOG 0.4.16.

Unstable or constrained in beta

The following features may change shape before 1.0:

  • capture-free function literals and function-pointer coercions (a move closure is a struct, not a function pointer);
  • generic ergonomics with optional built-in trait bounds (Copy, Eq, Send);
  • byte-oriented string iteration;
  • AST-structured loop ownership joins without a full CFG (see ION_SPEC §5.2);
  • generated C layout details not covered by docs/ABI.md.

Compatibility policy

  • The compiler, bundled standard library, runtime C ABI, and ion-build manifest format are versioned together.
  • Public stdlib import paths such as stdlib/io.ion, stdlib/fmt.ion, stdlib/fs.ion, stdlib/result.ion, stdlib/handle.ion, stdlib/option.ion, stdlib/string.ion, stdlib/hash.ion, stdlib/map.ion, stdlib/math.ion, stdlib/path.ion, stdlib/env.ion, stdlib/time.ion, and stdlib/iter.ion should not be removed or renamed in a patch release.
  • Additions are allowed in patch releases. Breaking language, stdlib, runtime, or manifest changes require a minor version while Ion is 0.x.
  • Unsupported behavior inside unsafe remains outside the compatibility guarantee.

Platform support

Beta support is limited to platforms exercised in CI:

  • Linux with GCC or Clang-compatible C tooling.
  • Windows with MinGW GCC through Git Bash.
  • macOS (GitHub macos-14) with Clang-compatible C tooling.

MSVC is best-effort until CI covers it.