1pub mod fmt;
2pub mod map_notation;
3
4use crate::algebraic_value::de::{ValueDeserializeError, ValueDeserializer};
5use crate::algebraic_value::ser::value_serialize;
6use crate::de::Deserialize;
7use crate::meta_type::MetaType;
8use crate::product_type::{CONNECTION_ID_TAG, IDENTITY_TAG, TIMESTAMP_TAG, TIME_DURATION_TAG, UUID_TAG};
9use crate::sum_type::{OPTION_NONE_TAG, OPTION_SOME_TAG, RESULT_ERR_TAG, RESULT_OK_TAG};
10use crate::typespace::Typespace;
11use crate::{i256, u256};
12use crate::{AlgebraicTypeRef, AlgebraicValue, ArrayType, ProductType, SpacetimeType, SumType, SumTypeVariant};
13use derive_more::From;
14use enum_as_inner::EnumAsInner;
15
16#[derive(EnumAsInner, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, SpacetimeType, From)]
23#[sats(crate = crate)]
24pub enum AlgebraicType {
25 Ref(AlgebraicTypeRef),
31 Sum(SumType),
58 Product(ProductType),
84 Array(ArrayType),
87 String,
93 Bool,
95 I8,
97 U8,
99 I16,
101 U16,
103 I32,
105 U32,
107 I64,
109 U64,
111 I128,
113 U128,
115 I256,
117 U256,
119 F32,
121 F64,
123}
124
125impl MetaType for AlgebraicType {
126 fn meta_type() -> Self {
132 AlgebraicType::sum([
133 ("ref", AlgebraicTypeRef::meta_type()),
134 ("sum", SumType::meta_type()),
135 ("product", ProductType::meta_type()),
136 ("array", ArrayType::meta_type()),
137 ("string", AlgebraicType::unit()),
138 ("bool", AlgebraicType::unit()),
139 ("i8", AlgebraicType::unit()),
140 ("u8", AlgebraicType::unit()),
141 ("i16", AlgebraicType::unit()),
142 ("u16", AlgebraicType::unit()),
143 ("i32", AlgebraicType::unit()),
144 ("u32", AlgebraicType::unit()),
145 ("i64", AlgebraicType::unit()),
146 ("u64", AlgebraicType::unit()),
147 ("i128", AlgebraicType::unit()),
148 ("u128", AlgebraicType::unit()),
149 ("i256", AlgebraicType::unit()),
150 ("u256", AlgebraicType::unit()),
151 ("f32", AlgebraicType::unit()),
152 ("f64", AlgebraicType::unit()),
153 ])
154 }
155}
156
157impl Default for AlgebraicType {
159 fn default() -> Self {
160 Self::ZERO_REF
161 }
162}
163
164impl AlgebraicType {
165 pub const ZERO_REF: Self = Self::Ref(AlgebraicTypeRef(0));
167
168 pub fn is_connection_id(&self) -> bool {
172 matches!(self, Self::Product(p) if p.is_connection_id())
173 }
174
175 pub fn is_identity(&self) -> bool {
177 matches!(self, Self::Product(p) if p.is_identity())
178 }
179
180 pub fn is_timestamp(&self) -> bool {
182 matches!(self, Self::Product(p) if p.is_timestamp())
183 }
184
185 pub fn is_time_duration(&self) -> bool {
187 matches!(self, Self::Product(p) if p.is_time_duration())
188 }
189
190 pub fn is_uuid(&self) -> bool {
192 matches!(self, Self::Product(p) if p.is_uuid())
193 }
194
195 pub fn is_schedule_at(&self) -> bool {
197 matches!(self, Self::Sum(p) if p.is_schedule_at())
198 }
199
200 pub fn is_unit(&self) -> bool {
202 matches!(self, Self::Product(p) if p.is_unit())
203 }
204
205 pub fn is_never(&self) -> bool {
207 matches!(self, Self::Sum(p) if p.is_empty())
208 }
209
210 pub fn is_option(&self) -> bool {
212 matches!(self, Self::Sum(p) if p.is_option())
213 }
214
215 pub fn as_option(&self) -> Option<&AlgebraicType> {
218 self.as_sum()?.as_option()
219 }
220
221 pub fn is_result(&self) -> bool {
223 matches!(self, Self::Sum(p) if p.is_result())
224 }
225
226 pub fn as_result(&self) -> Option<(&AlgebraicType, &AlgebraicType)> {
229 self.as_sum()?.as_result()
230 }
231
232 pub fn is_scalar_or_string(&self) -> bool {
234 self.is_scalar() || self.is_string()
235 }
236
237 pub fn is_scalar(&self) -> bool {
244 self.is_bool() || self.is_integer() || self.is_float()
245 }
246
247 pub fn is_signed(&self) -> bool {
249 matches!(
250 self,
251 Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 | Self::I256
252 )
253 }
254
255 pub fn is_unsigned(&self) -> bool {
257 matches!(
258 self,
259 Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::U128 | Self::U256
260 )
261 }
262
263 pub fn is_integer(&self) -> bool {
265 self.is_signed() || self.is_unsigned()
266 }
267
268 pub fn is_float(&self) -> bool {
270 matches!(self, Self::F32 | Self::F64)
271 }
272
273 pub fn unit() -> Self {
275 let fs: [AlgebraicType; 0] = [];
276 Self::product(fs)
277 }
278
279 pub fn never() -> Self {
281 let vs: [SumTypeVariant; 0] = [];
282 Self::sum(vs)
283 }
284
285 pub fn bytes() -> Self {
287 Self::array(Self::U8)
288 }
289
290 pub fn is_bytes(&self) -> bool {
292 self.as_array().is_some_and(|ty| ty.elem_ty.is_u8())
293 }
294
295 pub fn contains_refs(&self) -> bool {
297 match self {
298 AlgebraicType::Ref(_) => true,
299 AlgebraicType::Product(ProductType { elements }) => {
300 elements.iter().any(|elem| elem.algebraic_type.contains_refs())
301 }
302 AlgebraicType::Sum(SumType { variants }) => {
303 variants.iter().any(|variant| variant.algebraic_type.contains_refs())
304 }
305 AlgebraicType::Array(array) => array.elem_ty.contains_refs(),
306 _ => false,
307 }
308 }
309
310 pub fn sum<S: Into<SumType>>(sum: S) -> Self {
312 AlgebraicType::Sum(sum.into())
313 }
314
315 pub fn product<P: Into<ProductType>>(prod: P) -> Self {
317 AlgebraicType::Product(prod.into())
318 }
319
320 pub fn option(some_type: Self) -> Self {
322 Self::sum([(OPTION_SOME_TAG, some_type), (OPTION_NONE_TAG, AlgebraicType::unit())])
323 }
324
325 pub fn result(ok_type: Self, err_type: Self) -> Self {
328 Self::sum([(RESULT_OK_TAG, ok_type), (RESULT_ERR_TAG, err_type)])
329 }
330
331 pub fn array(ty: Self) -> Self {
333 ArrayType { elem_ty: Box::new(ty) }.into()
334 }
335
336 pub fn identity() -> Self {
338 AlgebraicType::product([(IDENTITY_TAG, AlgebraicType::U256)])
339 }
340
341 pub fn connection_id() -> Self {
343 AlgebraicType::product([(CONNECTION_ID_TAG, AlgebraicType::U128)])
344 }
345
346 pub fn timestamp() -> Self {
348 AlgebraicType::product([(TIMESTAMP_TAG, AlgebraicType::I64)])
349 }
350
351 pub fn time_duration() -> Self {
353 AlgebraicType::product([(TIME_DURATION_TAG, AlgebraicType::I64)])
354 }
355
356 pub fn uuid() -> Self {
358 AlgebraicType::product([(UUID_TAG, AlgebraicType::U128)])
359 }
360
361 pub fn simple_enum<'a>(var_names: impl Iterator<Item = &'a str>) -> Self {
363 Self::sum(var_names.into_iter().map(SumTypeVariant::unit).collect::<Box<[_]>>())
364 }
365
366 pub fn as_value(&self) -> AlgebraicValue {
367 value_serialize(self)
368 }
369
370 pub fn from_value(value: &AlgebraicValue) -> Result<Self, ValueDeserializeError> {
371 Self::deserialize(ValueDeserializer::from_ref(value))
372 }
373
374 #[inline]
375 pub fn min_value(&self) -> Option<AlgebraicValue> {
377 match *self {
378 Self::I8 => Some(i8::MIN.into()),
379 Self::U8 => Some(u8::MIN.into()),
380 Self::I16 => Some(i16::MIN.into()),
381 Self::U16 => Some(u16::MIN.into()),
382 Self::I32 => Some(i32::MIN.into()),
383 Self::U32 => Some(u32::MIN.into()),
384 Self::I64 => Some(i64::MIN.into()),
385 Self::U64 => Some(u64::MIN.into()),
386 Self::I128 => Some(i128::MIN.into()),
387 Self::U128 => Some(u128::MIN.into()),
388 Self::I256 => Some(i256::MIN.into()),
389 Self::U256 => Some(u256::MIN.into()),
390 Self::F32 => Some(f32::MIN.into()),
391 Self::F64 => Some(f64::MIN.into()),
392 _ => None,
393 }
394 }
395
396 #[inline]
397 pub fn max_value(&self) -> Option<AlgebraicValue> {
399 match *self {
400 Self::I8 => Some(i8::MAX.into()),
401 Self::U8 => Some(u8::MAX.into()),
402 Self::I16 => Some(i16::MAX.into()),
403 Self::U16 => Some(u16::MAX.into()),
404 Self::I32 => Some(i32::MAX.into()),
405 Self::U32 => Some(u32::MAX.into()),
406 Self::I64 => Some(i64::MAX.into()),
407 Self::U64 => Some(u64::MAX.into()),
408 Self::I128 => Some(i128::MAX.into()),
409 Self::U128 => Some(u128::MAX.into()),
410 Self::I256 => Some(i256::MAX.into()),
411 Self::U256 => Some(u256::MAX.into()),
412 Self::F32 => Some(f32::MAX.into()),
413 Self::F64 => Some(f64::MAX.into()),
414 _ => None,
415 }
416 }
417
418 pub fn is_special(&self) -> bool {
422 match self {
423 AlgebraicType::Product(product) => product.is_special(),
424 AlgebraicType::Sum(sum) => sum.is_special(),
425 _ => false,
426 }
427 }
428
429 pub fn is_valid_for_client_type_definition(&self) -> bool {
438 if self.is_special() {
440 return false;
441 }
442 match self {
443 AlgebraicType::Sum(sum) => sum
444 .variants
445 .iter()
446 .all(|variant| variant.algebraic_type.is_valid_for_client_type_use()),
447 AlgebraicType::Product(product) => product
448 .elements
449 .iter()
450 .all(|elem| elem.algebraic_type.is_valid_for_client_type_use()),
451 _ => false,
452 }
453 }
454
455 pub fn is_valid_for_client_type_use(&self) -> bool {
467 match self {
468 AlgebraicType::Sum(sum) => {
469 if let Some(wrapped) = sum.as_option() {
470 wrapped.is_valid_for_client_type_use()
471 } else if let Some((ok_ty, err_ty)) = sum.as_result() {
472 ok_ty.is_valid_for_client_type_use() && err_ty.is_valid_for_client_type_use()
473 } else {
474 sum.is_special() || sum.is_empty()
475 }
476 }
477 AlgebraicType::Product(product) => product.is_special() || product.is_unit(),
478 AlgebraicType::Array(array) => array.elem_ty.is_valid_for_client_type_use(),
479 AlgebraicType::Ref(_) => true,
480 _ => true,
481 }
482 }
483
484 pub fn type_check(&self, value: &AlgebraicValue, typespace: &Typespace) -> bool {
485 match (self, value) {
486 (_, AlgebraicValue::Min | AlgebraicValue::Max) => true,
487 (AlgebraicType::Ref(r), _) => {
488 if let Some(resolved_ty) = typespace.get(*r) {
489 resolved_ty.type_check(value, typespace)
490 } else {
491 false
492 }
493 }
494 (AlgebraicType::Sum(sum_ty), AlgebraicValue::Sum(sv)) => sum_ty.type_check(sv, typespace),
495 (AlgebraicType::Product(product_ty), AlgebraicValue::Product(pv)) => product_ty.type_check(pv, typespace),
496 (AlgebraicType::Array(array_ty), AlgebraicValue::Array(arr)) => array_ty.type_check(arr, typespace),
497
498 (AlgebraicType::String, AlgebraicValue::String(_))
499 | (AlgebraicType::Bool, AlgebraicValue::Bool(_))
500 | (AlgebraicType::I8, AlgebraicValue::I8(_))
501 | (AlgebraicType::U8, AlgebraicValue::U8(_))
502 | (AlgebraicType::I16, AlgebraicValue::I16(_))
503 | (AlgebraicType::U16, AlgebraicValue::U16(_))
504 | (AlgebraicType::I32, AlgebraicValue::I32(_))
505 | (AlgebraicType::U32, AlgebraicValue::U32(_))
506 | (AlgebraicType::I64, AlgebraicValue::I64(_))
507 | (AlgebraicType::U64, AlgebraicValue::U64(_))
508 | (AlgebraicType::I128, AlgebraicValue::I128(_))
509 | (AlgebraicType::U128, AlgebraicValue::U128(_))
510 | (AlgebraicType::I256, AlgebraicValue::I256(_))
511 | (AlgebraicType::U256, AlgebraicValue::U256(_))
512 | (AlgebraicType::F32, AlgebraicValue::F32(_))
513 | (AlgebraicType::F64, AlgebraicValue::F64(_)) => true,
514 _ => false,
515 }
516 }
517}
518#[cfg(test)]
519mod tests {
520 use super::AlgebraicType;
521 use crate::meta_type::MetaType;
522 use crate::satn::Satn;
523 use crate::{
524 algebraic_type::fmt::fmt_algebraic_type, algebraic_type::map_notation::fmt_algebraic_type as fmt_map,
525 algebraic_type_ref::AlgebraicTypeRef, typespace::Typespace,
526 };
527 use crate::{product, AlgebraicValue, ValueWithType, WithTypespace};
528
529 #[test]
530 fn never() {
531 assert_eq!("(|)", fmt_algebraic_type(&AlgebraicType::never()).to_string());
532 }
533
534 #[test]
535 fn never_map() {
536 assert_eq!("{ ty_: Sum }", fmt_map(&AlgebraicType::never()).to_string());
537 }
538
539 #[test]
540 fn unit() {
541 assert_eq!("()", fmt_algebraic_type(&AlgebraicType::unit()).to_string());
542 }
543
544 #[test]
545 fn unit_map() {
546 assert_eq!("{ ty_: Product }", fmt_map(&AlgebraicType::unit()).to_string());
547 }
548
549 #[test]
550 fn primitive() {
551 assert_eq!("U8", fmt_algebraic_type(&AlgebraicType::U8).to_string());
552 }
553
554 #[test]
555 fn primitive_map() {
556 assert_eq!("{ ty_: U8 }", fmt_map(&AlgebraicType::U8).to_string());
557 }
558
559 #[test]
560 fn option() {
561 let option = AlgebraicType::option(AlgebraicType::never());
562 assert_eq!("(some: (|) | none: ())", fmt_algebraic_type(&option).to_string());
563 }
564
565 #[test]
566 fn option_map() {
567 let option = AlgebraicType::option(AlgebraicType::never());
568 assert_eq!(
569 "{ ty_: Sum, some: { ty_: Sum }, none: { ty_: Product } }",
570 fmt_map(&option).to_string()
571 );
572 }
573
574 #[test]
575 fn result() {
576 let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String);
577 assert_eq!("(ok: U8 | err: String)", fmt_algebraic_type(&result).to_string());
578 }
579
580 #[test]
581 fn result_map() {
582 let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String);
583 assert_eq!(
584 "{ ty_: Sum, ok: { ty_: U8 }, err: { ty_: String } }",
585 fmt_map(&result).to_string()
586 );
587 }
588
589 #[test]
590 fn algebraic_type() {
591 let algebraic_type = AlgebraicType::meta_type();
592 assert_eq!(
593 "(\
594 ref: U32 \
595 | sum: (variants: Array<(\
596 name: (some: String | none: ()), \
597 algebraic_type: &0\
598 )>) \
599 | product: (elements: Array<(\
600 name: (some: String | none: ()), \
601 algebraic_type: &0\
602 )>) \
603 | array: &0 \
604 | string: () \
605 | bool: () \
606 | i8: () | u8: () \
607 | i16: () | u16: () \
608 | i32: () | u32: () \
609 | i64: () | u64: () \
610 | i128: () | u128: () \
611 | i256: () | u256: () \
612 | f32: () | f64: ()\
613 )",
614 fmt_algebraic_type(&algebraic_type).to_string()
615 );
616 }
617
618 #[test]
619 fn algebraic_type_map() {
620 let algebraic_type = AlgebraicType::meta_type();
621 assert_eq!(
622 "{ \
623 ty_: Sum, \
624 ref: { ty_: U32 }, \
625 sum: { \
626 ty_: Product, \
627 variants: { \
628 ty_: Array, \
629 0: { \
630 ty_: Product, \
631 name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, \
632 algebraic_type: { ty_: Ref, 0: 0 } \
633 } \
634 } \
635 }, \
636 product: { \
637 ty_: Product, \
638 elements: { \
639 ty_: Array, \
640 0: { \
641 ty_: Product, \
642 name: { ty_: Sum, some: { ty_: String }, none: { ty_: Product } }, \
643 algebraic_type: { ty_: Ref, 0: 0 } \
644 } \
645 } \
646 }, \
647 array: { ty_: Ref, 0: 0 }, \
648 string: { ty_: Product }, \
649 bool: { ty_: Product }, \
650 i8: { ty_: Product }, u8: { ty_: Product }, \
651 i16: { ty_: Product }, u16: { ty_: Product }, \
652 i32: { ty_: Product }, u32: { ty_: Product }, \
653 i64: { ty_: Product }, u64: { ty_: Product }, \
654 i128: { ty_: Product }, u128: { ty_: Product }, \
655 i256: { ty_: Product }, u256: { ty_: Product }, \
656 f32: { ty_: Product }, f64: { ty_: Product } \
657 }",
658 fmt_map(&algebraic_type).to_string()
659 );
660 }
661
662 #[test]
663 fn nested_products_and_sums() {
664 let builtin = AlgebraicType::U8;
665 let product = AlgebraicType::product([("thing", AlgebraicType::U8)]);
666 let sum = AlgebraicType::sum([builtin.clone(), builtin.clone(), product]);
667 let next = AlgebraicType::product([
668 (Some("test"), builtin.clone()),
669 (None, sum),
670 (None, builtin),
671 (Some("never"), AlgebraicType::never()),
672 ]);
673 assert_eq!(
674 "(test: U8, 1: (U8 | U8 | (thing: U8)), 2: U8, never: (|))",
675 fmt_algebraic_type(&next).to_string()
676 );
677 }
678
679 fn in_space<'a, T: crate::Value>(ts: &'a Typespace, ty: &'a T::Type, val: &'a T) -> ValueWithType<'a, T> {
680 WithTypespace::new(ts, ty).with_value(val)
681 }
682
683 #[test]
684 fn option_as_value() {
685 let option = AlgebraicType::option(AlgebraicType::never());
686 let algebraic_type = AlgebraicType::meta_type();
687 let typespace = Typespace::new(vec![algebraic_type]);
688 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
689 assert_eq!(
690 r#"(sum = (variants = [(name = (some = "some"), algebraic_type = (sum = (variants = []))), (name = (some = "none"), algebraic_type = (product = (elements = [])))]))"#,
691 in_space(&typespace, &at_ref, &option.as_value()).to_satn()
692 );
693 }
694
695 #[test]
696 fn result_as_value() {
697 let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String);
698 let algebraic_type = AlgebraicType::meta_type();
699 let typespace = Typespace::new(vec![algebraic_type]);
700 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
701 assert_eq!(
702 r#"(sum = (variants = [(name = (some = "ok"), algebraic_type = (u8 = ())), (name = (some = "err"), algebraic_type = (string = ()))]))"#,
703 in_space(&typespace, &at_ref, &result.as_value()).to_satn()
704 );
705 }
706
707 #[test]
708 fn algebraic_type_as_value() {
709 let algebraic_type = AlgebraicType::meta_type();
710 let typespace = Typespace::new(vec![algebraic_type.clone()]);
711 let at_ref = AlgebraicType::Ref(AlgebraicTypeRef(0));
712
713 let ref0 = "algebraic_type = (ref = 0)";
714 let unit = "algebraic_type = (product = (elements = []))";
715 let aggr_elems_ty = format!(
716 "algebraic_type = (array = (product = (elements = [\
717 (\
718 name = (some = \"name\"), \
719 algebraic_type = (sum = (variants = [\
720 (name = (some = \"some\"), algebraic_type = (string = ())), \
721 (name = (some = \"none\"), {unit})\
722 ]))\
723 ), \
724 (name = (some = \"algebraic_type\"), {ref0})\
725 ])))"
726 );
727
728 assert_eq!(
729 format!(
730 "(\
731 sum = (\
732 variants = [\
733 (name = (some = \"ref\"), algebraic_type = (u32 = ())), \
734 (\
735 name = (some = \"sum\"), \
736 algebraic_type = (product = (elements = [\
737 (name = (some = \"variants\"), {aggr_elems_ty})\
738 ]))\
739 ), \
740 (\
741 name = (some = \"product\"), \
742 algebraic_type = (product = (elements = [\
743 (name = (some = \"elements\"), {aggr_elems_ty})\
744 ]))\
745 ), \
746 (name = (some = \"array\"), {ref0}), \
747 (name = (some = \"string\"), {unit}), \
748 (name = (some = \"bool\"), {unit}), \
749 (name = (some = \"i8\"), {unit}), \
750 (name = (some = \"u8\"), {unit}), \
751 (name = (some = \"i16\"), {unit}), \
752 (name = (some = \"u16\"), {unit}), \
753 (name = (some = \"i32\"), {unit}), \
754 (name = (some = \"u32\"), {unit}), \
755 (name = (some = \"i64\"), {unit}), \
756 (name = (some = \"u64\"), {unit}), \
757 (name = (some = \"i128\"), {unit}), \
758 (name = (some = \"u128\"), {unit}), \
759 (name = (some = \"i256\"), {unit}), \
760 (name = (some = \"u256\"), {unit}), \
761 (name = (some = \"f32\"), {unit}), \
762 (name = (some = \"f64\"), {unit})\
763 ]\
764 )\
765 )"
766 ),
767 in_space(&typespace, &at_ref, &algebraic_type.as_value()).to_satn()
768 );
769 }
770
771 #[test]
772 fn option_from_value() {
773 let option = AlgebraicType::option(AlgebraicType::never());
774 AlgebraicType::from_value(&option.as_value()).expect("No errors.");
775 }
776
777 #[test]
778 fn result_from_value() {
779 let result = AlgebraicType::result(AlgebraicType::U8, AlgebraicType::String);
780 AlgebraicType::from_value(&result.as_value()).expect("No errors.");
781 }
782
783 #[test]
784 fn builtin_from_value() {
785 let u8 = AlgebraicType::U8;
786 AlgebraicType::from_value(&u8.as_value()).expect("No errors.");
787 }
788
789 #[test]
790 fn algebraic_type_from_value() {
791 let algebraic_type = AlgebraicType::meta_type();
792 AlgebraicType::from_value(&algebraic_type.as_value()).expect("No errors.");
793 }
794
795 #[test]
796 fn special_types_are_special() {
797 assert!(AlgebraicType::identity().is_identity());
798 assert!(AlgebraicType::identity().is_special());
799 assert!(AlgebraicType::connection_id().is_connection_id());
800 assert!(AlgebraicType::connection_id().is_special());
801 assert!(AlgebraicType::timestamp().is_timestamp());
802 assert!(AlgebraicType::timestamp().is_special());
803 assert!(AlgebraicType::time_duration().is_special());
804 assert!(AlgebraicType::time_duration().is_time_duration());
805 assert!(AlgebraicType::uuid().is_uuid());
806 assert!(AlgebraicType::uuid().is_special());
807 }
808
809 #[test]
810 fn type_check() {
811 let av = AlgebraicValue::sum(1, AlgebraicValue::from(product![0u16, 1u32]));
812 let at = AlgebraicType::sum([
813 ("a", AlgebraicType::U8),
814 ("b", AlgebraicType::product([AlgebraicType::U16, AlgebraicType::U32])),
815 ]);
816
817 at.type_check(&av, Typespace::EMPTY);
818 }
819}