1use gruel_util::PreviewFeature;
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub enum IntrinsicId {
54 Dbg,
56 Panic,
57 Assert,
58 CompileError,
59
60 Cast,
62
63 SizeOf,
72 AlignOf,
73 TypeName,
74 TypeInfo,
75 Ownership,
76 ThreadSafety,
79 Implements,
80 Field,
81 Import,
82 EmbedFile,
83
84 TargetArch,
86 TargetOs,
87
88 PtrRead,
90 PtrWrite,
91 PtrReadVolatile,
92 PtrWriteVolatile,
93 PtrOffset,
94 PtrToInt,
95 IntToPtr,
96 NullPtr,
97 IsNull,
98 PtrCopy,
99 Raw,
100 RawMut,
101
102 Syscall,
104
105 Range,
107
108 SliceLen,
110 SliceIsEmpty,
111 SliceIndexRead,
112 SliceIndexWrite,
113 SlicePtr,
114 SlicePtrMut,
115 PartsToSlice,
116 PartsToMutSlice,
117
118 VecLiteral,
125 VecRepeat,
126 PartsToVec,
127
128 CStrToVec,
134
135 PtrCast,
144 Uninit,
151 Finalize,
154 FieldSet,
158 VariantUninit,
161 VariantField,
165
166 Spawn,
169 ThreadJoin,
176
177 TestPreviewGate,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum IntrinsicKind {
185 Expr,
187 Type,
189 TypeInterface,
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub enum Category {
198 Debug,
199 Cast,
200 Io,
201 Parse,
202 Random,
203 Comptime,
204 Platform,
205 Pointer,
206 Syscall,
207 Iteration,
208 Slice,
209 Vec,
210 Meta,
211}
212
213impl Category {
214 pub fn heading(&self) -> &'static str {
216 match self {
217 Category::Debug => "Debug & Diagnostics",
218 Category::Cast => "Type Casts",
219 Category::Io => "I/O",
220 Category::Parse => "String Parsing",
221 Category::Random => "Random Numbers",
222 Category::Comptime => "Compile-time Reflection",
223 Category::Platform => "Target Platform",
224 Category::Pointer => "Raw Pointers",
225 Category::Syscall => "System Calls",
226 Category::Iteration => "Iteration",
227 Category::Slice => "Slices",
228 Category::Vec => "Vectors",
229 Category::Meta => "Preview / Meta",
230 }
231 }
232
233 pub const RENDER_ORDER: &'static [Category] = &[
240 Category::Debug,
241 Category::Cast,
242 Category::Io,
243 Category::Parse,
244 Category::Random,
245 Category::Comptime,
246 Category::Platform,
247 Category::Iteration,
248 Category::Slice,
249 Category::Vec,
250 Category::Pointer,
251 Category::Syscall,
252 Category::Meta,
253 ];
254
255 fn render_index(self) -> usize {
258 Self::RENDER_ORDER
259 .iter()
260 .position(|c| *c == self)
261 .expect("every Category variant must appear in RENDER_ORDER")
262 }
263}
264
265#[derive(Debug, Clone, Copy)]
272pub struct IntrinsicDef {
273 pub id: IntrinsicId,
275 pub name: &'static str,
277 pub kind: IntrinsicKind,
279 pub category: Category,
281 pub requires_unchecked: bool,
283 pub preview: Option<PreviewFeature>,
285 pub runtime_fn: Option<&'static str>,
289 pub summary: &'static str,
291 pub description: &'static str,
293 pub examples: &'static [&'static str],
295}
296
297pub const INTRINSICS: &[IntrinsicDef] = &[
308 IntrinsicDef {
309 id: IntrinsicId::Dbg,
310 name: "dbg",
311 kind: IntrinsicKind::Expr,
312 category: Category::Debug,
313 requires_unchecked: false,
314 preview: None,
315 runtime_fn: None, summary: "Print values to stderr with a trailing newline.",
317 description: "`@dbg(v1, v2, ...)` prints each argument separated by spaces, then a newline. Accepts integers, bools, and `String` values.",
318 examples: &["@dbg(42, true, \"hello\")"],
319 },
320 IntrinsicDef {
321 id: IntrinsicId::Panic,
322 name: "panic",
323 kind: IntrinsicKind::Expr,
324 category: Category::Debug,
325 requires_unchecked: false,
326 preview: None,
327 runtime_fn: None,
328 summary: "Abort the program with an optional message.",
329 description: "`@panic()` or `@panic(\"message\")` terminates the program. Diverges (returns `Never`).",
330 examples: &["@panic(\"unreachable\")"],
331 },
332 IntrinsicDef {
333 id: IntrinsicId::Assert,
334 name: "assert",
335 kind: IntrinsicKind::Expr,
336 category: Category::Debug,
337 requires_unchecked: false,
338 preview: None,
339 runtime_fn: None,
340 summary: "Check a boolean condition; panic if false.",
341 description: "`@assert(cond)` panics with a diagnostic if `cond` is false. Elided in release builds (future work).",
342 examples: &["@assert(x > 0)"],
343 },
344 IntrinsicDef {
345 id: IntrinsicId::CompileError,
346 name: "compile_error",
347 kind: IntrinsicKind::Expr,
348 category: Category::Comptime,
349 requires_unchecked: false,
350 preview: None,
351 runtime_fn: None,
352 summary: "Emit a compile-time error.",
353 description: "`@compile_error(\"msg\")` aborts compilation with the given message. Useful for unreachable comptime branches.",
354 examples: &["@compile_error(\"unsupported target\")"],
355 },
356 IntrinsicDef {
357 id: IntrinsicId::Cast,
358 name: "cast",
359 kind: IntrinsicKind::Expr,
360 category: Category::Cast,
361 requires_unchecked: false,
362 preview: None,
363 runtime_fn: None,
364 summary: "Numeric type conversion.",
365 description: "`@cast(x)` converts between integer and/or float types. The target type is inferred from context.",
366 examples: &["let y: i64 = @cast(x);"],
367 },
368 IntrinsicDef {
375 id: IntrinsicId::SizeOf,
376 name: "size_of",
377 kind: IntrinsicKind::Type,
378 category: Category::Comptime,
379 requires_unchecked: false,
380 preview: None,
381 runtime_fn: None,
382 summary: "Size of a type in bytes.",
383 description: "`@size_of(T)` returns `sizeof(T)` as `usize`, evaluated at compile time.",
384 examples: &["@size_of(i64)"],
385 },
386 IntrinsicDef {
387 id: IntrinsicId::AlignOf,
388 name: "align_of",
389 kind: IntrinsicKind::Type,
390 category: Category::Comptime,
391 requires_unchecked: false,
392 preview: None,
393 runtime_fn: None,
394 summary: "Alignment of a type in bytes.",
395 description: "`@align_of(T)` returns the required alignment of `T` as `usize`, evaluated at compile time.",
396 examples: &["@align_of(i64)"],
397 },
398 IntrinsicDef {
399 id: IntrinsicId::TypeName,
400 name: "type_name",
401 kind: IntrinsicKind::Type,
402 category: Category::Comptime,
403 requires_unchecked: false,
404 preview: None,
405 runtime_fn: None,
406 summary: "Name of a type as a comptime string.",
407 description: "`@type_name(T)` returns the canonical name of `T` as a comptime-known string.",
408 examples: &["@type_name(i64) // \"i64\""],
409 },
410 IntrinsicDef {
411 id: IntrinsicId::TypeInfo,
412 name: "type_info",
413 kind: IntrinsicKind::Type,
414 category: Category::Comptime,
415 requires_unchecked: false,
416 preview: None,
417 runtime_fn: None,
418 summary: "Reflective info about a type.",
419 description: "`@type_info(T)` returns a comptime struct describing `T` (kind, fields, variants, ...).",
420 examples: &["@type_info(MyStruct)"],
421 },
422 IntrinsicDef {
423 id: IntrinsicId::Ownership,
424 name: "ownership",
425 kind: IntrinsicKind::Type,
426 category: Category::Comptime,
427 requires_unchecked: false,
428 preview: None,
429 runtime_fn: None,
430 summary: "Ownership posture of a type (`Copy`, `Affine`, or `Linear`).",
431 description: "`@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.",
432 examples: &[
433 "@ownership(i32) // Ownership::Copy",
434 "@ownership(String) // Ownership::Affine",
435 "match @ownership(T) { Ownership::Copy => ..., Ownership::Affine => ..., Ownership::Linear => ... }",
436 ],
437 },
438 IntrinsicDef {
439 id: IntrinsicId::ThreadSafety,
440 name: "thread_safety",
441 kind: IntrinsicKind::Type,
442 category: Category::Comptime,
443 requires_unchecked: false,
444 preview: None,
445 runtime_fn: None,
446 summary: "Thread-safety classification of a type (`Unsend`, `Send`, or `Sync`).",
447 description: "`@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.",
448 examples: &[
449 "@thread_safety(i32) // ThreadSafety::Sync",
450 "@thread_safety(MutPtr(u8)) // ThreadSafety::Unsend",
451 "comptime if (@thread_safety(T) == ThreadSafety::Sync) { ... }",
452 ],
453 },
454 IntrinsicDef {
455 id: IntrinsicId::Implements,
456 name: "implements",
457 kind: IntrinsicKind::TypeInterface,
458 category: Category::Comptime,
459 requires_unchecked: false,
460 preview: None,
461 runtime_fn: None,
462 summary: "Whether a type structurally implements an interface.",
463 description: "`@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.",
464 examples: &[
465 "@implements(i32, Copy) // true",
466 "@implements(String, Copy) // false",
467 "@implements(MyType, Drop)",
468 ],
469 },
470 IntrinsicDef {
471 id: IntrinsicId::Field,
472 name: "field",
473 kind: IntrinsicKind::Expr,
474 category: Category::Comptime,
475 requires_unchecked: false,
476 preview: None,
477 runtime_fn: None,
478 summary: "Access a field by comptime-known name.",
479 description: "`@field(value, \"name\")` reads the named field of `value`, with the name resolved at compile time.",
480 examples: &["@field(s, \"x\")"],
481 },
482 IntrinsicDef {
483 id: IntrinsicId::Import,
484 name: "import",
485 kind: IntrinsicKind::Expr,
486 category: Category::Comptime,
487 requires_unchecked: false,
488 preview: None,
489 runtime_fn: None,
490 summary: "Import another source file (placeholder).",
491 description: "`@import(\"path\")` — planned module-system hook; currently accepted by the compiler as a placeholder.",
492 examples: &["@import(\"utils.gruel\")"],
493 },
494 IntrinsicDef {
495 id: IntrinsicId::EmbedFile,
496 name: "embed_file",
497 kind: IntrinsicKind::Expr,
498 category: Category::Comptime,
499 requires_unchecked: false,
500 preview: None,
501 runtime_fn: None,
502 summary: "Embed a file's contents at compile time as `Slice(u8)`.",
503 description: "`@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.",
504 examples: &["let data: Slice(u8) = @embed_file(\"asset.bin\");"],
505 },
506 IntrinsicDef {
507 id: IntrinsicId::TargetArch,
508 name: "target_arch",
509 kind: IntrinsicKind::Expr,
510 category: Category::Platform,
511 requires_unchecked: false,
512 preview: None,
513 runtime_fn: None,
514 summary: "Compile target CPU architecture.",
515 description: "`@target_arch()` returns a variant of the built-in `Arch` enum.",
516 examples: &["if @target_arch() == Arch::Aarch64 { ... }"],
517 },
518 IntrinsicDef {
519 id: IntrinsicId::TargetOs,
520 name: "target_os",
521 kind: IntrinsicKind::Expr,
522 category: Category::Platform,
523 requires_unchecked: false,
524 preview: None,
525 runtime_fn: None,
526 summary: "Compile target operating system.",
527 description: "`@target_os()` returns a variant of the built-in `Os` enum.",
528 examples: &["if @target_os() == Os::Linux { ... }"],
529 },
530 IntrinsicDef {
538 id: IntrinsicId::PtrRead,
539 name: "ptr_read",
540 kind: IntrinsicKind::Expr,
541 category: Category::Pointer,
542 requires_unchecked: true,
543 preview: None,
544 runtime_fn: None,
545 summary: "Load a value through a raw pointer (internal).",
546 description: "Internal lowering target for `p.read()` (ADR-0063).",
547 examples: &[],
548 },
549 IntrinsicDef {
550 id: IntrinsicId::PtrWrite,
551 name: "ptr_write",
552 kind: IntrinsicKind::Expr,
553 category: Category::Pointer,
554 requires_unchecked: true,
555 preview: None,
556 runtime_fn: None,
557 summary: "Store a value through a raw mutable pointer (internal).",
558 description: "Internal lowering target for `p.write(v)` (ADR-0063).",
559 examples: &[],
560 },
561 IntrinsicDef {
562 id: IntrinsicId::PtrReadVolatile,
563 name: "ptr_read_volatile",
564 kind: IntrinsicKind::Expr,
565 category: Category::Pointer,
566 requires_unchecked: true,
567 preview: None,
568 runtime_fn: None,
569 summary: "Volatile load through a raw pointer (internal).",
570 description: "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.",
571 examples: &[],
572 },
573 IntrinsicDef {
574 id: IntrinsicId::PtrWriteVolatile,
575 name: "ptr_write_volatile",
576 kind: IntrinsicKind::Expr,
577 category: Category::Pointer,
578 requires_unchecked: true,
579 preview: None,
580 runtime_fn: None,
581 summary: "Volatile store through a raw mutable pointer (internal).",
582 description: "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.",
583 examples: &[],
584 },
585 IntrinsicDef {
586 id: IntrinsicId::PtrOffset,
587 name: "ptr_offset",
588 kind: IntrinsicKind::Expr,
589 category: Category::Pointer,
590 requires_unchecked: true,
591 preview: None,
592 runtime_fn: None,
593 summary: "Pointer arithmetic by element count (internal).",
594 description: "Internal lowering target for `p.offset(n)` (ADR-0063).",
595 examples: &[],
596 },
597 IntrinsicDef {
598 id: IntrinsicId::PtrToInt,
599 name: "ptr_to_int",
600 kind: IntrinsicKind::Expr,
601 category: Category::Pointer,
602 requires_unchecked: true,
603 preview: None,
604 runtime_fn: None,
605 summary: "Convert a pointer to its integer address (internal).",
606 description: "Internal lowering target for `p.to_int()` (ADR-0063).",
607 examples: &[],
608 },
609 IntrinsicDef {
610 id: IntrinsicId::IntToPtr,
611 name: "int_to_ptr",
612 kind: IntrinsicKind::Expr,
613 category: Category::Pointer,
614 requires_unchecked: true,
615 preview: None,
616 runtime_fn: None,
617 summary: "Construct a pointer from an integer address (internal).",
618 description: "Internal lowering target for `Ptr(T)::from_int(addr)` (ADR-0063).",
619 examples: &[],
620 },
621 IntrinsicDef {
622 id: IntrinsicId::NullPtr,
623 name: "null_ptr",
624 kind: IntrinsicKind::Expr,
625 category: Category::Pointer,
626 requires_unchecked: true,
627 preview: None,
628 runtime_fn: None,
629 summary: "A null pointer of the inferred type (internal).",
630 description: "Internal lowering target for `Ptr(T)::null()` (ADR-0063).",
631 examples: &[],
632 },
633 IntrinsicDef {
634 id: IntrinsicId::IsNull,
635 name: "is_null",
636 kind: IntrinsicKind::Expr,
637 category: Category::Pointer,
638 requires_unchecked: true,
639 preview: None,
640 runtime_fn: None,
641 summary: "Test whether a pointer is null (internal).",
642 description: "Internal lowering target for `p.is_null()` (ADR-0063).",
643 examples: &[],
644 },
645 IntrinsicDef {
646 id: IntrinsicId::PtrCopy,
647 name: "ptr_copy",
648 kind: IntrinsicKind::Expr,
649 category: Category::Pointer,
650 requires_unchecked: true,
651 preview: None,
652 runtime_fn: None,
653 summary: "Bulk copy between pointers (internal).",
654 description: "Internal lowering target for `dst.copy_from(src, n)` (ADR-0063).",
655 examples: &[],
656 },
657 IntrinsicDef {
658 id: IntrinsicId::Raw,
659 name: "raw",
660 kind: IntrinsicKind::Expr,
661 category: Category::Pointer,
662 requires_unchecked: true,
663 preview: None,
664 runtime_fn: None,
665 summary: "Take a const pointer to an lvalue (internal).",
666 description: "Internal lowering target for `Ptr(T)::from(&x)` (ADR-0063).",
667 examples: &[],
668 },
669 IntrinsicDef {
670 id: IntrinsicId::RawMut,
671 name: "raw_mut",
672 kind: IntrinsicKind::Expr,
673 category: Category::Pointer,
674 requires_unchecked: true,
675 preview: None,
676 runtime_fn: None,
677 summary: "Take a mutable pointer to an lvalue (internal).",
678 description: "Internal lowering target for `MutPtr(T)::from(&mut x)` (ADR-0063).",
679 examples: &[],
680 },
681 IntrinsicDef {
682 id: IntrinsicId::Syscall,
683 name: "syscall",
684 kind: IntrinsicKind::Expr,
685 category: Category::Syscall,
686 requires_unchecked: true,
687 preview: None,
688 runtime_fn: None,
689 summary: "Direct OS system call.",
690 description: "`@syscall(num, arg1, ...)` issues a raw syscall. Takes the syscall number plus up to 6 arguments; returns `i64`. Requires an `unchecked` block.",
691 examples: &["checked { let ret = @syscall(1, 1, buf, n); }"],
692 },
693 IntrinsicDef {
694 id: IntrinsicId::Range,
695 name: "range",
696 kind: IntrinsicKind::Expr,
697 category: Category::Iteration,
698 requires_unchecked: false,
699 preview: None,
700 runtime_fn: None,
701 summary: "Iterable range for `for`-loops.",
702 description: "`@range(end)`, `@range(start, end)`, or `@range(start, end, step)` produces an iterable over integers.",
703 examples: &["for i in @range(0, 10) { ... }"],
704 },
705 IntrinsicDef {
706 id: IntrinsicId::SliceLen,
707 name: "slice_len",
708 kind: IntrinsicKind::Expr,
709 category: Category::Slice,
710 requires_unchecked: false,
711 preview: None,
712 runtime_fn: None,
713 summary: "Length of a slice.",
714 description: "`@slice_len(s)` returns the number of elements in `s` (a `Slice(T)` or `MutSlice(T)`) as `usize`. Surface form: `s.len()`.",
715 examples: &[],
716 },
717 IntrinsicDef {
718 id: IntrinsicId::SliceIsEmpty,
719 name: "slice_is_empty",
720 kind: IntrinsicKind::Expr,
721 category: Category::Slice,
722 requires_unchecked: false,
723 preview: None,
724 runtime_fn: None,
725 summary: "Whether a slice has length zero.",
726 description: "`@slice_is_empty(s)` returns `s.len() == 0`. Surface form: `s.is_empty()`.",
727 examples: &[],
728 },
729 IntrinsicDef {
730 id: IntrinsicId::SliceIndexRead,
731 name: "slice_index_read",
732 kind: IntrinsicKind::Expr,
733 category: Category::Slice,
734 requires_unchecked: false,
735 preview: None,
736 runtime_fn: None,
737 summary: "Read an element from a slice with bounds checking.",
738 description: "`@slice_index_read(s, i)` returns `s[i]`. Bounds-checks at runtime; panics on out-of-range. Surface form: `s[i]`.",
739 examples: &[],
740 },
741 IntrinsicDef {
742 id: IntrinsicId::SlicePtr,
743 name: "slice_ptr",
744 kind: IntrinsicKind::Expr,
745 category: Category::Slice,
746 requires_unchecked: true,
747 preview: None,
748 runtime_fn: None,
749 summary: "Extract the data pointer from a slice.",
750 description: "`@slice_ptr(s)` returns a `Ptr(T)` to the slice's first element. Requires a `checked` block. Surface form: `s.ptr()`.",
751 examples: &[],
752 },
753 IntrinsicDef {
754 id: IntrinsicId::SlicePtrMut,
755 name: "slice_ptr_mut",
756 kind: IntrinsicKind::Expr,
757 category: Category::Slice,
758 requires_unchecked: true,
759 preview: None,
760 runtime_fn: None,
761 summary: "Extract the mutable data pointer from a mutable slice.",
762 description: "`@slice_ptr_mut(m)` returns a `MutPtr(T)` to a `MutSlice(T)`'s first element. Requires a `checked` block. Surface form: `m.ptr_mut()`.",
763 examples: &[],
764 },
765 IntrinsicDef {
766 id: IntrinsicId::PartsToSlice,
767 name: "parts_to_slice",
768 kind: IntrinsicKind::Expr,
769 category: Category::Slice,
770 requires_unchecked: true,
771 preview: None,
772 runtime_fn: None,
773 summary: "Build a slice from a raw pointer and a length.",
774 description: "`@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.",
775 examples: &[],
776 },
777 IntrinsicDef {
778 id: IntrinsicId::PartsToMutSlice,
779 name: "parts_to_mut_slice",
780 kind: IntrinsicKind::Expr,
781 category: Category::Slice,
782 requires_unchecked: true,
783 preview: None,
784 runtime_fn: None,
785 summary: "Build a mutable slice from a raw mutable pointer and a length.",
786 description: "`@parts_to_mut_slice(p: MutPtr(T), n: usize) -> MutSlice(T)`. Requires a `checked` block.",
787 examples: &[],
788 },
789 IntrinsicDef {
790 id: IntrinsicId::SliceIndexWrite,
791 name: "slice_index_write",
792 kind: IntrinsicKind::Expr,
793 category: Category::Slice,
794 requires_unchecked: false,
795 preview: None,
796 runtime_fn: None,
797 summary: "Write an element to a mutable slice with bounds checking.",
798 description: "`@slice_index_write(m, i, v)` performs `m[i] = v`. Requires `MutSlice(T)`. Bounds-checks at runtime. Surface form: `m[i] = v`.",
799 examples: &[],
800 },
801 IntrinsicDef {
807 id: IntrinsicId::VecLiteral,
808 name: "vec",
809 kind: IntrinsicKind::Expr,
810 category: Category::Vec,
811 requires_unchecked: false,
812 preview: None,
813 runtime_fn: None,
814 summary: "Construct a Vec from individual elements.",
815 description: "`@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`.",
816 examples: &["@vec(1, 2, 3)"],
817 },
818 IntrinsicDef {
819 id: IntrinsicId::VecRepeat,
820 name: "vec_repeat",
821 kind: IntrinsicKind::Expr,
822 category: Category::Vec,
823 requires_unchecked: false,
824 preview: None,
825 runtime_fn: None,
826 summary: "Construct a Vec with N copies of a value.",
827 description: "`@vec_repeat(v, n)` returns a `Vec(T)` of length `n` where every slot holds a clone of `v`. Requires `T: Clone`.",
828 examples: &["@vec_repeat(0, 100)"],
829 },
830 IntrinsicDef {
831 id: IntrinsicId::PartsToVec,
832 name: "parts_to_vec",
833 kind: IntrinsicKind::Expr,
834 category: Category::Vec,
835 requires_unchecked: true,
836 preview: None,
837 runtime_fn: None,
838 summary: "Build a Vec from raw parts.",
839 description: "`@parts_to_vec(p: MutPtr(T), len: usize, cap: usize) -> Vec(T)` takes ownership of `p`. Requires a `checked` block.",
840 examples: &[],
841 },
842 IntrinsicDef {
843 id: IntrinsicId::TestPreviewGate,
844 name: "test_preview_gate",
845 kind: IntrinsicKind::Expr,
846 category: Category::Meta,
847 requires_unchecked: false,
848 preview: Some(PreviewFeature::TestInfra),
849 runtime_fn: None,
850 summary: "Test hook for the preview-feature gate.",
851 description: "`@test_preview_gate()` exists solely to verify that the preview-feature gating mechanism works. Always gated behind `--preview test_infra`.",
852 examples: &[],
853 },
854 IntrinsicDef {
855 id: IntrinsicId::Spawn,
856 name: "spawn",
857 kind: IntrinsicKind::Expr,
858 category: Category::Comptime,
859 requires_unchecked: false,
860 preview: None,
861 runtime_fn: Some("__gruel_thread_spawn"),
862 summary: "Spawn a worker thread running `fn(arg) -> R`.",
863 description: "`@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.",
864 examples: &[
865 "let h = @spawn(worker, Job { id: 1 });",
866 "let report = h.join();",
867 ],
868 },
869 IntrinsicDef {
870 id: IntrinsicId::ThreadJoin,
871 name: "thread_join",
872 kind: IntrinsicKind::Expr,
873 category: Category::Comptime,
874 requires_unchecked: true,
875 preview: None,
876 runtime_fn: Some("__gruel_thread_join"),
877 summary: "Internal lowering target for JoinHandle::join (ADR-0084).",
878 description: "`@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.",
879 examples: &[],
880 },
881 IntrinsicDef {
882 id: IntrinsicId::Uninit,
883 name: "uninit",
884 kind: IntrinsicKind::Type,
885 category: Category::Comptime,
886 requires_unchecked: false,
887 preview: None,
888 runtime_fn: None,
889 summary: "Allocate a partially-initialized value of a given type (ADR-0079).",
890 description: "`@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`.",
891 examples: &[
892 "let mut h = @uninit(Point);",
893 "@field(h, \"x\") = 1;",
894 "@field(h, \"y\") = 2;",
895 "let p: Point = @finalize(h);",
896 ],
897 },
898 IntrinsicDef {
899 id: IntrinsicId::Finalize,
900 name: "finalize",
901 kind: IntrinsicKind::Expr,
902 category: Category::Comptime,
903 requires_unchecked: false,
904 preview: None,
905 runtime_fn: None,
906 summary: "Consume an `Uninit(T)` handle and return a real `T` (ADR-0079).",
907 description: "`@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.",
908 examples: &["@finalize(h)"],
909 },
910 IntrinsicDef {
911 id: IntrinsicId::FieldSet,
912 name: "field_set",
913 kind: IntrinsicKind::Expr,
914 category: Category::Comptime,
915 requires_unchecked: false,
916 preview: None,
917 runtime_fn: None,
918 summary: "Write a field of an in-progress `@uninit`/`@variant_uninit` handle (ADR-0079).",
919 description: "`@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.",
920 examples: &["@field_set(out, f.name, @field(self, f.name).clone())"],
921 },
922 IntrinsicDef {
923 id: IntrinsicId::VariantUninit,
924 name: "variant_uninit",
925 kind: IntrinsicKind::Expr,
926 category: Category::Comptime,
927 requires_unchecked: false,
928 preview: None,
929 runtime_fn: None,
930 summary: "Allocate an `Uninit(Self)` pre-tagged for a specific enum variant (ADR-0079).",
931 description: "`@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.",
932 examples: &[
933 "let mut out = @variant_uninit(Self, v.tag);",
934 "@field(out, f.name) = ...;",
935 "let result: Self = @finalize(out);",
936 ],
937 },
938 IntrinsicDef {
939 id: IntrinsicId::VariantField,
940 name: "variant_field",
941 kind: IntrinsicKind::Expr,
942 category: Category::Comptime,
943 requires_unchecked: false,
944 preview: None,
945 runtime_fn: None,
946 summary: "Read a payload field of a known enum variant (ADR-0079).",
947 description: "`@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.",
948 examples: &["@variant_field(self, v.tag, f.name)"],
949 },
950 IntrinsicDef {
951 id: IntrinsicId::CStrToVec,
952 name: "cstr_to_vec",
953 kind: IntrinsicKind::Expr,
954 category: Category::Meta,
955 requires_unchecked: true,
956 preview: None,
960 runtime_fn: Some("__gruel_cstr_to_vec"),
961 summary: "Copy a NUL-terminated C string into a fresh Vec(u8).",
962 description: "`@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).",
963 examples: &["@cstr_to_vec(p)"],
964 },
965 IntrinsicDef {
975 id: IntrinsicId::PtrCast,
976 name: "ptr_cast",
977 kind: IntrinsicKind::Expr,
978 category: Category::Pointer,
979 requires_unchecked: true,
980 preview: None,
981 runtime_fn: None,
982 summary: "Reinterpret a pointer as another pointer type (ADR-0082).",
983 description: "`@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.",
984 examples: &["let p: MutPtr(T) = checked { @ptr_cast(p_u8) };"],
985 },
986 ];
989
990#[derive(Debug, Clone, Copy, PartialEq, Eq)]
996pub enum PointerKind {
997 Ptr,
999 MutPtr,
1001}
1002
1003#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1005pub enum PointerOpForm {
1006 Method,
1008 AssocFn,
1010}
1011
1012#[derive(Debug, Clone, Copy)]
1024pub struct PointerMethod {
1025 pub kind: PointerKind,
1027 pub name: &'static str,
1030 pub form: PointerOpForm,
1032 pub intrinsic: IntrinsicId,
1034 pub intrinsic_name: &'static str,
1036 pub is_unchecked: bool,
1046}
1047
1048pub const POINTER_METHODS: &[PointerMethod] = &[
1054 PointerMethod {
1056 kind: PointerKind::Ptr,
1057 name: "read",
1058 form: PointerOpForm::Method,
1059 intrinsic: IntrinsicId::PtrRead,
1060 intrinsic_name: "ptr_read",
1061 is_unchecked: true,
1062 },
1063 PointerMethod {
1064 kind: PointerKind::Ptr,
1065 name: "read_volatile",
1066 form: PointerOpForm::Method,
1067 intrinsic: IntrinsicId::PtrReadVolatile,
1068 intrinsic_name: "ptr_read_volatile",
1069 is_unchecked: true,
1070 },
1071 PointerMethod {
1072 kind: PointerKind::Ptr,
1073 name: "offset",
1074 form: PointerOpForm::Method,
1075 intrinsic: IntrinsicId::PtrOffset,
1076 intrinsic_name: "ptr_offset",
1077 is_unchecked: true,
1078 },
1079 PointerMethod {
1080 kind: PointerKind::Ptr,
1081 name: "is_null",
1082 form: PointerOpForm::Method,
1083 intrinsic: IntrinsicId::IsNull,
1084 intrinsic_name: "is_null",
1085 is_unchecked: false,
1086 },
1087 PointerMethod {
1088 kind: PointerKind::Ptr,
1089 name: "to_int",
1090 form: PointerOpForm::Method,
1091 intrinsic: IntrinsicId::PtrToInt,
1092 intrinsic_name: "ptr_to_int",
1093 is_unchecked: false,
1094 },
1095 PointerMethod {
1097 kind: PointerKind::Ptr,
1098 name: "from",
1099 form: PointerOpForm::AssocFn,
1100 intrinsic: IntrinsicId::Raw,
1101 intrinsic_name: "raw",
1102 is_unchecked: false,
1103 },
1104 PointerMethod {
1105 kind: PointerKind::Ptr,
1106 name: "null",
1107 form: PointerOpForm::AssocFn,
1108 intrinsic: IntrinsicId::NullPtr,
1109 intrinsic_name: "null_ptr",
1110 is_unchecked: false,
1111 },
1112 PointerMethod {
1113 kind: PointerKind::Ptr,
1114 name: "from_int",
1115 form: PointerOpForm::AssocFn,
1116 intrinsic: IntrinsicId::IntToPtr,
1117 intrinsic_name: "int_to_ptr",
1118 is_unchecked: false,
1119 },
1120 PointerMethod {
1122 kind: PointerKind::MutPtr,
1123 name: "read",
1124 form: PointerOpForm::Method,
1125 intrinsic: IntrinsicId::PtrRead,
1126 intrinsic_name: "ptr_read",
1127 is_unchecked: true,
1128 },
1129 PointerMethod {
1130 kind: PointerKind::MutPtr,
1131 name: "read_volatile",
1132 form: PointerOpForm::Method,
1133 intrinsic: IntrinsicId::PtrReadVolatile,
1134 intrinsic_name: "ptr_read_volatile",
1135 is_unchecked: true,
1136 },
1137 PointerMethod {
1138 kind: PointerKind::MutPtr,
1139 name: "write",
1140 form: PointerOpForm::Method,
1141 intrinsic: IntrinsicId::PtrWrite,
1142 intrinsic_name: "ptr_write",
1143 is_unchecked: true,
1144 },
1145 PointerMethod {
1146 kind: PointerKind::MutPtr,
1147 name: "write_volatile",
1148 form: PointerOpForm::Method,
1149 intrinsic: IntrinsicId::PtrWriteVolatile,
1150 intrinsic_name: "ptr_write_volatile",
1151 is_unchecked: true,
1152 },
1153 PointerMethod {
1154 kind: PointerKind::MutPtr,
1155 name: "offset",
1156 form: PointerOpForm::Method,
1157 intrinsic: IntrinsicId::PtrOffset,
1158 intrinsic_name: "ptr_offset",
1159 is_unchecked: true,
1160 },
1161 PointerMethod {
1162 kind: PointerKind::MutPtr,
1163 name: "is_null",
1164 form: PointerOpForm::Method,
1165 intrinsic: IntrinsicId::IsNull,
1166 intrinsic_name: "is_null",
1167 is_unchecked: false,
1168 },
1169 PointerMethod {
1170 kind: PointerKind::MutPtr,
1171 name: "to_int",
1172 form: PointerOpForm::Method,
1173 intrinsic: IntrinsicId::PtrToInt,
1174 intrinsic_name: "ptr_to_int",
1175 is_unchecked: false,
1176 },
1177 PointerMethod {
1178 kind: PointerKind::MutPtr,
1179 name: "copy_from",
1180 form: PointerOpForm::Method,
1181 intrinsic: IntrinsicId::PtrCopy,
1182 intrinsic_name: "ptr_copy",
1183 is_unchecked: true,
1184 },
1185 PointerMethod {
1187 kind: PointerKind::MutPtr,
1188 name: "from",
1189 form: PointerOpForm::AssocFn,
1190 intrinsic: IntrinsicId::RawMut,
1191 intrinsic_name: "raw_mut",
1192 is_unchecked: false,
1193 },
1194 PointerMethod {
1195 kind: PointerKind::MutPtr,
1196 name: "null",
1197 form: PointerOpForm::AssocFn,
1198 intrinsic: IntrinsicId::NullPtr,
1199 intrinsic_name: "null_ptr",
1200 is_unchecked: false,
1201 },
1202 PointerMethod {
1203 kind: PointerKind::MutPtr,
1204 name: "from_int",
1205 form: PointerOpForm::AssocFn,
1206 intrinsic: IntrinsicId::IntToPtr,
1207 intrinsic_name: "int_to_ptr",
1208 is_unchecked: false,
1209 },
1210];
1211
1212pub fn lookup_pointer_method(
1214 kind: PointerKind,
1215 name: &str,
1216 form: PointerOpForm,
1217) -> Option<&'static PointerMethod> {
1218 POINTER_METHODS
1219 .iter()
1220 .find(|m| m.kind == kind && m.form == form && m.name == name)
1221}
1222
1223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1229pub enum SliceKind {
1230 Slice,
1232 MutSlice,
1234}
1235
1236#[derive(Debug, Clone, Copy)]
1241pub struct SliceMethod {
1242 pub kind: SliceKind,
1244 pub name: &'static str,
1246 pub intrinsic: IntrinsicId,
1248 pub intrinsic_name: &'static str,
1250 pub requires_checked: bool,
1252}
1253
1254pub const SLICE_METHODS: &[SliceMethod] = &[
1256 SliceMethod {
1258 kind: SliceKind::Slice,
1259 name: "len",
1260 intrinsic: IntrinsicId::SliceLen,
1261 intrinsic_name: "slice_len",
1262 requires_checked: false,
1263 },
1264 SliceMethod {
1265 kind: SliceKind::Slice,
1266 name: "is_empty",
1267 intrinsic: IntrinsicId::SliceIsEmpty,
1268 intrinsic_name: "slice_is_empty",
1269 requires_checked: false,
1270 },
1271 SliceMethod {
1272 kind: SliceKind::Slice,
1273 name: "ptr",
1274 intrinsic: IntrinsicId::SlicePtr,
1275 intrinsic_name: "slice_ptr",
1276 requires_checked: true,
1277 },
1278 SliceMethod {
1280 kind: SliceKind::MutSlice,
1281 name: "len",
1282 intrinsic: IntrinsicId::SliceLen,
1283 intrinsic_name: "slice_len",
1284 requires_checked: false,
1285 },
1286 SliceMethod {
1287 kind: SliceKind::MutSlice,
1288 name: "is_empty",
1289 intrinsic: IntrinsicId::SliceIsEmpty,
1290 intrinsic_name: "slice_is_empty",
1291 requires_checked: false,
1292 },
1293 SliceMethod {
1294 kind: SliceKind::MutSlice,
1295 name: "ptr",
1296 intrinsic: IntrinsicId::SlicePtr,
1297 intrinsic_name: "slice_ptr",
1298 requires_checked: true,
1299 },
1300 SliceMethod {
1301 kind: SliceKind::MutSlice,
1302 name: "ptr_mut",
1303 intrinsic: IntrinsicId::SlicePtrMut,
1304 intrinsic_name: "slice_ptr_mut",
1305 requires_checked: true,
1306 },
1307];
1308
1309pub fn lookup_slice_method(kind: SliceKind, name: &str) -> Option<&'static SliceMethod> {
1311 SLICE_METHODS
1312 .iter()
1313 .find(|m| m.kind == kind && m.name == name)
1314}
1315
1316pub fn lookup_by_name(name: &str) -> Option<&'static IntrinsicDef> {
1322 INTRINSICS.iter().find(|d| d.name == name)
1323}
1324
1325pub fn lookup_by_id(id: IntrinsicId) -> &'static IntrinsicDef {
1327 INTRINSICS
1328 .iter()
1329 .find(|d| d.id == id)
1330 .expect("every IntrinsicId must have exactly one INTRINSICS entry (checked by tests)")
1331}
1332
1333pub fn iter() -> impl Iterator<Item = &'static IntrinsicDef> {
1335 INTRINSICS.iter()
1336}
1337
1338pub fn by_category(cat: Category) -> impl Iterator<Item = &'static IntrinsicDef> {
1340 INTRINSICS.iter().filter(move |d| d.category == cat)
1341}
1342
1343pub fn is_type_intrinsic(name: &str) -> bool {
1345 lookup_by_name(name).is_some_and(|d| d.kind == IntrinsicKind::Type)
1346}
1347
1348pub fn render_reference_markdown() -> String {
1363 let mut out = String::new();
1364 out.push_str("<!-- AUTO-GENERATED by `cargo run -p gruel-intrinsics-docs`. Do not edit by hand; edit the IntrinsicDef entries in `crates/gruel-intrinsics/src/lib.rs` and regenerate. -->\n\n");
1365 out.push_str("# Intrinsics Reference\n\n");
1366 out.push_str("This page documents every `@intrinsic` the Gruel compiler recognizes. It is generated from the [`gruel-intrinsics`] registry (see [ADR-0050](../designs/0050-intrinsics-crate.md)); any changes must be made in Rust, not here.\n\n");
1367
1368 out.push_str("## Quick Reference\n\n");
1374 out.push_str("| Intrinsic | Kind | Category | Preview | Unchecked | Summary |\n");
1375 out.push_str("|---|---|---|---|---|---|\n");
1376 let mut ordered: Vec<&IntrinsicDef> = INTRINSICS.iter().collect();
1377 ordered.sort_by_key(|d| d.category.render_index());
1378 for d in ordered {
1379 let kind = match d.kind {
1380 IntrinsicKind::Expr => "expr",
1381 IntrinsicKind::Type => "type",
1382 IntrinsicKind::TypeInterface => "type+iface",
1383 };
1384 let preview = match d.preview {
1385 Some(f) => f.name(),
1386 None => "—",
1387 };
1388 let unchecked = if d.requires_unchecked { "yes" } else { "—" };
1389 out.push_str(&format!(
1390 "| `@{}` | {} | {} | {} | {} | {} |\n",
1391 d.name,
1392 kind,
1393 d.category.heading(),
1394 preview,
1395 unchecked,
1396 d.summary,
1397 ));
1398 }
1399 out.push('\n');
1400
1401 for &cat in Category::RENDER_ORDER {
1403 let mut entries = by_category(cat).peekable();
1404 if entries.peek().is_none() {
1405 continue;
1406 }
1407 out.push_str(&format!("## {}\n\n", cat.heading()));
1408 for d in entries {
1409 out.push_str(&format!("### `@{}`\n\n", d.name));
1410 out.push_str(&format!("{}\n\n", d.description));
1411 if let Some(rt) = d.runtime_fn {
1412 out.push_str(&format!("- **Runtime symbol:** `{rt}`\n"));
1413 }
1414 if let Some(feature) = d.preview {
1415 out.push_str(&format!(
1416 "- **Preview gate:** `--preview {}` ({})\n",
1417 feature.name(),
1418 feature.adr()
1419 ));
1420 }
1421 if d.requires_unchecked {
1422 out.push_str("- **Requires:** `checked { ... }` block\n");
1423 }
1424 if !d.examples.is_empty() {
1425 out.push_str("\n**Examples:**\n\n");
1426 for ex in d.examples {
1427 out.push_str("```gruel\n");
1428 out.push_str(ex);
1429 if !ex.ends_with('\n') {
1430 out.push('\n');
1431 }
1432 out.push_str("```\n\n");
1433 }
1434 } else {
1435 out.push('\n');
1436 }
1437 }
1438 }
1439 out
1440}
1441
1442#[cfg(test)]
1447mod tests {
1448 use super::*;
1449 use rustc_hash::FxHashSet as HashSet;
1450
1451 #[test]
1452 fn no_duplicate_names() {
1453 let mut seen = HashSet::default();
1454 for d in INTRINSICS {
1455 assert!(seen.insert(d.name), "duplicate intrinsic name: {}", d.name);
1456 }
1457 }
1458
1459 #[test]
1460 fn no_duplicate_ids() {
1461 let mut seen = HashSet::default();
1462 for d in INTRINSICS {
1463 assert!(seen.insert(d.id), "duplicate IntrinsicId: {:?}", d.id);
1464 }
1465 }
1466
1467 #[test]
1468 fn every_id_variant_covered() {
1469 for d in INTRINSICS {
1472 match d.id {
1473 IntrinsicId::Dbg
1474 | IntrinsicId::Panic
1475 | IntrinsicId::Assert
1476 | IntrinsicId::CompileError
1477 | IntrinsicId::Cast
1478 | IntrinsicId::SizeOf
1479 | IntrinsicId::AlignOf
1480 | IntrinsicId::TypeName
1481 | IntrinsicId::TypeInfo
1482 | IntrinsicId::Ownership
1483 | IntrinsicId::ThreadSafety
1484 | IntrinsicId::Implements
1485 | IntrinsicId::Field
1486 | IntrinsicId::Import
1487 | IntrinsicId::EmbedFile
1488 | IntrinsicId::TargetArch
1489 | IntrinsicId::TargetOs
1490 | IntrinsicId::PtrRead
1491 | IntrinsicId::PtrWrite
1492 | IntrinsicId::PtrReadVolatile
1493 | IntrinsicId::PtrWriteVolatile
1494 | IntrinsicId::PtrOffset
1495 | IntrinsicId::PtrToInt
1496 | IntrinsicId::IntToPtr
1497 | IntrinsicId::NullPtr
1498 | IntrinsicId::IsNull
1499 | IntrinsicId::PtrCopy
1500 | IntrinsicId::Raw
1501 | IntrinsicId::RawMut
1502 | IntrinsicId::Syscall
1503 | IntrinsicId::Range
1504 | IntrinsicId::SliceLen
1505 | IntrinsicId::SliceIsEmpty
1506 | IntrinsicId::SliceIndexRead
1507 | IntrinsicId::SliceIndexWrite
1508 | IntrinsicId::SlicePtr
1509 | IntrinsicId::SlicePtrMut
1510 | IntrinsicId::PartsToSlice
1511 | IntrinsicId::PartsToMutSlice
1512 | IntrinsicId::VecLiteral
1513 | IntrinsicId::VecRepeat
1514 | IntrinsicId::PartsToVec
1515 | IntrinsicId::TestPreviewGate
1516 | IntrinsicId::Spawn
1517 | IntrinsicId::CStrToVec
1518 | IntrinsicId::Uninit
1519 | IntrinsicId::Finalize
1520 | IntrinsicId::FieldSet
1521 | IntrinsicId::VariantUninit
1522 | IntrinsicId::VariantField
1523 | IntrinsicId::PtrCast
1524 | IntrinsicId::ThreadJoin => {}
1525 }
1526 }
1527 }
1528
1529 #[test]
1530 fn lookup_by_name_roundtrip() {
1531 for d in INTRINSICS {
1532 let found = lookup_by_name(d.name).expect("name must resolve");
1533 assert_eq!(found.id, d.id);
1534 }
1535 assert!(lookup_by_name("definitely_not_an_intrinsic").is_none());
1536 }
1537
1538 #[test]
1539 fn lookup_by_id_roundtrip() {
1540 for d in INTRINSICS {
1541 assert_eq!(lookup_by_id(d.id).name, d.name);
1542 }
1543 }
1544
1545 #[test]
1546 fn type_intrinsics_match_legacy_list() {
1547 let from_registry: HashSet<&'static str> = INTRINSICS
1552 .iter()
1553 .filter(|d| d.kind == IntrinsicKind::Type)
1554 .map(|d| d.name)
1555 .collect();
1556 let expected: HashSet<&'static str> = [
1557 "size_of",
1558 "align_of",
1559 "type_name",
1560 "type_info",
1561 "ownership",
1562 "thread_safety",
1563 "uninit",
1564 ]
1565 .into_iter()
1566 .collect();
1567 assert_eq!(from_registry, expected);
1568 }
1569
1570 #[test]
1571 fn unchecked_intrinsics_match_legacy_set() {
1572 let from_registry: HashSet<&'static str> = INTRINSICS
1574 .iter()
1575 .filter(|d| d.requires_unchecked)
1576 .map(|d| d.name)
1577 .collect();
1578 let expected: HashSet<&'static str> = [
1579 "ptr_read",
1580 "ptr_write",
1581 "ptr_read_volatile",
1582 "ptr_write_volatile",
1583 "ptr_offset",
1584 "ptr_to_int",
1585 "int_to_ptr",
1586 "null_ptr",
1587 "is_null",
1588 "ptr_copy",
1589 "raw",
1590 "raw_mut",
1591 "syscall",
1592 "slice_ptr",
1593 "slice_ptr_mut",
1594 "parts_to_slice",
1595 "parts_to_mut_slice",
1596 "parts_to_vec",
1597 "cstr_to_vec",
1599 "ptr_cast",
1603 "thread_join",
1605 ]
1606 .into_iter()
1607 .collect();
1608 assert_eq!(from_registry, expected);
1609 }
1610
1611 #[test]
1612 fn by_category_filters() {
1613 let ptrs: Vec<_> = by_category(Category::Pointer).collect();
1614 assert!(!ptrs.is_empty());
1615 assert!(ptrs.iter().all(|d| d.category == Category::Pointer));
1616 }
1617
1618 #[test]
1622 fn category_render_order_is_exhaustive() {
1623 let all = [
1627 Category::Debug,
1628 Category::Cast,
1629 Category::Io,
1630 Category::Parse,
1631 Category::Random,
1632 Category::Comptime,
1633 Category::Platform,
1634 Category::Pointer,
1635 Category::Syscall,
1636 Category::Iteration,
1637 Category::Slice,
1638 Category::Vec,
1639 Category::Meta,
1640 ];
1641 for c in all {
1644 let _: &'static str = match c {
1645 Category::Debug => "Debug",
1646 Category::Cast => "Cast",
1647 Category::Io => "Io",
1648 Category::Parse => "Parse",
1649 Category::Random => "Random",
1650 Category::Comptime => "Comptime",
1651 Category::Platform => "Platform",
1652 Category::Pointer => "Pointer",
1653 Category::Syscall => "Syscall",
1654 Category::Iteration => "Iteration",
1655 Category::Slice => "Slice",
1656 Category::Vec => "Vec",
1657 Category::Meta => "Meta",
1658 };
1659 assert!(
1660 Category::RENDER_ORDER.contains(&c),
1661 "Category::{:?} is missing from Category::RENDER_ORDER \
1662 — add it to keep the intrinsics reference page complete",
1663 c
1664 );
1665 }
1666 assert_eq!(
1667 Category::RENDER_ORDER.len(),
1668 all.len(),
1669 "Category::RENDER_ORDER has duplicates or is out of sync with Category"
1670 );
1671 }
1672
1673 #[test]
1674 fn is_type_intrinsic_basic() {
1675 assert!(is_type_intrinsic("size_of"));
1676 assert!(is_type_intrinsic("type_name"));
1677 assert!(!is_type_intrinsic("dbg"));
1678 assert!(!is_type_intrinsic("nonexistent"));
1679 }
1680
1681 #[test]
1682 fn all_names_are_valid_identifiers() {
1683 for d in INTRINSICS {
1684 assert!(!d.name.is_empty());
1685 assert!(
1686 d.name
1687 .chars()
1688 .all(|c| c.is_ascii_alphanumeric() || c == '_'),
1689 "intrinsic name {:?} has unexpected characters",
1690 d.name
1691 );
1692 }
1693 }
1694
1695 #[test]
1696 fn preview_gated_intrinsics_are_known_features() {
1697 let gated: Vec<_> = INTRINSICS.iter().filter(|d| d.preview.is_some()).collect();
1701 assert!(
1702 gated.iter().any(|d| d.name == "test_preview_gate"),
1703 "test_preview_gate must be preview-gated"
1704 );
1705 }
1706}