Skip to main content
This page assumes prior knowledge of the Tolk type system and TVM. It serves as a concise low-level reference. A consolidated summary of how Tolk types are represented on the TVM stack.

int, intN, coins

  • All numeric types are backed by TVM INT.
  • Type intN uses full 257-bit precision, so any integer value fits into it. Overflow occurs only during serialization.

bool

  • The bool type is backed by TVM INT with value -1 or 0 at runtime.
  • The unsafe cast someBool as int is valid and produces -1 or 0.

address, any_address

  • Both address and any_address are backed by TVM SLICE values containing raw binary data.
  • A nullable address? is represented as either TVM NULL or SLICE.
  • The unsafe cast someAddr as slice is valid and reversible.

cell

  • The cell type is backed by TVM CELL.
  • The unsafe cast someCell as Cell<T> is valid.

Cell<T>

  • The Cell<T> type is also backed by TVM CELL. The type parameter T is compile-time metadata.

slice

  • Type slice is backed by TVM SLICE.

bitsN

  • The bitsN type is backed by TVM SLICE.
  • The unsafe cast someSlice as bitsN is valid and reversible.

RemainingBitsAndRefs

  • The RemainingBitsAndRefs type is backed TVM SLICE. It is an alias of slice that is handled specially during deserialization.

builder

  • The builder type is backed by TVM BUILDER. Bits written to a builder cannot be read directly. Access to the data is possible only by converting the builder to a slice.

struct

Fields of a structure are placed sequentially on the stack. For example, Point occupies two stack slots, and Line occupies four:
When constructing a Line value, four integers are placed onto the stack:
Single-field structures have no overhead compared to the plain values.

enum

  • Every enum is backed by TVM INT. Tolk supports integer enums only; for example, not addresses.

Nullable types T?

Primitive nullable types such as int?, address?, and cell? occupy a single stack slot. That slot holds either TVM NULL or the corresponding value.
A nullable structure with a single non-nullable primitive field can also be represented:
Nullable values of multi-slot types, such as Point or a tensor (bool, cell), occupy N + 1 stack slots. The last is used for “typeid”.
For every nullable type, the compiler assigns a unique typeid; for example, 4567 for Point. The typeid is stored in an extra stack slot. The typeid value for null is 0. Expressions such as p == null or p is Point check the typeid slot. The following structure, when nullable, requires an extra stack slot:

Union types T1 | T2 | ...

Union types are represented as tagged unions on the stack:
  • each alternative type is assigned a unique typeid; e.g., 1234 for int;
  • the union occupies N+1 stack slots, where N is the maximum size of T_i;
  • the(N+1)-th slot contains the typeid of the current value.
Thus, match is implemented as a comparison of the (N+1)-th slot, and passing or assigning a value involves stack rearrangement.
T | null is called nullable and optimized for atomic types: int? uses a single slot. Non-atomics are handled generally, with typeid=0.

Tensors (T1, T2, ...)

Tensor components are placed sequentially on the stack, identical to struct fields. For example, (coins, Point, int?) occupies 4 stack slots: INT (coins), INT (p.x), INT (p.y), INT/NULL.

string

Type string is backed by the TVM CELL containing character data in snake format: a chain of cells where each cell holds a portion of the string and a reference to the next. For example, a string "abcd" can be stored as a single chunk — cell(data: "abcd"), with 32 bits inside. The same string can also use nested chunks: cell(data: "ab", ref: cell(data: "cd")). Either way, a string is a cell that may contain chained refs.

unknown

The unknown type is an opaque type that represents a single TVM stack slot. Any type T can be cast to unknown. When cast, primitives remain as-is, while multi-slot types are packed into a sub-tuple. For example, 5 as unknown remains as 5 on the stack, whereas (10, 20) as unknown is converted to a 2-element tuple [10 20].

array<T> and tuple

An array of any T is backed by the TVM TUPLE and occupies a single stack slot, regardless of the number of elements within. The TVM TUPLE limit is 255 inner elements. The tuple is an alias for array<unknown>. For example, array<int> [1,2,3] is a TVM tuple [1 2 3], whereas for array<Point> [ {x:10,y:20}, {x:30,y:40} ] each sub-element is a 2-component tuple itself: [ [10 20] [30 40] ]. Under the hood, T is converted to unknown on write and reversed back on read: points.get(0) returns {x:10,y:20}.

Shaped tuple [T1, T2, ...]

A shaped tuple is a fixed-size array backed by the TVM TUPLE, whose structure is known at compile-time:

map<K, V>

Callables (...ArgsT) -> ResultT

  • A callable and continuation is backed by TVM CONT.

void, never

  • Both represent the absence of a value and occupy zero stack slots. For example, a function with return type void does not place any value onto the stack.