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
| Intrinsic | Kind | Category | Preview | Unchecked | Summary |
|---|---|---|---|---|---|
@dbg | expr | Debug & Diagnostics | — | — | Print values to stderr with a trailing newline. |
@panic | expr | Debug & Diagnostics | — | — | Abort the program with an optional message. |
@assert | expr | Debug & Diagnostics | — | — | Check a boolean condition; panic if false. |
@cast | expr | Type Casts | — | — | Numeric type conversion. |
@compile_error | expr | Compile-time Reflection | — | — | Emit a compile-time error. |
@size_of | type | Compile-time Reflection | — | — | Size of a type in bytes. |
@align_of | type | Compile-time Reflection | — | — | Alignment of a type in bytes. |
@type_name | type | Compile-time Reflection | — | — | Name of a type as a comptime string. |
@type_info | type | Compile-time Reflection | — | — | Reflective info about a type. |
@ownership | type | Compile-time Reflection | — | — | Ownership posture of a type (Copy, Affine, or Linear). |
@thread_safety | type | Compile-time Reflection | — | — | Thread-safety classification of a type (Unsend, Send, or Sync). |
@implements | type+iface | Compile-time Reflection | — | — | Whether a type structurally implements an interface. |
@field | expr | Compile-time Reflection | — | — | Access a field by comptime-known name. |
@import | expr | Compile-time Reflection | — | — | Import another source file (placeholder). |
@embed_file | expr | Compile-time Reflection | — | — | Embed a file's contents at compile time as Slice(u8). |
@spawn | expr | Compile-time Reflection | — | — | Spawn a worker thread running fn(arg) -> R. |
@thread_join | expr | Compile-time Reflection | — | yes | Internal lowering target for JoinHandle::join (ADR-0084). |
@uninit | type | Compile-time Reflection | — | — | Allocate a partially-initialized value of a given type (ADR-0079). |
@finalize | expr | Compile-time Reflection | — | — | Consume an Uninit(T) handle and return a real T (ADR-0079). |
@field_set | expr | Compile-time Reflection | — | — | Write a field of an in-progress @uninit/@variant_uninit handle (ADR-0079). |
@variant_uninit | expr | Compile-time Reflection | — | — | Allocate an Uninit(Self) pre-tagged for a specific enum variant (ADR-0079). |
@variant_field | expr | Compile-time Reflection | — | — | Read a payload field of a known enum variant (ADR-0079). |
@target_arch | expr | Target Platform | — | — | Compile target CPU architecture. |
@target_os | expr | Target Platform | — | — | Compile target operating system. |
@range | expr | Iteration | — | — | Iterable range for for-loops. |
@slice_len | expr | Slices | — | — | Length of a slice. |
@slice_is_empty | expr | Slices | — | — | Whether a slice has length zero. |
@slice_index_read | expr | Slices | — | — | Read an element from a slice with bounds checking. |
@slice_ptr | expr | Slices | — | yes | Extract the data pointer from a slice. |
@slice_ptr_mut | expr | Slices | — | yes | Extract the mutable data pointer from a mutable slice. |
@parts_to_slice | expr | Slices | — | yes | Build a slice from a raw pointer and a length. |
@parts_to_mut_slice | expr | Slices | — | yes | Build a mutable slice from a raw mutable pointer and a length. |
@slice_index_write | expr | Slices | — | — | Write an element to a mutable slice with bounds checking. |
@vec | expr | Vectors | — | — | Construct a Vec from individual elements. |
@vec_repeat | expr | Vectors | — | — | Construct a Vec with N copies of a value. |
@parts_to_vec | expr | Vectors | — | yes | Build a Vec from raw parts. |
@ptr_read | expr | Raw Pointers | — | yes | Load a value through a raw pointer (internal). |
@ptr_write | expr | Raw Pointers | — | yes | Store a value through a raw mutable pointer (internal). |
@ptr_read_volatile | expr | Raw Pointers | — | yes | Volatile load through a raw pointer (internal). |
@ptr_write_volatile | expr | Raw Pointers | — | yes | Volatile store through a raw mutable pointer (internal). |
@ptr_offset | expr | Raw Pointers | — | yes | Pointer arithmetic by element count (internal). |
@ptr_to_int | expr | Raw Pointers | — | yes | Convert a pointer to its integer address (internal). |
@int_to_ptr | expr | Raw Pointers | — | yes | Construct a pointer from an integer address (internal). |
@null_ptr | expr | Raw Pointers | — | yes | A null pointer of the inferred type (internal). |
@is_null | expr | Raw Pointers | — | yes | Test whether a pointer is null (internal). |
@ptr_copy | expr | Raw Pointers | — | yes | Bulk copy between pointers (internal). |
@raw | expr | Raw Pointers | — | yes | Take a const pointer to an lvalue (internal). |
@raw_mut | expr | Raw Pointers | — | yes | Take a mutable pointer to an lvalue (internal). |
@ptr_cast | expr | Raw Pointers | — | yes | Reinterpret a pointer as another pointer type (ADR-0082). |
@syscall | expr | System Calls | — | yes | Direct OS system call. |
@test_preview_gate | expr | Preview / Meta | test_infra | — | Test hook for the preview-feature gate. |
@cstr_to_vec | expr | Preview / Meta | — | yes | Copy 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)