Skip to main content

luau_syntax/ast/
types.rs

1use super::*;
2use crate::allocator::AstArena;
3use std::fmt;
4use std::marker::PhantomData;
5use std::ptr::NonNull;
6
7#[repr(u8)]
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum TypeTag {
10    Reference,
11    Table,
12    Function,
13    Typeof,
14    SingletonBool,
15    SingletonString,
16    Group,
17    Optional,
18    Union,
19    Intersection,
20    Error,
21}
22
23#[repr(C)]
24#[derive(Debug, PartialEq)]
25pub struct TypeHeader<'ast> {
26    pub tag: TypeTag,
27    pub location: Location,
28    _marker: PhantomData<&'ast ()>,
29}
30
31#[derive(Clone, Copy)]
32pub struct Type<'ast> {
33    ptr: NonNull<TypeHeader<'ast>>,
34    _marker: PhantomData<&'ast TypeHeader<'ast>>,
35}
36
37impl<'ast> std::ops::Deref for Type<'ast> {
38    type Target = TypeHeader<'ast>;
39
40    fn deref(&self) -> &Self::Target {
41        self.header()
42    }
43}
44
45impl fmt::Debug for Type<'_> {
46    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47        formatter
48            .debug_struct("Type")
49            .field("location", &self.location())
50            .field("kind", &self.kind())
51            .finish()
52    }
53}
54
55impl PartialEq for Type<'_> {
56    fn eq(&self, other: &Self) -> bool {
57        self.location() == other.location() && self.kind() == other.kind()
58    }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq)]
62pub enum TypeKind<'ast> {
63    Reference {
64        prefix: Option<AstName<'ast>>,
65        prefix_location: Option<Location>,
66        prefix_local: Option<&'ast Local<'ast>>,
67        name: AstName<'ast>,
68        location: Location,
69        name_location: Location,
70        has_parameter_list: bool,
71        parameters: &'ast [TypeOrPack<'ast>],
72    },
73    Table {
74        props: &'ast [TableTypeProp<'ast>],
75        indexer: Option<&'ast TableTypeIndexer<'ast>>,
76    },
77    Function {
78        attributes: &'ast [&'ast Attribute<'ast>],
79        generics: &'ast [&'ast GenericType<'ast>],
80        generic_packs: &'ast [&'ast GenericTypePack<'ast>],
81        arg_types: TypeList<'ast>,
82        arg_names: &'ast [Option<ArgumentName<'ast>>],
83        return_types: TypePack<'ast>,
84    },
85    Typeof {
86        expr: Expression<'ast>,
87    },
88    SingletonBool {
89        value: bool,
90    },
91    SingletonString {
92        value: AstString<'ast>,
93    },
94    Group {
95        ty: Type<'ast>,
96    },
97    Optional,
98    Union {
99        types: &'ast [Type<'ast>],
100    },
101    Intersection {
102        types: &'ast [Type<'ast>],
103    },
104    Error {
105        types: &'ast [Type<'ast>],
106        missing: bool,
107        message_index: usize,
108    },
109}
110
111#[derive(Debug, Clone, Copy, PartialEq)]
112pub enum TypeOrPack<'ast> {
113    Type(Type<'ast>),
114    Pack(TypePack<'ast>),
115}
116
117macro_rules! type_node {
118    ($name:ident { $($field:ident : $ty:ty),* $(,)? }, $tag:ident) => {
119        #[repr(C)]
120        #[derive(Debug, PartialEq)]
121        pub struct $name<'ast> {
122            pub base: TypeHeader<'ast>,
123            $(pub $field: $ty),*
124        }
125    };
126}
127
128#[repr(C)]
129#[derive(Debug, PartialEq)]
130pub struct TypeUnit<'ast> {
131    pub base: TypeHeader<'ast>,
132}
133
134type_node!(
135    TypeReference {
136        has_parameter_list: bool,
137        prefix: Option<AstName<'ast>>,
138        prefix_location: Option<Location>,
139        prefix_local: Option<&'ast Local<'ast>>,
140        name: AstName<'ast>,
141        name_location: Location,
142        parameters: &'ast [TypeOrPack<'ast>]
143    },
144    Reference
145);
146type_node!(
147    TypeTable {
148        props: &'ast [TableTypeProp<'ast>],
149        indexer: Option<&'ast TableTypeIndexer<'ast>>
150    },
151    Table
152);
153type_node!(
154    TypeFunction {
155        attributes: &'ast [&'ast Attribute<'ast>],
156        generics: &'ast [&'ast GenericType<'ast>],
157        generic_packs: &'ast [&'ast GenericTypePack<'ast>],
158        arg_types: TypeList<'ast>,
159        arg_names: &'ast [Option<ArgumentName<'ast>>],
160        return_types: TypePack<'ast>
161    },
162    Function
163);
164type_node!(TypeTypeof { expr: Expression<'ast> }, Typeof);
165type_node!(TypeSingletonBool { value: bool }, SingletonBool);
166type_node!(TypeSingletonString { value: AstString<'ast> }, SingletonString);
167type_node!(TypeGroup { ty: Type<'ast> }, Group);
168type_node!(TypeUnion { types: &'ast [Type<'ast>] }, Union);
169type_node!(TypeIntersection { types: &'ast [Type<'ast>] }, Intersection);
170type_node!(
171    TypeError {
172        types: &'ast [Type<'ast>],
173        missing: bool,
174        message_index: usize
175    },
176    Error
177);
178
179impl<'ast> Type<'ast> {
180    const fn new_header(tag: TypeTag, location: Location) -> TypeHeader<'ast> {
181        TypeHeader {
182            tag,
183            location,
184            _marker: PhantomData,
185        }
186    }
187
188    pub(crate) fn from_node<T>(node: &'ast mut T) -> Self {
189        Self {
190            ptr: NonNull::from(node).cast(),
191            _marker: PhantomData,
192        }
193    }
194
195    pub fn as_ptr(self) -> *const () {
196        self.ptr.as_ptr().cast()
197    }
198
199    #[inline(always)]
200    fn header(&self) -> &TypeHeader<'ast> {
201        unsafe { self.ptr.as_ref() }
202    }
203
204    #[inline(always)]
205    pub fn location(self) -> Location {
206        self.header().location
207    }
208
209    #[inline(always)]
210    pub fn kind(&self) -> TypeKind<'ast> {
211        match self.tag {
212            TypeTag::Reference => {
213                let node = self.cast_ref::<TypeReference>();
214                TypeKind::Reference {
215                    prefix: node.prefix,
216                    prefix_location: node.prefix_location,
217                    prefix_local: node.prefix_local,
218                    name: node.name,
219                    location: self.location,
220                    name_location: node.name_location,
221                    has_parameter_list: node.has_parameter_list,
222                    parameters: node.parameters,
223                }
224            }
225            TypeTag::Table => {
226                let node = self.cast_ref::<TypeTable>();
227                TypeKind::Table {
228                    props: node.props,
229                    indexer: node.indexer,
230                }
231            }
232            TypeTag::Function => {
233                let node = self.cast_ref::<TypeFunction>();
234                TypeKind::Function {
235                    attributes: node.attributes,
236                    generics: node.generics,
237                    generic_packs: node.generic_packs,
238                    arg_types: node.arg_types,
239                    arg_names: node.arg_names,
240                    return_types: node.return_types,
241                }
242            }
243            TypeTag::Typeof => TypeKind::Typeof {
244                expr: self.cast_ref::<TypeTypeof>().expr,
245            },
246            TypeTag::SingletonBool => TypeKind::SingletonBool {
247                value: self.cast_ref::<TypeSingletonBool>().value,
248            },
249            TypeTag::SingletonString => TypeKind::SingletonString {
250                value: self.cast_ref::<TypeSingletonString>().value,
251            },
252            TypeTag::Group => TypeKind::Group {
253                ty: self.cast_ref::<TypeGroup>().ty,
254            },
255            TypeTag::Optional => TypeKind::Optional,
256            TypeTag::Union => TypeKind::Union {
257                types: self.cast_ref::<TypeUnion>().types,
258            },
259            TypeTag::Intersection => TypeKind::Intersection {
260                types: self.cast_ref::<TypeIntersection>().types,
261            },
262            TypeTag::Error => {
263                let node = self.cast_ref::<TypeError>();
264                TypeKind::Error {
265                    types: node.types,
266                    missing: node.missing,
267                    message_index: node.message_index,
268                }
269            }
270        }
271    }
272
273    pub fn visit<V: AstVisitor>(self, visitor: &mut V) {
274        let should_visit = match self.tag {
275            TypeTag::Reference => visitor.visit_reference_type(self),
276            TypeTag::Table => visitor.visit_table_type(self),
277            TypeTag::Function => visitor.visit_function_type(self),
278            TypeTag::Typeof => visitor.visit_typeof_type(self),
279            TypeTag::SingletonBool => visitor.visit_singleton_bool_type(self),
280            TypeTag::SingletonString => visitor.visit_singleton_string_type(self),
281            TypeTag::Group => visitor.visit_group_type(self),
282            TypeTag::Optional => visitor.visit_optional_type(self),
283            TypeTag::Union => visitor.visit_union_type(self),
284            TypeTag::Intersection => visitor.visit_intersection_type(self),
285            TypeTag::Error => visitor.visit_error_type(self),
286        };
287
288        if !should_visit {
289            return;
290        }
291
292        match self.kind() {
293            TypeKind::Reference { parameters, .. } => {
294                for parameter in parameters {
295                    match parameter {
296                        TypeOrPack::Type(annotation) => annotation.visit(visitor),
297                        TypeOrPack::Pack(pack) => pack.visit(visitor),
298                    }
299                }
300            }
301            TypeKind::Union { types, .. } | TypeKind::Intersection { types, .. } => {
302                for annotation in types {
303                    annotation.visit(visitor);
304                }
305            }
306            TypeKind::Table { props, indexer, .. } => {
307                for prop in props {
308                    prop.ty.visit(visitor);
309                }
310                if let Some(indexer) = indexer {
311                    indexer.index_type.visit(visitor);
312                    indexer.result_type.visit(visitor);
313                }
314            }
315            TypeKind::Function {
316                arg_types,
317                return_types,
318                ..
319            } => {
320                arg_types.visit(visitor);
321                return_types.visit(visitor);
322            }
323            TypeKind::Typeof { expr, .. } => expr.visit(visitor),
324            TypeKind::Group { ty, .. } => ty.visit(visitor),
325            TypeKind::Error { types, .. } => {
326                for annotation in types {
327                    annotation.visit(visitor);
328                }
329            }
330            TypeKind::Optional
331            | TypeKind::SingletonBool { .. }
332            | TypeKind::SingletonString { .. } => {}
333        }
334    }
335
336    #[inline(always)]
337    fn cast_ref<T>(self) -> &'ast T {
338        unsafe { self.ptr.cast::<T>().as_ref() }
339    }
340
341    #[inline(always)]
342    fn cast_if_tag<T>(self, tag: TypeTag) -> Option<&'ast T> {
343        (self.tag == tag).then(|| self.cast_ref())
344    }
345
346    #[inline(always)]
347    pub fn as_reference(self) -> Option<&'ast TypeReference<'ast>> {
348        self.cast_if_tag(TypeTag::Reference)
349    }
350
351    #[inline(always)]
352    pub fn as_table(self) -> Option<&'ast TypeTable<'ast>> {
353        self.cast_if_tag(TypeTag::Table)
354    }
355
356    #[inline(always)]
357    pub fn as_function(self) -> Option<&'ast TypeFunction<'ast>> {
358        self.cast_if_tag(TypeTag::Function)
359    }
360
361    #[inline(always)]
362    pub fn as_typeof(self) -> Option<&'ast TypeTypeof<'ast>> {
363        self.cast_if_tag(TypeTag::Typeof)
364    }
365
366    #[inline(always)]
367    pub fn as_singleton_bool(self) -> Option<&'ast TypeSingletonBool<'ast>> {
368        self.cast_if_tag(TypeTag::SingletonBool)
369    }
370
371    #[inline(always)]
372    pub fn as_singleton_string(self) -> Option<&'ast TypeSingletonString<'ast>> {
373        self.cast_if_tag(TypeTag::SingletonString)
374    }
375
376    #[inline(always)]
377    pub fn as_group(self) -> Option<&'ast TypeGroup<'ast>> {
378        self.cast_if_tag(TypeTag::Group)
379    }
380
381    #[inline(always)]
382    pub fn as_union(self) -> Option<&'ast TypeUnion<'ast>> {
383        self.cast_if_tag(TypeTag::Union)
384    }
385
386    #[inline(always)]
387    pub fn as_intersection(self) -> Option<&'ast TypeIntersection<'ast>> {
388        self.cast_if_tag(TypeTag::Intersection)
389    }
390
391    #[inline(always)]
392    pub fn as_error(self) -> Option<&'ast TypeError<'ast>> {
393        self.cast_if_tag(TypeTag::Error)
394    }
395}
396
397impl<'ast> TypeKind<'ast> {
398    pub fn is_checked_function(&self) -> bool {
399        self.has_function_attribute(AttributeKind::Checked)
400    }
401
402    pub fn has_function_attribute(&self, kind: AttributeKind) -> bool {
403        self.get_function_attribute(kind).is_some()
404    }
405
406    pub fn get_function_attribute(&self, kind: AttributeKind) -> Option<&'ast Attribute<'ast>> {
407        match self {
408            Self::Function { attributes, .. } => find_attribute(attributes, kind),
409            _ => None,
410        }
411    }
412}
413
414#[repr(u8)]
415#[derive(Debug, Clone, Copy, PartialEq, Eq)]
416pub enum TypePackTag {
417    Explicit,
418    Variadic,
419    Generic,
420}
421
422#[repr(C)]
423#[derive(Debug, PartialEq)]
424pub struct TypePackHeader<'ast> {
425    pub tag: TypePackTag,
426    pub location: Location,
427    _marker: PhantomData<&'ast ()>,
428}
429
430#[derive(Clone, Copy)]
431pub struct TypePack<'ast> {
432    ptr: NonNull<TypePackHeader<'ast>>,
433    _marker: PhantomData<&'ast TypePackHeader<'ast>>,
434}
435
436impl<'ast> std::ops::Deref for TypePack<'ast> {
437    type Target = TypePackHeader<'ast>;
438
439    fn deref(&self) -> &Self::Target {
440        self.header()
441    }
442}
443
444impl fmt::Debug for TypePack<'_> {
445    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
446        formatter
447            .debug_struct("TypePack")
448            .field("location", &self.location())
449            .field("kind", &self.kind())
450            .finish()
451    }
452}
453
454impl PartialEq for TypePack<'_> {
455    fn eq(&self, other: &Self) -> bool {
456        self.location() == other.location() && self.kind() == other.kind()
457    }
458}
459
460#[derive(Debug, Clone, Copy, PartialEq)]
461pub struct TypeList<'ast> {
462    pub types: &'ast [Type<'ast>],
463    pub tail_type: Option<TypePack<'ast>>,
464}
465
466#[derive(Debug, Clone, Copy, PartialEq)]
467pub enum TypePackKind<'ast> {
468    Explicit { type_list: TypeList<'ast> },
469    Variadic { variadic_type: Type<'ast> },
470    Generic { generic_name: AstName<'ast> },
471}
472
473macro_rules! type_pack_node {
474    ($name:ident { $($field:ident : $ty:ty),* $(,)? }, $tag:ident) => {
475        #[repr(C)]
476        #[derive(Debug, PartialEq)]
477        pub struct $name<'ast> {
478            pub base: TypePackHeader<'ast>,
479            $(pub $field: $ty),*
480        }
481    };
482}
483
484type_pack_node!(TypePackExplicitNode { type_list: TypeList<'ast> }, Explicit);
485type_pack_node!(TypePackVariadicNode { variadic_type: Type<'ast> }, Variadic);
486type_pack_node!(TypePackGenericNode { generic_name: AstName<'ast> }, Generic);
487
488impl TypeList<'_> {
489    pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
490        for annotation in self.types {
491            annotation.visit(visitor);
492        }
493        if let Some(tail_type) = self.tail_type {
494            tail_type.visit(visitor);
495        }
496    }
497}
498
499impl<'ast> TypePack<'ast> {
500    const fn new_header(tag: TypePackTag, location: Location) -> TypePackHeader<'ast> {
501        TypePackHeader {
502            tag,
503            location,
504            _marker: PhantomData,
505        }
506    }
507
508    pub(crate) fn from_node<T>(node: &'ast mut T) -> Self {
509        Self {
510            ptr: NonNull::from(node).cast(),
511            _marker: PhantomData,
512        }
513    }
514
515    pub fn as_ptr(self) -> *const () {
516        self.ptr.as_ptr().cast()
517    }
518
519    #[inline(always)]
520    fn header(&self) -> &TypePackHeader<'ast> {
521        unsafe { self.ptr.as_ref() }
522    }
523
524    #[inline(always)]
525    pub fn location(self) -> Location {
526        self.header().location
527    }
528
529    #[inline(always)]
530    pub fn kind(&self) -> TypePackKind<'ast> {
531        match self.tag {
532            TypePackTag::Explicit => TypePackKind::Explicit {
533                type_list: self.cast_ref::<TypePackExplicitNode>().type_list,
534            },
535            TypePackTag::Variadic => TypePackKind::Variadic {
536                variadic_type: self.cast_ref::<TypePackVariadicNode>().variadic_type,
537            },
538            TypePackTag::Generic => TypePackKind::Generic {
539                generic_name: self.cast_ref::<TypePackGenericNode>().generic_name,
540            },
541        }
542    }
543
544    pub fn explicit_type_list(&self) -> Option<TypeList<'ast>> {
545        match self.kind() {
546            TypePackKind::Explicit { type_list } => Some(type_list),
547            _ => None,
548        }
549    }
550
551    pub fn visit<V: AstVisitor>(self, visitor: &mut V) {
552        let should_visit = match self.tag {
553            TypePackTag::Explicit => visitor.visit_explicit_type_pack(self),
554            TypePackTag::Variadic => visitor.visit_variadic_type_pack(self),
555            TypePackTag::Generic => visitor.visit_generic_type_pack_type(self),
556        };
557
558        if !should_visit {
559            return;
560        }
561
562        match self.kind() {
563            TypePackKind::Explicit { type_list } => type_list.visit(visitor),
564            TypePackKind::Variadic { variadic_type } => variadic_type.visit(visitor),
565            TypePackKind::Generic { .. } => {}
566        }
567    }
568
569    #[inline(always)]
570    fn cast_ref<T>(self) -> &'ast T {
571        unsafe { self.ptr.cast::<T>().as_ref() }
572    }
573
574    #[inline(always)]
575    fn cast_if_tag<T>(self, tag: TypePackTag) -> Option<&'ast T> {
576        (self.tag == tag).then(|| self.cast_ref())
577    }
578
579    #[inline(always)]
580    pub fn as_explicit(self) -> Option<&'ast TypePackExplicitNode<'ast>> {
581        self.cast_if_tag(TypePackTag::Explicit)
582    }
583
584    #[inline(always)]
585    pub fn as_variadic(self) -> Option<&'ast TypePackVariadicNode<'ast>> {
586        self.cast_if_tag(TypePackTag::Variadic)
587    }
588
589    #[inline(always)]
590    pub fn as_generic(self) -> Option<&'ast TypePackGenericNode<'ast>> {
591        self.cast_if_tag(TypePackTag::Generic)
592    }
593}
594
595#[derive(Debug, Clone, Copy, PartialEq)]
596pub struct Attribute<'ast> {
597    pub location: Location,
598    pub kind: AttributeKind,
599    pub args: &'ast [Expression<'ast>],
600    pub name: AstName<'ast>,
601}
602
603#[derive(Debug, Clone, Copy, PartialEq, Eq)]
604pub enum AttributeKind {
605    Checked,
606    Native,
607    Deprecated,
608    DebugNoinline,
609    Unknown,
610}
611
612#[derive(Debug, Clone, PartialEq, Eq)]
613pub struct DeprecatedInfo {
614    pub deprecated: bool,
615    pub use_replacement: Option<Vec<u8>>,
616    pub reason: Option<Vec<u8>>,
617}
618
619impl Attribute<'_> {
620    pub fn kind(&self) -> AttributeKind {
621        self.kind
622    }
623
624    pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
625        let _ = visitor.visit_attribute(self);
626    }
627
628    pub fn deprecated_info(&self) -> DeprecatedInfo {
629        let mut info = DeprecatedInfo {
630            deprecated: self.kind == AttributeKind::Deprecated,
631            use_replacement: None,
632            reason: None,
633        };
634
635        if !info.deprecated {
636            return info;
637        }
638
639        let Some(argument) = self.args.first() else {
640            return info;
641        };
642        let ExpressionKind::Table { items } = argument.kind() else {
643            return info;
644        };
645
646        for item in items {
647            let TableItem::Record { key, value } = item else {
648                continue;
649            };
650            let ExpressionKind::String {
651                value: key_value, ..
652            } = key.kind()
653            else {
654                continue;
655            };
656            let ExpressionKind::String { value, .. } = value.kind() else {
657                continue;
658            };
659
660            match key_value.as_bytes() {
661                b"use" => info.use_replacement = Some(value.as_bytes().to_vec()),
662                b"reason" => info.reason = Some(value.as_bytes().to_vec()),
663                _ => {}
664            }
665        }
666
667        info
668    }
669}
670
671#[derive(Debug, Clone, Copy, PartialEq)]
672pub struct TableTypeProp<'ast> {
673    pub name: AstName<'ast>,
674    pub location: Location,
675    pub ty: Type<'ast>,
676    pub access: TableAccess,
677    pub access_location: Option<Location>,
678}
679
680#[derive(Debug, Clone, Copy, PartialEq)]
681pub struct TableTypeIndexer<'ast> {
682    pub index_type: Type<'ast>,
683    pub result_type: Type<'ast>,
684    pub location: Location,
685    pub access: TableAccess,
686    pub access_location: Option<Location>,
687}
688
689#[derive(Debug, Clone, Copy, PartialEq)]
690pub struct DeclaredExternTypeProperty<'ast> {
691    pub name: AstName<'ast>,
692    pub name_location: Location,
693    pub ty: Type<'ast>,
694    pub is_method: bool,
695    pub location: Location,
696    pub access: TableAccess,
697}
698
699#[derive(Debug, Clone, Copy, PartialEq, Eq)]
700pub enum TableAccess {
701    Read,
702    Write,
703    ReadWrite,
704}
705
706impl AstArena {
707    fn alloc_type_node<'ast, T: 'ast>(&'ast self, node: T) -> Type<'ast> {
708        Type::from_node(self.alloc(node))
709    }
710
711    fn alloc_type_pack_node<'ast, T: 'ast>(&'ast self, node: T) -> TypePack<'ast> {
712        TypePack::from_node(self.alloc(node))
713    }
714
715    pub fn alloc_type_kind<'ast>(
716        &'ast self,
717        location: Location,
718        kind: TypeKind<'ast>,
719    ) -> Type<'ast> {
720        match kind {
721            TypeKind::Reference {
722                prefix,
723                prefix_location,
724                prefix_local,
725                name,
726                name_location,
727                has_parameter_list,
728                parameters,
729                ..
730            } => self.alloc_type_node(TypeReference {
731                base: Type::new_header(TypeTag::Reference, location),
732                has_parameter_list,
733                prefix,
734                prefix_location,
735                prefix_local,
736                name,
737                name_location,
738                parameters,
739            }),
740            TypeKind::Table { props, indexer } => self.alloc_type_node(TypeTable {
741                base: Type::new_header(TypeTag::Table, location),
742                props,
743                indexer,
744            }),
745            TypeKind::Function {
746                attributes,
747                generics,
748                generic_packs,
749                arg_types,
750                arg_names,
751                return_types,
752            } => self.alloc_type_node(TypeFunction {
753                base: Type::new_header(TypeTag::Function, location),
754                attributes,
755                generics,
756                generic_packs,
757                arg_types,
758                arg_names,
759                return_types,
760            }),
761            TypeKind::Typeof { expr } => self.alloc_type_node(TypeTypeof {
762                base: Type::new_header(TypeTag::Typeof, location),
763                expr,
764            }),
765            TypeKind::SingletonBool { value } => self.alloc_type_node(TypeSingletonBool {
766                base: Type::new_header(TypeTag::SingletonBool, location),
767                value,
768            }),
769            TypeKind::SingletonString { value } => self.alloc_type_node(TypeSingletonString {
770                base: Type::new_header(TypeTag::SingletonString, location),
771                value,
772            }),
773            TypeKind::Group { ty } => self.alloc_type_node(TypeGroup {
774                base: Type::new_header(TypeTag::Group, location),
775                ty,
776            }),
777            TypeKind::Optional => self.alloc_type_node(TypeUnit {
778                base: Type::new_header(TypeTag::Optional, location),
779            }),
780            TypeKind::Union { types } => self.alloc_type_node(TypeUnion {
781                base: Type::new_header(TypeTag::Union, location),
782                types,
783            }),
784            TypeKind::Intersection { types } => self.alloc_type_node(TypeIntersection {
785                base: Type::new_header(TypeTag::Intersection, location),
786                types,
787            }),
788            TypeKind::Error {
789                types,
790                missing,
791                message_index,
792            } => self.alloc_type_node(TypeError {
793                base: Type::new_header(TypeTag::Error, location),
794                types,
795                missing,
796                message_index,
797            }),
798        }
799    }
800
801    pub fn alloc_type_pack_kind<'ast>(
802        &'ast self,
803        location: Location,
804        kind: TypePackKind<'ast>,
805    ) -> TypePack<'ast> {
806        match kind {
807            TypePackKind::Explicit { type_list } => {
808                self.alloc_type_pack_node(TypePackExplicitNode {
809                    base: TypePack::new_header(TypePackTag::Explicit, location),
810                    type_list,
811                })
812            }
813            TypePackKind::Variadic { variadic_type } => {
814                self.alloc_type_pack_node(TypePackVariadicNode {
815                    base: TypePack::new_header(TypePackTag::Variadic, location),
816                    variadic_type,
817                })
818            }
819            TypePackKind::Generic { generic_name } => {
820                self.alloc_type_pack_node(TypePackGenericNode {
821                    base: TypePack::new_header(TypePackTag::Generic, location),
822                    generic_name,
823                })
824            }
825        }
826    }
827}