1use std::collections::HashMap;
12
13pub use bock_air::stubs::EffectRef;
14
15pub mod checker;
16pub use checker::{TypeChecker, TypeEnv};
17
18pub mod traits;
19pub use traits::{
20 check_supertrait_obligations, resolve_impl, resolve_method, ImplId, ImplTable, ResolvedMethod,
21 TraitRef,
22};
23
24pub mod ownership;
25pub use ownership::{analyze_ownership, AIRModule, OwnershipInfo, OwnershipState};
26
27pub mod effects;
28pub use effects::{infer_effects, track_effects, Strictness};
29
30pub mod capabilities;
31pub use capabilities::{compute_capabilities, verify_capabilities, CapabilitySet};
32
33pub mod exports;
34pub use exports::{collect_exports, type_to_type_ref};
35
36pub mod seed_imports;
37pub use seed_imports::{seed_imports, seed_prelude, PRELUDE_FROM_CORE};
38
39pub mod vocab;
40
41#[derive(Debug, Clone, PartialEq, Eq, Hash)]
45pub enum PrimitiveType {
46 Int,
48 Float,
49 Int8,
51 Int16,
52 Int32,
53 Int64,
54 Int128,
55 UInt8,
56 UInt16,
57 UInt32,
58 UInt64,
59 Float32,
61 Float64,
62 BigInt,
64 BigFloat,
65 Decimal,
66 Bool,
68 Char,
69 String,
70 Byte,
71 Bytes,
72 Void,
74 Never,
75}
76
77impl std::fmt::Display for PrimitiveType {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 write!(f, "{self:?}")
84 }
85}
86
87#[derive(Debug, Clone, PartialEq)]
96pub struct NamedType {
97 pub name: String,
99}
100
101#[derive(Debug, Clone, PartialEq)]
107pub struct GenericType {
108 pub constructor: String,
110 pub args: Vec<Type>,
112}
113
114#[derive(Debug, Clone, PartialEq)]
118pub struct FnType {
119 pub params: Vec<Type>,
121 pub ret: Box<Type>,
123 pub effects: Vec<EffectRef>,
125}
126
127#[derive(Debug, Clone, PartialEq)]
134pub struct Predicate {
135 pub source: String,
137}
138
139#[derive(Debug, Clone, PartialEq, Default)]
146pub struct StructuralConstraints {
147 pub fields: Vec<(String, Type)>,
149}
150
151pub type TypeVarId = u32;
155
156#[derive(Debug, Clone, PartialEq)]
165pub enum Type {
166 Primitive(PrimitiveType),
168 Named(NamedType),
170 Generic(GenericType),
172 Tuple(Vec<Type>),
174 Function(FnType),
176 Optional(Box<Type>),
178 Result(Box<Type>, Box<Type>),
180 TypeVar(TypeVarId),
182 Refined(Box<Type>, Predicate),
184 Flexible(StructuralConstraints),
186 Error,
188}
189
190impl std::fmt::Display for Type {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 match self {
202 Type::Primitive(p) => write!(f, "{p}"),
203 Type::Named(n) => write!(f, "{}", n.name),
204 Type::Generic(g) => {
205 write!(f, "{}[", g.constructor)?;
206 for (i, arg) in g.args.iter().enumerate() {
207 if i > 0 {
208 write!(f, ", ")?;
209 }
210 write!(f, "{arg}")?;
211 }
212 write!(f, "]")
213 }
214 Type::Tuple(elems) => {
215 write!(f, "(")?;
216 for (i, e) in elems.iter().enumerate() {
217 if i > 0 {
218 write!(f, ", ")?;
219 }
220 write!(f, "{e}")?;
221 }
222 write!(f, ")")
223 }
224 Type::Function(func) => {
225 write!(f, "Fn(")?;
226 for (i, p) in func.params.iter().enumerate() {
227 if i > 0 {
228 write!(f, ", ")?;
229 }
230 write!(f, "{p}")?;
231 }
232 write!(f, ") -> {}", func.ret)?;
233 if !func.effects.is_empty() {
234 write!(f, " with ")?;
235 for (i, e) in func.effects.iter().enumerate() {
236 if i > 0 {
237 write!(f, " + ")?;
238 }
239 write!(f, "{}", e.name)?;
240 }
241 }
242 Ok(())
243 }
244 Type::Optional(inner) => write!(f, "{inner}?"),
245 Type::Result(ok, err) => write!(f, "Result[{ok}, {err}]"),
246 Type::TypeVar(_) | Type::Flexible(_) => write!(f, "_"),
247 Type::Refined(base, pred) => write!(f, "{base} where {}", pred.source),
248 Type::Error => write!(f, "<error>"),
249 }
250 }
251}
252
253#[derive(Debug, Clone, PartialEq)]
257pub enum TypeError {
258 Mismatch {
260 left: Type,
262 right: Type,
264 },
265 OccursCheck {
268 var: TypeVarId,
270 ty: Type,
272 },
273 TupleArity { expected: usize, found: usize },
275 FnArity { expected: usize, found: usize },
277}
278
279impl std::fmt::Display for TypeError {
280 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 match self {
291 TypeError::Mismatch { left, right } => {
292 write!(f, "expected `{left}`, found `{right}`")
293 }
294 TypeError::OccursCheck { var: _, ty } => {
295 write!(
296 f,
297 "the inferred type would be infinite (`_` occurs in `{ty}`)"
298 )
299 }
300 TypeError::TupleArity { expected, found } => {
301 write!(
302 f,
303 "expected a tuple with {expected} elements, found {found}"
304 )
305 }
306 TypeError::FnArity { expected, found } => {
307 write!(
308 f,
309 "expected a function taking {expected} parameters, found one taking {found}"
310 )
311 }
312 }
313 }
314}
315
316impl std::error::Error for TypeError {}
317
318#[derive(Debug, Clone, Default)]
325pub struct Substitution {
326 map: HashMap<TypeVarId, Type>,
327}
328
329impl Substitution {
330 #[must_use]
332 pub fn new() -> Self {
333 Self::default()
334 }
335
336 #[must_use]
340 pub fn lookup(&self, mut id: TypeVarId) -> Type {
341 loop {
342 match self.map.get(&id) {
343 None => return Type::TypeVar(id),
344 Some(Type::TypeVar(next)) => {
345 id = *next;
346 }
347 Some(ty) => return ty.clone(),
348 }
349 }
350 }
351
352 pub fn bind(&mut self, id: TypeVarId, ty: Type) {
357 debug_assert!(
358 !self.map.contains_key(&id),
359 "TypeVar ?{id} is already bound"
360 );
361 self.map.insert(id, ty);
362 }
363
364 #[must_use]
367 pub fn apply(&self, ty: &Type) -> Type {
368 match ty {
369 Type::TypeVar(id) => {
370 let resolved = self.lookup(*id);
371 if resolved == *ty {
372 resolved
373 } else {
374 self.apply(&resolved)
375 }
376 }
377 Type::Primitive(_) | Type::Error => ty.clone(),
378 Type::Named(_) => ty.clone(),
379 Type::Generic(g) => Type::Generic(GenericType {
380 constructor: g.constructor.clone(),
381 args: g.args.iter().map(|a| self.apply(a)).collect(),
382 }),
383 Type::Tuple(elems) => Type::Tuple(elems.iter().map(|e| self.apply(e)).collect()),
384 Type::Function(f) => Type::Function(FnType {
385 params: f.params.iter().map(|p| self.apply(p)).collect(),
386 ret: Box::new(self.apply(&f.ret)),
387 effects: f.effects.clone(),
388 }),
389 Type::Optional(inner) => Type::Optional(Box::new(self.apply(inner))),
390 Type::Result(ok, err) => {
391 Type::Result(Box::new(self.apply(ok)), Box::new(self.apply(err)))
392 }
393 Type::Refined(base, pred) => Type::Refined(Box::new(self.apply(base)), pred.clone()),
394 Type::Flexible(constraints) => Type::Flexible(StructuralConstraints {
395 fields: constraints
396 .fields
397 .iter()
398 .map(|(name, ty)| (name.clone(), self.apply(ty)))
399 .collect(),
400 }),
401 }
402 }
403
404 #[must_use]
406 pub fn is_unbound(&self, id: TypeVarId) -> bool {
407 matches!(self.lookup(id), Type::TypeVar(_))
408 }
409}
410
411fn occurs(id: TypeVarId, ty: &Type, subst: &Substitution) -> bool {
416 match ty {
417 Type::TypeVar(other) => {
418 let resolved = subst.lookup(*other);
419 match resolved {
420 Type::TypeVar(rid) => rid == id,
421 _ => occurs(id, &resolved, subst),
422 }
423 }
424 Type::Primitive(_) | Type::Named(_) | Type::Error => false,
425 Type::Generic(g) => g.args.iter().any(|a| occurs(id, a, subst)),
426 Type::Tuple(elems) => elems.iter().any(|e| occurs(id, e, subst)),
427 Type::Function(f) => {
428 f.params.iter().any(|p| occurs(id, p, subst)) || occurs(id, &f.ret, subst)
429 }
430 Type::Optional(inner) => occurs(id, inner, subst),
431 Type::Result(ok, err) => occurs(id, ok, subst) || occurs(id, err, subst),
432 Type::Refined(base, _) => occurs(id, base, subst),
433 Type::Flexible(c) => c.fields.iter().any(|(_, t)| occurs(id, t, subst)),
434 }
435}
436
437pub fn unify(a: &Type, b: &Type, subst: &mut Substitution) -> Result<(), TypeError> {
451 let a = subst.apply(a);
453 let b = subst.apply(b);
454
455 match (&a, &b) {
456 (Type::Error, _) | (_, Type::Error) => Ok(()),
458
459 (Type::Primitive(PrimitiveType::Never), _) | (_, Type::Primitive(PrimitiveType::Never)) => {
461 Ok(())
462 }
463
464 _ if a == b => Ok(()),
466
467 (Type::TypeVar(id), other) | (other, Type::TypeVar(id)) => {
469 let id = *id;
470 if occurs(id, other, subst) {
471 return Err(TypeError::OccursCheck {
472 var: id,
473 ty: other.clone(),
474 });
475 }
476 subst.bind(id, other.clone());
477 Ok(())
478 }
479
480 (Type::Optional(a_inner), Type::Optional(b_inner)) => unify(a_inner, b_inner, subst),
484
485 (Type::Result(a_ok, a_err), Type::Result(b_ok, b_err)) => {
486 unify(a_ok, b_ok, subst)?;
487 unify(a_err, b_err, subst)
488 }
489
490 (Type::Tuple(a_elems), Type::Tuple(b_elems)) => {
491 if a_elems.len() != b_elems.len() {
492 return Err(TypeError::TupleArity {
493 expected: a_elems.len(),
494 found: b_elems.len(),
495 });
496 }
497 for (ae, be) in a_elems.iter().zip(b_elems.iter()) {
498 unify(ae, be, subst)?;
499 }
500 Ok(())
501 }
502
503 (Type::Function(fa), Type::Function(fb)) => {
504 if fa.params.len() != fb.params.len() {
505 return Err(TypeError::FnArity {
506 expected: fa.params.len(),
507 found: fb.params.len(),
508 });
509 }
510 for (ap, bp) in fa.params.iter().zip(fb.params.iter()) {
511 unify(ap, bp, subst)?;
512 }
513 unify(&fa.ret, &fb.ret, subst)
514 }
515
516 (Type::Generic(ga), Type::Generic(gb)) => {
517 if ga.constructor != gb.constructor {
518 return Err(TypeError::Mismatch {
519 left: a.clone(),
520 right: b.clone(),
521 });
522 }
523 if ga.args.len() != gb.args.len() {
524 return Err(TypeError::Mismatch {
525 left: a.clone(),
526 right: b.clone(),
527 });
528 }
529 for (aa, ba) in ga.args.iter().zip(gb.args.iter()) {
530 unify(aa, ba, subst)?;
531 }
532 Ok(())
533 }
534
535 (Type::Refined(base_a, _), Type::Refined(base_b, _)) => unify(base_a, base_b, subst),
537
538 (Type::Named(nt), Type::Generic(g)) | (Type::Generic(g), Type::Named(nt))
543 if nt.name == g.constructor =>
544 {
545 Ok(())
546 }
547
548 _ => Err(TypeError::Mismatch {
550 left: a.clone(),
551 right: b.clone(),
552 }),
553 }
554}
555
556#[must_use]
563pub fn types_equal(a: &Type, b: &Type, subst: &Substitution) -> bool {
564 let mut scratch = subst.clone();
565 unify(a, b, &mut scratch).is_ok()
566}
567
568#[cfg(test)]
571mod tests {
572 use super::*;
573
574 fn int() -> Type {
575 Type::Primitive(PrimitiveType::Int)
576 }
577
578 fn bool_ty() -> Type {
579 Type::Primitive(PrimitiveType::Bool)
580 }
581
582 fn string_ty() -> Type {
583 Type::Primitive(PrimitiveType::String)
584 }
585
586 fn var(id: TypeVarId) -> Type {
587 Type::TypeVar(id)
588 }
589
590 #[test]
593 fn type_display_renders_surface_syntax() {
594 assert_eq!(int().to_string(), "Int");
595 assert_eq!(string_ty().to_string(), "String");
596 assert_eq!(
597 Type::Named(NamedType {
598 name: "Point".into()
599 })
600 .to_string(),
601 "Point"
602 );
603 assert_eq!(
604 Type::Generic(GenericType {
605 constructor: "List".into(),
606 args: vec![int()],
607 })
608 .to_string(),
609 "List[Int]"
610 );
611 assert_eq!(
612 Type::Generic(GenericType {
613 constructor: "Map".into(),
614 args: vec![string_ty(), int()],
615 })
616 .to_string(),
617 "Map[String, Int]"
618 );
619 assert_eq!(
620 Type::Tuple(vec![int(), bool_ty()]).to_string(),
621 "(Int, Bool)"
622 );
623 assert_eq!(
624 Type::Function(FnType {
625 params: vec![int()],
626 ret: Box::new(bool_ty()),
627 effects: vec![],
628 })
629 .to_string(),
630 "Fn(Int) -> Bool"
631 );
632 assert_eq!(
633 Type::Function(FnType {
634 params: vec![],
635 ret: Box::new(int()),
636 effects: vec![EffectRef::new("Log")],
637 })
638 .to_string(),
639 "Fn() -> Int with Log"
640 );
641 assert_eq!(Type::Optional(Box::new(string_ty())).to_string(), "String?");
642 assert_eq!(
643 Type::Result(Box::new(int()), Box::new(string_ty())).to_string(),
644 "Result[Int, String]"
645 );
646 assert_eq!(var(7).to_string(), "_");
649 assert_eq!(
650 Type::Flexible(StructuralConstraints::default()).to_string(),
651 "_"
652 );
653 }
654
655 #[test]
656 fn type_error_display_uses_surface_syntax() {
657 let err = TypeError::Mismatch {
658 left: int(),
659 right: string_ty(),
660 };
661 assert_eq!(err.to_string(), "expected `Int`, found `String`");
662 assert!(!err.to_string().contains("Primitive("));
663 }
664
665 #[test]
668 fn subst_lookup_unbound() {
669 let s = Substitution::new();
670 assert_eq!(s.lookup(0), var(0));
671 }
672
673 #[test]
674 fn subst_bind_and_lookup() {
675 let mut s = Substitution::new();
676 s.bind(0, int());
677 assert_eq!(s.lookup(0), int());
678 }
679
680 #[test]
681 fn subst_chain_lookup() {
682 let mut s = Substitution::new();
683 s.bind(0, var(1));
684 s.bind(1, int());
685 assert_eq!(s.lookup(0), int());
686 }
687
688 #[test]
689 fn subst_apply_nested() {
690 let mut s = Substitution::new();
691 s.bind(0, int());
692 let ty = Type::Optional(Box::new(var(0)));
693 assert_eq!(s.apply(&ty), Type::Optional(Box::new(int())));
694 }
695
696 #[test]
697 fn subst_apply_tuple() {
698 let mut s = Substitution::new();
699 s.bind(0, int());
700 s.bind(1, bool_ty());
701 let ty = Type::Tuple(vec![var(0), var(1)]);
702 assert_eq!(s.apply(&ty), Type::Tuple(vec![int(), bool_ty()]));
703 }
704
705 #[test]
706 fn subst_apply_function() {
707 let mut s = Substitution::new();
708 s.bind(0, int());
709 s.bind(1, bool_ty());
710 let ty = Type::Function(FnType {
711 params: vec![var(0)],
712 ret: Box::new(var(1)),
713 effects: vec![],
714 });
715 let result = s.apply(&ty);
716 assert_eq!(
717 result,
718 Type::Function(FnType {
719 params: vec![int()],
720 ret: Box::new(bool_ty()),
721 effects: vec![],
722 })
723 );
724 }
725
726 #[test]
729 fn unify_same_primitive() {
730 let mut s = Substitution::new();
731 assert!(unify(&int(), &int(), &mut s).is_ok());
732 }
733
734 #[test]
735 fn unify_different_primitives_fails() {
736 let mut s = Substitution::new();
737 assert!(matches!(
738 unify(&int(), &bool_ty(), &mut s),
739 Err(TypeError::Mismatch { .. })
740 ));
741 }
742
743 #[test]
744 fn unify_error_with_anything() {
745 let mut s = Substitution::new();
746 assert!(unify(&Type::Error, &int(), &mut s).is_ok());
747 assert!(unify(&bool_ty(), &Type::Error, &mut s).is_ok());
748 assert!(unify(&Type::Error, &Type::Error, &mut s).is_ok());
749 assert!(unify(&Type::Error, &var(0), &mut s).is_ok());
750 }
751
752 #[test]
753 fn unify_never_with_anything() {
754 let mut s = Substitution::new();
755 let never = Type::Primitive(PrimitiveType::Never);
756 assert!(unify(&never, &int(), &mut s).is_ok());
757 assert!(unify(&bool_ty(), &never, &mut s).is_ok());
758 assert!(unify(&never, &never, &mut s).is_ok());
759 assert!(unify(&never, &var(10), &mut s).is_ok());
760 }
761
762 #[test]
765 fn unify_var_with_concrete() {
766 let mut s = Substitution::new();
767 assert!(unify(&var(0), &int(), &mut s).is_ok());
768 assert_eq!(s.lookup(0), int());
769 }
770
771 #[test]
772 fn unify_concrete_with_var() {
773 let mut s = Substitution::new();
774 assert!(unify(&int(), &var(0), &mut s).is_ok());
775 assert_eq!(s.lookup(0), int());
776 }
777
778 #[test]
779 fn unify_var_with_var() {
780 let mut s = Substitution::new();
781 assert!(unify(&var(0), &var(1), &mut s).is_ok());
782 s.bind(1, int());
787 assert_eq!(s.lookup(0), int());
788 }
789
790 #[test]
793 fn occurs_check_prevents_infinite_type() {
794 let mut s = Substitution::new();
795 let ty = Type::Optional(Box::new(var(0)));
797 assert!(matches!(
798 unify(&var(0), &ty, &mut s),
799 Err(TypeError::OccursCheck { var: 0, .. })
800 ));
801 }
802
803 #[test]
804 fn occurs_check_list_generic() {
805 let mut s = Substitution::new();
806 let list_t = Type::Generic(GenericType {
807 constructor: "List".into(),
808 args: vec![var(0)],
809 });
810 assert!(matches!(
811 unify(&var(0), &list_t, &mut s),
812 Err(TypeError::OccursCheck { var: 0, .. })
813 ));
814 }
815
816 #[test]
819 fn unify_optional() {
820 let mut s = Substitution::new();
821 assert!(unify(
822 &Type::Optional(Box::new(var(0))),
823 &Type::Optional(Box::new(int())),
824 &mut s
825 )
826 .is_ok());
827 assert_eq!(s.lookup(0), int());
828 }
829
830 #[test]
831 fn unify_result() {
832 let mut s = Substitution::new();
833 let a = Type::Result(Box::new(var(0)), Box::new(var(1)));
834 let b = Type::Result(Box::new(int()), Box::new(string_ty()));
835 assert!(unify(&a, &b, &mut s).is_ok());
836 assert_eq!(s.lookup(0), int());
837 assert_eq!(s.lookup(1), string_ty());
838 }
839
840 #[test]
841 fn unify_tuple_element_wise() {
842 let mut s = Substitution::new();
843 let a = Type::Tuple(vec![var(0), var(1)]);
844 let b = Type::Tuple(vec![int(), bool_ty()]);
845 assert!(unify(&a, &b, &mut s).is_ok());
846 assert_eq!(s.lookup(0), int());
847 assert_eq!(s.lookup(1), bool_ty());
848 }
849
850 #[test]
851 fn unify_tuple_arity_mismatch() {
852 let mut s = Substitution::new();
853 let a = Type::Tuple(vec![int(), bool_ty()]);
854 let b = Type::Tuple(vec![int()]);
855 assert!(matches!(
856 unify(&a, &b, &mut s),
857 Err(TypeError::TupleArity {
858 expected: 2,
859 found: 1
860 })
861 ));
862 }
863
864 #[test]
865 fn unify_function_types() {
866 let mut s = Substitution::new();
867 let a = Type::Function(FnType {
868 params: vec![var(0)],
869 ret: Box::new(var(1)),
870 effects: vec![],
871 });
872 let b = Type::Function(FnType {
873 params: vec![int()],
874 ret: Box::new(bool_ty()),
875 effects: vec![],
876 });
877 assert!(unify(&a, &b, &mut s).is_ok());
878 assert_eq!(s.lookup(0), int());
879 assert_eq!(s.lookup(1), bool_ty());
880 }
881
882 #[test]
883 fn unify_function_arity_mismatch() {
884 let mut s = Substitution::new();
885 let a = Type::Function(FnType {
886 params: vec![int(), bool_ty()],
887 ret: Box::new(int()),
888 effects: vec![],
889 });
890 let b = Type::Function(FnType {
891 params: vec![int()],
892 ret: Box::new(int()),
893 effects: vec![],
894 });
895 assert!(matches!(
896 unify(&a, &b, &mut s),
897 Err(TypeError::FnArity {
898 expected: 2,
899 found: 1
900 })
901 ));
902 }
903
904 #[test]
905 fn unify_generic_same_constructor() {
906 let mut s = Substitution::new();
907 let a = Type::Generic(GenericType {
908 constructor: "List".into(),
909 args: vec![var(0)],
910 });
911 let b = Type::Generic(GenericType {
912 constructor: "List".into(),
913 args: vec![int()],
914 });
915 assert!(unify(&a, &b, &mut s).is_ok());
916 assert_eq!(s.lookup(0), int());
917 }
918
919 #[test]
920 fn unify_generic_different_constructor_fails() {
921 let mut s = Substitution::new();
922 let a = Type::Generic(GenericType {
923 constructor: "List".into(),
924 args: vec![int()],
925 });
926 let b = Type::Generic(GenericType {
927 constructor: "Set".into(),
928 args: vec![int()],
929 });
930 assert!(matches!(
931 unify(&a, &b, &mut s),
932 Err(TypeError::Mismatch { .. })
933 ));
934 }
935
936 #[test]
939 fn unify_refined_base_types() {
940 let mut s = Substitution::new();
941 let a = Type::Refined(
942 Box::new(var(0)),
943 Predicate {
944 source: "self > 0".into(),
945 },
946 );
947 let b = Type::Refined(
948 Box::new(int()),
949 Predicate {
950 source: "self >= 0".into(),
951 },
952 );
953 assert!(unify(&a, &b, &mut s).is_ok());
954 assert_eq!(s.lookup(0), int());
955 }
956
957 #[test]
960 fn types_equal_same() {
961 let s = Substitution::new();
962 assert!(types_equal(&int(), &int(), &s));
963 }
964
965 #[test]
966 fn types_equal_different() {
967 let s = Substitution::new();
968 assert!(!types_equal(&int(), &bool_ty(), &s));
969 }
970
971 #[test]
972 fn types_equal_via_subst() {
973 let mut s = Substitution::new();
974 s.bind(0, int());
975 assert!(types_equal(&var(0), &int(), &s));
976 }
977
978 #[test]
981 fn all_primitive_variants() {
982 let prims = [
983 PrimitiveType::Int,
984 PrimitiveType::Float,
985 PrimitiveType::Int8,
986 PrimitiveType::Int16,
987 PrimitiveType::Int32,
988 PrimitiveType::Int64,
989 PrimitiveType::Int128,
990 PrimitiveType::UInt8,
991 PrimitiveType::UInt16,
992 PrimitiveType::UInt32,
993 PrimitiveType::UInt64,
994 PrimitiveType::Float32,
995 PrimitiveType::Float64,
996 PrimitiveType::BigInt,
997 PrimitiveType::BigFloat,
998 PrimitiveType::Decimal,
999 PrimitiveType::Bool,
1000 PrimitiveType::Char,
1001 PrimitiveType::String,
1002 PrimitiveType::Byte,
1003 PrimitiveType::Bytes,
1004 PrimitiveType::Void,
1005 PrimitiveType::Never,
1006 ];
1007 for p in &prims {
1008 let ty = Type::Primitive(p.clone());
1009 assert!(matches!(ty, Type::Primitive(_)));
1010 }
1011 }
1012}