Built-in Types Reference
This page documents every built-in type constructor, enum, and interface the Gruel compiler hard-codes by name. ADR-0081 retired the BUILTIN_TYPES registry; built-in types (currently just String) live in the prelude alongside Option / Result. The constructors, enums, and interfaces here are still hard-wired because their semantics aren't expressible as ordinary Gruel code.
Quick Reference
Type Constructors
| Name | Arity | Description |
|---|---|---|
Ptr | 1 | immutable raw pointer (ADR-0061) |
MutPtr | 1 | mutable raw pointer (ADR-0061) |
Ref | 1 | immutable reference (ADR-0062) |
MutRef | 1 | mutable reference (ADR-0062) |
Slice | 1 | immutable slice (ADR-0064) |
MutSlice | 1 | mutable slice (ADR-0064) |
Vec | 1 | owned, growable vector (ADR-0066) |
Enums
Platform-reflection enums (Arch, Os) live in prelude/target.gruel; type-reflection enums (TypeKind, Ownership) live in prelude/type_info.gruel. The corresponding intrinsics produce values of these types by name lookup.
| Name | Variants |
|---|---|
Arch | X86_64, Aarch64, X86, Arm, Riscv32, Riscv64, Wasm32, Wasm64 |
Os | Linux, Macos, Windows, Freestanding, Wasi |
TypeKind | Struct, Enum, Int, Bool, Unit, Never, Array |
Ownership | Copy, Affine, Linear |
ThreadSafety | Unsend, Send, Sync |
Interfaces
Compiler-recognized interfaces are declared in prelude/interfaces.gruel. The compiler keys off these names for hardcoded behaviors (drop glue, @derive(Clone) synthesis, Handle linearity carve-out). ADR-0080 retired Copy from this set: posture is declared on the type with the copy keyword and queried via @ownership(T).
| Name | Method | Conformance |
|---|---|---|
Drop | fn __drop(self) | method presence |
Clone | fn clone(self: Ref(Self)) -> Self | @derive(Clone) |
Handle | fn handle(self: Ref(Self)) -> Self | method presence |
Markers
Marker names recognized inside the @mark(...) directive (ADR-0083). Markers attach declaration-time metadata to a struct/enum head; future markers plug in by adding a row to the BUILTIN_MARKERS registry.
| Name | Kind | Applies to |
|---|---|---|
copy | Posture(Copy) | struct or enum |
affine | Posture(Affine) | struct or enum |
linear | Posture(Linear) | struct or enum |
unsend | ThreadSafety(Unsend) | struct or enum |
checked_send | ThreadSafety(Send) | struct or enum |
checked_sync | ThreadSafety(Sync) | struct or enum |
c | Abi(C) | (none) |
unchecked | Unchecked | fn only |
Type Constructors
Built-in type constructors are written Name(arg1, arg2, ...) in type position. Sema resolves the name against the registry and lowers directly to a TypeKind without running the comptime interpreter.
Ptr(T)
immutable raw pointer (ADR-0061).
MutPtr(T)
mutable raw pointer (ADR-0061).
Ref(T)
immutable reference (ADR-0062).
MutRef(T)
mutable reference (ADR-0062).
Slice(T)
immutable slice (ADR-0064).
MutSlice(T)
mutable slice (ADR-0064).
Vec(T)
owned, growable vector (ADR-0066).
Enums
Platform-reflection (Arch, Os) and type-reflection (TypeKind, Ownership) enums. Declarations live in prelude/target.gruel and prelude/type_info.gruel respectively; the corresponding intrinsics (@target_arch, @target_os, @type_info, @ownership) materialize values of these types.
Arch
| Index | Variant |
|---|---|
| 0 | Arch::X86_64 |
| 1 | Arch::Aarch64 |
| 2 | Arch::X86 |
| 3 | Arch::Arm |
| 4 | Arch::Riscv32 |
| 5 | Arch::Riscv64 |
| 6 | Arch::Wasm32 |
| 7 | Arch::Wasm64 |
Os
| Index | Variant |
|---|---|
| 0 | Os::Linux |
| 1 | Os::Macos |
| 2 | Os::Windows |
| 3 | Os::Freestanding |
| 4 | Os::Wasi |
TypeKind
| Index | Variant |
|---|---|
| 0 | TypeKind::Struct |
| 1 | TypeKind::Enum |
| 2 | TypeKind::Int |
| 3 | TypeKind::Bool |
| 4 | TypeKind::Unit |
| 5 | TypeKind::Never |
| 6 | TypeKind::Array |
Ownership
| Index | Variant |
|---|---|
| 0 | Ownership::Copy |
| 1 | Ownership::Affine |
| 2 | Ownership::Linear |
ThreadSafety
| Index | Variant |
|---|---|
| 0 | ThreadSafety::Unsend |
| 1 | ThreadSafety::Send |
| 2 | ThreadSafety::Sync |
Interfaces
Compiler-recognized interfaces. Declarations live in prelude/interfaces.gruel; the compiler keys off the interface names for hardcoded behaviors. Conformance is structural — a type satisfies the interface when it provides matching methods.
Drop
Types with custom cleanup logic that runs when the value goes out of scope (ADR-0059).
Required methods:
fn __drop(self)
Conformance: structural (no derive). Defining fn __drop(self) on a struct or enum makes it conform — there is no @derive(Drop) directive.
Clone
Types that may be explicitly duplicated via .clone(). All Copy types auto-conform (ADR-0065).
Required methods:
fn clone(self: Ref(Self)) -> Self
Conformance derive: @derive(Clone) (compiler-recognized; no user derive declaration required). Synthesizes a clone method that recursively calls clone on every field (struct) or variant payload (enum). Synthesis fails if any field is not Clone. Rejected on linear types.
Handle
Types that may be explicitly duplicated via .handle(), typically because the duplication has visible cost (refcount bumps, transaction forks). Unlike Clone, Handle is permitted on linear types (ADR-0075).
Required methods:
fn handle(self: Ref(Self)) -> Self
Conformance: structural (no derive). Defining fn handle(self: Ref(Self)) -> Self on a struct or enum makes it conform — there is no @derive(Handle) directive.
Markers
Markers are declaration-time-only attributes on struct/enum heads, written inside @mark(...) (ADR-0083). The marker set is closed; user-defined markers are out of scope. New markers must go through an ADR.
@mark(copy)
Asserts the type is Copy. Under uniform structural inference, a struct/enum of all-Copy fields would already be Copy without the directive — @mark(copy) exists so the user can document intent and turn a silent posture downgrade (adding a non-Copy field later) into a declaration-site error.
@mark(affine)
Suppresses Copy inference. A type whose members would otherwise infer Copy is forced to remain Affine, so move-on-use semantics are preserved even when bitwise duplication is safe. Has no effect on Linear inference: a Linear member still propagates upward.
@mark(linear)
Forces the type to be Linear regardless of member postures. Use when the type has linear semantics that are not visible from its fields (e.g. an i32 handle that is actually a kernel resource ID).
@mark(unsend)
Downgrades the type's thread-safety classification to Unsend, even if its members would structurally permit Send or Sync. Always safe — the marker only restricts. Use when the type has thread-affine state that isn't visible from its fields (e.g. a handle to a thread-local resource).
@mark(checked_send)
Asserts the type is Send, even if a member's type would structurally pull it down to Unsend (e.g. a raw pointer field). The compiler cannot verify this — the checked_ prefix flags it as a user assertion (analogous to Rust's unsafe impl Send). Mis-applying breaks data-race freedom; the user takes responsibility.
@mark(checked_sync)
Asserts the type is Sync, even if its structural minimum would be Send or Unsend. The compiler cannot verify this — the checked_ prefix flags it as a user assertion (analogous to Rust's unsafe impl Sync). Mis-applying breaks data-race freedom; the user takes responsibility.
@mark(c)
Selects the C ABI / C layout (ADR-0085). On a function, uses the platform C calling convention and suppresses Gruel name mangling. On a struct, switches to C field layout (declaration order, natural alignment, no reordering, niches disabled), making the type eligible to cross the FFI boundary by value.
@mark(unchecked)
Declares a fn (top-level, method, interface method, or FFI import) as unchecked (ADR-0088). Every caller must wrap the call in a checked { } block; the body's soundness rests on a caller-asserted precondition the type system can't verify. Replaces the legacy unchecked keyword and extends the surface to methods, interface method signatures, and FFI imports under a single uniform spelling.