nickel_lang_core/bytecode/ast/
alloc.rs

1//! Everything related to memory allocation of AST components.
2
3use std::{ffi::OsString, fmt, iter};
4
5use bumpalo::Bump;
6
7use super::*;
8
9/// Marker trait for AST nodes that don't need to be dropped (in practice, it's often equivalent to
10/// not owning any heap allocated data) and can be used with [allocator][AstAlloc::alloc]. The
11/// current exceptions are [Number] and [crate::error::ParseError], which must be allocated through
12/// specialized method in [AstAlloc].
13pub trait Allocable {}
14
15impl Allocable for Ast<'_> {}
16impl Allocable for Node<'_> {}
17impl<T: Allocable> Allocable for StringChunk<T> {}
18impl Allocable for LetBinding<'_> {}
19impl Allocable for LetMetadata<'_> {}
20impl Allocable for PrimOp {}
21impl Allocable for Annotation<'_> {}
22impl Allocable for MatchBranch<'_> {}
23
24impl Allocable for Record<'_> {}
25impl Allocable for record::FieldPathElem<'_> {}
26impl Allocable for record::FieldDef<'_> {}
27impl Allocable for record::FieldMetadata<'_> {}
28impl Allocable for record::Include<'_> {}
29
30impl Allocable for Pattern<'_> {}
31impl Allocable for EnumPattern<'_> {}
32impl Allocable for FieldPattern<'_> {}
33impl Allocable for RecordPattern<'_> {}
34impl Allocable for ArrayPattern<'_> {}
35impl Allocable for OrPattern<'_> {}
36impl Allocable for ConstantPattern<'_> {}
37impl Allocable for ConstantPatternData<'_> {}
38
39impl Allocable for Type<'_> {}
40impl Allocable for typ::RecordRows<'_> {}
41impl Allocable for typ::EnumRows<'_> {}
42impl Allocable for typ::EnumRow<'_> {}
43impl Allocable for typ::RecordRow<'_> {}
44
45impl Allocable for Ident {}
46impl Allocable for LocIdent {}
47
48/// Owns the arenas required to allocate new AST nodes and provide builder methods to create them.
49///
50/// # Drop and arena allocation
51///
52/// The most popular choice for arena is the `bumpalo` crate, which is a fast bump allocator that
53/// can handle heterogeneous data. However, it doesn't support destructors, which is a problem
54/// because some of the nodes in the AST owns heap allocated data and needs to be de-allocated
55/// (numbers and parse errors currently).
56///
57/// Another choice is `typed-arena` and derivatives, which do run destructors, but can only store
58/// one type of values. As the number of types that need to be dropped is relatively small, we use
59/// a general `bumpalo` arena by default, and specialized typed arenas for stuff that need to be
60/// dropped.
61///
62/// # Guarantees
63///
64/// [AstAlloc] guarantees that the memory that has been allocated won't be moved until [Self] is
65/// deallocated.
66pub struct AstAlloc {
67    generic_arena: Bump,
68    number_arena: typed_arena::Arena<Number>,
69    error_arena: typed_arena::Arena<ParseError>,
70}
71
72impl AstAlloc {
73    /// Creates a new ast allocator.
74    pub fn new() -> Self {
75        Self {
76            generic_arena: Bump::new(),
77            number_arena: typed_arena::Arena::new(),
78            error_arena: typed_arena::Arena::new(),
79        }
80    }
81
82    /// Return the current number of allocated bytes.
83    pub fn allocated_bytes(&self) -> usize {
84        self.generic_arena.allocated_bytes() + self.number_arena.len() + self.error_arena.len()
85    }
86
87    /// Allocates an AST component in the arena.
88    ///
89    /// [Self] never guarantees that all destructors are going to be run when using such a generic
90    /// allocation function. We don't want to allocate values that need to be dropped through this
91    /// method, typically because they own heap-allocated data, such as numbers or parse errors.
92    /// That's why we use a marker trait to specify which types can be allocated freely. Types that
93    /// need to be dropped don't implement [Allocable] and have a dedicated method for allocation.
94    pub fn alloc<T: Allocable>(&self, value: T) -> &T {
95        self.generic_arena.alloc(value)
96    }
97
98    /// Allocates a sequence of AST components in the arena.
99    ///
100    /// See [Self::alloc].
101    pub fn alloc_many<T: Allocable, I>(&self, iter: I) -> &[T]
102    where
103        I: IntoIterator<Item = T>,
104        I::IntoIter: ExactSizeIterator,
105    {
106        self.generic_arena.alloc_slice_fill_iter(iter)
107    }
108
109    /// Allocates an array with exactly one element in the arena.
110    pub fn alloc_singleton<T: Allocable>(&self, value: T) -> &[T] {
111        self.generic_arena.alloc_slice_fill_iter(iter::once(value))
112    }
113
114    /// Allocates a string in the arena.
115    pub fn alloc_str<'ast>(&'ast self, s: &str) -> &'ast str {
116        self.generic_arena.alloc_str(s)
117    }
118
119    /// Deep clone an already allocated AST component from another arena to the current one.
120    pub fn clone_from<'to, T: CloneTo>(&'to self, data: T::Data<'_>) -> T::Data<'to> {
121        T::clone_to(data, self)
122    }
123
124    /// Same as [Self::clone_from] but take an arena-allocated reference instead.
125    pub fn clone_ref_from<'from, 'to, T>(
126        &'to self,
127        data: &'from T::Data<'from>,
128    ) -> &'to T::Data<'to>
129    where
130        T: for<'a> CloneTo<Data<'a>: Clone + Allocable>,
131    {
132        self.alloc(T::clone_to(data.clone(), self))
133    }
134
135    pub fn number(&self, number: Number) -> Node<'_> {
136        Node::Number(self.number_arena.alloc(number))
137    }
138
139    pub fn alloc_number(&self, number: Number) -> &'_ Number {
140        self.number_arena.alloc(number)
141    }
142
143    pub fn string<'ast>(&'ast self, s: &str) -> Node<'ast> {
144        Node::String(self.generic_arena.alloc_str(s))
145    }
146
147    pub fn string_chunks<'ast, I>(&'ast self, chunks: I) -> Node<'ast>
148    where
149        I: IntoIterator<Item = StringChunk<Ast<'ast>>>,
150        I::IntoIter: ExactSizeIterator,
151    {
152        Node::StringChunks(self.alloc_many(chunks))
153    }
154
155    pub fn fun<'ast, I>(&'ast self, args: I, body: Ast<'ast>) -> Node<'ast>
156    where
157        I: IntoIterator<Item = Pattern<'ast>>,
158        I::IntoIter: ExactSizeIterator,
159    {
160        Node::Fun {
161            args: self.generic_arena.alloc_slice_fill_iter(args),
162            body: self.generic_arena.alloc(body),
163        }
164    }
165
166    pub fn unary_fun<'ast>(&'ast self, arg: Pattern<'ast>, body: Ast<'ast>) -> Node<'ast> {
167        Node::Fun {
168            args: self.alloc_singleton(arg),
169            body: self.generic_arena.alloc(body),
170        }
171    }
172
173    pub fn let_block<'ast, I>(&'ast self, bindings: I, body: Ast<'ast>, rec: bool) -> Node<'ast>
174    where
175        I: IntoIterator<Item = LetBinding<'ast>>,
176        I::IntoIter: ExactSizeIterator,
177    {
178        let bindings = self.generic_arena.alloc_slice_fill_iter(bindings);
179        let body = self.generic_arena.alloc(body);
180
181        Node::Let {
182            bindings,
183            body,
184            rec,
185        }
186    }
187
188    pub fn app<'ast, I>(&'ast self, head: Ast<'ast>, args: I) -> Node<'ast>
189    where
190        I: IntoIterator<Item = Ast<'ast>>,
191        I::IntoIter: ExactSizeIterator,
192    {
193        Node::App {
194            head: self.generic_arena.alloc(head),
195            args: self.generic_arena.alloc_slice_fill_iter(args),
196        }
197    }
198
199    pub fn enum_variant<'ast>(&'ast self, tag: LocIdent, arg: Option<Ast<'ast>>) -> Node<'ast> {
200        Node::EnumVariant {
201            tag,
202            arg: arg.map(|arg| &*self.generic_arena.alloc(arg)),
203        }
204    }
205
206    pub fn record<'ast>(&'ast self, record: Record<'ast>) -> Node<'ast> {
207        let record = self.generic_arena.alloc(record);
208        Node::Record(record)
209    }
210
211    pub fn record_data<'ast, Is, Ds>(
212        &'ast self,
213        includes: Is,
214        field_defs: Ds,
215        open: bool,
216    ) -> &'ast Record<'ast>
217    where
218        Ds: IntoIterator<Item = FieldDef<'ast>>,
219        Is: IntoIterator<Item = Include<'ast>>,
220        Ds::IntoIter: ExactSizeIterator,
221        Is::IntoIter: ExactSizeIterator,
222    {
223        self.generic_arena.alloc(Record {
224            includes: self.generic_arena.alloc_slice_fill_iter(includes),
225            field_defs: self.generic_arena.alloc_slice_fill_iter(field_defs),
226            open,
227        })
228    }
229
230    pub fn if_then_else<'ast>(
231        &'ast self,
232        cond: Ast<'ast>,
233        then_branch: Ast<'ast>,
234        else_branch: Ast<'ast>,
235    ) -> Node<'ast> {
236        Node::IfThenElse {
237            cond: self.generic_arena.alloc(cond),
238            then_branch: self.generic_arena.alloc(then_branch),
239            else_branch: self.generic_arena.alloc(else_branch),
240        }
241    }
242
243    pub fn match_expr<'ast, I>(&'ast self, branches: I) -> Node<'ast>
244    where
245        I: IntoIterator<Item = MatchBranch<'ast>>,
246        I::IntoIter: ExactSizeIterator,
247    {
248        Node::Match(Match {
249            branches: self.generic_arena.alloc_slice_fill_iter(branches),
250        })
251    }
252
253    pub fn array<'ast, I>(&'ast self, elts: I) -> Node<'ast>
254    where
255        I: IntoIterator<Item = Ast<'ast>>,
256        I::IntoIter: ExactSizeIterator,
257    {
258        Node::Array(self.generic_arena.alloc_slice_fill_iter(elts))
259    }
260
261    pub fn prim_op<'ast, I>(&'ast self, op: PrimOp, args: I) -> Node<'ast>
262    where
263        I: IntoIterator<Item = Ast<'ast>>,
264        I::IntoIter: ExactSizeIterator,
265    {
266        let op = self.generic_arena.alloc(op);
267        let args = self.generic_arena.alloc_slice_fill_iter(args);
268        Node::PrimOpApp { op, args }
269    }
270
271    pub fn annotated<'ast>(&'ast self, annot: Annotation<'ast>, inner: Ast<'ast>) -> Node<'ast> {
272        Node::Annotated {
273            annot: self.generic_arena.alloc(annot),
274            inner: self.generic_arena.alloc(inner),
275        }
276    }
277
278    pub fn annotation<'ast, I>(
279        &'ast self,
280        typ: Option<Type<'ast>>,
281        contracts: I,
282    ) -> Annotation<'ast>
283    where
284        I: IntoIterator<Item = Type<'ast>>,
285        I::IntoIter: ExactSizeIterator,
286    {
287        Annotation {
288            typ,
289            contracts: self.generic_arena.alloc_slice_fill_iter(contracts),
290        }
291    }
292
293    pub fn import_path(&self, path: OsString, format: InputFormat) -> Node<'_> {
294        Node::Import(Import::Path {
295            path: self.generic_arena.alloc(path),
296            format,
297        })
298    }
299
300    pub fn import_package(&self, id: Ident) -> Node<'_> {
301        Node::Import(Import::Package { id })
302    }
303
304    pub fn typ<'ast>(&'ast self, typ: Type<'ast>) -> Node<'ast> {
305        Node::Type(self.generic_arena.alloc(typ))
306    }
307
308    pub fn type_data<'ast>(&'ast self, typ: TypeUnr<'ast>, pos: TermPos) -> &'ast Type<'ast> {
309        self.generic_arena.alloc(Type { typ, pos })
310    }
311
312    pub fn enum_rows<'ast>(&'ast self, erows: EnumRowsUnr<'ast>) -> &'ast EnumRows<'ast> {
313        self.generic_arena.alloc(EnumRows(erows))
314    }
315
316    pub fn record_rows<'ast>(&'ast self, rrows: RecordRowsUnr<'ast>) -> &'ast RecordRows<'ast> {
317        self.generic_arena.alloc(RecordRows(rrows))
318    }
319
320    pub fn parse_error(&self, error: ParseError) -> Node<'_> {
321        Node::ParseError(self.error_arena.alloc(error))
322    }
323
324    pub fn record_pattern<'ast, I>(
325        &'ast self,
326        patterns: I,
327        tail: TailPattern,
328        pos: TermPos,
329    ) -> &'ast RecordPattern<'ast>
330    where
331        I: IntoIterator<Item = FieldPattern<'ast>>,
332        I::IntoIter: ExactSizeIterator,
333    {
334        self.generic_arena.alloc(RecordPattern {
335            patterns: self.generic_arena.alloc_slice_fill_iter(patterns),
336            tail,
337            pos,
338        })
339    }
340
341    pub fn array_pattern<'ast, I>(
342        &'ast self,
343        patterns: I,
344        tail: TailPattern,
345        pos: TermPos,
346    ) -> &'ast ArrayPattern<'ast>
347    where
348        I: IntoIterator<Item = Pattern<'ast>>,
349        I::IntoIter: ExactSizeIterator,
350    {
351        self.generic_arena.alloc(ArrayPattern {
352            patterns: self.generic_arena.alloc_slice_fill_iter(patterns),
353            tail,
354            pos,
355        })
356    }
357
358    pub fn or_pattern<'ast, I>(&'ast self, patterns: I, pos: TermPos) -> &'ast OrPattern<'ast>
359    where
360        I: IntoIterator<Item = Pattern<'ast>>,
361        I::IntoIter: ExactSizeIterator,
362    {
363        self.generic_arena.alloc(OrPattern {
364            patterns: self.generic_arena.alloc_slice_fill_iter(patterns),
365            pos,
366        })
367    }
368}
369
370// Phony implementation of `Debug` so that we can still derive the trait for structure that holds
371// onto an allocator.
372impl fmt::Debug for AstAlloc {
373    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
374        write!(f, "AstAlloc")
375    }
376}
377
378/// Deeply clones an AST component from one allocator to the other.
379pub trait CloneTo {
380    /// This is always `Self`, be we need associated types to make Rust understand that `Self` is
381    /// always parametric over the `'ast` lifetime. We're using GATs to emulate higher-kinded
382    /// types.
383    type Data<'a>;
384
385    /// Clones owned data from the current allocator to `dest`.
386    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to>;
387}
388
389impl CloneTo for Ast<'_> {
390    type Data<'a> = Ast<'a>;
391
392    fn clone_to<'to>(data: Ast<'_>, dest: &'to AstAlloc) -> Ast<'to> {
393        Ast {
394            node: Node::clone_to(data.node.clone(), dest),
395            pos: data.pos,
396        }
397    }
398}
399
400impl CloneTo for Node<'_> {
401    type Data<'a> = Node<'a>;
402
403    fn clone_to<'to>(data: Node<'_>, dest: &'to AstAlloc) -> Node<'to> {
404        match data {
405            Node::Null => Node::Null,
406            Node::Bool(b) => Node::Bool(b),
407            Node::Number(rational) => dest.number(rational.clone()),
408            Node::String(s) => Node::String(dest.alloc_str(s)),
409            Node::StringChunks(str_chunks) => Node::StringChunks(
410                dest.alloc_many(
411                    str_chunks
412                        .iter()
413                        .map(|chunk| StringChunk::clone_to(chunk.clone(), dest)),
414                ),
415            ),
416            Node::Fun { args, body } => Node::Fun {
417                args: dest.alloc_many(args.iter().map(|arg| Pattern::clone_to(arg.clone(), dest))),
418                body: dest.clone_ref_from::<Ast>(body),
419            },
420            Node::Let {
421                bindings,
422                body,
423                rec,
424            } => Node::Let {
425                bindings: dest.alloc_many(
426                    bindings
427                        .iter()
428                        .map(|binding| LetBinding::clone_to(binding.clone(), dest)),
429                ),
430                body: dest.clone_ref_from::<Ast>(body),
431                rec,
432            },
433            Node::App { head, args } => Node::App {
434                head: dest.clone_ref_from::<Ast>(head),
435                args: dest.alloc_many(args.iter().map(|arg| Ast::clone_to(arg.clone(), dest))),
436            },
437            Node::Var(loc_ident) => Node::Var(loc_ident),
438            Node::EnumVariant { tag, arg } => Node::EnumVariant {
439                tag,
440                arg: arg.map(|arg| dest.clone_ref_from::<Ast>(arg)),
441            },
442            Node::Record(record) => Node::Record(dest.clone_ref_from::<Record>(record)),
443            Node::IfThenElse {
444                cond,
445                then_branch,
446                else_branch,
447            } => Node::IfThenElse {
448                cond: dest.clone_ref_from::<Ast>(cond),
449                then_branch: dest.clone_ref_from::<Ast>(then_branch),
450                else_branch: dest.clone_ref_from::<Ast>(else_branch),
451            },
452            Node::Match(data) => Node::Match(Match {
453                branches: dest.alloc_many(
454                    data.branches
455                        .iter()
456                        .map(|branch| MatchBranch::clone_to(branch.clone(), dest)),
457                ),
458            }),
459            Node::Array(asts) => Node::Array(
460                dest.alloc_many(asts.iter().map(|ast| Ast::clone_to(ast.clone(), dest))),
461            ),
462            Node::PrimOpApp { op, args } => Node::PrimOpApp {
463                op: dest.alloc(*op),
464                args: dest.alloc_many(args.iter().map(|arg| Ast::clone_to(arg.clone(), dest))),
465            },
466            Node::Annotated { annot, inner } => Node::Annotated {
467                annot: dest.clone_ref_from::<Annotation>(annot),
468                inner: dest.clone_ref_from::<Ast>(inner),
469            },
470            Node::Import(import) => match import {
471                Import::Path { path, format } => dest.import_path(path.to_owned(), format),
472                Import::Package { id } => Node::Import(Import::Package { id }),
473            },
474            Node::Type(ty) => Node::Type(dest.clone_ref_from::<Type>(ty)),
475            Node::ParseError(parse_error) => dest.parse_error(parse_error.clone()),
476        }
477    }
478}
479
480impl CloneTo for LetBinding<'_> {
481    type Data<'ast> = LetBinding<'ast>;
482
483    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
484        LetBinding {
485            pattern: Pattern::clone_to(data.pattern, dest),
486            metadata: LetMetadata::clone_to(data.metadata, dest),
487            value: Ast::clone_to(data.value, dest),
488        }
489    }
490}
491
492impl CloneTo for LetMetadata<'_> {
493    type Data<'ast> = LetMetadata<'ast>;
494
495    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
496        LetMetadata {
497            doc: data.doc.map(|s| dest.alloc_str(s)),
498            annotation: Annotation::clone_to(data.annotation, dest),
499        }
500    }
501}
502
503impl CloneTo for Include<'_> {
504    type Data<'ast> = Include<'ast>;
505
506    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
507        Include {
508            ident: data.ident,
509            metadata: FieldMetadata::clone_to(data.metadata, dest),
510        }
511    }
512}
513
514impl CloneTo for Record<'_> {
515    type Data<'ast> = Record<'ast>;
516
517    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
518        Record {
519            includes: dest.alloc_many(
520                data.includes
521                    .iter()
522                    .cloned()
523                    .map(|include| Include::clone_to(include, dest)),
524            ),
525            field_defs: dest.alloc_many(
526                data.field_defs
527                    .iter()
528                    .cloned()
529                    .map(|field_def| FieldDef::clone_to(field_def, dest)),
530            ),
531            open: data.open,
532        }
533    }
534}
535
536impl CloneTo for FieldDef<'_> {
537    type Data<'ast> = FieldDef<'ast>;
538
539    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
540        FieldDef {
541            path: dest.alloc_many(
542                data.path
543                    .iter()
544                    .map(|elem| record::FieldPathElem::clone_to(elem.clone(), dest)),
545            ),
546            metadata: record::FieldMetadata::clone_to(data.metadata, dest),
547            value: data.value.map(|v| Ast::clone_to(v, dest)),
548            pos: data.pos,
549        }
550    }
551}
552
553impl CloneTo for record::FieldPathElem<'_> {
554    type Data<'ast> = record::FieldPathElem<'ast>;
555
556    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
557        match data {
558            record::FieldPathElem::Ident(loc_ident) => record::FieldPathElem::Ident(loc_ident),
559            record::FieldPathElem::Expr(ast) => {
560                record::FieldPathElem::Expr(Ast::clone_to(ast, dest))
561            }
562        }
563    }
564}
565
566impl CloneTo for record::FieldMetadata<'_> {
567    type Data<'ast> = record::FieldMetadata<'ast>;
568
569    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
570        record::FieldMetadata {
571            doc: data.doc.map(|doc| dest.alloc_str(doc)),
572            annotation: Annotation::clone_to(data.annotation, dest),
573            ..data
574        }
575    }
576}
577
578impl CloneTo for MatchBranch<'_> {
579    type Data<'ast> = MatchBranch<'ast>;
580
581    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
582        MatchBranch {
583            pattern: Pattern::clone_to(data.pattern, dest),
584            guard: data.guard.map(|ast| Ast::clone_to(ast, dest)),
585            body: Ast::clone_to(data.body, dest),
586        }
587    }
588}
589
590impl CloneTo for Annotation<'_> {
591    type Data<'ast> = Annotation<'ast>;
592
593    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
594        Annotation {
595            typ: data.typ.map(|typ| Type::clone_to(typ, dest)),
596            contracts: dest.alloc_many(
597                data.contracts
598                    .iter()
599                    .map(|typ| Type::clone_to(typ.clone(), dest)),
600            ),
601        }
602    }
603}
604
605impl CloneTo for Type<'_> {
606    type Data<'ast> = Type<'ast>;
607
608    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
609        let typ = match data.typ {
610            TypeF::Dyn => TypeF::Dyn,
611            TypeF::Number => TypeF::Number,
612            TypeF::Bool => TypeF::Bool,
613            TypeF::String => TypeF::String,
614            TypeF::Symbol => TypeF::Symbol,
615            TypeF::ForeignId => TypeF::ForeignId,
616            TypeF::Contract(ast) => TypeF::Contract(dest.clone_ref_from::<Ast>(ast)),
617            TypeF::Arrow(src, tgt) => TypeF::Arrow(
618                dest.clone_ref_from::<Type>(src),
619                dest.clone_ref_from::<Type>(tgt),
620            ),
621            TypeF::Var(id) => TypeF::Var(id),
622            TypeF::Forall {
623                var,
624                var_kind,
625                body,
626            } => TypeF::Forall {
627                var,
628                var_kind,
629                body: dest.clone_ref_from::<Type>(body),
630            },
631            TypeF::Enum(erows) => TypeF::Enum(typ::EnumRows::clone_to(erows, dest)),
632            TypeF::Record(rrows) => TypeF::Record(typ::RecordRows::clone_to(rrows, dest)),
633            TypeF::Dict {
634                type_fields,
635                flavour,
636            } => TypeF::Dict {
637                type_fields: dest.clone_ref_from::<Type>(type_fields),
638                flavour,
639            },
640            TypeF::Array(ty) => TypeF::Array(dest.clone_ref_from::<Type>(ty)),
641            TypeF::Wildcard(wildcard_id) => TypeF::Wildcard(wildcard_id),
642        };
643
644        Type { typ, pos: data.pos }
645    }
646}
647
648impl CloneTo for typ::EnumRows<'_> {
649    type Data<'ast> = typ::EnumRows<'ast>;
650
651    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
652        use typ::*;
653
654        let inner = match data.0 {
655            EnumRowsF::Empty => EnumRowsF::Empty,
656            EnumRowsF::Extend { row, tail } => EnumRowsF::Extend {
657                row: EnumRow::clone_to(row, dest),
658                tail: dest.clone_ref_from::<EnumRows>(tail),
659            },
660            EnumRowsF::TailVar(loc_ident) => EnumRowsF::TailVar(loc_ident),
661        };
662
663        EnumRows(inner)
664    }
665}
666
667impl CloneTo for typ::EnumRow<'_> {
668    type Data<'ast> = typ::EnumRow<'ast>;
669
670    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
671        typ::EnumRow {
672            id: data.id,
673            typ: data.typ.map(|ty| dest.clone_ref_from::<Type>(ty)),
674        }
675    }
676}
677
678impl CloneTo for typ::RecordRows<'_> {
679    type Data<'ast> = typ::RecordRows<'ast>;
680
681    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
682        use typ::*;
683
684        let inner = match data.0 {
685            RecordRowsF::Empty => RecordRowsF::Empty,
686            RecordRowsF::Extend { row, tail } => RecordRowsF::Extend {
687                row: RecordRow::clone_to(row, dest),
688                tail: dest.clone_ref_from::<RecordRows>(tail),
689            },
690            RecordRowsF::TailVar(loc_ident) => RecordRowsF::TailVar(loc_ident),
691            RecordRowsF::TailDyn => RecordRowsF::TailDyn,
692        };
693
694        RecordRows(inner)
695    }
696}
697
698impl CloneTo for typ::RecordRow<'_> {
699    type Data<'ast> = typ::RecordRow<'ast>;
700
701    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
702        typ::RecordRow {
703            id: data.id,
704            typ: dest.clone_ref_from::<Type>(data.typ),
705        }
706    }
707}
708
709impl CloneTo for StringChunk<Ast<'_>> {
710    type Data<'ast> = StringChunk<Ast<'ast>>;
711
712    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
713        match data {
714            StringChunk::Literal(s) => StringChunk::Literal(s),
715            StringChunk::Expr(ast, indent) => StringChunk::Expr(Ast::clone_to(ast, dest), indent),
716        }
717    }
718}
719
720impl CloneTo for Pattern<'_> {
721    type Data<'ast> = Pattern<'ast>;
722
723    fn clone_to<'to>(pat: Pattern<'_>, dest: &'to AstAlloc) -> Pattern<'to> {
724        let data = match pat.data {
725            PatternData::Wildcard => PatternData::Wildcard,
726            PatternData::Any(id) => PatternData::Any(id),
727            PatternData::Record(record_pat) => {
728                PatternData::Record(dest.clone_ref_from::<RecordPattern>(record_pat))
729            }
730            PatternData::Array(array_pat) => {
731                PatternData::Array(dest.clone_ref_from::<ArrayPattern>(array_pat))
732            }
733            PatternData::Enum(enum_pat) => {
734                PatternData::Enum(dest.clone_ref_from::<EnumPattern>(enum_pat))
735            }
736            PatternData::Constant(const_pat) => {
737                PatternData::Constant(dest.clone_ref_from::<ConstantPattern>(const_pat))
738            }
739            PatternData::Or(or_pat) => PatternData::Or(dest.clone_ref_from::<OrPattern>(or_pat)),
740        };
741
742        Pattern { data, ..pat }
743    }
744}
745
746impl CloneTo for EnumPattern<'_> {
747    type Data<'ast> = EnumPattern<'ast>;
748
749    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
750        EnumPattern {
751            pattern: data.pattern.map(|pat| Pattern::clone_to(pat, dest)),
752            ..data
753        }
754    }
755}
756
757impl CloneTo for RecordPattern<'_> {
758    type Data<'ast> = RecordPattern<'ast>;
759
760    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
761        RecordPattern {
762            patterns: dest.alloc_many(
763                pat.patterns
764                    .iter()
765                    .map(|field_pat| FieldPattern::clone_to(field_pat.clone(), dest)),
766            ),
767            ..pat
768        }
769    }
770}
771
772impl CloneTo for FieldPattern<'_> {
773    type Data<'ast> = FieldPattern<'ast>;
774
775    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
776        FieldPattern {
777            annotation: Annotation::clone_to(pat.annotation, dest),
778            default: pat.default.map(|ast| Ast::clone_to(ast, dest)),
779            pattern: Pattern::clone_to(pat.pattern, dest),
780            ..pat
781        }
782    }
783}
784
785impl CloneTo for ArrayPattern<'_> {
786    type Data<'ast> = ArrayPattern<'ast>;
787
788    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
789        ArrayPattern {
790            patterns: dest.alloc_many(
791                data.patterns
792                    .iter()
793                    .map(|pat| Pattern::clone_to(pat.clone(), dest)),
794            ),
795            ..data
796        }
797    }
798}
799
800impl CloneTo for ConstantPattern<'_> {
801    type Data<'ast> = ConstantPattern<'ast>;
802
803    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
804        ConstantPattern {
805            data: ConstantPatternData::clone_to(pat.data, dest),
806            ..pat
807        }
808    }
809}
810
811impl CloneTo for ConstantPatternData<'_> {
812    type Data<'ast> = ConstantPatternData<'ast>;
813
814    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
815        match data {
816            ConstantPatternData::Bool(b) => ConstantPatternData::Bool(b),
817            ConstantPatternData::Number(n) => {
818                ConstantPatternData::Number(dest.alloc_number(n.clone()))
819            }
820            ConstantPatternData::String(s) => ConstantPatternData::String(dest.alloc_str(s)),
821            ConstantPatternData::Null => ConstantPatternData::Null,
822        }
823    }
824}
825
826impl CloneTo for OrPattern<'_> {
827    type Data<'ast> = OrPattern<'ast>;
828
829    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
830        OrPattern {
831            patterns: dest.alloc_many(
832                pat.patterns
833                    .iter()
834                    .map(|pat| Pattern::clone_to(pat.clone(), dest)),
835            ),
836            ..pat
837        }
838    }
839}