Library exports and callbacks passed text only as a pointer and length.
profile_format 2 adds the cstring class, a NUL-terminated `const char *`
(an i32 pointer in Wasm reactors), for export parameters, export results
and callback parameters. Parameters are copied in and decoded as UTF-8,
with U+FFFD for malformed bytes; a NULL pointer is the SC4012
host-contract trap. Results live in the result arena like string
results. A result or callback argument containing U+0000 traps instead
of being truncated.
Closes#615
Co-authored-by: ailuoku6 <23209876+ailuoku6@users.noreply.github.com>
An async generator that fell off its end, with a return type other than
void, settled its last next() one microtask turn after Node, so for await
loops over it also ended a turn late. The appended implicit return now
marks the completion as settled, like a bare `return;`.
return() at a suspended yield ran the generator's finally blocks before
awaiting the return value. The request now awaits the value first and
resumes the body on the next turn, and the completion that follows settles
without a further turn, also when a finally block yields or awaits first.
An explicit `return x` reached during that unwind still takes its own turn
to await x.
Array.fromAsync accepts typed async generator sources: each next() result
is awaited and its value used as is, a throwing or rejecting mapping
function closes the generator, and a rejected next() rejects the result on
the turn Node rejects it.
Float16Array is a native typed-array kind with IEEE 754 binary16 storage.
Stores round the number to nearest-even in one step from the double, as
Node does, including overflow to Infinity, subnormals, -0 and NaN; reads
widen exactly. The runtime converts with integer operations, so no target
needs half-precision hardware or compiler-rt support.
Construction, element reads and writes, ArrayBuffer views, fill, set,
subarray, slice, both sort orders, constructor values and checked-dynamic
storage work as for the other typed arrays. Math.f16round,
DataView.prototype.getFloat16 and setFloat16, and util.types.isFloat16Array
compile.
new DisposableStack() compiles to a native stack handle. use, adopt, defer,
move, dispose, disposed and [Symbol.dispose] are members of its dynamic
view, and the stack works with `using`. Disposal runs the resources in
reverse order, calls use() resources' dispose methods with the resource as
`this`, and raises a SuppressedError chain when more than one disposal
throws; a single failure is rethrown as thrown. Calls on a disposed stack
throw Node's ReferenceError, and invalid receivers, resources and
callbacks throw Node's TypeErrors.
use() of a class instance registers a function that calls the class's
[Symbol.dispose] method, and returns the instance at its static type; use()
of a union that includes class instances is refused. The stack is
collected with its callbacks when a callback captures the stack.
x instanceof DisposableStack compiles. Handles can expose symbol-keyed
members through a new symbol_get hook.
After socket.setEncoding("utf8"), Node passes strings to 'data'
listeners, while @types/node types the chunk as a Buffer. An inline
listener whose chunk is typed Buffer (annotated or inferred) received a
Buffer. When a program can call setEncoding on a socket, such listeners
now take the chunk as a checked dynamic value, so console.log, typeof,
string methods and concatenation behave as in Node, and Buffer-only
methods throw Node's TypeError. Programs without setEncoding on a socket
compile to the same IR as before.
- util.format %d and %i format bigint, symbol, null and undefined arguments
- util.format %j prints [Circular] for circular arguments
- util.types answers the remaining brand checks
- util.inspect prints WeakMap, WeakSet, Date and numeric typed array values as Node does
- util.inspect lowers the breakLength, compact and sorted options
- URLSearchParams iterators compile outside a for-of head
- URLSearchParams can be built from [string, string] tuple pairs
- querystring.stringify writes bigint values
- StringDecoder accepts an encoding known only at run time
- os.setPriority is lowered
- The EventEmitter leak warning reaches process 'warning' listeners on the next tick
- The events listener-count and max-listener helpers work over EventEmitter instances
- timers/promises setTimeout, setImmediate and scheduler.wait accept an AbortSignal
- timers/promises scheduler.wait and scheduler.yield are lowered
The WebAssembly and platform docs now say that wasm32-wasi builds need
zig and the @scriptc/runtime-wasm32-wasi package where the target is
introduced. A missing cross-target runtime pack still reports SC3003
with the package name and version; its hint now says that scriptc
includes the runtime pack for its own platform only, instead of
suggesting a reinstall with optional dependencies.
Fixes#717
Co-authored-by: guest271314 <4174848+guest271314@users.noreply.github.com>
The ESNext error lib is now part of the type world, and Error.isError(value)
compiles. A catch binding tests its payload against the Error class, an
unknown value tests the checked-dynamic error encoding, and a union tests its
runtime tag against the arms whose class extends Error. Other values answer
statically: true for instances of Error and its subclasses, false for
everything else, including objects that only have an error's shape. The
argument is always evaluated. Unions with unknown arms are refused.
TypeScript class fields declared `unknown` or `object`, also with `null`
or `undefined` or as arrays of those, were refused with SC1090. They now
use the checked-dynamic storage that JavaScript class fields without a
declared type already use. This covers instance fields, static fields and
parameter properties. Fields declared `any` stay refused.
Fixes#1147
Co-authored-by: Alan Leal <33952+alantriesagain@users.noreply.github.com>
net.SocketAddress and net.BlockList were refused at compile time. They
are now native checked-dynamic handles in scr_net.c, so their getters
and methods also work on untyped values, and they match Node 24:
- new SocketAddress(options) checks the options in Node's order
(ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE for the family,
ERR_SOCKET_BAD_PORT, ERR_OUT_OF_RANGE for the flow label) and throws
ERR_INVALID_ADDRESS for an address that does not parse. parse() reads
URL.parse(`http://${input}`)'s hostname and port and answers undefined
on failure; isSocketAddress(), toJSON() and util.inspect match.
- BlockList takes address, range, subnet and CIDR rules (addAddress,
addAddresses, addRange, addSubnet, addCIDR, addCIDRs), removes them
(removeAddress, removeRange, removeSubnet, removeCIDR, clear) and lists
them in Node's order: IPv4 addresses, IPv6 addresses, subnets, then
ranges, each newest first, with a repeated address kept once.
- check() compares across families through the IPv4-mapped IPv6 form,
as Node's SocketAddress::compare and is_in_network do, and answers
false for a string that does not parse in the given family.
- rules, size, toJSON(), fromJSON() (Node's rule patterns), isBlockList(),
PRIVATE_RANGES, instanceof and util.inspect match, with the validation
errors of lib/internal/blocklist.js.
Corpus 5659 and the node-types fixture net-blocklist.ts cover both
classes.
The compatibility registry lists the BlockList methods and
SocketAddress.parse as supported, and both classes as partial: their
structured clone and worker transfer forms are not modeled.
`Int32` from @scriptc/types now also annotates the element type of a
declared number array (`Int32[]`, `readonly Int32[]`, `Array<Int32>`,
`ReadonlyArray<Int32>`) on parameters, variables, class instance fields
and function results. The contract promises that every element stored
into the array, through any reference, is an int32 by construction.
contracts/int32-elements.ts checks it over a whole-program flow graph of
the places array references live (locals, parameters, globals, results,
class field families, record fields, container element slots), with one
node per allocation and per opaque origin. Allocations that can reach an
annotated slot are constrained and every element store into an array that
may be constrained must be range-proven an int32 (SC7002); element copies
constrain their sources by fixpoint; arrays from or escaping to code the
IR does not show refuse the contract (SC7003). Slots only constrained
arrays reach are recorded as IrContracts.int32Elements.
Element reads that find a value through those slots carry the int32
range, `getNumber` reads are integer-or-NaN operands of wrapping sums, and
ToInt32 of any integer-or-NaN operand is branch-free. Holes, missing
indices and length changes keep their JavaScript behavior.
Integer kernels over a 2^20-element array: `(s + a[i]) | 0` 1086 -> 175 ms,
`(Math.imul(h, 31) + a[i]) | 0` 602 -> 150 ms, prefix sums 575 -> 155 ms;
programs without the annotation compile to identical binaries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Native async bodies whose only suspension points are their own awaits now
compile to LLVM switched coroutines, the lowering WASI async bodies and
native synchronous generators already use. A suspended call keeps a heap
frame of the values live across its awaits instead of a fiber with its own
stack. Bodies that reach other suspension points (async generator
consumption, dyn awaits, node:test subtests), module evaluation bodies,
dyn results, worker and library programs, and Windows keep their fibers.
The emitter selects bodies by emitting them as usual first: that text may
suspend only through await runtime calls and await-call entries, and may
call no function that parks. The coroutine form is then emitted and
checked again. Each await prepares its continuation in the runtime (a
pending promise's waiter list, or one READY-queue turn, continuing in place
exactly where a fiber's hop would) and extracts the settled result after
resuming. The eager prefix runs on the spawner's stack and moves to a fresh
stack near the stack guard, so deep async recursion keeps working.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A structural type that receives class instances became a checked view
for all of its values, even when nothing could tell a copy from the
original. In tsc-ts this turned ResolvedProjectReference, the redirect
parameter of every module resolution, into a checked-dynamic value.
markIdentityFlows still finds every flow, then keeps a type marked only
when the program can observe the difference:
- values of the type are written through, compared by identity (also
inside generic functions), used as Set or Map keys or array search
needles, or passed to whole-object observers or any-value parameters;
- a field the type exposes is written on the source class after
construction, or is an accessor;
- its values flow into another kept view or class-backed protocol.
Other types stay native records.
- JavaScript calls of Promise.withResolvers' resolve/reject through the
record no longer fail with an internal compiler error.
- new RegExp with the d or v flag is refused (SC1120) for literal flags
and throws a named error for computed flags, instead of SyntaxError.
- JavaScript .groups reads on matches whose regex is not traceable are
refused like TypeScript's, instead of reading undefined.
- Iterator helpers on the string iterator are refused instead of
failing at run time.
node:test changes, matching Node 24.22:
- { concurrency } on describe, suite, test, it and t.test sets how many
subtests run at once: a number, true for os.availableParallelism() - 1,
or false for 1. Subtests inherit the parent's value.
- Above 1, each subtest runs on its own fiber. Subtests start in
declaration order as slots free up, and t.test and test() calls inside a
concurrent test start the subtest at once; t.test's promise settles when
it finishes. The parent finishes after all of them.
- Results, diagnostics and failures are reported in declaration order.
- A concurrent subtest waits after its beforeEach hooks, and a concurrent
suite before its children, for as many turns as Node's runner does, so
sibling bodies interleave as they do there.
- A concurrency that is not an integer from 1 to 4294967295 throws Node's
ERR_OUT_OF_RANGE RangeError when the test or suite is created.
- Nested test() calls and hooks inside a concurrent subtest attach to the
subtest that runs on the calling fiber.
The concurrency fixture compares the reporter output, the order of the
bodies' side effects, and the range errors with Node, plain and with
SCRIPTC_SAN=1.
promisify(zlib.deflate) and the other callback one-shots (inflate,
deflateRaw, inflateRaw, gzip, gunzip, unzip) over a named or namespace
import of node:zlib now lower. A call through the binding,
gzipAsync(data, options?), runs the callback form's work on the worker
pool and returns a promise that settles where the callback would run:
fulfilled with the Buffer, or rejected with the callback form's Error
(errno, code and message). An invalid option or input rejects the promise
instead of throwing, as the throw inside Node's promisify wrapper does.
The runtime adds scr_zlib_codec_promise and its checked-dynamic twin,
which share the callback forms' options ladder and worker-pool operation
and settle a pending promise in place of the callback. The fallback
declarations gain the matching util.promisify overload.