Skip to content

describe wire types again - #132

Open
alii wants to merge 1 commit into
masterfrom
wire-descriptors
Open

alii wants to merge 1 commit into
masterfrom
wire-descriptors

Conversation

@alii

@alii alii commented Sep 27, 2026

Copy link
Copy Markdown
Member

Stage 1 of bringing scarlet/wire back: the descriptor. The compiler describes wire types again and refuses the ones it cannot. The VM does not walk bytes yet — a wire call still stops with "not built yet", and the walks are stage 2.

All of this existed before the VM rewrite and was deleted in 44218b7. It is brought back rather than reinvented, retargeted at the crate layout it has to live in now.

Where it lives

scarlet_ir::wire holds the descriptor the compiler and the VM share: NodeIdx, Ctor, HandleKind, Node, Desc. It used to sit in the VM crate, which the compiler cannot depend on; scarlet_ir is the contract between them, which is where docs/vm-design.md said this had to come back through.

It deliberately carries less than the compiler's own descriptor: no type, constructor or field names. The walks need structure, and a decoder rebuilds a constructor through Program::types, keyed on the identity a VariantRef already has. A name in here would be a second identity for a constructor that has one. The fingerprint travels with it rather than being recomputed, because it folds names as text and this table holds none.

HandleKind used to borrow its numbers from the VM's SocketKind. Sockets are not built yet, so it stands alone with its bytes written down as the stable wire surface, and says that whatever re-introduces sockets must line its numbers up rather than mint a second set.

How the descriptor reaches the VM

Program carries a TiVec<WireDescIdx, Desc>, and Core IR gains its own atom:

let %3:9 = wire.encode[wire#0](%2)

Its own atom rather than an argument smuggled through Atom::Intrinsic, for the same reason Atom::Ctor is one: a descriptor is not a value. Two call sites at one type share an entry — the dedup is on the descriptor itself, never on its fingerprint, which excludes a type's identity and so is shared by two different types of one shape.

The builder

Back at crates/scarlet_core/src/typed_ir/wire.rs. The two things worth knowing are in its module doc:

  • A finite table for an infinite value. List(Int) is unbounded; its descriptor is two nodes, and Cons.tail is an index back at the node it sits in. That closure is bought by memoising a nominal node before its fields are walked. The memo is keyed on the arguments' descriptor nodes, never their RTys — substitution mints a fresh RTy for Cons.tail's List(Int) every time, so an RTy-keyed memo would never hit and the walk would not terminate.
  • Encoding refuses exactly what decoding refuses. The asymmetry is tempting, since bytes can be written for things that cannot be read back, and it is precisely what must not be allowed: a program that can write what it can never read has been handed a corruption it finds later, elsewhere.

Tests un-ignored

wire_descriptor.rs (4) and the wire refusal tests in type_errors.rs (3) were parked with "waits for the wire redesign: check stopped refusing wire types in #50". They pass again. wire_handles.rs, wire_closures.rs, wire_bool.rs and wire_uninhabited.rs stay parked — they need the byte walks — and one in type_errors.rs now says so accurately rather than "needs the VM".

On version 4

docs/wire-format.md (#131) specifies version 4 for the new VM. The fingerprint constant here is still 3, deliberately: version 4 changes what a closure node contributes, so the bump belongs with the work that builds closures, not here, where nothing writes a byte and no peer holds a number. The constant says so.

All seven CI gates pass locally. hawk ran for the host target, and nothing here is gated on a cfg.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant