1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub enum BuiltinTypeConstructorKind {
44 Ptr,
46 MutPtr,
48 Ref,
50 MutRef,
52 Slice,
54 MutSlice,
56 Vec,
58}
59
60#[derive(Debug, Clone, Copy)]
71pub struct BuiltinTypeConstructor {
72 pub name: &'static str,
74 pub arity: usize,
76 pub kind: BuiltinTypeConstructorKind,
78}
79
80pub static PTR_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
82 name: "Ptr",
83 arity: 1,
84 kind: BuiltinTypeConstructorKind::Ptr,
85};
86
87pub static MUT_PTR_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
89 name: "MutPtr",
90 arity: 1,
91 kind: BuiltinTypeConstructorKind::MutPtr,
92};
93
94pub static REF_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
96 name: "Ref",
97 arity: 1,
98 kind: BuiltinTypeConstructorKind::Ref,
99};
100
101pub static MUT_REF_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
103 name: "MutRef",
104 arity: 1,
105 kind: BuiltinTypeConstructorKind::MutRef,
106};
107
108pub static SLICE_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
110 name: "Slice",
111 arity: 1,
112 kind: BuiltinTypeConstructorKind::Slice,
113};
114
115pub static MUT_SLICE_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
117 name: "MutSlice",
118 arity: 1,
119 kind: BuiltinTypeConstructorKind::MutSlice,
120};
121
122pub static VEC_CONSTRUCTOR: BuiltinTypeConstructor = BuiltinTypeConstructor {
124 name: "Vec",
125 arity: 1,
126 kind: BuiltinTypeConstructorKind::Vec,
127};
128
129pub static BUILTIN_TYPE_CONSTRUCTORS: &[&BuiltinTypeConstructor] = &[
134 &PTR_CONSTRUCTOR,
135 &MUT_PTR_CONSTRUCTOR,
136 &REF_CONSTRUCTOR,
137 &MUT_REF_CONSTRUCTOR,
138 &SLICE_CONSTRUCTOR,
139 &MUT_SLICE_CONSTRUCTOR,
140 &VEC_CONSTRUCTOR,
141];
142
143pub fn get_builtin_type_constructor(name: &str) -> Option<&'static BuiltinTypeConstructor> {
145 BUILTIN_TYPE_CONSTRUCTORS
146 .iter()
147 .find(|c| c.name == name)
148 .copied()
149}
150
151pub fn is_reserved_type_constructor_name(name: &str) -> bool {
153 BUILTIN_TYPE_CONSTRUCTORS.iter().any(|c| c.name == name)
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179pub enum MarkerKind {
180 Posture(Posture),
181 ThreadSafety(ThreadSafety),
185 Abi(Abi),
187 Unchecked,
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum Abi {
199 C,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
205pub enum Posture {
206 Copy,
208 Affine,
213 Linear,
216}
217
218#[derive(
229 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
230)]
231pub enum ThreadSafety {
232 Unsend,
234 Send,
236 Sync,
238}
239
240impl Default for ThreadSafety {
241 fn default() -> Self {
246 ThreadSafety::Sync
247 }
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256pub struct ItemKinds(u8);
257
258impl ItemKinds {
259 pub const STRUCT: ItemKinds = ItemKinds(0b001);
260 pub const ENUM: ItemKinds = ItemKinds(0b010);
261 pub const FUNCTION: ItemKinds = ItemKinds(0b100);
262 pub const STRUCT_OR_ENUM: ItemKinds = ItemKinds(0b011);
263 pub const FN_OR_STRUCT: ItemKinds = ItemKinds(0b101);
264 pub const FN_STRUCT_OR_ENUM: ItemKinds = ItemKinds(0b111);
266
267 pub fn includes_struct(self) -> bool {
268 (self.0 & Self::STRUCT.0) != 0
269 }
270
271 pub fn includes_enum(self) -> bool {
272 (self.0 & Self::ENUM.0) != 0
273 }
274
275 pub fn includes_function(self) -> bool {
276 (self.0 & Self::FUNCTION.0) != 0
277 }
278}
279
280#[derive(Debug, Clone, Copy)]
286pub struct BuiltinMarker {
287 pub name: &'static str,
289 pub kind: MarkerKind,
291 pub applicable_to: ItemKinds,
293}
294
295pub static BUILTIN_MARKERS: &[BuiltinMarker] = &[
300 BuiltinMarker {
301 name: "copy",
302 kind: MarkerKind::Posture(Posture::Copy),
303 applicable_to: ItemKinds::STRUCT_OR_ENUM,
304 },
305 BuiltinMarker {
306 name: "affine",
307 kind: MarkerKind::Posture(Posture::Affine),
308 applicable_to: ItemKinds::STRUCT_OR_ENUM,
309 },
310 BuiltinMarker {
311 name: "linear",
312 kind: MarkerKind::Posture(Posture::Linear),
313 applicable_to: ItemKinds::STRUCT_OR_ENUM,
314 },
315 BuiltinMarker {
320 name: "unsend",
321 kind: MarkerKind::ThreadSafety(ThreadSafety::Unsend),
322 applicable_to: ItemKinds::STRUCT_OR_ENUM,
323 },
324 BuiltinMarker {
325 name: "checked_send",
326 kind: MarkerKind::ThreadSafety(ThreadSafety::Send),
327 applicable_to: ItemKinds::STRUCT_OR_ENUM,
328 },
329 BuiltinMarker {
330 name: "checked_sync",
331 kind: MarkerKind::ThreadSafety(ThreadSafety::Sync),
332 applicable_to: ItemKinds::STRUCT_OR_ENUM,
333 },
334 BuiltinMarker {
340 name: "c",
341 kind: MarkerKind::Abi(Abi::C),
342 applicable_to: ItemKinds::FN_STRUCT_OR_ENUM,
343 },
344 BuiltinMarker {
350 name: "unchecked",
351 kind: MarkerKind::Unchecked,
352 applicable_to: ItemKinds::FUNCTION,
353 },
354];
355
356pub fn get_builtin_marker(name: &str) -> Option<&'static BuiltinMarker> {
358 BUILTIN_MARKERS.iter().find(|m| m.name == name)
359}
360
361pub fn all_marker_names() -> Vec<&'static str> {
363 BUILTIN_MARKERS.iter().map(|m| m.name).collect()
364}
365
366pub static BUILTIN_ENUM_NAMES: &[&str] = &["Arch", "Os", "TypeKind", "Ownership", "ThreadSafety"];
384
385pub static BUILTIN_INTERFACE_NAMES: &[&str] = &["Drop", "Clone", "Handle"];
402
403#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
421pub enum LangInterfaceItem {
422 Drop,
424 Clone,
427 Handle,
430 OpEq,
432 OpCmp,
434}
435
436#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
438pub enum LangEnumItem {
439 Ordering,
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
448pub enum LangFnItem {
449 Vec,
454}
455
456impl LangFnItem {
457 pub fn name(self) -> &'static str {
458 match self {
459 LangFnItem::Vec => "vec",
460 }
461 }
462
463 pub fn from_str(s: &str) -> Option<Self> {
464 Some(match s {
465 "vec" => LangFnItem::Vec,
466 _ => return None,
467 })
468 }
469
470 pub fn all() -> &'static [LangFnItem] {
471 &[LangFnItem::Vec]
472 }
473}
474
475impl LangInterfaceItem {
476 pub fn name(self) -> &'static str {
478 match self {
479 LangInterfaceItem::Drop => "drop",
480 LangInterfaceItem::Clone => "clone",
481 LangInterfaceItem::Handle => "handle",
482 LangInterfaceItem::OpEq => "op_eq",
483 LangInterfaceItem::OpCmp => "op_cmp",
484 }
485 }
486
487 pub fn from_str(s: &str) -> Option<Self> {
488 Some(match s {
489 "drop" => LangInterfaceItem::Drop,
490 "clone" => LangInterfaceItem::Clone,
491 "handle" => LangInterfaceItem::Handle,
492 "op_eq" => LangInterfaceItem::OpEq,
493 "op_cmp" => LangInterfaceItem::OpCmp,
494 _ => return None,
495 })
496 }
497
498 pub fn all() -> &'static [LangInterfaceItem] {
499 use LangInterfaceItem::*;
500 &[Drop, Clone, Handle, OpEq, OpCmp]
501 }
502}
503
504impl LangEnumItem {
505 pub fn name(self) -> &'static str {
506 match self {
507 LangEnumItem::Ordering => "ordering",
508 }
509 }
510
511 pub fn from_str(s: &str) -> Option<Self> {
512 Some(match s {
513 "ordering" => LangEnumItem::Ordering,
514 _ => return None,
515 })
516 }
517
518 pub fn all() -> &'static [LangEnumItem] {
519 &[LangEnumItem::Ordering]
520 }
521}
522
523pub enum LangItemKind {
526 Interface(LangInterfaceItem),
527 Enum(LangEnumItem),
528 Fn(LangFnItem),
529}
530
531impl LangItemKind {
532 pub fn from_str(s: &str) -> Option<Self> {
533 if let Some(i) = LangInterfaceItem::from_str(s) {
534 Some(LangItemKind::Interface(i))
535 } else if let Some(e) = LangEnumItem::from_str(s) {
536 Some(LangItemKind::Enum(e))
537 } else {
538 LangFnItem::from_str(s).map(LangItemKind::Fn)
539 }
540 }
541}
542
543pub fn all_lang_item_names() -> Vec<&'static str> {
548 let mut names: Vec<&'static str> = LangInterfaceItem::all()
549 .iter()
550 .map(|i| i.name())
551 .chain(LangEnumItem::all().iter().map(|e| e.name()))
552 .chain(LangFnItem::all().iter().map(|f| f.name()))
553 .collect();
554 names.sort();
555 names
556}
557
558impl BuiltinTypeConstructorKind {
563 fn description(self) -> &'static str {
564 match self {
565 BuiltinTypeConstructorKind::Ptr => "immutable raw pointer (ADR-0061)",
566 BuiltinTypeConstructorKind::MutPtr => "mutable raw pointer (ADR-0061)",
567 BuiltinTypeConstructorKind::Ref => "immutable reference (ADR-0062)",
568 BuiltinTypeConstructorKind::MutRef => "mutable reference (ADR-0062)",
569 BuiltinTypeConstructorKind::Slice => "immutable slice (ADR-0064)",
570 BuiltinTypeConstructorKind::MutSlice => "mutable slice (ADR-0064)",
571 BuiltinTypeConstructorKind::Vec => "owned, growable vector (ADR-0066)",
572 }
573 }
574}
575
576pub fn render_reference_markdown() -> String {
584 let mut out = String::new();
585 out.push_str("<!-- AUTO-GENERATED by `cargo run -p gruel-builtins-docs`. Do not edit by hand; edit the registries in `crates/gruel-builtins/src/lib.rs` and regenerate. -->\n\n");
586 out.push_str("# Built-in Types Reference\n\n");
587 out.push_str("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.\n\n");
588
589 out.push_str("## Quick Reference\n\n");
591
592 out.push_str("### Type Constructors\n\n");
593 out.push_str("| Name | Arity | Description |\n");
594 out.push_str("|---|---|---|\n");
595 for c in BUILTIN_TYPE_CONSTRUCTORS {
596 out.push_str(&format!(
597 "| `{}` | {} | {} |\n",
598 c.name,
599 c.arity,
600 c.kind.description(),
601 ));
602 }
603 out.push('\n');
604
605 out.push_str("### Enums\n\n");
606 out.push_str("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.\n\n");
607 out.push_str("| Name | Variants |\n");
608 out.push_str("|---|---|\n");
609 out.push_str("| `Arch` | `X86_64`, `Aarch64`, `X86`, `Arm`, `Riscv32`, `Riscv64`, `Wasm32`, `Wasm64` |\n");
610 out.push_str("| `Os` | `Linux`, `Macos`, `Windows`, `Freestanding`, `Wasi` |\n");
611 out.push_str("| `TypeKind` | `Struct`, `Enum`, `Int`, `Bool`, `Unit`, `Never`, `Array` |\n");
612 out.push_str("| `Ownership` | `Copy`, `Affine`, `Linear` |\n");
613 out.push_str("| `ThreadSafety` | `Unsend`, `Send`, `Sync` |\n");
614 out.push('\n');
615
616 out.push_str("### Interfaces\n\n");
617 out.push_str("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)`.\n\n");
618 out.push_str("| Name | Method | Conformance |\n");
619 out.push_str("|---|---|---|\n");
620 out.push_str("| `Drop` | `fn __drop(self)` | method presence |\n");
621 out.push_str("| `Clone` | `fn clone(self: Ref(Self)) -> Self` | `@derive(Clone)` |\n");
622 out.push_str("| `Handle` | `fn handle(self: Ref(Self)) -> Self` | method presence |\n");
623 out.push('\n');
624
625 out.push_str("### Markers\n\n");
626 out.push_str("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.\n\n");
627 out.push_str("| Name | Kind | Applies to |\n");
628 out.push_str("|---|---|---|\n");
629 for m in BUILTIN_MARKERS {
630 let kind_str = match m.kind {
631 MarkerKind::Posture(Posture::Copy) => "Posture(Copy)",
632 MarkerKind::Posture(Posture::Affine) => "Posture(Affine)",
633 MarkerKind::Posture(Posture::Linear) => "Posture(Linear)",
634 MarkerKind::ThreadSafety(ThreadSafety::Unsend) => "ThreadSafety(Unsend)",
635 MarkerKind::ThreadSafety(ThreadSafety::Send) => "ThreadSafety(Send)",
636 MarkerKind::ThreadSafety(ThreadSafety::Sync) => "ThreadSafety(Sync)",
637 MarkerKind::Abi(Abi::C) => "Abi(C)",
638 MarkerKind::Unchecked => "Unchecked",
639 };
640 let apply_str = match (
641 m.applicable_to.includes_struct(),
642 m.applicable_to.includes_enum(),
643 m.applicable_to.includes_function(),
644 ) {
645 (true, true, false) => "struct or enum",
646 (true, false, false) => "struct only",
647 (false, true, false) => "enum only",
648 (true, false, true) => "fn or struct",
649 (false, false, true) => "fn only",
650 _ => "(none)",
651 };
652 out.push_str(&format!(
653 "| `{}` | {} | {} |\n",
654 m.name, kind_str, apply_str
655 ));
656 }
657 out.push('\n');
658
659 out.push_str("## Type Constructors\n\n");
661 out.push_str("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.\n\n");
662 for c in BUILTIN_TYPE_CONSTRUCTORS {
663 let args = (0..c.arity)
664 .map(|i| {
665 if c.arity == 1 {
666 "T".to_string()
667 } else {
668 format!("T{}", i + 1)
669 }
670 })
671 .collect::<Vec<_>>()
672 .join(", ");
673 out.push_str(&format!("### `{}({})`\n\n", c.name, args));
674 out.push_str(&format!("{}.\n\n", c.kind.description()));
675 }
676
677 out.push_str("## Enums\n\n");
683 out.push_str("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.\n\n");
684
685 for (name, variants) in [
686 (
687 "Arch",
688 &[
689 "X86_64", "Aarch64", "X86", "Arm", "Riscv32", "Riscv64", "Wasm32", "Wasm64",
690 ][..],
691 ),
692 (
693 "Os",
694 &["Linux", "Macos", "Windows", "Freestanding", "Wasi"][..],
695 ),
696 (
697 "TypeKind",
698 &["Struct", "Enum", "Int", "Bool", "Unit", "Never", "Array"][..],
699 ),
700 ("Ownership", &["Copy", "Affine", "Linear"][..]),
701 ("ThreadSafety", &["Unsend", "Send", "Sync"][..]),
702 ] {
703 out.push_str(&format!("### `{}`\n\n", name));
704 out.push_str("| Index | Variant |\n");
705 out.push_str("|---|---|\n");
706 for (i, v) in variants.iter().enumerate() {
707 out.push_str(&format!("| {} | `{}::{}` |\n", i, name, v));
708 }
709 out.push('\n');
710 }
711
712 out.push_str("## Interfaces\n\n");
718 out.push_str("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.\n\n");
719
720 out.push_str("### `Drop`\n\n");
721 out.push_str("Types with custom cleanup logic that runs when the value goes out of scope (ADR-0059).\n\n");
722 out.push_str("**Required methods:**\n\n");
723 out.push_str("- `fn __drop(self)`\n\n");
724 out.push_str("**Conformance:** structural (no derive). Defining `fn __drop(self)` on a struct or enum makes it conform — there is no `@derive(Drop)` directive.\n\n");
725
726 out.push_str("### `Clone`\n\n");
727 out.push_str("Types that may be explicitly duplicated via `.clone()`. All `Copy` types auto-conform (ADR-0065).\n\n");
728 out.push_str("**Required methods:**\n\n");
729 out.push_str("- `fn clone(self: Ref(Self)) -> Self`\n\n");
730 out.push_str("**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.\n\n");
731
732 out.push_str("### `Handle`\n\n");
733 out.push_str("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).\n\n");
734 out.push_str("**Required methods:**\n\n");
735 out.push_str("- `fn handle(self: Ref(Self)) -> Self`\n\n");
736 out.push_str("**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.\n\n");
737
738 out.push_str("## Markers\n\n");
740 out.push_str("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.\n\n");
741 for m in BUILTIN_MARKERS {
742 out.push_str(&format!("### `@mark({})`\n\n", m.name));
743 match m.kind {
744 MarkerKind::Posture(Posture::Copy) => out.push_str(
745 "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.\n\n",
746 ),
747 MarkerKind::Posture(Posture::Affine) => out.push_str(
748 "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.\n\n",
749 ),
750 MarkerKind::Posture(Posture::Linear) => out.push_str(
751 "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).\n\n",
752 ),
753 MarkerKind::ThreadSafety(ThreadSafety::Unsend) => out.push_str(
754 "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).\n\n",
755 ),
756 MarkerKind::ThreadSafety(ThreadSafety::Send) => out.push_str(
757 "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.\n\n",
758 ),
759 MarkerKind::ThreadSafety(ThreadSafety::Sync) => out.push_str(
760 "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.\n\n",
761 ),
762 MarkerKind::Abi(Abi::C) => out.push_str(
763 "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.\n\n",
764 ),
765 MarkerKind::Unchecked => out.push_str(
766 "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.\n\n",
767 ),
768 }
769 }
770
771 out
772}
773
774#[cfg(test)]
775mod tests {
776 use super::*;
777
778 #[test]
779 fn test_builtin_enum_names() {
780 assert_eq!(
781 BUILTIN_ENUM_NAMES,
782 &["Arch", "Os", "TypeKind", "Ownership", "ThreadSafety"]
783 );
784 }
785
786 #[test]
787 fn test_builtin_type_constructors_registry() {
788 assert_eq!(BUILTIN_TYPE_CONSTRUCTORS.len(), 7);
791 }
792
793 #[test]
794 fn test_get_builtin_type_constructor() {
795 let ptr = get_builtin_type_constructor("Ptr").unwrap();
796 assert_eq!(ptr.name, "Ptr");
797 assert_eq!(ptr.arity, 1);
798 assert_eq!(ptr.kind, BuiltinTypeConstructorKind::Ptr);
799
800 let mut_ptr = get_builtin_type_constructor("MutPtr").unwrap();
801 assert_eq!(mut_ptr.name, "MutPtr");
802 assert_eq!(mut_ptr.arity, 1);
803 assert_eq!(mut_ptr.kind, BuiltinTypeConstructorKind::MutPtr);
804
805 assert!(get_builtin_type_constructor("MyConstructor").is_none());
806 }
807
808 #[test]
809 fn test_is_reserved_type_constructor_name() {
810 assert!(is_reserved_type_constructor_name("Ptr"));
811 assert!(is_reserved_type_constructor_name("MutPtr"));
812 assert!(!is_reserved_type_constructor_name("MyConstructor"));
813 }
814}