Intrinsics Reference

This page documents every @intrinsic the Gruel compiler recognizes. It is generated from the [gruel-intrinsics] registry (see ADR-0050); any changes must be made in Rust, not here.

Quick Reference

IntrinsicKindCategoryPreviewUncheckedSummary
@dbgexprDebug & DiagnosticsPrint values to stderr with a trailing newline.
@panicexprDebug & DiagnosticsAbort the program with an optional message.
@assertexprDebug & DiagnosticsCheck a boolean condition; panic if false.
@castexprType CastsNumeric type conversion.
@compile_errorexprCompile-time ReflectionEmit a compile-time error.
@size_oftypeCompile-time ReflectionSize of a type in bytes.
@align_oftypeCompile-time ReflectionAlignment of a type in bytes.
@type_nametypeCompile-time ReflectionName of a type as a comptime string.
@type_infotypeCompile-time ReflectionReflective info about a type.
@ownershiptypeCompile-time ReflectionOwnership posture of a type (Copy, Affine, or Linear).
@thread_safetytypeCompile-time ReflectionThread-safety classification of a type (Unsend, Send, or Sync).
@implementstype+ifaceCompile-time ReflectionWhether a type structurally implements an interface.
@fieldexprCompile-time ReflectionAccess a field by comptime-known name.
@importexprCompile-time ReflectionImport another source file (placeholder).
@embed_fileexprCompile-time ReflectionEmbed a file's contents at compile time as Slice(u8).
@spawnexprCompile-time ReflectionSpawn a worker thread running fn(arg) -> R.
@thread_joinexprCompile-time ReflectionyesInternal lowering target for JoinHandle::join (ADR-0084).
@uninittypeCompile-time ReflectionAllocate a partially-initialized value of a given type (ADR-0079).
@finalizeexprCompile-time ReflectionConsume an Uninit(T) handle and return a real T (ADR-0079).
@field_setexprCompile-time ReflectionWrite a field of an in-progress @uninit/@variant_uninit handle (ADR-0079).
@variant_uninitexprCompile-time ReflectionAllocate an Uninit(Self) pre-tagged for a specific enum variant (ADR-0079).
@variant_fieldexprCompile-time ReflectionRead a payload field of a known enum variant (ADR-0079).
@target_archexprTarget PlatformCompile target CPU architecture.
@target_osexprTarget PlatformCompile target operating system.
@rangeexprIterationIterable range for for-loops.
@slice_lenexprSlicesLength of a slice.
@slice_is_emptyexprSlicesWhether a slice has length zero.
@slice_index_readexprSlicesRead an element from a slice with bounds checking.
@slice_ptrexprSlicesyesExtract the data pointer from a slice.
@slice_ptr_mutexprSlicesyesExtract the mutable data pointer from a mutable slice.
@parts_to_sliceexprSlicesyesBuild a slice from a raw pointer and a length.
@parts_to_mut_sliceexprSlicesyesBuild a mutable slice from a raw mutable pointer and a length.
@slice_index_writeexprSlicesWrite an element to a mutable slice with bounds checking.
@vecexprVectorsConstruct a Vec from individual elements.
@vec_repeatexprVectorsConstruct a Vec with N copies of a value.
@parts_to_vecexprVectorsyesBuild a Vec from raw parts.
@ptr_readexprRaw PointersyesLoad a value through a raw pointer (internal).
@ptr_writeexprRaw PointersyesStore a value through a raw mutable pointer (internal).
@ptr_read_volatileexprRaw PointersyesVolatile load through a raw pointer (internal).
@ptr_write_volatileexprRaw PointersyesVolatile store through a raw mutable pointer (internal).
@ptr_offsetexprRaw PointersyesPointer arithmetic by element count (internal).
@ptr_to_intexprRaw PointersyesConvert a pointer to its integer address (internal).
@int_to_ptrexprRaw PointersyesConstruct a pointer from an integer address (internal).
@null_ptrexprRaw PointersyesA null pointer of the inferred type (internal).
@is_nullexprRaw PointersyesTest whether a pointer is null (internal).
@ptr_copyexprRaw PointersyesBulk copy between pointers (internal).
@rawexprRaw PointersyesTake a const pointer to an lvalue (internal).
@raw_mutexprRaw PointersyesTake a mutable pointer to an lvalue (internal).
@ptr_castexprRaw PointersyesReinterpret a pointer as another pointer type (ADR-0082).
@syscallexprSystem CallsyesDirect OS system call.
@test_preview_gateexprPreview / Metatest_infraTest hook for the preview-feature gate.
@cstr_to_vecexprPreview / MetayesCopy a NUL-terminated C string into a fresh Vec(u8).

Debug & Diagnostics

@dbg

@dbg(v1, v2, ...) prints each argument separated by spaces, then a newline. Accepts integers, bools, and String values.

Examples:

@dbg(42, true, "hello")

@panic

@panic() or @panic("message") terminates the program. Diverges (returns Never).

Examples:

@panic("unreachable")

@assert

@assert(cond) panics with a diagnostic if cond is false. Elided in release builds (future work).

Examples:

@assert(x > 0)

Type Casts

@cast

@cast(x) converts between integer and/or float types. The target type is inferred from context.

Examples:

let y: i64 = @cast(x);

Compile-time Reflection

@compile_error

@compile_error("msg") aborts compilation with the given message. Useful for unreachable comptime branches.

Examples:

@compile_error("unsupported target")

@size_of

@size_of(T) returns sizeof(T) as usize, evaluated at compile time.

Examples:

@size_of(i64)

@align_of

@align_of(T) returns the required alignment of T as usize, evaluated at compile time.

Examples:

@align_of(i64)

@type_name

@type_name(T) returns the canonical name of T as a comptime-known string.

Examples:

@type_name(i64) // "i64"

@type_info

@type_info(T) returns a comptime struct describing T (kind, fields, variants, ...).

Examples:

@type_info(MyStruct)

@ownership

@ownership(T) returns a variant of the built-in Ownership enum classifying T's ownership posture (see ADR-0008): Copy if values can be implicitly duplicated, Linear if values must be explicitly consumed, or Affine otherwise (move-once with implicit drop). Evaluated at compile time.

Examples:

@ownership(i32) // Ownership::Copy
@ownership(String) // Ownership::Affine
match @ownership(T) { Ownership::Copy => ..., Ownership::Affine => ..., Ownership::Linear => ... }

@thread_safety

@thread_safety(T) returns a variant of the built-in ThreadSafety enum classifying T on the trichotomy Unsend < Send < Sync (see ADR-0084): Unsend if T cannot cross a thread boundary, Send if it can be moved between threads, Sync if it can be shared. Primitives are intrinsically Sync; raw pointers (Ptr(T) / MutPtr(T)) are intrinsically Unsend. Composite types take the structural minimum over their members, optionally overridden by @mark(unsend) / @mark(checked_send) / @mark(checked_sync). Evaluated at compile time.

Examples:

@thread_safety(i32) // ThreadSafety::Sync
@thread_safety(MutPtr(u8)) // ThreadSafety::Unsend
comptime if (@thread_safety(T) == ThreadSafety::Sync) { ... }

@implements

@implements(T, I) returns true if type T satisfies every method requirement of interface I (see ADR-0056), and false otherwise. Built-in interfaces Copy and Drop use the language's ownership rules rather than user methods. The result is a bool evaluated at compile time, so @implements(...) can be used to gate comptime if branches and other comptime decisions.

Examples:

@implements(i32, Copy) // true
@implements(String, Copy) // false
@implements(MyType, Drop)

@field

@field(value, "name") reads the named field of value, with the name resolved at compile time.

Examples:

@field(s, "x")

@import

@import("path") — planned module-system hook; currently accepted by the compiler as a placeholder.

Examples:

@import("utils.gruel")

@embed_file

@embed_file("path") reads the file at compile time and produces a Slice(u8) whose bytes are baked into the binary as a read-only global. The path is resolved relative to the source file containing the call.

Examples:

let data: Slice(u8) = @embed_file("asset.bin");

@spawn

@spawn(fn, arg) -> JoinHandle(R) runs fn on a new thread with arg and yields a linear JoinHandle(R) consumed via join(self) -> R. The function and argument types are checked: arity must be one, the argument must be ≥ Send and not Linear or a reference, and the return type must be ≥ Send. Multi-argument workers wrap their inputs in a tuple/struct on the caller's side. ADR-0084.

  • Runtime symbol: __gruel_thread_spawn

Examples:

let h = @spawn(worker, Job { id: 1 });
let report = h.join();

@thread_join

@thread_join(h: MutPtr(u8)) -> R is the codegen-level wrapper around __gruel_thread_join. Called only from the prelude JoinHandle::join body inside a checked block; user code reaches the runtime through the prelude method. Result type comes from the surrounding context.

  • Runtime symbol: __gruel_thread_join
  • Requires: checked { ... } block

@uninit

@uninit(T) -> Uninit(T) returns a handle to T-sized storage. The compiler does not run drop on the slot until @finalize consumes it. Sema tracks per-field initialization through CFG analysis; reads, returns, or escapes of the handle are blocked until every field has been written via @field(handle, name) = expr.

Examples:

let mut h = @uninit(Point);
@field(h, "x") = 1;
@field(h, "y") = 2;
let p: Point = @finalize(h);

@finalize

@finalize(handle: Uninit(T)) -> T takes an Uninit(T) handle whose every field has been written and produces a fully-initialized T. From this point on, the value drops normally. Compile error if any field is uninitialized along any path that reaches the call.

Examples:

@finalize(h)

@field_set

@field_set(handle, name, value) writes the named field of an in-progress construction handle. Used inside derive bodies to populate the result one field at a time; sema records each write and @finalize verifies all fields are present.

Examples:

@field_set(out, f.name, @field(self, f.name).clone())

@variant_uninit

@variant_uninit(Self, comptime tag) -> Uninit(Self) is the variant-shaped counterpart to @uninit(T). Subsequent @field(out, name) = expr writes target the named variant's payload fields; @finalize(out) produces a Self of the correct variant. tag must be comptime-known.

Examples:

let mut out = @variant_uninit(Self, v.tag);
@field(out, f.name) = ...;
let result: Self = @finalize(out);

@variant_field

@variant_field(self, comptime tag, name) reads the named payload field of variant tag from self. Only valid when self's runtime variant is known to be tag — typically inside an arm dispatched by comptime_unroll for v in @type_info(Self).variants. tag and name are both comptime.

Examples:

@variant_field(self, v.tag, f.name)

Target Platform

@target_arch

@target_arch() returns a variant of the built-in Arch enum.

Examples:

if @target_arch() == Arch::Aarch64 { ... }

@target_os

@target_os() returns a variant of the built-in Os enum.

Examples:

if @target_os() == Os::Linux { ... }

Iteration

@range

@range(end), @range(start, end), or @range(start, end, step) produces an iterable over integers.

Examples:

for i in @range(0, 10) { ... }

Slices

@slice_len

@slice_len(s) returns the number of elements in s (a Slice(T) or MutSlice(T)) as usize. Surface form: s.len().

@slice_is_empty

@slice_is_empty(s) returns s.len() == 0. Surface form: s.is_empty().

@slice_index_read

@slice_index_read(s, i) returns s[i]. Bounds-checks at runtime; panics on out-of-range. Surface form: s[i].

@slice_ptr

@slice_ptr(s) returns a Ptr(T) to the slice's first element. Requires a checked block. Surface form: s.ptr().

  • Requires: checked { ... } block

@slice_ptr_mut

@slice_ptr_mut(m) returns a MutPtr(T) to a MutSlice(T)'s first element. Requires a checked block. Surface form: m.ptr_mut().

  • Requires: checked { ... } block

@parts_to_slice

@parts_to_slice(p: Ptr(T), n: usize) -> Slice(T) constructs a slice without checking that the underlying storage is valid. Requires a checked block.

  • Requires: checked { ... } block

@parts_to_mut_slice

@parts_to_mut_slice(p: MutPtr(T), n: usize) -> MutSlice(T). Requires a checked block.

  • Requires: checked { ... } block

@slice_index_write

@slice_index_write(m, i, v) performs m[i] = v. Requires MutSlice(T). Bounds-checks at runtime. Surface form: m[i] = v.

Vectors

@vec

@vec(a, b, c) returns a Vec(T) of length 3 with the given elements. Mirrors Rust's vec![…]. Requires at least one argument; element types unify to a single T.

Examples:

@vec(1, 2, 3)

@vec_repeat

@vec_repeat(v, n) returns a Vec(T) of length n where every slot holds a clone of v. Requires T: Clone.

Examples:

@vec_repeat(0, 100)

@parts_to_vec

@parts_to_vec(p: MutPtr(T), len: usize, cap: usize) -> Vec(T) takes ownership of p. Requires a checked block.

  • Requires: checked { ... } block

Raw Pointers

@ptr_read

Internal lowering target for p.read() (ADR-0063).

  • Requires: checked { ... } block

@ptr_write

Internal lowering target for p.write(v) (ADR-0063).

  • Requires: checked { ... } block

@ptr_read_volatile

Internal lowering target for p.read_volatile(). Lowers to an LLVM load volatile, which the optimizer may not elide, duplicate, or reorder relative to other volatile accesses. Intended for memory-mapped I/O where every read has externally visible side effects.

  • Requires: checked { ... } block

@ptr_write_volatile

Internal lowering target for p.write_volatile(v). Lowers to an LLVM store volatile, which the optimizer may not elide, duplicate, or reorder relative to other volatile accesses. Intended for memory-mapped I/O where every write has externally visible side effects.

  • Requires: checked { ... } block

@ptr_offset

Internal lowering target for p.offset(n) (ADR-0063).

  • Requires: checked { ... } block

@ptr_to_int

Internal lowering target for p.to_int() (ADR-0063).

  • Requires: checked { ... } block

@int_to_ptr

Internal lowering target for Ptr(T)::from_int(addr) (ADR-0063).

  • Requires: checked { ... } block

@null_ptr

Internal lowering target for Ptr(T)::null() (ADR-0063).

  • Requires: checked { ... } block

@is_null

Internal lowering target for p.is_null() (ADR-0063).

  • Requires: checked { ... } block

@ptr_copy

Internal lowering target for dst.copy_from(src, n) (ADR-0063).

  • Requires: checked { ... } block

@raw

Internal lowering target for Ptr(T)::from(&x) (ADR-0063).

  • Requires: checked { ... } block

@raw_mut

Internal lowering target for MutPtr(T)::from(&mut x) (ADR-0063).

  • Requires: checked { ... } block

@ptr_cast

@ptr_cast(p) -> MutPtr(T) / Ptr(T) reinterprets the raw pointer p as a pointer of the target type, where the target is inferred from the binding context (HM inference, like @cast). Both source and target must be MutPtr(_) / Ptr(_). The cast is a no-op at the LLVM level (pointers are opaque); only the Gruel-side type tracking changes. Requires a checked block.

  • Requires: checked { ... } block

Examples:

let p: MutPtr(T) = checked { @ptr_cast(p_u8) };

System Calls

@syscall

@syscall(num, arg1, ...) issues a raw syscall. Takes the syscall number plus up to 6 arguments; returns i64. Requires an unchecked block.

  • Requires: checked { ... } block

Examples:

checked { let ret = @syscall(1, 1, buf, n); }

Preview / Meta

@test_preview_gate

@test_preview_gate() exists solely to verify that the preview-feature gating mechanism works. Always gated behind --preview test_infra.

  • Preview gate: --preview test_infra (ADR-0005)

@cstr_to_vec

@cstr_to_vec(p: Ptr(u8)) -> Vec(u8) runs strlen(p), allocates cap >= len bytes, and copies. Used by String::from_c_str (ADR-0072).

  • Runtime symbol: __gruel_cstr_to_vec
  • Requires: checked { ... } block

Examples:

@cstr_to_vec(p)