Skip to main content

nickel_lang_parser/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<T> CloneTo for &T
390where
391    T: for<'a> CloneTo<Data<'a>: Clone + Allocable>,
392    for<'a> <T as CloneTo>::Data<'a>: 'a,
393{
394    type Data<'a> = &'a T::Data<'a>;
395
396    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
397        dest.clone_ref_from::<T>(data)
398    }
399}
400
401impl<T: CloneTo> CloneTo for Box<T> {
402    type Data<'a> = Box<T::Data<'a>>;
403
404    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
405        Box::new(dest.clone_from::<T>(*data))
406    }
407}
408
409impl<S: CloneTo, T: CloneTo> CloneTo for (S, T) {
410    type Data<'a> = (S::Data<'a>, T::Data<'a>);
411
412    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
413        (dest.clone_from::<S>(data.0), dest.clone_from::<T>(data.1))
414    }
415}
416
417impl CloneTo for Ast<'_> {
418    type Data<'a> = Ast<'a>;
419
420    fn clone_to<'to>(data: Ast<'_>, dest: &'to AstAlloc) -> Ast<'to> {
421        Ast {
422            node: Node::clone_to(data.node.clone(), dest),
423            pos: data.pos,
424        }
425    }
426}
427
428impl CloneTo for Node<'_> {
429    type Data<'a> = Node<'a>;
430
431    fn clone_to<'to>(data: Node<'_>, dest: &'to AstAlloc) -> Node<'to> {
432        match data {
433            Node::Null => Node::Null,
434            Node::Bool(b) => Node::Bool(b),
435            Node::Number(rational) => dest.number(rational.clone()),
436            Node::String(s) => Node::String(dest.alloc_str(s)),
437            Node::StringChunks(str_chunks) => Node::StringChunks(
438                dest.alloc_many(
439                    str_chunks
440                        .iter()
441                        .map(|chunk| StringChunk::clone_to(chunk.clone(), dest)),
442                ),
443            ),
444            Node::Fun { args, body } => Node::Fun {
445                args: dest.alloc_many(args.iter().map(|arg| Pattern::clone_to(arg.clone(), dest))),
446                body: dest.clone_ref_from::<Ast>(body),
447            },
448            Node::Let {
449                bindings,
450                body,
451                rec,
452            } => Node::Let {
453                bindings: dest.alloc_many(
454                    bindings
455                        .iter()
456                        .map(|binding| LetBinding::clone_to(binding.clone(), dest)),
457                ),
458                body: dest.clone_ref_from::<Ast>(body),
459                rec,
460            },
461            Node::App { head, args } => Node::App {
462                head: dest.clone_ref_from::<Ast>(head),
463                args: dest.alloc_many(args.iter().map(|arg| Ast::clone_to(arg.clone(), dest))),
464            },
465            Node::Var(loc_ident) => Node::Var(loc_ident),
466            Node::EnumVariant { tag, arg } => Node::EnumVariant {
467                tag,
468                arg: arg.map(|arg| dest.clone_ref_from::<Ast>(arg)),
469            },
470            Node::Record(record) => Node::Record(dest.clone_ref_from::<Record>(record)),
471            Node::IfThenElse {
472                cond,
473                then_branch,
474                else_branch,
475            } => Node::IfThenElse {
476                cond: dest.clone_ref_from::<Ast>(cond),
477                then_branch: dest.clone_ref_from::<Ast>(then_branch),
478                else_branch: dest.clone_ref_from::<Ast>(else_branch),
479            },
480            Node::Match(data) => Node::Match(Match {
481                branches: dest.alloc_many(
482                    data.branches
483                        .iter()
484                        .map(|branch| MatchBranch::clone_to(branch.clone(), dest)),
485                ),
486            }),
487            Node::Array(asts) => Node::Array(
488                dest.alloc_many(asts.iter().map(|ast| Ast::clone_to(ast.clone(), dest))),
489            ),
490            Node::PrimOpApp { op, args } => Node::PrimOpApp {
491                op: dest.alloc(*op),
492                args: dest.alloc_many(args.iter().map(|arg| Ast::clone_to(arg.clone(), dest))),
493            },
494            Node::Annotated { annot, inner } => Node::Annotated {
495                annot: dest.clone_ref_from::<Annotation>(annot),
496                inner: dest.clone_ref_from::<Ast>(inner),
497            },
498            Node::Import(import) => match import {
499                Import::Path { path, format } => dest.import_path(path.to_owned(), format),
500                Import::Package { id } => Node::Import(Import::Package { id }),
501            },
502            Node::Type(ty) => Node::Type(dest.clone_ref_from::<Type>(ty)),
503            Node::ParseError(parse_error) => dest.parse_error(parse_error.clone()),
504        }
505    }
506}
507
508impl CloneTo for LetBinding<'_> {
509    type Data<'ast> = LetBinding<'ast>;
510
511    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
512        LetBinding {
513            pattern: Pattern::clone_to(data.pattern, dest),
514            metadata: LetMetadata::clone_to(data.metadata, dest),
515            value: Ast::clone_to(data.value, dest),
516        }
517    }
518}
519
520impl CloneTo for LetMetadata<'_> {
521    type Data<'ast> = LetMetadata<'ast>;
522
523    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
524        LetMetadata {
525            doc: data.doc.map(|s| dest.alloc_str(s)),
526            annotation: Annotation::clone_to(data.annotation, dest),
527        }
528    }
529}
530
531impl CloneTo for Include<'_> {
532    type Data<'ast> = Include<'ast>;
533
534    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
535        Include {
536            ident: data.ident,
537            metadata: FieldMetadata::clone_to(data.metadata, dest),
538        }
539    }
540}
541
542impl CloneTo for Record<'_> {
543    type Data<'ast> = Record<'ast>;
544
545    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
546        Record {
547            includes: dest.alloc_many(
548                data.includes
549                    .iter()
550                    .cloned()
551                    .map(|include| Include::clone_to(include, dest)),
552            ),
553            field_defs: dest.alloc_many(
554                data.field_defs
555                    .iter()
556                    .cloned()
557                    .map(|field_def| FieldDef::clone_to(field_def, dest)),
558            ),
559            open: data.open,
560        }
561    }
562}
563
564impl CloneTo for FieldDef<'_> {
565    type Data<'ast> = FieldDef<'ast>;
566
567    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
568        FieldDef {
569            path: dest.alloc_many(
570                data.path
571                    .iter()
572                    .map(|elem| record::FieldPathElem::clone_to(elem.clone(), dest)),
573            ),
574            metadata: record::FieldMetadata::clone_to(data.metadata, dest),
575            value: data.value.map(|v| Ast::clone_to(v, dest)),
576            pos: data.pos,
577        }
578    }
579}
580
581impl CloneTo for record::FieldPathElem<'_> {
582    type Data<'ast> = record::FieldPathElem<'ast>;
583
584    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
585        match data {
586            record::FieldPathElem::Ident(loc_ident) => record::FieldPathElem::Ident(loc_ident),
587            record::FieldPathElem::Expr(ast) => {
588                record::FieldPathElem::Expr(Ast::clone_to(ast, dest))
589            }
590        }
591    }
592}
593
594impl CloneTo for record::FieldMetadata<'_> {
595    type Data<'ast> = record::FieldMetadata<'ast>;
596
597    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
598        record::FieldMetadata {
599            doc: data.doc.map(|doc| dest.alloc_str(doc)),
600            annotation: Annotation::clone_to(data.annotation, dest),
601            ..data
602        }
603    }
604}
605
606impl CloneTo for MatchBranch<'_> {
607    type Data<'ast> = MatchBranch<'ast>;
608
609    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
610        MatchBranch {
611            pattern: Pattern::clone_to(data.pattern, dest),
612            guard: data.guard.map(|ast| Ast::clone_to(ast, dest)),
613            body: Ast::clone_to(data.body, dest),
614        }
615    }
616}
617
618impl CloneTo for Annotation<'_> {
619    type Data<'ast> = Annotation<'ast>;
620
621    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
622        Annotation {
623            typ: data.typ.map(|typ| Type::clone_to(typ, dest)),
624            contracts: dest.alloc_many(
625                data.contracts
626                    .iter()
627                    .map(|typ| Type::clone_to(typ.clone(), dest)),
628            ),
629        }
630    }
631}
632
633impl CloneTo for Type<'_> {
634    type Data<'ast> = Type<'ast>;
635
636    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
637        let typ = match data.typ {
638            TypeF::Dyn => TypeF::Dyn,
639            TypeF::Number => TypeF::Number,
640            TypeF::Bool => TypeF::Bool,
641            TypeF::String => TypeF::String,
642            TypeF::Symbol => TypeF::Symbol,
643            TypeF::ForeignId => TypeF::ForeignId,
644            TypeF::Contract(ast) => TypeF::Contract(dest.clone_ref_from::<Ast>(ast)),
645            TypeF::Arrow(src, tgt) => TypeF::Arrow(
646                dest.clone_ref_from::<Type>(src),
647                dest.clone_ref_from::<Type>(tgt),
648            ),
649            TypeF::Var(id) => TypeF::Var(id),
650            TypeF::Forall {
651                var,
652                var_kind,
653                body,
654            } => TypeF::Forall {
655                var,
656                var_kind,
657                body: dest.clone_ref_from::<Type>(body),
658            },
659            TypeF::Enum(erows) => TypeF::Enum(typ::EnumRows::clone_to(erows, dest)),
660            TypeF::Record(rrows) => TypeF::Record(typ::RecordRows::clone_to(rrows, dest)),
661            TypeF::Dict {
662                type_fields,
663                flavour,
664            } => TypeF::Dict {
665                type_fields: dest.clone_ref_from::<Type>(type_fields),
666                flavour,
667            },
668            TypeF::Array(ty) => TypeF::Array(dest.clone_ref_from::<Type>(ty)),
669            TypeF::Wildcard(wildcard_id) => TypeF::Wildcard(wildcard_id),
670        };
671
672        Type { typ, pos: data.pos }
673    }
674}
675
676impl<Ty: CloneTo, ERows: CloneTo> CloneTo for typ::EnumRowsF<Ty, ERows> {
677    type Data<'ast> = typ::EnumRowsF<Ty::Data<'ast>, ERows::Data<'ast>>;
678
679    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
680        use typ::*;
681
682        match data {
683            EnumRowsF::Empty => EnumRowsF::Empty,
684            EnumRowsF::Extend { row, tail } => EnumRowsF::Extend {
685                row: EnumRowF::<Ty>::clone_to(row, dest),
686                tail: dest.clone_from::<ERows>(tail),
687            },
688            EnumRowsF::TailVar(loc_ident) => EnumRowsF::TailVar(loc_ident),
689        }
690    }
691}
692
693impl CloneTo for typ::EnumRows<'_> {
694    type Data<'ast> = typ::EnumRows<'ast>;
695
696    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
697        EnumRows(dest.clone_from::<EnumRowsUnr>(data.0))
698    }
699}
700
701impl<Ty: CloneTo> CloneTo for typ::EnumRowF<Ty> {
702    type Data<'ast> = typ::EnumRowF<Ty::Data<'ast>>;
703
704    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
705        typ::EnumRowF {
706            id: data.id,
707            typ: data.typ.map(|ty| dest.clone_from::<Ty>(ty)),
708        }
709    }
710}
711
712impl<Ty: CloneTo, RRows: CloneTo> CloneTo for typ::RecordRowsF<Ty, RRows> {
713    type Data<'ast> = typ::RecordRowsF<Ty::Data<'ast>, RRows::Data<'ast>>;
714
715    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
716        use typ::*;
717
718        match data {
719            RecordRowsF::Empty => RecordRowsF::Empty,
720            RecordRowsF::Extend { row, tail } => RecordRowsF::Extend {
721                row: RecordRowF::<Ty>::clone_to(row, dest),
722                tail: dest.clone_from::<RRows>(tail),
723            },
724            RecordRowsF::TailVar(loc_ident) => RecordRowsF::TailVar(loc_ident),
725            RecordRowsF::TailDyn => RecordRowsF::TailDyn,
726        }
727    }
728}
729
730impl CloneTo for typ::RecordRows<'_> {
731    type Data<'ast> = typ::RecordRows<'ast>;
732
733    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
734        RecordRows(dest.clone_from::<RecordRowsUnr>(data.0))
735    }
736}
737
738impl<Ty: CloneTo> CloneTo for typ::RecordRowF<Ty> {
739    type Data<'ast> = typ::RecordRowF<Ty::Data<'ast>>;
740
741    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
742        typ::RecordRowF {
743            id: data.id,
744            typ: dest.clone_from::<Ty>(data.typ),
745        }
746    }
747}
748
749impl CloneTo for StringChunk<Ast<'_>> {
750    type Data<'ast> = StringChunk<Ast<'ast>>;
751
752    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
753        match data {
754            StringChunk::Literal(s) => StringChunk::Literal(s),
755            StringChunk::Expr(ast, indent) => StringChunk::Expr(Ast::clone_to(ast, dest), indent),
756        }
757    }
758}
759
760impl CloneTo for Pattern<'_> {
761    type Data<'ast> = Pattern<'ast>;
762
763    fn clone_to<'to>(pat: Pattern<'_>, dest: &'to AstAlloc) -> Pattern<'to> {
764        let data = match pat.data {
765            PatternData::Wildcard => PatternData::Wildcard,
766            PatternData::Any(id) => PatternData::Any(id),
767            PatternData::Record(record_pat) => {
768                PatternData::Record(dest.clone_ref_from::<RecordPattern>(record_pat))
769            }
770            PatternData::Array(array_pat) => {
771                PatternData::Array(dest.clone_ref_from::<ArrayPattern>(array_pat))
772            }
773            PatternData::Enum(enum_pat) => {
774                PatternData::Enum(dest.clone_ref_from::<EnumPattern>(enum_pat))
775            }
776            PatternData::Constant(const_pat) => {
777                PatternData::Constant(dest.clone_ref_from::<ConstantPattern>(const_pat))
778            }
779            PatternData::Or(or_pat) => PatternData::Or(dest.clone_ref_from::<OrPattern>(or_pat)),
780        };
781
782        Pattern { data, ..pat }
783    }
784}
785
786impl CloneTo for EnumPattern<'_> {
787    type Data<'ast> = EnumPattern<'ast>;
788
789    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
790        EnumPattern {
791            pattern: data.pattern.map(|pat| Pattern::clone_to(pat, dest)),
792            ..data
793        }
794    }
795}
796
797impl CloneTo for RecordPattern<'_> {
798    type Data<'ast> = RecordPattern<'ast>;
799
800    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
801        RecordPattern {
802            patterns: dest.alloc_many(
803                pat.patterns
804                    .iter()
805                    .map(|field_pat| FieldPattern::clone_to(field_pat.clone(), dest)),
806            ),
807            ..pat
808        }
809    }
810}
811
812impl CloneTo for FieldPattern<'_> {
813    type Data<'ast> = FieldPattern<'ast>;
814
815    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
816        FieldPattern {
817            annotation: Annotation::clone_to(pat.annotation, dest),
818            default: pat.default.map(|ast| Ast::clone_to(ast, dest)),
819            pattern: Pattern::clone_to(pat.pattern, dest),
820            ..pat
821        }
822    }
823}
824
825impl CloneTo for ArrayPattern<'_> {
826    type Data<'ast> = ArrayPattern<'ast>;
827
828    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
829        ArrayPattern {
830            patterns: dest.alloc_many(
831                data.patterns
832                    .iter()
833                    .map(|pat| Pattern::clone_to(pat.clone(), dest)),
834            ),
835            ..data
836        }
837    }
838}
839
840impl CloneTo for ConstantPattern<'_> {
841    type Data<'ast> = ConstantPattern<'ast>;
842
843    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
844        ConstantPattern {
845            data: ConstantPatternData::clone_to(pat.data, dest),
846            ..pat
847        }
848    }
849}
850
851impl CloneTo for ConstantPatternData<'_> {
852    type Data<'ast> = ConstantPatternData<'ast>;
853
854    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
855        match data {
856            ConstantPatternData::Bool(b) => ConstantPatternData::Bool(b),
857            ConstantPatternData::Number(n) => {
858                ConstantPatternData::Number(dest.alloc_number(n.clone()))
859            }
860            ConstantPatternData::String(s) => ConstantPatternData::String(dest.alloc_str(s)),
861            ConstantPatternData::Null => ConstantPatternData::Null,
862        }
863    }
864}
865
866impl CloneTo for OrPattern<'_> {
867    type Data<'ast> = OrPattern<'ast>;
868
869    fn clone_to<'to>(pat: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
870        OrPattern {
871            patterns: dest.alloc_many(
872                pat.patterns
873                    .iter()
874                    .map(|pat| Pattern::clone_to(pat.clone(), dest)),
875            ),
876            ..pat
877        }
878    }
879}
880
881impl<Ty, RRows, ERows, Te> CloneTo for TypeF<Ty, RRows, ERows, Te>
882where
883    Ty: CloneTo,
884    RRows: CloneTo,
885    ERows: CloneTo,
886    Te: CloneTo,
887{
888    type Data<'a> = TypeF<Ty::Data<'a>, RRows::Data<'a>, ERows::Data<'a>, Te::Data<'a>>;
889
890    fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to> {
891        match data {
892            TypeF::Dyn => TypeF::Dyn,
893            TypeF::Number => TypeF::Number,
894            TypeF::Bool => TypeF::Bool,
895            TypeF::String => TypeF::String,
896            TypeF::Symbol => TypeF::Symbol,
897            TypeF::ForeignId => TypeF::ForeignId,
898            TypeF::Contract(te) => TypeF::Contract(dest.clone_from::<Te>(te)),
899            TypeF::Arrow(src, tgt) => {
900                TypeF::Arrow(dest.clone_from::<Ty>(src), dest.clone_from::<Ty>(tgt))
901            }
902            TypeF::Var(id) => TypeF::Var(id),
903            TypeF::Forall {
904                var,
905                var_kind,
906                body,
907            } => TypeF::Forall {
908                var,
909                var_kind,
910                body: dest.clone_from::<Ty>(body),
911            },
912            TypeF::Enum(erows) => TypeF::Enum(dest.clone_from::<ERows>(erows)),
913            TypeF::Record(rrows) => TypeF::Record(dest.clone_from::<RRows>(rrows)),
914            TypeF::Dict {
915                type_fields,
916                flavour,
917            } => TypeF::Dict {
918                type_fields: dest.clone_from::<Ty>(type_fields),
919                flavour,
920            },
921            TypeF::Array(ty) => TypeF::Array(dest.clone_from::<Ty>(ty)),
922            TypeF::Wildcard(wildcard_id) => TypeF::Wildcard(wildcard_id),
923        }
924    }
925}