Skip to main content

geam_core/plan/module/
function.rs

1use super::expression::{
2    BitArrayExpr, BitArrayListExpr, BoolExpr, BoolListExpr, CallArg, CustomExpr, CustomListExpr,
3    ExternalExpr, ExternalListExpr, FloatExpr, FloatListExpr, FunctionListExpr, IntExpr,
4    IntListExpr, ListListExpr, NilExpr, NilListExpr, StringExpr, StringListExpr, TupleExpr,
5    TupleListExpr, UtfCodepointExpr, UtfCodepointListExpr,
6};
7use super::id::{
8    BitArrayFunctionLocalId, BitArrayLocalId, BoolFunctionLocalId, BoolLocalId,
9    CustomFunctionLocal, CustomLocal, CustomLocalId, ExternalFunctionLocal, ExternalLocal,
10    ExternalLocalId, FloatFunctionLocalId, FloatLocalId, FunctionFunctionLocal, FunctionTemplateId,
11    GenericFunctionLocal, GenericLocal, IntFunctionLocalId, IntLocalId, ListFunctionLocal,
12    ListLocal, NilFunctionLocalId, NilLocalId, StringFunctionLocalId, StringLocalId,
13    TupleFunctionLocalId, TupleLocalId, UtfCodepointFunctionLocalId, UtfCodepointLocalId,
14};
15use super::step::Step;
16use super::{FunctionInstantiation, FunctionTemplateSignature, TypeScheme};
17use crate::plan::{
18    CustomFunctionType, CustomType, ExternalFunctionType, ExternalType, FunctionFunctionType,
19    FunctionType, ValueStorageShape, ValueType,
20};
21use ecow::EcoString;
22use num_bigint::BigInt;
23
24#[cfg(test)]
25use super::expression::ListExpr;
26#[cfg(test)]
27use super::id::{BoolFunctionId, IntFunctionId};
28#[cfg(test)]
29use crate::plan::{ValueRepresentation, ValueShape};
30
31#[derive(Debug, PartialEq)]
32pub struct FunctionTemplate {
33    signature: FunctionTemplateSignature,
34    name: EcoString,
35    entry: FunctionEntry,
36    steps: Vec<Step>,
37    return_: ReturnExpr,
38}
39
40#[derive(Debug, PartialEq)]
41pub(crate) struct FunctionEntry {
42    params: Box<[Param]>,
43    captures: Box<[ParamSlot]>,
44}
45
46#[derive(Debug, PartialEq)]
47pub struct Param {
48    slot: ParamSlot,
49    binding: ParamBinding,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub(crate) struct ParamSlot {
54    local: ParamLocal,
55    shape: crate::plan::ValueShape,
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub(crate) struct CapturePosition(usize);
60
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub enum ParamBinding {
63    Named(EcoString),
64    Discard,
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
68pub(crate) enum ParamLocal {
69    Generic(GenericLocal),
70    Int(IntLocalId),
71    Float(FloatLocalId),
72    String(StringLocalId),
73    BitArray(BitArrayLocalId),
74    UtfCodepoint(UtfCodepointLocalId),
75    Custom(CustomLocal),
76    External(ExternalLocal),
77    Bool(BoolLocalId),
78    Nil(NilLocalId),
79    Tuple {
80        local: TupleLocalId,
81        type_: Vec<ValueType>,
82    },
83    List(ListLocal),
84    IntFunction {
85        local: IntFunctionLocalId,
86        type_: FunctionType,
87    },
88    FloatFunction {
89        local: FloatFunctionLocalId,
90        type_: FunctionType,
91    },
92    StringFunction {
93        local: StringFunctionLocalId,
94        type_: FunctionType,
95    },
96    BitArrayFunction {
97        local: BitArrayFunctionLocalId,
98        type_: FunctionType,
99    },
100    UtfCodepointFunction {
101        local: UtfCodepointFunctionLocalId,
102        type_: FunctionType,
103    },
104    CustomFunction(CustomFunctionLocal),
105    ExternalFunction(ExternalFunctionLocal),
106    BoolFunction {
107        local: BoolFunctionLocalId,
108        type_: FunctionType,
109    },
110    NilFunction {
111        local: NilFunctionLocalId,
112        type_: FunctionType,
113    },
114    TupleFunction {
115        local: TupleFunctionLocalId,
116        type_: FunctionType,
117    },
118    ListFunction(ListFunctionLocal),
119    FunctionFunction(FunctionFunctionLocal),
120    GenericFunction(GenericFunctionLocal),
121}
122
123pub(crate) type GenericReturn =
124    ReturnBody<super::GenericExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
125pub(crate) type IntReturn =
126    ReturnBody<IntExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
127pub(crate) type FloatReturn =
128    ReturnBody<FloatExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
129pub(crate) type StringReturn =
130    ReturnBody<StringExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
131pub(crate) type BitArrayReturn =
132    ReturnBody<BitArrayExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
133pub(crate) type UtfCodepointReturn =
134    ReturnBody<UtfCodepointExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
135#[derive(Debug, Clone, PartialEq)]
136pub(crate) struct CustomReturn {
137    signature_shape: crate::plan::CustomValueShape,
138    body_shape: crate::plan::CustomValueShape,
139    body: ReturnBody<super::CustomExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>>,
140}
141#[derive(Debug, Clone, PartialEq)]
142pub(crate) struct ExternalReturn {
143    signature_shape: crate::plan::ExternalValueShape,
144    body_shape: crate::plan::ExternalValueShape,
145    body:
146        ReturnBody<super::ExternalExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>>,
147}
148pub(crate) type BoolReturn =
149    ReturnBody<BoolExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
150pub(crate) type NilReturn =
151    ReturnBody<NilExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
152pub(crate) type TupleReturn =
153    ReturnBody<TupleExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
154pub(crate) type GenericListReturn =
155    ReturnBody<super::GenericListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
156pub(crate) type ParameterListListReturn = ReturnBody<
157    super::ParameterListListExpr,
158    crate::plan::FunctionCallTarget<FunctionInstantiation>,
159>;
160pub(crate) type IntListReturn =
161    ReturnBody<IntListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
162pub(crate) type FloatListReturn =
163    ReturnBody<FloatListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
164pub(crate) type StringListReturn =
165    ReturnBody<StringListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
166pub(crate) type BitArrayListReturn =
167    ReturnBody<BitArrayListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
168pub(crate) type UtfCodepointListReturn =
169    ReturnBody<UtfCodepointListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
170pub(crate) type CustomListReturn =
171    ReturnBody<CustomListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
172pub(crate) type ExternalListReturn =
173    ReturnBody<ExternalListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
174pub(crate) type BoolListReturn =
175    ReturnBody<BoolListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
176pub(crate) type NilListReturn =
177    ReturnBody<NilListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
178pub(crate) type TupleListReturn =
179    ReturnBody<TupleListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
180pub(crate) type ListListReturn =
181    ReturnBody<ListListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
182pub(crate) type FunctionListReturn =
183    ReturnBody<FunctionListExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
184pub(crate) type GenericFunctionReturn =
185    ReturnBody<super::GenericFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
186pub(crate) type IntFunctionReturn =
187    ReturnBody<super::IntFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
188pub(crate) type FloatFunctionReturn =
189    ReturnBody<super::FloatFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
190pub(crate) type StringFunctionReturn =
191    ReturnBody<super::StringFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
192pub(crate) type BitArrayFunctionReturn =
193    ReturnBody<super::BitArrayFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
194pub(crate) type UtfCodepointFunctionReturn = ReturnBody<
195    super::UtfCodepointFunctionExpr,
196    crate::plan::FunctionCallTarget<FunctionInstantiation>,
197>;
198#[derive(Debug, Clone, PartialEq)]
199pub(crate) struct CustomFunctionReturn {
200    type_: CustomFunctionType,
201    body: ReturnBody<
202        super::CustomFunctionExprKind,
203        crate::plan::FunctionCallTarget<FunctionInstantiation>,
204    >,
205}
206#[derive(Debug, Clone, PartialEq)]
207pub(crate) struct ExternalFunctionReturn {
208    type_: ExternalFunctionType,
209    body: ReturnBody<
210        super::ExternalFunctionExprKind,
211        crate::plan::FunctionCallTarget<FunctionInstantiation>,
212    >,
213}
214pub(crate) type BoolFunctionReturn =
215    ReturnBody<super::BoolFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
216pub(crate) type NilFunctionReturn =
217    ReturnBody<super::NilFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
218pub(crate) type TupleFunctionReturn =
219    ReturnBody<super::TupleFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
220pub(crate) type ListFunctionReturn =
221    ReturnBody<super::ListFunctionExpr, crate::plan::FunctionCallTarget<FunctionInstantiation>>;
222#[derive(Debug, Clone, PartialEq)]
223pub(crate) struct FunctionFunctionReturn {
224    type_: FunctionFunctionType,
225    body: ReturnBody<
226        super::FunctionFunctionExprKind,
227        crate::plan::FunctionCallTarget<FunctionInstantiation>,
228    >,
229}
230
231#[cfg(test)]
232#[derive(Debug, Clone, PartialEq)]
233pub(crate) enum ListReturn {
234    Generic {
235        item_parameter: crate::plan::TypeParameterId,
236        body: GenericListReturn,
237    },
238    Int(IntListReturn),
239    Float(FloatListReturn),
240    String(StringListReturn),
241    BitArray(BitArrayListReturn),
242    UtfCodepoint(UtfCodepointListReturn),
243    Custom {
244        item_type: CustomType,
245        body: CustomListReturn,
246    },
247    External {
248        item_type: ExternalType,
249        body: ExternalListReturn,
250    },
251    Bool(BoolListReturn),
252    Nil(NilListReturn),
253    Tuple {
254        item_type: Vec<ValueType>,
255        body: TupleListReturn,
256    },
257    ParameterList {
258        item_parameter: crate::plan::TypeParameterId,
259        body: ParameterListListReturn,
260    },
261    List {
262        item_shape: ValueStorageShape,
263        body: ListListReturn,
264    },
265    Function {
266        item_type: FunctionType,
267        body: FunctionListReturn,
268    },
269}
270
271#[cfg(test)]
272impl ListReturn {
273    pub(crate) fn expr(expression: ListExpr) -> Self {
274        match expression {
275            ListExpr::Generic(expression) => Self::Generic {
276                item_parameter: expression.item().parameter(),
277                body: GenericListReturn::expr(expression),
278            },
279            ListExpr::Int(expression) => Self::Int(IntListReturn::expr(expression)),
280            ListExpr::Float(expression) => Self::Float(FloatListReturn::expr(expression)),
281            ListExpr::String(expression) => Self::String(StringListReturn::expr(expression)),
282            ListExpr::BitArray(expression) => Self::BitArray(BitArrayListReturn::expr(expression)),
283            ListExpr::UtfCodepoint(expression) => {
284                Self::UtfCodepoint(UtfCodepointListReturn::expr(expression))
285            }
286            ListExpr::Custom(expression) => Self::Custom {
287                item_type: expression.item().item_type(),
288                body: CustomListReturn::expr(expression),
289            },
290            ListExpr::External(expression) => Self::External {
291                item_type: expression.item().item_type(),
292                body: ExternalListReturn::expr(expression),
293            },
294            ListExpr::Bool(expression) => Self::Bool(BoolListReturn::expr(expression)),
295            ListExpr::Nil(expression) => Self::Nil(NilListReturn::expr(expression)),
296            ListExpr::Tuple(expression) => Self::Tuple {
297                item_type: expression.item().item_type(),
298                body: TupleListReturn::expr(expression),
299            },
300            ListExpr::ParameterList(expression) => Self::ParameterList {
301                item_parameter: expression.item().parameter(),
302                body: ParameterListListReturn::expr(expression),
303            },
304            ListExpr::List(expression) => Self::List {
305                item_shape: expression.item().item_shape().clone(),
306                body: ListListReturn::expr(expression),
307            },
308            ListExpr::Function(expression) => Self::Function {
309                item_type: expression.item().item_type(),
310                body: FunctionListReturn::expr(expression),
311            },
312        }
313    }
314
315    pub(crate) fn tail_call(
316        function: FunctionInstantiation,
317        item_type: ValueType,
318        args: Vec<CallArg>,
319    ) -> Self {
320        match item_type {
321            ValueType::Parameter(item_parameter) => Self::Generic {
322                item_parameter,
323                body: GenericListReturn::tail_call(function, args),
324            },
325            ValueType::Int => Self::Int(IntListReturn::tail_call(function, args)),
326            ValueType::Float => Self::Float(FloatListReturn::tail_call(function, args)),
327            ValueType::String => Self::String(StringListReturn::tail_call(function, args)),
328            ValueType::BitArray => Self::BitArray(BitArrayListReturn::tail_call(function, args)),
329            ValueType::UtfCodepoint => {
330                Self::UtfCodepoint(UtfCodepointListReturn::tail_call(function, args))
331            }
332            ValueType::Custom(item_type) => Self::Custom {
333                item_type,
334                body: CustomListReturn::tail_call(function, args),
335            },
336            ValueType::External(item_type) => Self::External {
337                item_type,
338                body: ExternalListReturn::tail_call(function, args),
339            },
340            ValueType::Bool => Self::Bool(BoolListReturn::tail_call(function, args)),
341            ValueType::Nil => Self::Nil(NilListReturn::tail_call(function, args)),
342            ValueType::Tuple(item_type) => Self::Tuple {
343                item_type,
344                body: TupleListReturn::tail_call(function, args),
345            },
346            ValueType::List(item_type) => {
347                match ValueShape::from_value_type(*item_type).representation() {
348                    ValueRepresentation::Uninhabited(item_parameter) => Self::ParameterList {
349                        item_parameter,
350                        body: ParameterListListReturn::tail_call(function, args),
351                    },
352                    ValueRepresentation::Stored(item_shape) => Self::List {
353                        item_shape,
354                        body: ListListReturn::tail_call(function, args),
355                    },
356                }
357            }
358            ValueType::Function(item_type) => Self::Function {
359                item_type: *item_type,
360                body: FunctionListReturn::tail_call(function, args),
361            },
362        }
363    }
364
365    pub(crate) fn try_bool_case(subject: BoolExpr, true_: Self, false_: Self) -> Option<Self> {
366        Some(match (true_, false_) {
367            (
368                Self::Generic {
369                    item_parameter: true_parameter,
370                    body: true_,
371                },
372                Self::Generic {
373                    item_parameter: false_parameter,
374                    body: false_,
375                },
376            ) if true_parameter == false_parameter => Self::Generic {
377                item_parameter: true_parameter,
378                body: GenericListReturn::bool_case(subject, true_, false_),
379            },
380            (Self::Int(true_), Self::Int(false_)) => {
381                Self::Int(IntListReturn::bool_case(subject, true_, false_))
382            }
383            (Self::Float(true_), Self::Float(false_)) => {
384                Self::Float(FloatListReturn::bool_case(subject, true_, false_))
385            }
386            (Self::String(true_), Self::String(false_)) => {
387                Self::String(StringListReturn::bool_case(subject, true_, false_))
388            }
389            (Self::BitArray(true_), Self::BitArray(false_)) => {
390                Self::BitArray(BitArrayListReturn::bool_case(subject, true_, false_))
391            }
392            (Self::UtfCodepoint(true_), Self::UtfCodepoint(false_)) => {
393                Self::UtfCodepoint(UtfCodepointListReturn::bool_case(subject, true_, false_))
394            }
395            (
396                Self::Custom {
397                    item_type: true_type,
398                    body: true_,
399                },
400                Self::Custom {
401                    item_type: false_type,
402                    body: false_,
403                },
404            ) if true_type == false_type => Self::Custom {
405                item_type: true_type,
406                body: CustomListReturn::bool_case(subject, true_, false_),
407            },
408            (
409                Self::External {
410                    item_type: true_type,
411                    body: true_,
412                },
413                Self::External {
414                    item_type: false_type,
415                    body: false_,
416                },
417            ) if true_type == false_type => Self::External {
418                item_type: true_type,
419                body: ExternalListReturn::bool_case(subject, true_, false_),
420            },
421            (Self::Bool(true_), Self::Bool(false_)) => {
422                Self::Bool(BoolListReturn::bool_case(subject, true_, false_))
423            }
424            (Self::Nil(true_), Self::Nil(false_)) => {
425                Self::Nil(NilListReturn::bool_case(subject, true_, false_))
426            }
427            (
428                Self::Tuple {
429                    item_type: true_type,
430                    body: true_,
431                },
432                Self::Tuple {
433                    item_type: false_type,
434                    body: false_,
435                },
436            ) if true_type == false_type => Self::Tuple {
437                item_type: true_type,
438                body: TupleListReturn::bool_case(subject, true_, false_),
439            },
440            (
441                Self::ParameterList {
442                    item_parameter: true_parameter,
443                    body: true_,
444                },
445                Self::ParameterList {
446                    item_parameter: false_parameter,
447                    body: false_,
448                },
449            ) if true_parameter == false_parameter => Self::ParameterList {
450                item_parameter: true_parameter,
451                body: ParameterListListReturn::bool_case(subject, true_, false_),
452            },
453            (
454                Self::List {
455                    item_shape: true_shape,
456                    body: true_,
457                },
458                Self::List {
459                    item_shape: false_shape,
460                    body: false_,
461                },
462            ) if true_shape == false_shape => Self::List {
463                item_shape: true_shape,
464                body: ListListReturn::bool_case(subject, true_, false_),
465            },
466            (
467                Self::Function {
468                    item_type: true_type,
469                    body: true_,
470                },
471                Self::Function {
472                    item_type: false_type,
473                    body: false_,
474                },
475            ) if true_type == false_type => Self::Function {
476                item_type: true_type,
477                body: FunctionListReturn::bool_case(subject, true_, false_),
478            },
479            _ => return None,
480        })
481    }
482
483    pub(crate) fn try_int_case(
484        subject: IntExpr,
485        clauses: Vec<(BigInt, Self)>,
486        fallback: Self,
487    ) -> Option<Self> {
488        match fallback {
489            Self::Generic {
490                item_parameter,
491                body: fallback,
492            } => {
493                let clauses = into_list_return_clauses(clauses, |branch| match branch {
494                    Self::Generic {
495                        item_parameter: branch_parameter,
496                        body,
497                    } if branch_parameter == item_parameter => Some(body),
498                    _ => None,
499                })?;
500                Some(Self::Generic {
501                    item_parameter,
502                    body: GenericListReturn::int_case(subject, clauses, fallback),
503                })
504            }
505            Self::Int(fallback) => Some(Self::Int(IntListReturn::int_case(
506                subject,
507                into_list_return_clauses(clauses, |branch| match branch {
508                    Self::Int(branch) => Some(branch),
509                    _ => None,
510                })?,
511                fallback,
512            ))),
513            Self::Float(fallback) => Some(Self::Float(FloatListReturn::int_case(
514                subject,
515                into_list_return_clauses(clauses, |branch| match branch {
516                    Self::Float(branch) => Some(branch),
517                    _ => None,
518                })?,
519                fallback,
520            ))),
521            Self::String(fallback) => Some(Self::String(StringListReturn::int_case(
522                subject,
523                into_list_return_clauses(clauses, |branch| match branch {
524                    Self::String(branch) => Some(branch),
525                    _ => None,
526                })?,
527                fallback,
528            ))),
529            Self::BitArray(fallback) => Some(Self::BitArray(BitArrayListReturn::int_case(
530                subject,
531                into_list_return_clauses(clauses, |branch| match branch {
532                    Self::BitArray(branch) => Some(branch),
533                    _ => None,
534                })?,
535                fallback,
536            ))),
537            Self::UtfCodepoint(fallback) => {
538                Some(Self::UtfCodepoint(UtfCodepointListReturn::int_case(
539                    subject,
540                    into_list_return_clauses(clauses, |branch| match branch {
541                        Self::UtfCodepoint(branch) => Some(branch),
542                        _ => None,
543                    })?,
544                    fallback,
545                )))
546            }
547            Self::Custom {
548                item_type,
549                body: fallback,
550            } => {
551                let clauses = into_list_return_clauses(clauses, |branch| match branch {
552                    Self::Custom {
553                        item_type: branch_type,
554                        body,
555                    } if branch_type == item_type => Some(body),
556                    _ => None,
557                })?;
558                Some(Self::Custom {
559                    item_type,
560                    body: CustomListReturn::int_case(subject, clauses, fallback),
561                })
562            }
563            Self::External {
564                item_type,
565                body: fallback,
566            } => {
567                let clauses = into_list_return_clauses(clauses, |branch| match branch {
568                    Self::External {
569                        item_type: branch_type,
570                        body,
571                    } if branch_type == item_type => Some(body),
572                    _ => None,
573                })?;
574                Some(Self::External {
575                    item_type,
576                    body: ExternalListReturn::int_case(subject, clauses, fallback),
577                })
578            }
579            Self::Bool(fallback) => Some(Self::Bool(BoolListReturn::int_case(
580                subject,
581                into_list_return_clauses(clauses, |branch| match branch {
582                    Self::Bool(branch) => Some(branch),
583                    _ => None,
584                })?,
585                fallback,
586            ))),
587            Self::Nil(fallback) => Some(Self::Nil(NilListReturn::int_case(
588                subject,
589                into_list_return_clauses(clauses, |branch| match branch {
590                    Self::Nil(branch) => Some(branch),
591                    _ => None,
592                })?,
593                fallback,
594            ))),
595            Self::Tuple {
596                item_type,
597                body: fallback,
598            } => {
599                let clauses = into_list_return_clauses(clauses, |branch| match branch {
600                    Self::Tuple {
601                        item_type: branch_type,
602                        body,
603                    } if branch_type == item_type => Some(body),
604                    _ => None,
605                })?;
606                Some(Self::Tuple {
607                    item_type,
608                    body: TupleListReturn::int_case(subject, clauses, fallback),
609                })
610            }
611            Self::ParameterList {
612                item_parameter,
613                body: fallback,
614            } => {
615                let clauses = into_list_return_clauses(clauses, |branch| match branch {
616                    Self::ParameterList {
617                        item_parameter: branch_parameter,
618                        body,
619                    } if branch_parameter == item_parameter => Some(body),
620                    _ => None,
621                })?;
622                Some(Self::ParameterList {
623                    item_parameter,
624                    body: ParameterListListReturn::int_case(subject, clauses, fallback),
625                })
626            }
627            Self::List {
628                item_shape,
629                body: fallback,
630            } => {
631                let clauses = into_list_return_clauses(clauses, |branch| match branch {
632                    Self::List {
633                        item_shape: branch_shape,
634                        body,
635                    } if branch_shape == item_shape => Some(body),
636                    _ => None,
637                })?;
638                Some(Self::List {
639                    item_shape,
640                    body: ListListReturn::int_case(subject, clauses, fallback),
641                })
642            }
643            Self::Function {
644                item_type,
645                body: fallback,
646            } => {
647                let clauses = into_list_return_clauses(clauses, |branch| match branch {
648                    Self::Function {
649                        item_type: branch_type,
650                        body,
651                    } if branch_type == item_type => Some(body),
652                    _ => None,
653                })?;
654                Some(Self::Function {
655                    item_type,
656                    body: FunctionListReturn::int_case(subject, clauses, fallback),
657                })
658            }
659        }
660    }
661
662    pub(crate) fn try_float_case(
663        subject: FloatExpr,
664        clauses: Vec<(f64, Self)>,
665        fallback: Self,
666    ) -> Option<Self> {
667        match fallback {
668            Self::Generic {
669                item_parameter,
670                body: fallback,
671            } => {
672                let clauses = into_list_return_clauses(clauses, |branch| match branch {
673                    Self::Generic {
674                        item_parameter: branch_parameter,
675                        body,
676                    } if branch_parameter == item_parameter => Some(body),
677                    _ => None,
678                })?;
679                Some(Self::Generic {
680                    item_parameter,
681                    body: GenericListReturn::float_case(subject, clauses, fallback),
682                })
683            }
684            Self::Int(fallback) => Some(Self::Int(IntListReturn::float_case(
685                subject,
686                into_list_return_clauses(clauses, |branch| match branch {
687                    Self::Int(branch) => Some(branch),
688                    _ => None,
689                })?,
690                fallback,
691            ))),
692            Self::Float(fallback) => Some(Self::Float(FloatListReturn::float_case(
693                subject,
694                into_list_return_clauses(clauses, |branch| match branch {
695                    Self::Float(branch) => Some(branch),
696                    _ => None,
697                })?,
698                fallback,
699            ))),
700            Self::String(fallback) => Some(Self::String(StringListReturn::float_case(
701                subject,
702                into_list_return_clauses(clauses, |branch| match branch {
703                    Self::String(branch) => Some(branch),
704                    _ => None,
705                })?,
706                fallback,
707            ))),
708            Self::BitArray(fallback) => Some(Self::BitArray(BitArrayListReturn::float_case(
709                subject,
710                into_list_return_clauses(clauses, |branch| match branch {
711                    Self::BitArray(branch) => Some(branch),
712                    _ => None,
713                })?,
714                fallback,
715            ))),
716            Self::UtfCodepoint(fallback) => {
717                Some(Self::UtfCodepoint(UtfCodepointListReturn::float_case(
718                    subject,
719                    into_list_return_clauses(clauses, |branch| match branch {
720                        Self::UtfCodepoint(branch) => Some(branch),
721                        _ => None,
722                    })?,
723                    fallback,
724                )))
725            }
726            Self::Custom {
727                item_type,
728                body: fallback,
729            } => {
730                let clauses = into_list_return_clauses(clauses, |branch| match branch {
731                    Self::Custom {
732                        item_type: branch_type,
733                        body,
734                    } if branch_type == item_type => Some(body),
735                    _ => None,
736                })?;
737                Some(Self::Custom {
738                    item_type,
739                    body: CustomListReturn::float_case(subject, clauses, fallback),
740                })
741            }
742            Self::External {
743                item_type,
744                body: fallback,
745            } => {
746                let clauses = into_list_return_clauses(clauses, |branch| match branch {
747                    Self::External {
748                        item_type: branch_type,
749                        body,
750                    } if branch_type == item_type => Some(body),
751                    _ => None,
752                })?;
753                Some(Self::External {
754                    item_type,
755                    body: ExternalListReturn::float_case(subject, clauses, fallback),
756                })
757            }
758            Self::Bool(fallback) => Some(Self::Bool(BoolListReturn::float_case(
759                subject,
760                into_list_return_clauses(clauses, |branch| match branch {
761                    Self::Bool(branch) => Some(branch),
762                    _ => None,
763                })?,
764                fallback,
765            ))),
766            Self::Nil(fallback) => Some(Self::Nil(NilListReturn::float_case(
767                subject,
768                into_list_return_clauses(clauses, |branch| match branch {
769                    Self::Nil(branch) => Some(branch),
770                    _ => None,
771                })?,
772                fallback,
773            ))),
774            Self::Tuple {
775                item_type,
776                body: fallback,
777            } => {
778                let clauses = into_list_return_clauses(clauses, |branch| match branch {
779                    Self::Tuple {
780                        item_type: branch_type,
781                        body,
782                    } if branch_type == item_type => Some(body),
783                    _ => None,
784                })?;
785                Some(Self::Tuple {
786                    item_type,
787                    body: TupleListReturn::float_case(subject, clauses, fallback),
788                })
789            }
790            Self::ParameterList {
791                item_parameter,
792                body: fallback,
793            } => {
794                let clauses = into_list_return_clauses(clauses, |branch| match branch {
795                    Self::ParameterList {
796                        item_parameter: branch_parameter,
797                        body,
798                    } if branch_parameter == item_parameter => Some(body),
799                    _ => None,
800                })?;
801                Some(Self::ParameterList {
802                    item_parameter,
803                    body: ParameterListListReturn::float_case(subject, clauses, fallback),
804                })
805            }
806            Self::List {
807                item_shape,
808                body: fallback,
809            } => {
810                let clauses = into_list_return_clauses(clauses, |branch| match branch {
811                    Self::List {
812                        item_shape: branch_shape,
813                        body,
814                    } if branch_shape == item_shape => Some(body),
815                    _ => None,
816                })?;
817                Some(Self::List {
818                    item_shape,
819                    body: ListListReturn::float_case(subject, clauses, fallback),
820                })
821            }
822            Self::Function {
823                item_type,
824                body: fallback,
825            } => {
826                let clauses = into_list_return_clauses(clauses, |branch| match branch {
827                    Self::Function {
828                        item_type: branch_type,
829                        body,
830                    } if branch_type == item_type => Some(body),
831                    _ => None,
832                })?;
833                Some(Self::Function {
834                    item_type,
835                    body: FunctionListReturn::float_case(subject, clauses, fallback),
836                })
837            }
838        }
839    }
840
841    pub(crate) fn try_string_case(
842        subject: StringExpr,
843        clauses: Vec<(EcoString, Self)>,
844        fallback: Self,
845    ) -> Option<Self> {
846        match fallback {
847            Self::Generic {
848                item_parameter,
849                body: fallback,
850            } => {
851                let clauses = into_list_return_clauses(clauses, |branch| match branch {
852                    Self::Generic {
853                        item_parameter: branch_parameter,
854                        body,
855                    } if branch_parameter == item_parameter => Some(body),
856                    _ => None,
857                })?;
858                Some(Self::Generic {
859                    item_parameter,
860                    body: GenericListReturn::string_case(subject, clauses, fallback),
861                })
862            }
863            Self::Int(fallback) => Some(Self::Int(IntListReturn::string_case(
864                subject,
865                into_list_return_clauses(clauses, |branch| match branch {
866                    Self::Int(branch) => Some(branch),
867                    _ => None,
868                })?,
869                fallback,
870            ))),
871            Self::Float(fallback) => Some(Self::Float(FloatListReturn::string_case(
872                subject,
873                into_list_return_clauses(clauses, |branch| match branch {
874                    Self::Float(branch) => Some(branch),
875                    _ => None,
876                })?,
877                fallback,
878            ))),
879            Self::String(fallback) => Some(Self::String(StringListReturn::string_case(
880                subject,
881                into_list_return_clauses(clauses, |branch| match branch {
882                    Self::String(branch) => Some(branch),
883                    _ => None,
884                })?,
885                fallback,
886            ))),
887            Self::BitArray(fallback) => Some(Self::BitArray(BitArrayListReturn::string_case(
888                subject,
889                into_list_return_clauses(clauses, |branch| match branch {
890                    Self::BitArray(branch) => Some(branch),
891                    _ => None,
892                })?,
893                fallback,
894            ))),
895            Self::UtfCodepoint(fallback) => {
896                Some(Self::UtfCodepoint(UtfCodepointListReturn::string_case(
897                    subject,
898                    into_list_return_clauses(clauses, |branch| match branch {
899                        Self::UtfCodepoint(branch) => Some(branch),
900                        _ => None,
901                    })?,
902                    fallback,
903                )))
904            }
905            Self::Custom {
906                item_type,
907                body: fallback,
908            } => {
909                let clauses = into_list_return_clauses(clauses, |branch| match branch {
910                    Self::Custom {
911                        item_type: branch_type,
912                        body,
913                    } if branch_type == item_type => Some(body),
914                    _ => None,
915                })?;
916                Some(Self::Custom {
917                    item_type,
918                    body: CustomListReturn::string_case(subject, clauses, fallback),
919                })
920            }
921            Self::External {
922                item_type,
923                body: fallback,
924            } => {
925                let clauses = into_list_return_clauses(clauses, |branch| match branch {
926                    Self::External {
927                        item_type: branch_type,
928                        body,
929                    } if branch_type == item_type => Some(body),
930                    _ => None,
931                })?;
932                Some(Self::External {
933                    item_type,
934                    body: ExternalListReturn::string_case(subject, clauses, fallback),
935                })
936            }
937            Self::Bool(fallback) => Some(Self::Bool(BoolListReturn::string_case(
938                subject,
939                into_list_return_clauses(clauses, |branch| match branch {
940                    Self::Bool(branch) => Some(branch),
941                    _ => None,
942                })?,
943                fallback,
944            ))),
945            Self::Nil(fallback) => Some(Self::Nil(NilListReturn::string_case(
946                subject,
947                into_list_return_clauses(clauses, |branch| match branch {
948                    Self::Nil(branch) => Some(branch),
949                    _ => None,
950                })?,
951                fallback,
952            ))),
953            Self::Tuple {
954                item_type,
955                body: fallback,
956            } => {
957                let clauses = into_list_return_clauses(clauses, |branch| match branch {
958                    Self::Tuple {
959                        item_type: branch_type,
960                        body,
961                    } if branch_type == item_type => Some(body),
962                    _ => None,
963                })?;
964                Some(Self::Tuple {
965                    item_type,
966                    body: TupleListReturn::string_case(subject, clauses, fallback),
967                })
968            }
969            Self::ParameterList {
970                item_parameter,
971                body: fallback,
972            } => {
973                let clauses = into_list_return_clauses(clauses, |branch| match branch {
974                    Self::ParameterList {
975                        item_parameter: branch_parameter,
976                        body,
977                    } if branch_parameter == item_parameter => Some(body),
978                    _ => None,
979                })?;
980                Some(Self::ParameterList {
981                    item_parameter,
982                    body: ParameterListListReturn::string_case(subject, clauses, fallback),
983                })
984            }
985            Self::List {
986                item_shape,
987                body: fallback,
988            } => {
989                let clauses = into_list_return_clauses(clauses, |branch| match branch {
990                    Self::List {
991                        item_shape: branch_shape,
992                        body,
993                    } if branch_shape == item_shape => Some(body),
994                    _ => None,
995                })?;
996                Some(Self::List {
997                    item_shape,
998                    body: ListListReturn::string_case(subject, clauses, fallback),
999                })
1000            }
1001            Self::Function {
1002                item_type,
1003                body: fallback,
1004            } => {
1005                let clauses = into_list_return_clauses(clauses, |branch| match branch {
1006                    Self::Function {
1007                        item_type: branch_type,
1008                        body,
1009                    } if branch_type == item_type => Some(body),
1010                    _ => None,
1011                })?;
1012                Some(Self::Function {
1013                    item_type,
1014                    body: FunctionListReturn::string_case(subject, clauses, fallback),
1015                })
1016            }
1017        }
1018    }
1019
1020    pub(crate) fn try_block(steps: Vec<Step>, return_: Self) -> Self {
1021        match return_ {
1022            Self::Generic {
1023                item_parameter,
1024                body,
1025            } => Self::Generic {
1026                item_parameter,
1027                body: GenericListReturn::block(steps, body),
1028            },
1029            Self::Int(return_) => Self::Int(IntListReturn::block(steps, return_)),
1030            Self::Float(return_) => Self::Float(FloatListReturn::block(steps, return_)),
1031            Self::String(return_) => Self::String(StringListReturn::block(steps, return_)),
1032            Self::BitArray(return_) => Self::BitArray(BitArrayListReturn::block(steps, return_)),
1033            Self::UtfCodepoint(return_) => {
1034                Self::UtfCodepoint(UtfCodepointListReturn::block(steps, return_))
1035            }
1036            Self::Custom { item_type, body } => Self::Custom {
1037                item_type,
1038                body: CustomListReturn::block(steps, body),
1039            },
1040            Self::External { item_type, body } => Self::External {
1041                item_type,
1042                body: ExternalListReturn::block(steps, body),
1043            },
1044            Self::Bool(return_) => Self::Bool(BoolListReturn::block(steps, return_)),
1045            Self::Nil(return_) => Self::Nil(NilListReturn::block(steps, return_)),
1046            Self::Tuple { item_type, body } => Self::Tuple {
1047                item_type,
1048                body: TupleListReturn::block(steps, body),
1049            },
1050            Self::ParameterList {
1051                item_parameter,
1052                body,
1053            } => Self::ParameterList {
1054                item_parameter,
1055                body: ParameterListListReturn::block(steps, body),
1056            },
1057            Self::List { item_shape, body } => Self::List {
1058                item_shape,
1059                body: ListListReturn::block(steps, body),
1060            },
1061            Self::Function { item_type, body } => Self::Function {
1062                item_type,
1063                body: FunctionListReturn::block(steps, body),
1064            },
1065        }
1066    }
1067}
1068
1069#[cfg(test)]
1070fn into_list_return_clauses<Pattern, Body>(
1071    clauses: Vec<(Pattern, ListReturn)>,
1072    mut into_body: impl FnMut(ListReturn) -> Option<Body>,
1073) -> Option<Vec<(Pattern, Body)>> {
1074    clauses
1075        .into_iter()
1076        .map(|(pattern, branch)| into_body(branch).map(|branch| (pattern, branch)))
1077        .collect()
1078}
1079
1080#[derive(Debug, Clone, PartialEq)]
1081pub(crate) struct ReturnBody<Expression, Function> {
1082    kind: ReturnBodyKind<Expression, Function>,
1083}
1084
1085#[derive(Debug, Clone, PartialEq)]
1086pub(crate) enum ReturnBodyKind<Expression, Function> {
1087    Expr(Expression),
1088    TailCall {
1089        function: Function,
1090        args: Vec<CallArg>,
1091    },
1092    BoolCase {
1093        subject: BoolExpr,
1094        true_: Box<ReturnBody<Expression, Function>>,
1095        false_: Box<ReturnBody<Expression, Function>>,
1096    },
1097    IntCase {
1098        subject: IntExpr,
1099        clauses: Vec<(BigInt, ReturnBody<Expression, Function>)>,
1100        fallback: Box<ReturnBody<Expression, Function>>,
1101    },
1102    FloatCase {
1103        subject: FloatExpr,
1104        clauses: Vec<(f64, ReturnBody<Expression, Function>)>,
1105        fallback: Box<ReturnBody<Expression, Function>>,
1106    },
1107    StringCase {
1108        subject: StringExpr,
1109        clauses: Vec<(EcoString, ReturnBody<Expression, Function>)>,
1110        fallback: Box<ReturnBody<Expression, Function>>,
1111    },
1112    Block {
1113        steps: Vec<Step>,
1114        return_: Box<ReturnBody<Expression, Function>>,
1115    },
1116}
1117
1118#[derive(Debug, Clone, PartialEq)]
1119pub struct ReturnExpr {
1120    kind: ReturnExprKind,
1121}
1122
1123#[derive(Debug, Clone, PartialEq)]
1124pub(crate) enum ReturnExprKind {
1125    Generic {
1126        parameter: crate::plan::TypeParameterId,
1127        body: GenericReturn,
1128    },
1129    Int {
1130        body: IntReturn,
1131    },
1132    Float {
1133        body: FloatReturn,
1134    },
1135    String {
1136        body: StringReturn,
1137    },
1138    BitArray {
1139        body: BitArrayReturn,
1140    },
1141    UtfCodepoint {
1142        body: UtfCodepointReturn,
1143    },
1144    Custom {
1145        body: CustomReturn,
1146    },
1147    External {
1148        body: ExternalReturn,
1149    },
1150    Bool {
1151        body: BoolReturn,
1152    },
1153    Nil {
1154        body: NilReturn,
1155    },
1156    Tuple {
1157        type_: Vec<ValueType>,
1158        body: TupleReturn,
1159    },
1160    GenericList {
1161        parameter: crate::plan::TypeParameterId,
1162        body: GenericListReturn,
1163    },
1164    ParameterListList {
1165        parameter: crate::plan::TypeParameterId,
1166        body: ParameterListListReturn,
1167    },
1168    IntList {
1169        body: IntListReturn,
1170    },
1171    StringList {
1172        body: StringListReturn,
1173    },
1174    BitArrayList {
1175        body: BitArrayListReturn,
1176    },
1177    UtfCodepointList {
1178        body: UtfCodepointListReturn,
1179    },
1180    CustomList {
1181        item_type: CustomType,
1182        body: CustomListReturn,
1183    },
1184    ExternalList {
1185        item_type: ExternalType,
1186        body: ExternalListReturn,
1187    },
1188    FloatList {
1189        body: FloatListReturn,
1190    },
1191    BoolList {
1192        body: BoolListReturn,
1193    },
1194    NilList {
1195        body: NilListReturn,
1196    },
1197    TupleList {
1198        item_type: Vec<ValueType>,
1199        body: TupleListReturn,
1200    },
1201    ListList {
1202        item_shape: ValueStorageShape,
1203        body: ListListReturn,
1204    },
1205    FunctionList {
1206        item_type: FunctionType,
1207        body: FunctionListReturn,
1208    },
1209    GenericFunction {
1210        shape: crate::plan::FunctionShape,
1211        body: GenericFunctionReturn,
1212    },
1213    IntFunction {
1214        shape: crate::plan::FunctionShape,
1215        body: IntFunctionReturn,
1216    },
1217    FloatFunction {
1218        shape: crate::plan::FunctionShape,
1219        body: FloatFunctionReturn,
1220    },
1221    StringFunction {
1222        shape: crate::plan::FunctionShape,
1223        body: StringFunctionReturn,
1224    },
1225    BitArrayFunction {
1226        shape: crate::plan::FunctionShape,
1227        body: BitArrayFunctionReturn,
1228    },
1229    UtfCodepointFunction {
1230        shape: crate::plan::FunctionShape,
1231        body: UtfCodepointFunctionReturn,
1232    },
1233    CustomFunction {
1234        shape: crate::plan::FunctionShape,
1235        body: CustomFunctionReturn,
1236    },
1237    ExternalFunction {
1238        shape: crate::plan::FunctionShape,
1239        body: ExternalFunctionReturn,
1240    },
1241    BoolFunction {
1242        shape: crate::plan::FunctionShape,
1243        body: BoolFunctionReturn,
1244    },
1245    NilFunction {
1246        shape: crate::plan::FunctionShape,
1247        body: NilFunctionReturn,
1248    },
1249    TupleFunction {
1250        shape: crate::plan::FunctionShape,
1251        body: TupleFunctionReturn,
1252    },
1253    ListFunction {
1254        shape: crate::plan::FunctionShape,
1255        item_type: ValueType,
1256        body: ListFunctionReturn,
1257    },
1258    FunctionFunction {
1259        shape: crate::plan::FunctionShape,
1260        body: FunctionFunctionReturn,
1261    },
1262}
1263
1264impl FunctionTemplate {
1265    #[cfg(test)]
1266    pub(crate) fn new(
1267        id: FunctionTemplateId,
1268        name: EcoString,
1269        params: Vec<Param>,
1270        steps: Vec<Step>,
1271        return_: ReturnExpr,
1272    ) -> Self {
1273        Self::with_captures(id, name, params, Vec::new(), steps, return_)
1274    }
1275
1276    #[cfg(test)]
1277    pub(crate) fn with_captures(
1278        id: FunctionTemplateId,
1279        name: EcoString,
1280        params: Vec<Param>,
1281        captures: Vec<ParamSlot>,
1282        steps: Vec<Step>,
1283        return_: ReturnExpr,
1284    ) -> Self {
1285        let signature = FunctionTemplateSignature::new(
1286            id,
1287            TypeScheme::new(0),
1288            crate::plan::FunctionShape::new(
1289                params.iter().map(|param| param.shape().clone()).collect(),
1290                crate::plan::ValueShape::from_value_type(return_.value_type()),
1291            ),
1292        );
1293        Self::from_signature(signature, name, params, captures, steps, return_)
1294    }
1295
1296    pub(crate) fn from_signature(
1297        signature: FunctionTemplateSignature,
1298        name: EcoString,
1299        params: Vec<Param>,
1300        captures: Vec<ParamSlot>,
1301        steps: Vec<Step>,
1302        return_: ReturnExpr,
1303    ) -> Self {
1304        Self {
1305            signature,
1306            name,
1307            entry: FunctionEntry::new(params, captures),
1308            steps,
1309            return_,
1310        }
1311    }
1312
1313    pub fn id(&self) -> FunctionTemplateId {
1314        self.signature.id()
1315    }
1316
1317    pub fn scheme(&self) -> &TypeScheme {
1318        self.signature.scheme()
1319    }
1320
1321    pub fn name(&self) -> &EcoString {
1322        &self.name
1323    }
1324
1325    pub fn params(&self) -> &[Param] {
1326        self.entry.params()
1327    }
1328
1329    pub fn steps(&self) -> &[Step] {
1330        &self.steps
1331    }
1332
1333    pub fn return_(&self) -> &ReturnExpr {
1334        &self.return_
1335    }
1336
1337    pub(crate) fn signature(&self) -> &FunctionTemplateSignature {
1338        &self.signature
1339    }
1340
1341    pub(crate) fn entry(&self) -> &FunctionEntry {
1342        &self.entry
1343    }
1344}
1345
1346impl ReturnExpr {
1347    pub(crate) fn generic_body(
1348        parameter: crate::plan::TypeParameterId,
1349        body: GenericReturn,
1350    ) -> Self {
1351        Self {
1352            kind: ReturnExprKind::Generic { parameter, body },
1353        }
1354    }
1355
1356    #[cfg(test)]
1357    pub(crate) fn int(_runtime_id: IntFunctionId, expression: IntExpr) -> Self {
1358        Self::int_body(ReturnBody::expr(expression))
1359    }
1360
1361    pub(crate) fn int_body(body: IntReturn) -> Self {
1362        Self {
1363            kind: ReturnExprKind::Int { body },
1364        }
1365    }
1366
1367    pub(crate) fn float_body(body: FloatReturn) -> Self {
1368        Self {
1369            kind: ReturnExprKind::Float { body },
1370        }
1371    }
1372
1373    pub(crate) fn string_body(body: StringReturn) -> Self {
1374        Self {
1375            kind: ReturnExprKind::String { body },
1376        }
1377    }
1378
1379    pub(crate) fn bit_array_body(body: BitArrayReturn) -> Self {
1380        Self {
1381            kind: ReturnExprKind::BitArray { body },
1382        }
1383    }
1384
1385    pub(crate) fn utf_codepoint_body(body: UtfCodepointReturn) -> Self {
1386        Self {
1387            kind: ReturnExprKind::UtfCodepoint { body },
1388        }
1389    }
1390
1391    pub(crate) fn custom_body(body: CustomReturn) -> Self {
1392        Self {
1393            kind: ReturnExprKind::Custom { body },
1394        }
1395    }
1396
1397    pub(crate) fn external_body(body: ExternalReturn) -> Self {
1398        Self {
1399            kind: ReturnExprKind::External { body },
1400        }
1401    }
1402
1403    #[cfg(test)]
1404    pub(crate) fn bool(_runtime_id: BoolFunctionId, expression: BoolExpr) -> Self {
1405        Self::bool_body(ReturnBody::expr(expression))
1406    }
1407
1408    pub(crate) fn bool_body(body: BoolReturn) -> Self {
1409        Self {
1410            kind: ReturnExprKind::Bool { body },
1411        }
1412    }
1413
1414    pub(crate) fn nil_body(body: NilReturn) -> Self {
1415        Self {
1416            kind: ReturnExprKind::Nil { body },
1417        }
1418    }
1419
1420    pub(crate) fn tuple_body(type_: Vec<ValueType>, body: TupleReturn) -> Self {
1421        Self {
1422            kind: ReturnExprKind::Tuple { type_, body },
1423        }
1424    }
1425
1426    pub(crate) fn generic_list_body(
1427        parameter: crate::plan::TypeParameterId,
1428        body: GenericListReturn,
1429    ) -> Self {
1430        Self {
1431            kind: ReturnExprKind::GenericList { parameter, body },
1432        }
1433    }
1434
1435    pub(crate) fn parameter_list_list_body(
1436        parameter: crate::plan::TypeParameterId,
1437        body: ParameterListListReturn,
1438    ) -> Self {
1439        Self {
1440            kind: ReturnExprKind::ParameterListList { parameter, body },
1441        }
1442    }
1443
1444    pub(crate) fn int_list_body(body: IntListReturn) -> Self {
1445        Self {
1446            kind: ReturnExprKind::IntList { body },
1447        }
1448    }
1449
1450    pub(crate) fn string_list_body(body: StringListReturn) -> Self {
1451        Self {
1452            kind: ReturnExprKind::StringList { body },
1453        }
1454    }
1455
1456    pub(crate) fn bit_array_list_body(body: BitArrayListReturn) -> Self {
1457        Self {
1458            kind: ReturnExprKind::BitArrayList { body },
1459        }
1460    }
1461
1462    pub(crate) fn utf_codepoint_list_body(body: UtfCodepointListReturn) -> Self {
1463        Self {
1464            kind: ReturnExprKind::UtfCodepointList { body },
1465        }
1466    }
1467
1468    pub(crate) fn custom_list_body(item_type: CustomType, body: CustomListReturn) -> Self {
1469        Self {
1470            kind: ReturnExprKind::CustomList { item_type, body },
1471        }
1472    }
1473
1474    pub(crate) fn external_list_body(item_type: ExternalType, body: ExternalListReturn) -> Self {
1475        Self {
1476            kind: ReturnExprKind::ExternalList { item_type, body },
1477        }
1478    }
1479
1480    pub(crate) fn float_list_body(body: FloatListReturn) -> Self {
1481        Self {
1482            kind: ReturnExprKind::FloatList { body },
1483        }
1484    }
1485
1486    pub(crate) fn bool_list_body(body: BoolListReturn) -> Self {
1487        Self {
1488            kind: ReturnExprKind::BoolList { body },
1489        }
1490    }
1491
1492    pub(crate) fn nil_list_body(body: NilListReturn) -> Self {
1493        Self {
1494            kind: ReturnExprKind::NilList { body },
1495        }
1496    }
1497
1498    pub(crate) fn tuple_list_body(item_type: Vec<ValueType>, body: TupleListReturn) -> Self {
1499        Self {
1500            kind: ReturnExprKind::TupleList { item_type, body },
1501        }
1502    }
1503
1504    pub(crate) fn list_list_body(item_shape: ValueStorageShape, body: ListListReturn) -> Self {
1505        Self {
1506            kind: ReturnExprKind::ListList { item_shape, body },
1507        }
1508    }
1509
1510    pub(crate) fn function_list_body(item_type: FunctionType, body: FunctionListReturn) -> Self {
1511        Self {
1512            kind: ReturnExprKind::FunctionList { item_type, body },
1513        }
1514    }
1515
1516    pub(crate) fn generic_function_shape_body(
1517        shape: crate::plan::FunctionShape,
1518        body: GenericFunctionReturn,
1519    ) -> Self {
1520        Self {
1521            kind: ReturnExprKind::GenericFunction { shape, body },
1522        }
1523    }
1524
1525    pub(crate) fn int_function_shape_body(
1526        shape: crate::plan::FunctionShape,
1527        body: IntFunctionReturn,
1528    ) -> Self {
1529        Self {
1530            kind: ReturnExprKind::IntFunction { shape, body },
1531        }
1532    }
1533
1534    pub(crate) fn float_function_shape_body(
1535        shape: crate::plan::FunctionShape,
1536        body: FloatFunctionReturn,
1537    ) -> Self {
1538        Self {
1539            kind: ReturnExprKind::FloatFunction { shape, body },
1540        }
1541    }
1542
1543    pub(crate) fn string_function_shape_body(
1544        shape: crate::plan::FunctionShape,
1545        body: StringFunctionReturn,
1546    ) -> Self {
1547        Self {
1548            kind: ReturnExprKind::StringFunction { shape, body },
1549        }
1550    }
1551
1552    pub(crate) fn bit_array_function_shape_body(
1553        shape: crate::plan::FunctionShape,
1554        body: BitArrayFunctionReturn,
1555    ) -> Self {
1556        Self {
1557            kind: ReturnExprKind::BitArrayFunction { shape, body },
1558        }
1559    }
1560
1561    pub(crate) fn utf_codepoint_function_shape_body(
1562        shape: crate::plan::FunctionShape,
1563        body: UtfCodepointFunctionReturn,
1564    ) -> Self {
1565        Self {
1566            kind: ReturnExprKind::UtfCodepointFunction { shape, body },
1567        }
1568    }
1569
1570    pub(crate) fn custom_function_shape_body(
1571        shape: crate::plan::FunctionShape,
1572        body: CustomFunctionReturn,
1573    ) -> Self {
1574        Self {
1575            kind: ReturnExprKind::CustomFunction { shape, body },
1576        }
1577    }
1578
1579    pub(crate) fn external_function_shape_body(
1580        shape: crate::plan::FunctionShape,
1581        body: ExternalFunctionReturn,
1582    ) -> Self {
1583        Self {
1584            kind: ReturnExprKind::ExternalFunction { shape, body },
1585        }
1586    }
1587
1588    pub(crate) fn bool_function_shape_body(
1589        shape: crate::plan::FunctionShape,
1590        body: BoolFunctionReturn,
1591    ) -> Self {
1592        Self {
1593            kind: ReturnExprKind::BoolFunction { shape, body },
1594        }
1595    }
1596
1597    pub(crate) fn nil_function_shape_body(
1598        shape: crate::plan::FunctionShape,
1599        body: NilFunctionReturn,
1600    ) -> Self {
1601        Self {
1602            kind: ReturnExprKind::NilFunction { shape, body },
1603        }
1604    }
1605
1606    pub(crate) fn tuple_function_shape_body(
1607        shape: crate::plan::FunctionShape,
1608        body: TupleFunctionReturn,
1609    ) -> Self {
1610        Self {
1611            kind: ReturnExprKind::TupleFunction { shape, body },
1612        }
1613    }
1614
1615    pub(crate) fn list_function_shape_body(
1616        shape: crate::plan::FunctionShape,
1617        item_type: ValueType,
1618        body: ListFunctionReturn,
1619    ) -> Self {
1620        Self {
1621            kind: ReturnExprKind::ListFunction {
1622                shape,
1623                item_type,
1624                body,
1625            },
1626        }
1627    }
1628
1629    pub(crate) fn function_function_shape_body(
1630        shape: crate::plan::FunctionShape,
1631        body: FunctionFunctionReturn,
1632    ) -> Self {
1633        Self {
1634            kind: ReturnExprKind::FunctionFunction { shape, body },
1635        }
1636    }
1637
1638    pub fn value_type(&self) -> ValueType {
1639        match self.kind() {
1640            ReturnExprKind::Generic { parameter, .. } => ValueType::Parameter(*parameter),
1641            ReturnExprKind::Int { .. } => ValueType::Int,
1642            ReturnExprKind::Float { .. } => ValueType::Float,
1643            ReturnExprKind::String { .. } => ValueType::String,
1644            ReturnExprKind::BitArray { .. } => ValueType::BitArray,
1645            ReturnExprKind::UtfCodepoint { .. } => ValueType::UtfCodepoint,
1646            ReturnExprKind::Custom { body } => ValueType::Custom(body.shape().type_().clone()),
1647            ReturnExprKind::External { body } => ValueType::External(body.shape().type_().clone()),
1648            ReturnExprKind::Bool { .. } => ValueType::Bool,
1649            ReturnExprKind::Nil { .. } => ValueType::Nil,
1650            ReturnExprKind::Tuple { type_, .. } => ValueType::Tuple(type_.clone()),
1651            ReturnExprKind::GenericList { parameter, .. } => {
1652                ValueType::List(Box::new(ValueType::Parameter(*parameter)))
1653            }
1654            ReturnExprKind::ParameterListList { parameter, .. } => ValueType::List(Box::new(
1655                ValueType::List(Box::new(ValueType::Parameter(*parameter))),
1656            )),
1657            ReturnExprKind::IntList { .. } => ValueType::List(Box::new(ValueType::Int)),
1658            ReturnExprKind::StringList { .. } => ValueType::List(Box::new(ValueType::String)),
1659            ReturnExprKind::BitArrayList { .. } => ValueType::List(Box::new(ValueType::BitArray)),
1660            ReturnExprKind::UtfCodepointList { .. } => {
1661                ValueType::List(Box::new(ValueType::UtfCodepoint))
1662            }
1663            ReturnExprKind::CustomList { item_type, .. } => {
1664                ValueType::List(Box::new(ValueType::Custom(item_type.clone())))
1665            }
1666            ReturnExprKind::ExternalList { item_type, .. } => {
1667                ValueType::List(Box::new(ValueType::External(item_type.clone())))
1668            }
1669            ReturnExprKind::FloatList { .. } => ValueType::List(Box::new(ValueType::Float)),
1670            ReturnExprKind::BoolList { .. } => ValueType::List(Box::new(ValueType::Bool)),
1671            ReturnExprKind::NilList { .. } => ValueType::List(Box::new(ValueType::Nil)),
1672            ReturnExprKind::TupleList { item_type, .. } => {
1673                ValueType::List(Box::new(ValueType::Tuple(item_type.clone())))
1674            }
1675            ReturnExprKind::ListList { item_shape, .. } => {
1676                ValueType::List(Box::new(ValueType::List(Box::new(item_shape.value_type()))))
1677            }
1678            ReturnExprKind::FunctionList { item_type, .. } => {
1679                ValueType::List(Box::new(ValueType::Function(Box::new(item_type.clone()))))
1680            }
1681            ReturnExprKind::GenericFunction { shape, .. }
1682            | ReturnExprKind::IntFunction { shape, .. }
1683            | ReturnExprKind::FloatFunction { shape, .. }
1684            | ReturnExprKind::StringFunction { shape, .. }
1685            | ReturnExprKind::BitArrayFunction { shape, .. }
1686            | ReturnExprKind::UtfCodepointFunction { shape, .. }
1687            | ReturnExprKind::CustomFunction { shape, .. }
1688            | ReturnExprKind::ExternalFunction { shape, .. }
1689            | ReturnExprKind::BoolFunction { shape, .. }
1690            | ReturnExprKind::NilFunction { shape, .. }
1691            | ReturnExprKind::TupleFunction { shape, .. }
1692            | ReturnExprKind::ListFunction { shape, .. }
1693            | ReturnExprKind::FunctionFunction { shape, .. } => {
1694                ValueType::Function(Box::new(shape.type_()))
1695            }
1696        }
1697    }
1698
1699    pub(crate) fn kind(&self) -> &ReturnExprKind {
1700        &self.kind
1701    }
1702}
1703
1704impl CustomReturn {
1705    #[cfg(test)]
1706    pub(crate) fn expr(expression: CustomExpr) -> Self {
1707        let shape = expression.shape().clone();
1708        Self::with_signature_shape(shape, expression)
1709    }
1710
1711    pub(crate) fn with_signature_shape(
1712        signature_shape: crate::plan::CustomValueShape,
1713        expression: CustomExpr,
1714    ) -> Self {
1715        let (body_shape, kind) = expression.into_parts();
1716        Self {
1717            signature_shape,
1718            body_shape,
1719            body: custom_return_body(kind),
1720        }
1721    }
1722
1723    #[cfg(test)]
1724    pub(crate) fn block(steps: Vec<Step>, return_: Self) -> Self {
1725        Self {
1726            signature_shape: return_.signature_shape,
1727            body_shape: return_.body_shape,
1728            body: ReturnBody::block(steps, return_.body),
1729        }
1730    }
1731
1732    pub(crate) fn shape(&self) -> &crate::plan::CustomValueShape {
1733        &self.body_shape
1734    }
1735
1736    pub(crate) fn signature_shape(&self) -> &crate::plan::CustomValueShape {
1737        &self.signature_shape
1738    }
1739
1740    pub(crate) fn body(
1741        &self,
1742    ) -> &ReturnBody<super::CustomExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>>
1743    {
1744        &self.body
1745    }
1746}
1747
1748fn custom_return_body(
1749    kind: super::CustomExprKind,
1750) -> ReturnBody<super::CustomExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>> {
1751    use super::CustomExprKind as K;
1752
1753    match kind {
1754        K::Call {
1755            function,
1756            args,
1757            site,
1758        } => ReturnBody::tail_call(crate::plan::FunctionCallTarget::new(function, site), args),
1759        K::BoolCase {
1760            subject,
1761            true_,
1762            false_,
1763        } => ReturnBody::bool_case(
1764            *subject,
1765            custom_return_body(*true_),
1766            custom_return_body(*false_),
1767        ),
1768        K::IntCase {
1769            subject,
1770            clauses,
1771            fallback,
1772        } => ReturnBody::int_case(
1773            *subject,
1774            clauses
1775                .into_iter()
1776                .map(|(pattern, branch)| (pattern, custom_return_body(branch)))
1777                .collect(),
1778            custom_return_body(*fallback),
1779        ),
1780        K::FloatCase {
1781            subject,
1782            clauses,
1783            fallback,
1784        } => ReturnBody::float_case(
1785            *subject,
1786            clauses
1787                .into_iter()
1788                .map(|(pattern, branch)| (pattern, custom_return_body(branch)))
1789                .collect(),
1790            custom_return_body(*fallback),
1791        ),
1792        K::StringCase {
1793            subject,
1794            clauses,
1795            fallback,
1796        } => ReturnBody::string_case(
1797            *subject,
1798            clauses
1799                .into_iter()
1800                .map(|(pattern, branch)| (pattern, custom_return_body(branch)))
1801                .collect(),
1802            custom_return_body(*fallback),
1803        ),
1804        K::Block { steps, return_ } => ReturnBody::block(steps, custom_return_body(*return_)),
1805        kind => ReturnBody::expr(kind),
1806    }
1807}
1808
1809impl ExternalReturn {
1810    pub(crate) fn with_signature_shape(
1811        signature_shape: crate::plan::ExternalValueShape,
1812        expression: ExternalExpr,
1813    ) -> Self {
1814        let (body_shape, kind) = expression.into_parts();
1815        Self {
1816            signature_shape,
1817            body_shape,
1818            body: external_return_body(kind),
1819        }
1820    }
1821
1822    pub(crate) fn shape(&self) -> &crate::plan::ExternalValueShape {
1823        &self.body_shape
1824    }
1825
1826    pub(crate) fn signature_shape(&self) -> &crate::plan::ExternalValueShape {
1827        &self.signature_shape
1828    }
1829
1830    pub(crate) fn body(
1831        &self,
1832    ) -> &ReturnBody<super::ExternalExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>>
1833    {
1834        &self.body
1835    }
1836}
1837
1838fn external_return_body(
1839    kind: super::ExternalExprKind,
1840) -> ReturnBody<super::ExternalExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>> {
1841    use super::ExternalExprKind as K;
1842
1843    match kind {
1844        K::Call {
1845            function,
1846            args,
1847            site,
1848        } => ReturnBody::tail_call(crate::plan::FunctionCallTarget::new(function, site), args),
1849        K::BoolCase {
1850            subject,
1851            true_,
1852            false_,
1853        } => ReturnBody::bool_case(
1854            *subject,
1855            external_return_expression(*true_),
1856            external_return_expression(*false_),
1857        ),
1858        K::IntCase {
1859            subject,
1860            clauses,
1861            fallback,
1862        } => ReturnBody::int_case(
1863            *subject,
1864            clauses
1865                .into_iter()
1866                .map(|(pattern, branch)| (pattern, external_return_expression(branch)))
1867                .collect(),
1868            external_return_expression(*fallback),
1869        ),
1870        K::FloatCase {
1871            subject,
1872            clauses,
1873            fallback,
1874        } => ReturnBody::float_case(
1875            *subject,
1876            clauses
1877                .into_iter()
1878                .map(|(pattern, branch)| (pattern, external_return_expression(branch)))
1879                .collect(),
1880            external_return_expression(*fallback),
1881        ),
1882        K::StringCase {
1883            subject,
1884            clauses,
1885            fallback,
1886        } => ReturnBody::string_case(
1887            *subject,
1888            clauses
1889                .into_iter()
1890                .map(|(pattern, branch)| (pattern, external_return_expression(branch)))
1891                .collect(),
1892            external_return_expression(*fallback),
1893        ),
1894        K::Block { steps, return_ } => {
1895            ReturnBody::block(steps, external_return_expression(*return_))
1896        }
1897        kind => ReturnBody::expr(kind),
1898    }
1899}
1900
1901fn external_return_expression(
1902    expression: ExternalExpr,
1903) -> ReturnBody<super::ExternalExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>> {
1904    let (_, kind) = expression.into_parts();
1905    external_return_body(kind)
1906}
1907
1908impl CustomFunctionReturn {
1909    pub(crate) fn expr(expression: super::CustomFunctionExpr) -> Self {
1910        let (type_, kind) = expression.into_parts();
1911        Self {
1912            type_,
1913            body: custom_function_return_body(kind),
1914        }
1915    }
1916
1917    pub(crate) fn type_(&self) -> &CustomFunctionType {
1918        &self.type_
1919    }
1920
1921    pub(crate) fn body(
1922        &self,
1923    ) -> &ReturnBody<
1924        super::CustomFunctionExprKind,
1925        crate::plan::FunctionCallTarget<FunctionInstantiation>,
1926    > {
1927        &self.body
1928    }
1929}
1930
1931fn custom_function_return_body(
1932    kind: super::CustomFunctionExprKind,
1933) -> ReturnBody<super::CustomFunctionExprKind, crate::plan::FunctionCallTarget<FunctionInstantiation>>
1934{
1935    use super::CustomFunctionExprKind as K;
1936
1937    match kind {
1938        K::Call {
1939            function,
1940            args,
1941            site,
1942        } => ReturnBody::tail_call(crate::plan::FunctionCallTarget::new(function, site), args),
1943        K::BoolCase {
1944            subject,
1945            true_,
1946            false_,
1947        } => ReturnBody::bool_case(
1948            *subject,
1949            custom_function_return_body(*true_),
1950            custom_function_return_body(*false_),
1951        ),
1952        K::IntCase {
1953            subject,
1954            clauses,
1955            fallback,
1956        } => ReturnBody::int_case(
1957            *subject,
1958            clauses
1959                .into_iter()
1960                .map(|(pattern, branch)| (pattern, custom_function_return_body(branch)))
1961                .collect(),
1962            custom_function_return_body(*fallback),
1963        ),
1964        K::FloatCase {
1965            subject,
1966            clauses,
1967            fallback,
1968        } => ReturnBody::float_case(
1969            *subject,
1970            clauses
1971                .into_iter()
1972                .map(|(pattern, branch)| (pattern, custom_function_return_body(branch)))
1973                .collect(),
1974            custom_function_return_body(*fallback),
1975        ),
1976        K::StringCase {
1977            subject,
1978            clauses,
1979            fallback,
1980        } => ReturnBody::string_case(
1981            *subject,
1982            clauses
1983                .into_iter()
1984                .map(|(pattern, branch)| (pattern, custom_function_return_body(branch)))
1985                .collect(),
1986            custom_function_return_body(*fallback),
1987        ),
1988        K::Block { steps, return_ } => {
1989            ReturnBody::block(steps, custom_function_return_body(*return_))
1990        }
1991        kind => ReturnBody::expr(kind),
1992    }
1993}
1994
1995impl ExternalFunctionReturn {
1996    pub(crate) fn expr(expression: super::ExternalFunctionExpr) -> Self {
1997        let (type_, kind) = expression.into_parts();
1998        Self {
1999            type_,
2000            body: external_function_return_body(kind),
2001        }
2002    }
2003
2004    pub(crate) fn type_(&self) -> &ExternalFunctionType {
2005        &self.type_
2006    }
2007
2008    pub(crate) fn body(
2009        &self,
2010    ) -> &ReturnBody<
2011        super::ExternalFunctionExprKind,
2012        crate::plan::FunctionCallTarget<FunctionInstantiation>,
2013    > {
2014        &self.body
2015    }
2016}
2017
2018fn external_function_return_body(
2019    kind: super::ExternalFunctionExprKind,
2020) -> ReturnBody<
2021    super::ExternalFunctionExprKind,
2022    crate::plan::FunctionCallTarget<FunctionInstantiation>,
2023> {
2024    use super::ExternalFunctionExprKind as K;
2025
2026    match kind {
2027        K::Call {
2028            function,
2029            args,
2030            site,
2031        } => ReturnBody::tail_call(crate::plan::FunctionCallTarget::new(function, site), args),
2032        K::BoolCase {
2033            subject,
2034            true_,
2035            false_,
2036        } => ReturnBody::bool_case(
2037            *subject,
2038            external_function_return_body(*true_),
2039            external_function_return_body(*false_),
2040        ),
2041        K::IntCase {
2042            subject,
2043            clauses,
2044            fallback,
2045        } => ReturnBody::int_case(
2046            *subject,
2047            clauses
2048                .into_iter()
2049                .map(|(pattern, branch)| (pattern, external_function_return_body(branch)))
2050                .collect(),
2051            external_function_return_body(*fallback),
2052        ),
2053        K::FloatCase {
2054            subject,
2055            clauses,
2056            fallback,
2057        } => ReturnBody::float_case(
2058            *subject,
2059            clauses
2060                .into_iter()
2061                .map(|(pattern, branch)| (pattern, external_function_return_body(branch)))
2062                .collect(),
2063            external_function_return_body(*fallback),
2064        ),
2065        K::StringCase {
2066            subject,
2067            clauses,
2068            fallback,
2069        } => ReturnBody::string_case(
2070            *subject,
2071            clauses
2072                .into_iter()
2073                .map(|(pattern, branch)| (pattern, external_function_return_body(branch)))
2074                .collect(),
2075            external_function_return_body(*fallback),
2076        ),
2077        K::Block { steps, return_ } => {
2078            ReturnBody::block(steps, external_function_return_body(*return_))
2079        }
2080        kind => ReturnBody::expr(kind),
2081    }
2082}
2083
2084impl FunctionFunctionReturn {
2085    pub(crate) fn expr(expression: super::FunctionFunctionExpr) -> Self {
2086        let (type_, kind) = expression.into_parts();
2087        Self {
2088            type_,
2089            body: function_function_return_body(kind),
2090        }
2091    }
2092
2093    #[cfg(test)]
2094    pub(crate) fn int_case(subject: IntExpr, clauses: Vec<(BigInt, Self)>, fallback: Self) -> Self {
2095        let clauses = clauses
2096            .into_iter()
2097            .map(|(pattern, branch)| (pattern, branch.body))
2098            .collect();
2099        Self {
2100            type_: fallback.type_,
2101            body: ReturnBody::int_case(subject, clauses, fallback.body),
2102        }
2103    }
2104
2105    #[cfg(test)]
2106    pub(crate) fn string_case(
2107        subject: StringExpr,
2108        clauses: Vec<(EcoString, Self)>,
2109        fallback: Self,
2110    ) -> Self {
2111        let clauses = clauses
2112            .into_iter()
2113            .map(|(pattern, branch)| (pattern, branch.body))
2114            .collect();
2115        Self {
2116            type_: fallback.type_,
2117            body: ReturnBody::string_case(subject, clauses, fallback.body),
2118        }
2119    }
2120
2121    #[cfg(test)]
2122    pub(crate) fn block(steps: Vec<Step>, return_: Self) -> Self {
2123        Self {
2124            type_: return_.type_,
2125            body: ReturnBody::block(steps, return_.body),
2126        }
2127    }
2128
2129    pub(crate) fn type_(&self) -> &FunctionFunctionType {
2130        &self.type_
2131    }
2132
2133    pub(crate) fn body(
2134        &self,
2135    ) -> &ReturnBody<
2136        super::FunctionFunctionExprKind,
2137        crate::plan::FunctionCallTarget<FunctionInstantiation>,
2138    > {
2139        &self.body
2140    }
2141}
2142
2143fn function_function_return_body(
2144    kind: super::FunctionFunctionExprKind,
2145) -> ReturnBody<
2146    super::FunctionFunctionExprKind,
2147    crate::plan::FunctionCallTarget<FunctionInstantiation>,
2148> {
2149    use super::FunctionFunctionExprKind as K;
2150
2151    match kind {
2152        K::Call {
2153            function,
2154            args,
2155            site,
2156        } => ReturnBody::tail_call(crate::plan::FunctionCallTarget::new(function, site), args),
2157        K::BoolCase {
2158            subject,
2159            true_,
2160            false_,
2161        } => ReturnBody::bool_case(
2162            *subject,
2163            function_function_return_body(*true_),
2164            function_function_return_body(*false_),
2165        ),
2166        K::IntCase {
2167            subject,
2168            clauses,
2169            fallback,
2170        } => ReturnBody::int_case(
2171            *subject,
2172            clauses
2173                .into_iter()
2174                .map(|(pattern, branch)| (pattern, function_function_return_body(branch)))
2175                .collect(),
2176            function_function_return_body(*fallback),
2177        ),
2178        K::FloatCase {
2179            subject,
2180            clauses,
2181            fallback,
2182        } => ReturnBody::float_case(
2183            *subject,
2184            clauses
2185                .into_iter()
2186                .map(|(pattern, branch)| (pattern, function_function_return_body(branch)))
2187                .collect(),
2188            function_function_return_body(*fallback),
2189        ),
2190        K::StringCase {
2191            subject,
2192            clauses,
2193            fallback,
2194        } => ReturnBody::string_case(
2195            *subject,
2196            clauses
2197                .into_iter()
2198                .map(|(pattern, branch)| (pattern, function_function_return_body(branch)))
2199                .collect(),
2200            function_function_return_body(*fallback),
2201        ),
2202        K::Block { steps, return_ } => {
2203            ReturnBody::block(steps, function_function_return_body(*return_))
2204        }
2205        kind => ReturnBody::expr(kind),
2206    }
2207}
2208
2209impl<Expression, Function> ReturnBody<Expression, Function> {
2210    pub(crate) fn expr(expression: Expression) -> Self {
2211        Self {
2212            kind: ReturnBodyKind::Expr(expression),
2213        }
2214    }
2215
2216    pub(crate) fn tail_call(function: impl Into<Function>, args: Vec<CallArg>) -> Self {
2217        Self {
2218            kind: ReturnBodyKind::TailCall {
2219                function: function.into(),
2220                args,
2221            },
2222        }
2223    }
2224
2225    pub(crate) fn bool_case(subject: BoolExpr, true_: Self, false_: Self) -> Self {
2226        Self {
2227            kind: ReturnBodyKind::BoolCase {
2228                subject,
2229                true_: Box::new(true_),
2230                false_: Box::new(false_),
2231            },
2232        }
2233    }
2234
2235    pub(crate) fn int_case(subject: IntExpr, clauses: Vec<(BigInt, Self)>, fallback: Self) -> Self {
2236        Self {
2237            kind: ReturnBodyKind::IntCase {
2238                subject,
2239                clauses,
2240                fallback: Box::new(fallback),
2241            },
2242        }
2243    }
2244
2245    pub(crate) fn float_case(
2246        subject: FloatExpr,
2247        clauses: Vec<(f64, Self)>,
2248        fallback: Self,
2249    ) -> Self {
2250        Self {
2251            kind: ReturnBodyKind::FloatCase {
2252                subject,
2253                clauses,
2254                fallback: Box::new(fallback),
2255            },
2256        }
2257    }
2258
2259    pub(crate) fn string_case(
2260        subject: StringExpr,
2261        clauses: Vec<(EcoString, Self)>,
2262        fallback: Self,
2263    ) -> Self {
2264        Self {
2265            kind: ReturnBodyKind::StringCase {
2266                subject,
2267                clauses,
2268                fallback: Box::new(fallback),
2269            },
2270        }
2271    }
2272
2273    pub(crate) fn block(steps: Vec<Step>, return_: Self) -> Self {
2274        Self {
2275            kind: ReturnBodyKind::Block {
2276                steps,
2277                return_: Box::new(return_),
2278            },
2279        }
2280    }
2281
2282    pub(crate) fn kind(&self) -> &ReturnBodyKind<Expression, Function> {
2283        &self.kind
2284    }
2285}
2286
2287impl Param {
2288    #[cfg(test)]
2289    pub(crate) fn named(local: ParamLocal, name: EcoString) -> Self {
2290        let shape = local.value_shape();
2291        Self::named_shape(local, name, shape)
2292    }
2293
2294    pub(crate) fn named_shape(
2295        local: ParamLocal,
2296        name: EcoString,
2297        shape: crate::plan::ValueShape,
2298    ) -> Self {
2299        Self {
2300            slot: ParamSlot::new(local, shape),
2301            binding: ParamBinding::Named(name),
2302        }
2303    }
2304
2305    #[cfg(test)]
2306    pub(crate) fn discard(local: ParamLocal) -> Self {
2307        let shape = local.value_shape();
2308        Self::discard_shape(local, shape)
2309    }
2310
2311    pub(crate) fn discard_shape(local: ParamLocal, shape: crate::plan::ValueShape) -> Self {
2312        Self {
2313            slot: ParamSlot::new(local, shape),
2314            binding: ParamBinding::Discard,
2315        }
2316    }
2317
2318    pub fn name(&self) -> Option<&EcoString> {
2319        match &self.binding {
2320            ParamBinding::Named(name) => Some(name),
2321            ParamBinding::Discard => None,
2322        }
2323    }
2324
2325    pub fn binding(&self) -> &ParamBinding {
2326        &self.binding
2327    }
2328
2329    pub(crate) fn local(&self) -> &ParamLocal {
2330        self.slot.local()
2331    }
2332
2333    pub(crate) fn shape(&self) -> &crate::plan::ValueShape {
2334        self.slot.shape()
2335    }
2336}
2337
2338impl FunctionEntry {
2339    pub(crate) fn new(params: Vec<Param>, captures: Vec<ParamSlot>) -> Self {
2340        Self {
2341            params: params.into_boxed_slice(),
2342            captures: captures.into_boxed_slice(),
2343        }
2344    }
2345
2346    pub(crate) fn params(&self) -> &[Param] {
2347        &self.params
2348    }
2349
2350    pub(crate) fn captures(&self) -> &[ParamSlot] {
2351        &self.captures
2352    }
2353}
2354
2355impl CapturePosition {
2356    pub(crate) fn new(index: usize) -> Self {
2357        Self(index)
2358    }
2359
2360    pub(crate) fn index(self) -> usize {
2361        self.0
2362    }
2363}
2364
2365impl ParamSlot {
2366    pub(crate) fn new(local: ParamLocal, shape: crate::plan::ValueShape) -> Self {
2367        Self { local, shape }
2368    }
2369
2370    pub(crate) fn local(&self) -> &ParamLocal {
2371        &self.local
2372    }
2373
2374    pub(crate) fn shape(&self) -> &crate::plan::ValueShape {
2375        &self.shape
2376    }
2377
2378    #[cfg(test)]
2379    pub(crate) fn from_local(local: ParamLocal) -> Self {
2380        let shape = local.value_shape();
2381        Self::new(local, shape)
2382    }
2383}
2384
2385impl ParamLocal {
2386    pub(crate) fn generic(local: GenericLocal) -> Self {
2387        Self::Generic(local)
2388    }
2389
2390    pub(crate) fn int(local: IntLocalId) -> Self {
2391        Self::Int(local)
2392    }
2393
2394    pub(crate) fn float(local: FloatLocalId) -> Self {
2395        Self::Float(local)
2396    }
2397
2398    pub(crate) fn string(local: StringLocalId) -> Self {
2399        Self::String(local)
2400    }
2401
2402    pub(crate) fn bit_array(local: BitArrayLocalId) -> Self {
2403        Self::BitArray(local)
2404    }
2405
2406    pub(crate) fn utf_codepoint(local: UtfCodepointLocalId) -> Self {
2407        Self::UtfCodepoint(local)
2408    }
2409
2410    #[cfg(test)]
2411    pub(crate) fn custom(local: CustomLocalId, type_: CustomType) -> Self {
2412        Self::Custom(CustomLocal::new(local, type_))
2413    }
2414
2415    pub(crate) fn custom_shape(local: CustomLocalId, shape: crate::plan::CustomValueShape) -> Self {
2416        Self::Custom(CustomLocal::from_shape(local, shape))
2417    }
2418
2419    pub(crate) fn external_shape(
2420        local: ExternalLocalId,
2421        shape: crate::plan::ExternalValueShape,
2422    ) -> Self {
2423        Self::External(ExternalLocal::from_shape(local, shape))
2424    }
2425
2426    pub(crate) fn bool(local: BoolLocalId) -> Self {
2427        Self::Bool(local)
2428    }
2429
2430    pub(crate) fn nil(local: NilLocalId) -> Self {
2431        Self::Nil(local)
2432    }
2433
2434    pub(crate) fn tuple(local: TupleLocalId, type_: Vec<ValueType>) -> Self {
2435        Self::Tuple { local, type_ }
2436    }
2437
2438    pub(crate) fn list(local: ListLocal) -> Self {
2439        Self::List(local)
2440    }
2441
2442    pub(crate) fn int_function(local: IntFunctionLocalId, type_: FunctionType) -> Self {
2443        Self::IntFunction { local, type_ }
2444    }
2445
2446    pub(crate) fn float_function(local: FloatFunctionLocalId, type_: FunctionType) -> Self {
2447        Self::FloatFunction { local, type_ }
2448    }
2449
2450    pub(crate) fn string_function(local: StringFunctionLocalId, type_: FunctionType) -> Self {
2451        Self::StringFunction { local, type_ }
2452    }
2453
2454    pub(crate) fn bit_array_function(local: BitArrayFunctionLocalId, type_: FunctionType) -> Self {
2455        Self::BitArrayFunction { local, type_ }
2456    }
2457
2458    pub(crate) fn utf_codepoint_function(
2459        local: UtfCodepointFunctionLocalId,
2460        type_: FunctionType,
2461    ) -> Self {
2462        Self::UtfCodepointFunction { local, type_ }
2463    }
2464
2465    pub(crate) fn custom_function(local: CustomFunctionLocal) -> Self {
2466        Self::CustomFunction(local)
2467    }
2468
2469    pub(crate) fn external_function(local: ExternalFunctionLocal) -> Self {
2470        Self::ExternalFunction(local)
2471    }
2472
2473    pub(crate) fn bool_function(local: BoolFunctionLocalId, type_: FunctionType) -> Self {
2474        Self::BoolFunction { local, type_ }
2475    }
2476
2477    pub(crate) fn nil_function(local: NilFunctionLocalId, type_: FunctionType) -> Self {
2478        Self::NilFunction { local, type_ }
2479    }
2480
2481    pub(crate) fn tuple_function(local: TupleFunctionLocalId, type_: FunctionType) -> Self {
2482        Self::TupleFunction { local, type_ }
2483    }
2484
2485    pub(crate) fn list_function(local: ListFunctionLocal) -> Self {
2486        Self::ListFunction(local)
2487    }
2488
2489    pub(crate) fn function_function(local: FunctionFunctionLocal) -> Self {
2490        Self::FunctionFunction(local)
2491    }
2492
2493    pub(crate) fn generic_function(local: GenericFunctionLocal) -> Self {
2494        Self::GenericFunction(local)
2495    }
2496
2497    pub(crate) fn value_type(&self) -> ValueType {
2498        match self {
2499            Self::Generic(local) => ValueType::Parameter(local.parameter()),
2500            Self::Int(_) => ValueType::Int,
2501            Self::Float(_) => ValueType::Float,
2502            Self::String(_) => ValueType::String,
2503            Self::BitArray(_) => ValueType::BitArray,
2504            Self::UtfCodepoint(_) => ValueType::UtfCodepoint,
2505            Self::Custom(local) => ValueType::Custom(local.type_().clone()),
2506            Self::External(local) => ValueType::External(local.type_().clone()),
2507            Self::Bool(_) => ValueType::Bool,
2508            Self::Nil(_) => ValueType::Nil,
2509            Self::Tuple { type_, .. } => ValueType::Tuple(type_.clone()),
2510            Self::List(local) => local.value_type(),
2511            Self::IntFunction { type_, .. }
2512            | Self::FloatFunction { type_, .. }
2513            | Self::StringFunction { type_, .. }
2514            | Self::BitArrayFunction { type_, .. }
2515            | Self::UtfCodepointFunction { type_, .. }
2516            | Self::BoolFunction { type_, .. }
2517            | Self::NilFunction { type_, .. }
2518            | Self::TupleFunction { type_, .. } => ValueType::Function(Box::new(type_.clone())),
2519            Self::CustomFunction(local) => {
2520                ValueType::Function(Box::new(local.type_().to_function_type()))
2521            }
2522            Self::ExternalFunction(local) => {
2523                ValueType::Function(Box::new(local.type_().to_function_type()))
2524            }
2525            Self::ListFunction(local) => local.value_type(),
2526            Self::FunctionFunction(local) => {
2527                ValueType::Function(Box::new(local.type_().to_function_type()))
2528            }
2529            Self::GenericFunction(local) => {
2530                ValueType::Function(Box::new(local.type_().shape().type_()))
2531            }
2532        }
2533    }
2534
2535    #[cfg(test)]
2536    pub(crate) fn value_shape(&self) -> crate::plan::ValueShape {
2537        match self {
2538            Self::Generic(local) => crate::plan::ValueShape::Parameter(local.parameter()),
2539            Self::Custom(local) => crate::plan::ValueShape::Custom(local.shape().clone()),
2540            Self::External(local) => crate::plan::ValueShape::External(local.shape().clone()),
2541            Self::CustomFunction(local) => {
2542                crate::plan::ValueShape::Function(Box::new(crate::plan::FunctionShape::new(
2543                    local.type_().argument_shapes().to_vec(),
2544                    crate::plan::ValueShape::Custom(local.type_().return_().clone()),
2545                )))
2546            }
2547            Self::ExternalFunction(local) => {
2548                crate::plan::ValueShape::Function(Box::new(crate::plan::FunctionShape::new(
2549                    local.type_().argument_shapes().to_vec(),
2550                    crate::plan::ValueShape::External(local.type_().return_().clone()),
2551                )))
2552            }
2553            Self::GenericFunction(local) => {
2554                crate::plan::ValueShape::Function(Box::new(local.type_().shape()))
2555            }
2556            _ => crate::plan::ValueShape::from_value_type(self.value_type()),
2557        }
2558    }
2559}
2560
2561#[cfg(test)]
2562mod tests {
2563    use super::{
2564        BitArrayFunctionReturn, BitArrayListReturn, BoolListReturn, CapturePosition,
2565        CustomFunctionReturn, CustomListReturn, CustomReturn, ExternalFunctionReturn,
2566        ExternalListReturn, ExternalReturn, FloatListReturn, FunctionFunctionReturn,
2567        FunctionListReturn, FunctionTemplate, GenericFunctionReturn, GenericListReturn,
2568        GenericReturn, IntListReturn, ListListReturn, ListReturn, NilListReturn, Param,
2569        ParamBinding, ParamLocal, ParamSlot, ParameterListListReturn, ReturnBody, ReturnBodyKind,
2570        ReturnExpr, StringListReturn, TupleListReturn, UtfCodepointFunctionReturn,
2571    };
2572    use crate::plan::{
2573        BitArrayExpr, BoolExpr, BoolFunctionLocalId, BoolLocalId, CustomConstructorRefinement,
2574        CustomExpr, CustomFunctionExpr, CustomFunctionLocal, CustomFunctionLocalId,
2575        CustomFunctionType, CustomType, CustomTypeName, CustomValueShape, ExternalExpr,
2576        ExternalFunctionExpr, ExternalFunctionLocal, ExternalFunctionLocalId, ExternalFunctionType,
2577        ExternalLocalId, ExternalType, ExternalTypeName, ExternalValueShape, FloatExpr,
2578        FloatFunctionLocalId, FloatLocalId, FunctionFunctionExpr, FunctionFunctionLocal,
2579        FunctionFunctionLocalId, FunctionFunctionType, FunctionShape, FunctionTemplateId,
2580        FunctionType, GenericFunctionLocal, GenericFunctionLocalId, GenericFunctionType,
2581        GenericLocal, GenericLocalId, IntExpr, IntFunctionLocalId, IntListLocalId, IntLocalId,
2582        ListExpr, ListLocal, NilExpr, NilFunctionLocalId, PanicExpr, PanicSite, StringExpr,
2583        StringFunctionLocalId, TupleExpr, TupleFunctionLocalId, TypeParameterId, UtfCodepointExpr,
2584        UtfCodepointListReturn, UtfCodepointLocalId, ValueShape, ValueStorageShape, ValueType,
2585    };
2586    use num_bigint::BigInt;
2587
2588    fn custom_type() -> CustomType {
2589        CustomType::new(
2590            CustomTypeName::new("geam".into(), "main".into(), "Boxed".into()),
2591            Vec::new(),
2592        )
2593    }
2594
2595    fn external_type(name: &str) -> ExternalType {
2596        ExternalType::new(
2597            ExternalTypeName::new("geam".into(), "main".into(), name.into()),
2598            Vec::new(),
2599        )
2600    }
2601
2602    #[test]
2603    fn custom_function_parameter_helpers_preserve_recursive_value_shape() {
2604        let type_ = custom_type();
2605        let return_shape = CustomValueShape::new(
2606            type_.type_name().clone(),
2607            Vec::new(),
2608            CustomConstructorRefinement::Exact(0),
2609        );
2610        let type_ = CustomFunctionType::from_shapes(
2611            vec![ValueShape::Custom(return_shape.clone())],
2612            return_shape.clone(),
2613        );
2614        let local =
2615            ParamLocal::custom_function(CustomFunctionLocal::new(CustomFunctionLocalId(0), type_));
2616
2617        assert_eq!(
2618            local.value_shape(),
2619            ValueShape::Function(Box::new(crate::plan::FunctionShape::new(
2620                vec![ValueShape::Custom(return_shape.clone())],
2621                ValueShape::Custom(return_shape),
2622            ))),
2623        );
2624    }
2625
2626    #[test]
2627    fn callable_returns_own_exact_type_around_itemless_bodies() {
2628        let custom_function_type = CustomFunctionType::new(vec![ValueType::Int], custom_type());
2629        let custom_function_shape = crate::plan::FunctionShape::new(
2630            custom_function_type.argument_shapes().to_vec(),
2631            ValueShape::Custom(custom_function_type.return_().clone()),
2632        );
2633        let custom_instantiation = crate::plan::monomorphic_function_instantiation(
2634            7,
2635            crate::plan::FunctionShape::new(
2636                Vec::new(),
2637                ValueShape::Function(Box::new(custom_function_shape)),
2638            ),
2639        );
2640        let custom_return = CustomFunctionReturn::expr(CustomFunctionExpr::block(
2641            Vec::new(),
2642            CustomFunctionExpr::call(
2643                custom_instantiation.clone(),
2644                Vec::new(),
2645                custom_function_type.clone(),
2646            ),
2647        ));
2648
2649        assert_eq!(
2650            custom_return,
2651            CustomFunctionReturn {
2652                type_: custom_function_type,
2653                body: ReturnBody {
2654                    kind: ReturnBodyKind::Block {
2655                        steps: Vec::new(),
2656                        return_: Box::new(ReturnBody {
2657                            kind: ReturnBodyKind::TailCall {
2658                                function: custom_instantiation.into(),
2659                                args: Vec::new(),
2660                            },
2661                        }),
2662                    },
2663                },
2664            },
2665        );
2666
2667        let returned = FunctionType::new(vec![ValueType::String], ValueType::Int);
2668        let function_function_type = FunctionFunctionType::new(vec![ValueType::Bool], returned);
2669        let function_instantiation = crate::plan::monomorphic_function_instantiation(
2670            9,
2671            crate::plan::FunctionShape::new(
2672                Vec::new(),
2673                ValueShape::Function(Box::new(crate::plan::FunctionShape::from_function_type(
2674                    function_function_type.to_function_type(),
2675                ))),
2676            ),
2677        );
2678        let function_return = FunctionFunctionReturn::expr(FunctionFunctionExpr::call(
2679            function_instantiation.clone(),
2680            Vec::new(),
2681            function_function_type.clone(),
2682        ));
2683
2684        assert_eq!(
2685            function_return,
2686            FunctionFunctionReturn {
2687                type_: function_function_type,
2688                body: ReturnBody {
2689                    kind: ReturnBodyKind::TailCall {
2690                        function: function_instantiation.into(),
2691                        args: Vec::new(),
2692                    },
2693                },
2694            },
2695        );
2696    }
2697
2698    #[test]
2699    fn function_function_returns_convert_float_case_tail_calls() {
2700        let returned = FunctionType::new(Vec::new(), ValueType::Int);
2701        let type_ = FunctionFunctionType::new(Vec::new(), returned);
2702        let function = crate::plan::monomorphic_function_instantiation(
2703            9,
2704            crate::plan::FunctionShape::new(
2705                Vec::new(),
2706                ValueShape::Function(Box::new(crate::plan::FunctionShape::from_function_type(
2707                    type_.to_function_type(),
2708                ))),
2709            ),
2710        );
2711        let branch = FunctionFunctionExpr::call(function.clone(), Vec::new(), type_.clone());
2712        let fallback = FunctionFunctionExpr::call(function.clone(), Vec::new(), type_.clone());
2713
2714        assert_eq!(
2715            FunctionFunctionReturn::expr(FunctionFunctionExpr::float_case(
2716                FloatExpr::value(1.5),
2717                vec![(1.5, branch)],
2718                fallback,
2719            )),
2720            FunctionFunctionReturn {
2721                type_,
2722                body: ReturnBody::float_case(
2723                    FloatExpr::value(1.5),
2724                    vec![(1.5, ReturnBody::tail_call(function.clone(), Vec::new()))],
2725                    ReturnBody::tail_call(function, Vec::new()),
2726                ),
2727            },
2728        );
2729    }
2730
2731    #[test]
2732    fn custom_returns_own_one_type_around_itemless_tail_calls() {
2733        let type_ = custom_type();
2734        let custom_shape = CustomValueShape::any(type_.clone());
2735        let function = crate::plan::monomorphic_function_instantiation(
2736            7,
2737            crate::plan::FunctionShape::new(Vec::new(), ValueShape::Custom(custom_shape.clone())),
2738        );
2739        let body = CustomReturn::expr(CustomExpr::block(
2740            Vec::new(),
2741            CustomExpr::bool_case(
2742                BoolExpr::value(true),
2743                crate::plan::CustomBoolCaseBranches::from_resolved_shape(
2744                    custom_shape.clone(),
2745                    CustomExpr::call(function.clone(), Vec::new(), custom_shape.clone()),
2746                    CustomExpr::call(function.clone(), Vec::new(), custom_shape.clone()),
2747                ),
2748            ),
2749        ));
2750
2751        assert_eq!(
2752            body,
2753            CustomReturn {
2754                signature_shape: custom_shape.clone(),
2755                body_shape: custom_shape,
2756                body: ReturnBody {
2757                    kind: ReturnBodyKind::Block {
2758                        steps: Vec::new(),
2759                        return_: Box::new(ReturnBody {
2760                            kind: ReturnBodyKind::BoolCase {
2761                                subject: BoolExpr::value(true),
2762                                true_: Box::new(ReturnBody {
2763                                    kind: ReturnBodyKind::TailCall {
2764                                        function: function.clone().into(),
2765                                        args: Vec::new(),
2766                                    },
2767                                }),
2768                                false_: Box::new(ReturnBody {
2769                                    kind: ReturnBodyKind::TailCall {
2770                                        function: function.into(),
2771                                        args: Vec::new(),
2772                                    },
2773                                }),
2774                            },
2775                        }),
2776                    },
2777                },
2778            },
2779        );
2780    }
2781
2782    #[test]
2783    fn function_plan_accessors() {
2784        let param = Param::named(ParamLocal::int(IntLocalId(0)), "x".into());
2785        let return_ = ReturnExpr::int_body(ReturnBody::expr(IntExpr::value(BigInt::from(1))));
2786        let function = FunctionTemplate::new(
2787            FunctionTemplateId::new(0),
2788            "main".into(),
2789            vec![param],
2790            Vec::new(),
2791            return_,
2792        );
2793
2794        assert_eq!(function.id(), FunctionTemplateId::new(0));
2795        assert_eq!(function.name(), "main");
2796        assert_eq!(function.params().len(), 1);
2797        assert_eq!(function.params()[0].name(), Some(&"x".into()));
2798        assert_eq!(function.steps(), &[]);
2799        assert_eq!(
2800            function.return_(),
2801            &ReturnExpr::int_body(ReturnBody::expr(IntExpr::value(BigInt::from(1))))
2802        );
2803    }
2804
2805    #[test]
2806    fn function_entry_owns_ordered_parameter_and_capture_destinations() {
2807        let function = FunctionTemplate::with_captures(
2808            FunctionTemplateId::new(0),
2809            "anonymous".into(),
2810            vec![
2811                Param::named(ParamLocal::int(IntLocalId(0)), "first".into()),
2812                Param::discard(ParamLocal::string(crate::plan::StringLocalId(0))),
2813            ],
2814            vec![
2815                ParamSlot::from_local(ParamLocal::bool(BoolLocalId(0))),
2816                ParamSlot::from_local(ParamLocal::utf_codepoint(UtfCodepointLocalId(0))),
2817            ],
2818            Vec::new(),
2819            ReturnExpr::int_body(ReturnBody::expr(IntExpr::value(BigInt::from(1)))),
2820        );
2821        let entry = function.entry();
2822
2823        assert_eq!(
2824            entry.params(),
2825            &[
2826                Param::named(ParamLocal::int(IntLocalId(0)), "first".into()),
2827                Param::discard(ParamLocal::string(crate::plan::StringLocalId(0))),
2828            ],
2829        );
2830        assert_eq!(
2831            entry.captures(),
2832            &[
2833                ParamSlot::from_local(ParamLocal::bool(BoolLocalId(0))),
2834                ParamSlot::from_local(ParamLocal::utf_codepoint(UtfCodepointLocalId(0))),
2835            ],
2836        );
2837        assert_eq!(CapturePosition::new(1).index(), 1);
2838    }
2839
2840    #[test]
2841    fn return_expr_value_type_preserves_parametric_and_compound_families() {
2842        let parameter = TypeParameterId(0);
2843        let custom = custom_type();
2844        let external = external_type("Token");
2845        let external_shape = ExternalValueShape::any(external.clone());
2846        let tuple = vec![ValueType::Int, ValueType::String];
2847        let nested_type = Box::new(ValueType::List(Box::new(ValueType::Bool)));
2848        let nested_shape = ValueStorageShape::List(Box::new(ValueShape::Bool));
2849        let function = FunctionType::new(vec![ValueType::Int], ValueType::String);
2850        let function_shape = crate::plan::FunctionShape::new(
2851            vec![ValueShape::Parameter(parameter)],
2852            ValueShape::Parameter(parameter),
2853        );
2854        let tail_call = crate::plan::monomorphic_function_instantiation(
2855            0,
2856            crate::plan::FunctionShape::new(Vec::new(), ValueShape::Nil),
2857        );
2858
2859        let returns = [
2860            ReturnExpr::generic_body(
2861                parameter,
2862                GenericReturn::tail_call(tail_call.clone(), Vec::new()),
2863            ),
2864            ReturnExpr::generic_list_body(
2865                parameter,
2866                GenericListReturn::tail_call(tail_call.clone(), Vec::new()),
2867            ),
2868            ReturnExpr::parameter_list_list_body(
2869                parameter,
2870                ParameterListListReturn::tail_call(tail_call.clone(), Vec::new()),
2871            ),
2872            ReturnExpr::string_list_body(StringListReturn::tail_call(
2873                tail_call.clone(),
2874                Vec::new(),
2875            )),
2876            ReturnExpr::bit_array_list_body(BitArrayListReturn::tail_call(
2877                tail_call.clone(),
2878                Vec::new(),
2879            )),
2880            ReturnExpr::utf_codepoint_list_body(UtfCodepointListReturn::tail_call(
2881                tail_call.clone(),
2882                Vec::new(),
2883            )),
2884            ReturnExpr::custom_list_body(
2885                custom.clone(),
2886                CustomListReturn::tail_call(tail_call.clone(), Vec::new()),
2887            ),
2888            ReturnExpr::external_body(ExternalReturn::with_signature_shape(
2889                external_shape.clone(),
2890                ExternalExpr::panic_shape(
2891                    PanicExpr::panic_at(None, PanicSite::unknown()),
2892                    external_shape.clone(),
2893                ),
2894            )),
2895            ReturnExpr::external_list_body(
2896                external.clone(),
2897                ExternalListReturn::tail_call(tail_call.clone(), Vec::new()),
2898            ),
2899            ReturnExpr::float_list_body(FloatListReturn::tail_call(tail_call.clone(), Vec::new())),
2900            ReturnExpr::bool_list_body(BoolListReturn::tail_call(tail_call.clone(), Vec::new())),
2901            ReturnExpr::nil_list_body(NilListReturn::tail_call(tail_call.clone(), Vec::new())),
2902            ReturnExpr::tuple_list_body(
2903                tuple.clone(),
2904                TupleListReturn::tail_call(tail_call.clone(), Vec::new()),
2905            ),
2906            ReturnExpr::list_list_body(
2907                nested_shape,
2908                ListListReturn::tail_call(tail_call.clone(), Vec::new()),
2909            ),
2910            ReturnExpr::function_list_body(
2911                function.clone(),
2912                FunctionListReturn::tail_call(tail_call.clone(), Vec::new()),
2913            ),
2914            ReturnExpr::generic_function_shape_body(
2915                function_shape.clone(),
2916                GenericFunctionReturn::tail_call(tail_call.clone(), Vec::new()),
2917            ),
2918            ReturnExpr::external_function_shape_body(
2919                FunctionShape::new(
2920                    vec![ValueShape::Int],
2921                    ValueShape::External(external_shape.clone()),
2922                ),
2923                ExternalFunctionReturn::expr(ExternalFunctionExpr::panic(
2924                    PanicExpr::panic_at(None, PanicSite::unknown()),
2925                    ExternalFunctionType::from_shapes(
2926                        vec![ValueShape::Int],
2927                        external_shape.clone(),
2928                    ),
2929                )),
2930            ),
2931            ReturnExpr::bit_array_function_shape_body(
2932                function_shape.clone(),
2933                BitArrayFunctionReturn::tail_call(tail_call.clone(), Vec::new()),
2934            ),
2935            ReturnExpr::utf_codepoint_function_shape_body(
2936                function_shape.clone(),
2937                UtfCodepointFunctionReturn::tail_call(tail_call, Vec::new()),
2938            ),
2939        ];
2940
2941        assert_eq!(
2942            returns.map(|return_| return_.value_type()),
2943            [
2944                ValueType::Parameter(parameter),
2945                ValueType::List(Box::new(ValueType::Parameter(parameter))),
2946                ValueType::List(Box::new(ValueType::List(Box::new(ValueType::Parameter(
2947                    parameter,
2948                ))))),
2949                ValueType::List(Box::new(ValueType::String)),
2950                ValueType::List(Box::new(ValueType::BitArray)),
2951                ValueType::List(Box::new(ValueType::UtfCodepoint)),
2952                ValueType::List(Box::new(ValueType::Custom(custom))),
2953                ValueType::External(external.clone()),
2954                ValueType::List(Box::new(ValueType::External(external.clone()))),
2955                ValueType::List(Box::new(ValueType::Float)),
2956                ValueType::List(Box::new(ValueType::Bool)),
2957                ValueType::List(Box::new(ValueType::Nil)),
2958                ValueType::List(Box::new(ValueType::Tuple(tuple))),
2959                ValueType::List(Box::new(ValueType::List(nested_type))),
2960                ValueType::List(Box::new(ValueType::Function(Box::new(function)))),
2961                ValueType::Function(Box::new(function_shape.type_())),
2962                ValueType::Function(Box::new(FunctionType::new(
2963                    vec![ValueType::Int],
2964                    ValueType::External(external),
2965                ))),
2966                ValueType::Function(Box::new(function_shape.type_())),
2967                ValueType::Function(Box::new(function_shape.type_())),
2968            ],
2969        );
2970    }
2971
2972    #[test]
2973    fn param_binding_accessors() {
2974        let named = Param::named(ParamLocal::int(IntLocalId(0)), "x".into());
2975        let discard = Param::discard(ParamLocal::int(IntLocalId(1)));
2976
2977        assert_eq!(named.name(), Some(&"x".into()));
2978        assert_eq!(named.binding(), &ParamBinding::Named("x".into()));
2979        assert_eq!(discard.name(), None);
2980        assert_eq!(discard.binding(), &ParamBinding::Discard);
2981    }
2982
2983    #[test]
2984    fn param_local_value_type() {
2985        let parameter = TypeParameterId(0);
2986        let generic = ParamLocal::generic(GenericLocal::new(GenericLocalId(0), parameter));
2987        assert_eq!(generic.value_type(), ValueType::Parameter(parameter));
2988        assert_eq!(generic.value_shape(), ValueShape::Parameter(parameter));
2989
2990        let generic_function_type = GenericFunctionType::new(vec![ValueShape::Int], parameter);
2991        let generic_function = ParamLocal::generic_function(GenericFunctionLocal::new(
2992            GenericFunctionLocalId(0),
2993            generic_function_type.clone(),
2994        ));
2995        assert_eq!(
2996            generic_function.value_type(),
2997            ValueType::Function(Box::new(FunctionType::new(
2998                vec![ValueType::Int],
2999                ValueType::Parameter(parameter),
3000            ))),
3001        );
3002        assert_eq!(
3003            generic_function.value_shape(),
3004            ValueShape::Function(Box::new(generic_function_type.shape())),
3005        );
3006
3007        let external_shape = ExternalValueShape::any(external_type("Token"));
3008        let external = ParamLocal::external_shape(ExternalLocalId(0), external_shape.clone());
3009        assert_eq!(
3010            external.value_type(),
3011            ValueType::External(external_shape.type_().clone()),
3012        );
3013        assert_eq!(
3014            external.value_shape(),
3015            ValueShape::External(external_shape.clone()),
3016        );
3017
3018        let external_function_type =
3019            ExternalFunctionType::from_shapes(vec![ValueShape::Int], external_shape.clone());
3020        let external_function = ParamLocal::external_function(ExternalFunctionLocal::new(
3021            ExternalFunctionLocalId(0),
3022            external_function_type.clone(),
3023        ));
3024        assert_eq!(
3025            external_function.value_type(),
3026            ValueType::Function(Box::new(external_function_type.to_function_type())),
3027        );
3028        assert_eq!(
3029            external_function.value_shape(),
3030            ValueShape::Function(Box::new(FunctionShape::new(
3031                vec![ValueShape::Int],
3032                ValueShape::External(external_shape),
3033            ))),
3034        );
3035
3036        assert_eq!(ParamLocal::int(IntLocalId(0)).value_type(), ValueType::Int);
3037        assert_eq!(
3038            ParamLocal::string(crate::plan::StringLocalId(0)).value_type(),
3039            ValueType::String,
3040        );
3041        assert_eq!(
3042            ParamLocal::utf_codepoint(UtfCodepointLocalId(0)).value_type(),
3043            ValueType::UtfCodepoint,
3044        );
3045        assert_eq!(
3046            ParamLocal::float(FloatLocalId(0)).value_type(),
3047            ValueType::Float,
3048        );
3049        assert_eq!(
3050            ParamLocal::bool(BoolLocalId(0)).value_type(),
3051            ValueType::Bool,
3052        );
3053        assert_eq!(
3054            ParamLocal::nil(crate::plan::NilLocalId(0)).value_type(),
3055            ValueType::Nil,
3056        );
3057        assert_eq!(
3058            ParamLocal::list(ListLocal::int(IntListLocalId(0))).value_type(),
3059            ValueType::List(Box::new(ValueType::Int)),
3060        );
3061        assert_eq!(
3062            ParamLocal::int_function(
3063                IntFunctionLocalId(0),
3064                FunctionType::new(vec![ValueType::Int], ValueType::Int),
3065            )
3066            .value_type(),
3067            ValueType::Function(Box::new(FunctionType::new(
3068                vec![ValueType::Int],
3069                ValueType::Int,
3070            ))),
3071        );
3072        assert_eq!(
3073            ParamLocal::string_function(
3074                StringFunctionLocalId(0),
3075                FunctionType::new(vec![ValueType::String], ValueType::String),
3076            )
3077            .value_type(),
3078            ValueType::Function(Box::new(FunctionType::new(
3079                vec![ValueType::String],
3080                ValueType::String,
3081            ))),
3082        );
3083        assert_eq!(
3084            ParamLocal::utf_codepoint_function(
3085                crate::plan::UtfCodepointFunctionLocalId(0),
3086                FunctionType::new(vec![ValueType::UtfCodepoint], ValueType::UtfCodepoint,),
3087            )
3088            .value_type(),
3089            ValueType::Function(Box::new(FunctionType::new(
3090                vec![ValueType::UtfCodepoint],
3091                ValueType::UtfCodepoint,
3092            ))),
3093        );
3094        assert_eq!(
3095            ParamLocal::float_function(
3096                FloatFunctionLocalId(0),
3097                FunctionType::new(vec![ValueType::Float], ValueType::Float),
3098            )
3099            .value_type(),
3100            ValueType::Function(Box::new(FunctionType::new(
3101                vec![ValueType::Float],
3102                ValueType::Float,
3103            ))),
3104        );
3105        assert_eq!(
3106            ParamLocal::bool_function(
3107                BoolFunctionLocalId(0),
3108                FunctionType::new(vec![ValueType::Bool], ValueType::Bool),
3109            )
3110            .value_type(),
3111            ValueType::Function(Box::new(FunctionType::new(
3112                vec![ValueType::Bool],
3113                ValueType::Bool,
3114            ))),
3115        );
3116        assert_eq!(
3117            ParamLocal::nil_function(
3118                NilFunctionLocalId(0),
3119                FunctionType::new(vec![ValueType::Nil], ValueType::Nil),
3120            )
3121            .value_type(),
3122            ValueType::Function(Box::new(FunctionType::new(
3123                vec![ValueType::Nil],
3124                ValueType::Nil,
3125            ))),
3126        );
3127        assert_eq!(
3128            ParamLocal::tuple_function(
3129                TupleFunctionLocalId(0),
3130                FunctionType::new(
3131                    vec![ValueType::Tuple(vec![ValueType::Int])],
3132                    ValueType::Tuple(vec![ValueType::String]),
3133                ),
3134            )
3135            .value_type(),
3136            ValueType::Function(Box::new(FunctionType::new(
3137                vec![ValueType::Tuple(vec![ValueType::Int])],
3138                ValueType::Tuple(vec![ValueType::String]),
3139            ))),
3140        );
3141        assert_eq!(
3142            ParamLocal::list_function(crate::plan::ListFunctionLocal::from_item_type(
3143                0,
3144                FunctionType::new(
3145                    vec![ValueType::List(Box::new(ValueType::Int))],
3146                    ValueType::List(Box::new(ValueType::String)),
3147                ),
3148                ValueType::String,
3149            ))
3150            .value_type(),
3151            ValueType::Function(Box::new(FunctionType::new(
3152                vec![ValueType::List(Box::new(ValueType::Int))],
3153                ValueType::List(Box::new(ValueType::String)),
3154            ))),
3155        );
3156        assert_eq!(
3157            ParamLocal::function_function(FunctionFunctionLocal::new(
3158                FunctionFunctionLocalId(0),
3159                FunctionFunctionType::new(
3160                    Vec::new(),
3161                    FunctionType::new(Vec::new(), ValueType::Int),
3162                ),
3163            ),)
3164            .value_type(),
3165            ValueType::Function(Box::new(FunctionType::new(
3166                Vec::new(),
3167                ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Int))),
3168            ))),
3169        );
3170    }
3171
3172    #[test]
3173    fn list_return_expr_preserves_item_family() {
3174        let parameter = crate::plan::TypeParameterId(0);
3175        let generic = ListExpr::value(Vec::new(), ValueType::Parameter(parameter));
3176        assert_eq!(
3177            ListReturn::expr(generic.clone()),
3178            ListReturn::Generic {
3179                item_parameter: parameter,
3180                body: super::GenericListReturn::expr(generic.into_generic().expect("generic list"),),
3181            },
3182        );
3183
3184        let int = ListExpr::value(
3185            vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3186            ValueType::Int,
3187        );
3188        assert_eq!(
3189            ListReturn::expr(int.clone()),
3190            ListReturn::Int(IntListReturn::expr(int.into_int().expect("int list"))),
3191        );
3192
3193        let float = ListExpr::value(
3194            vec![crate::plan::Expr::float(FloatExpr::value(1.5))],
3195            ValueType::Float,
3196        );
3197        assert_eq!(
3198            ListReturn::expr(float.clone()),
3199            ListReturn::Float(FloatListReturn::expr(
3200                float.into_float().expect("float list")
3201            )),
3202        );
3203
3204        let string = ListExpr::value(
3205            vec![crate::plan::Expr::string(StringExpr::value("one".into()))],
3206            ValueType::String,
3207        );
3208        assert_eq!(
3209            ListReturn::expr(string.clone()),
3210            ListReturn::String(StringListReturn::expr(
3211                string.into_string().expect("string list"),
3212            )),
3213        );
3214
3215        let bit_array = ListExpr::value(
3216            vec![crate::plan::Expr::bit_array(
3217                BitArrayExpr::value(Vec::new()),
3218            )],
3219            ValueType::BitArray,
3220        );
3221        assert_eq!(
3222            ListReturn::expr(bit_array.clone()),
3223            ListReturn::BitArray(BitArrayListReturn::expr(
3224                bit_array.into_bit_array().expect("bit array list"),
3225            )),
3226        );
3227
3228        let utf_codepoint = ListExpr::value(
3229            vec![crate::plan::Expr::utf_codepoint(
3230                UtfCodepointExpr::local_get(UtfCodepointLocalId(0), "codepoint".into()),
3231            )],
3232            ValueType::UtfCodepoint,
3233        );
3234        assert_eq!(
3235            ListReturn::expr(utf_codepoint.clone()),
3236            ListReturn::UtfCodepoint(UtfCodepointListReturn::expr(
3237                utf_codepoint
3238                    .into_utf_codepoint()
3239                    .expect("UTF codepoint list"),
3240            )),
3241        );
3242
3243        let custom_type = custom_type();
3244        let custom = ListExpr::value(Vec::new(), ValueType::Custom(custom_type.clone()));
3245        assert_eq!(
3246            ListReturn::expr(custom.clone()),
3247            ListReturn::Custom {
3248                item_type: custom_type,
3249                body: CustomListReturn::expr(custom.into_custom().expect("custom list")),
3250            },
3251        );
3252
3253        let external_type = external_type("Token");
3254        let external = ListExpr::value(Vec::new(), ValueType::External(external_type.clone()));
3255        assert_eq!(
3256            ListReturn::expr(external.clone()),
3257            ListReturn::External {
3258                item_type: external_type,
3259                body: ExternalListReturn::expr(external.into_external().expect("external list"),),
3260            },
3261        );
3262
3263        let bool_ = ListExpr::value(
3264            vec![crate::plan::Expr::bool(BoolExpr::value(true))],
3265            ValueType::Bool,
3266        );
3267        assert_eq!(
3268            ListReturn::expr(bool_.clone()),
3269            ListReturn::Bool(BoolListReturn::expr(bool_.into_bool().expect("bool list"))),
3270        );
3271
3272        let nil = ListExpr::value(
3273            vec![crate::plan::Expr::nil(NilExpr::value())],
3274            ValueType::Nil,
3275        );
3276        assert_eq!(
3277            ListReturn::expr(nil.clone()),
3278            ListReturn::Nil(NilListReturn::expr(nil.into_nil().expect("nil list"))),
3279        );
3280
3281        let tuple = ListExpr::value(
3282            vec![crate::plan::Expr::tuple(TupleExpr::value(
3283                vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3284                vec![ValueType::Int],
3285            ))],
3286            ValueType::Tuple(vec![ValueType::Int]),
3287        );
3288        assert_eq!(
3289            ListReturn::expr(tuple.clone()),
3290            ListReturn::Tuple {
3291                item_type: vec![ValueType::Int],
3292                body: TupleListReturn::expr(tuple.into_tuple().expect("tuple list")),
3293            },
3294        );
3295
3296        let nested = ListExpr::value(
3297            vec![crate::plan::Expr::list(ListExpr::value(
3298                vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3299                ValueType::Int,
3300            ))],
3301            ValueType::List(Box::new(ValueType::Int)),
3302        );
3303        assert_eq!(
3304            ListReturn::expr(nested.clone()),
3305            ListReturn::List {
3306                item_shape: ValueStorageShape::Int,
3307                body: ListListReturn::expr(nested.into_list().expect("nested list")),
3308            },
3309        );
3310
3311        let parameter = TypeParameterId(0);
3312        let parameter_nested = ListExpr::value(
3313            Vec::new(),
3314            ValueType::List(Box::new(ValueType::Parameter(parameter))),
3315        );
3316        assert_eq!(
3317            ListReturn::expr(parameter_nested.clone()),
3318            ListReturn::ParameterList {
3319                item_parameter: parameter,
3320                body: ParameterListListReturn::expr(
3321                    parameter_nested
3322                        .into_parameter_list()
3323                        .expect("parameter-list list"),
3324                ),
3325            },
3326        );
3327
3328        let function_type = FunctionType::new(Vec::new(), ValueType::Int);
3329        let function_instantiation = crate::plan::monomorphic_function_instantiation(
3330            0,
3331            crate::plan::FunctionShape::from_function_type(function_type.clone()),
3332        );
3333        let function = ListExpr::value(
3334            vec![crate::plan::Expr::function(
3335                crate::plan::FunctionExpr::reference(crate::plan::FunctionReference::new(
3336                    function_instantiation,
3337                )),
3338            )],
3339            ValueType::Function(Box::new(function_type.clone())),
3340        );
3341        assert_eq!(
3342            ListReturn::expr(function.clone()),
3343            ListReturn::Function {
3344                item_type: function_type,
3345                body: FunctionListReturn::expr(function.into_function().expect("function list")),
3346            },
3347        );
3348    }
3349
3350    #[test]
3351    fn list_return_tail_call_preserves_item_family() {
3352        fn tail_call_function(item_type: ValueType) -> crate::plan::FunctionInstantiation {
3353            crate::plan::monomorphic_function_instantiation(
3354                0,
3355                crate::plan::FunctionShape::new(
3356                    Vec::new(),
3357                    ValueShape::List(Box::new(ValueShape::from_value_type(item_type))),
3358                ),
3359            )
3360        }
3361
3362        let parameter = crate::plan::TypeParameterId(0);
3363        let function = tail_call_function(ValueType::Parameter(parameter));
3364        assert_eq!(
3365            ListReturn::tail_call(
3366                function.clone(),
3367                ValueType::Parameter(parameter),
3368                Vec::new(),
3369            ),
3370            ListReturn::Generic {
3371                item_parameter: parameter,
3372                body: super::GenericListReturn::tail_call(function, Vec::new()),
3373            },
3374        );
3375
3376        let function = tail_call_function(ValueType::Int);
3377        assert_eq!(
3378            ListReturn::tail_call(function.clone(), ValueType::Int, Vec::new()),
3379            ListReturn::Int(IntListReturn::tail_call(function, Vec::new())),
3380        );
3381
3382        let function = tail_call_function(ValueType::Float);
3383        assert_eq!(
3384            ListReturn::tail_call(function.clone(), ValueType::Float, Vec::new()),
3385            ListReturn::Float(FloatListReturn::tail_call(function, Vec::new())),
3386        );
3387
3388        let function = tail_call_function(ValueType::String);
3389        assert_eq!(
3390            ListReturn::tail_call(function.clone(), ValueType::String, Vec::new()),
3391            ListReturn::String(StringListReturn::tail_call(function, Vec::new())),
3392        );
3393
3394        let function = tail_call_function(ValueType::BitArray);
3395        assert_eq!(
3396            ListReturn::tail_call(function.clone(), ValueType::BitArray, Vec::new()),
3397            ListReturn::BitArray(BitArrayListReturn::tail_call(function, Vec::new())),
3398        );
3399
3400        let function = tail_call_function(ValueType::UtfCodepoint);
3401        assert_eq!(
3402            ListReturn::tail_call(function.clone(), ValueType::UtfCodepoint, Vec::new()),
3403            ListReturn::UtfCodepoint(UtfCodepointListReturn::tail_call(function, Vec::new())),
3404        );
3405
3406        let custom_type = custom_type();
3407        let function = tail_call_function(ValueType::Custom(custom_type.clone()));
3408        assert_eq!(
3409            ListReturn::tail_call(
3410                function.clone(),
3411                ValueType::Custom(custom_type.clone()),
3412                Vec::new(),
3413            ),
3414            ListReturn::Custom {
3415                item_type: custom_type,
3416                body: CustomListReturn::tail_call(function, Vec::new()),
3417            },
3418        );
3419
3420        let external_type = external_type("Token");
3421        let function = tail_call_function(ValueType::External(external_type.clone()));
3422        assert_eq!(
3423            ListReturn::tail_call(
3424                function.clone(),
3425                ValueType::External(external_type.clone()),
3426                Vec::new(),
3427            ),
3428            ListReturn::External {
3429                item_type: external_type,
3430                body: ExternalListReturn::tail_call(function, Vec::new()),
3431            },
3432        );
3433
3434        let function = tail_call_function(ValueType::Bool);
3435        assert_eq!(
3436            ListReturn::tail_call(function.clone(), ValueType::Bool, Vec::new()),
3437            ListReturn::Bool(BoolListReturn::tail_call(function, Vec::new())),
3438        );
3439
3440        let function = tail_call_function(ValueType::Nil);
3441        assert_eq!(
3442            ListReturn::tail_call(function.clone(), ValueType::Nil, Vec::new()),
3443            ListReturn::Nil(NilListReturn::tail_call(function, Vec::new())),
3444        );
3445
3446        let tuple_type = vec![ValueType::Int];
3447        let function = tail_call_function(ValueType::Tuple(tuple_type.clone()));
3448        assert_eq!(
3449            ListReturn::tail_call(
3450                function.clone(),
3451                ValueType::Tuple(tuple_type.clone()),
3452                Vec::new(),
3453            ),
3454            ListReturn::Tuple {
3455                item_type: tuple_type,
3456                body: TupleListReturn::tail_call(function, Vec::new()),
3457            },
3458        );
3459
3460        let list_type = Box::new(ValueType::Int);
3461        let function = tail_call_function(ValueType::List(list_type.clone()));
3462        assert_eq!(
3463            ListReturn::tail_call(
3464                function.clone(),
3465                ValueType::List(list_type.clone()),
3466                Vec::new(),
3467            ),
3468            ListReturn::List {
3469                item_shape: ValueStorageShape::Int,
3470                body: ListListReturn::tail_call(function, Vec::new()),
3471            },
3472        );
3473
3474        let parameter = TypeParameterId(0);
3475        let parameter_list_type = Box::new(ValueType::Parameter(parameter));
3476        let function = tail_call_function(ValueType::List(parameter_list_type.clone()));
3477        assert_eq!(
3478            ListReturn::tail_call(
3479                function.clone(),
3480                ValueType::List(parameter_list_type),
3481                Vec::new(),
3482            ),
3483            ListReturn::ParameterList {
3484                item_parameter: parameter,
3485                body: ParameterListListReturn::tail_call(function, Vec::new()),
3486            },
3487        );
3488
3489        let function_type = FunctionType::new(Vec::new(), ValueType::Int);
3490        let function = tail_call_function(ValueType::Function(Box::new(function_type.clone())));
3491        assert_eq!(
3492            ListReturn::tail_call(
3493                function.clone(),
3494                ValueType::Function(Box::new(function_type.clone())),
3495                Vec::new(),
3496            ),
3497            ListReturn::Function {
3498                item_type: function_type,
3499                body: FunctionListReturn::tail_call(function, Vec::new()),
3500            },
3501        );
3502    }
3503
3504    #[test]
3505    fn list_return_cases_and_block_preserve_typed_body() {
3506        let true_ = IntListReturn::expr(
3507            ListExpr::value(
3508                vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3509                ValueType::Int,
3510            )
3511            .into_int()
3512            .expect("int list"),
3513        );
3514        let false_ = IntListReturn::expr(
3515            ListExpr::value(
3516                vec![crate::plan::Expr::int(IntExpr::value(2.into()))],
3517                ValueType::Int,
3518            )
3519            .into_int()
3520            .expect("int list"),
3521        );
3522        assert_eq!(
3523            ListReturn::try_bool_case(
3524                BoolExpr::value(true),
3525                ListReturn::Int(true_.clone()),
3526                ListReturn::Int(false_.clone()),
3527            ),
3528            Some(ListReturn::Int(IntListReturn::bool_case(
3529                BoolExpr::value(true),
3530                true_,
3531                false_,
3532            ))),
3533        );
3534
3535        let fallback = StringListReturn::expr(
3536            ListExpr::value(
3537                vec![crate::plan::Expr::string(StringExpr::value(
3538                    "fallback".into(),
3539                ))],
3540                ValueType::String,
3541            )
3542            .into_string()
3543            .expect("string list"),
3544        );
3545        let branch = StringListReturn::expr(
3546            ListExpr::value(
3547                vec![crate::plan::Expr::string(StringExpr::value(
3548                    "branch".into(),
3549                ))],
3550                ValueType::String,
3551            )
3552            .into_string()
3553            .expect("string list"),
3554        );
3555        assert_eq!(
3556            ListReturn::try_int_case(
3557                IntExpr::value(1.into()),
3558                vec![(BigInt::from(1), ListReturn::String(branch.clone()))],
3559                ListReturn::String(fallback.clone()),
3560            ),
3561            Some(ListReturn::String(StringListReturn::int_case(
3562                IntExpr::value(1.into()),
3563                vec![(BigInt::from(1), branch)],
3564                fallback,
3565            ))),
3566        );
3567
3568        let fallback = FloatListReturn::expr(
3569            ListExpr::value(
3570                vec![crate::plan::Expr::float(FloatExpr::value(1.5))],
3571                ValueType::Float,
3572            )
3573            .into_float()
3574            .expect("float list"),
3575        );
3576        let branch = FloatListReturn::expr(
3577            ListExpr::value(
3578                vec![crate::plan::Expr::float(FloatExpr::value(2.5))],
3579                ValueType::Float,
3580            )
3581            .into_float()
3582            .expect("float list"),
3583        );
3584        assert_eq!(
3585            ListReturn::try_string_case(
3586                StringExpr::value("key".into()),
3587                vec![("key".into(), ListReturn::Float(branch.clone()))],
3588                ListReturn::Float(fallback.clone()),
3589            ),
3590            Some(ListReturn::Float(FloatListReturn::string_case(
3591                StringExpr::value("key".into()),
3592                vec![("key".into(), branch)],
3593                fallback,
3594            ))),
3595        );
3596
3597        let fallback = BoolListReturn::expr(
3598            ListExpr::value(
3599                vec![crate::plan::Expr::bool(BoolExpr::value(false))],
3600                ValueType::Bool,
3601            )
3602            .into_bool()
3603            .expect("bool list"),
3604        );
3605        let branch = BoolListReturn::expr(
3606            ListExpr::value(
3607                vec![crate::plan::Expr::bool(BoolExpr::value(true))],
3608                ValueType::Bool,
3609            )
3610            .into_bool()
3611            .expect("bool list"),
3612        );
3613        assert_eq!(
3614            ListReturn::try_float_case(
3615                FloatExpr::value(1.5),
3616                vec![(1.5, ListReturn::Bool(branch.clone()))],
3617                ListReturn::Bool(fallback.clone()),
3618            ),
3619            Some(ListReturn::Bool(BoolListReturn::float_case(
3620                FloatExpr::value(1.5),
3621                vec![(1.5, branch)],
3622                fallback,
3623            ))),
3624        );
3625
3626        let return_ = NilListReturn::expr(
3627            ListExpr::value(
3628                vec![crate::plan::Expr::nil(NilExpr::value())],
3629                ValueType::Nil,
3630            )
3631            .into_nil()
3632            .expect("nil list"),
3633        );
3634        assert_eq!(
3635            ListReturn::try_block(
3636                Vec::<crate::plan::Step>::new(),
3637                ListReturn::Nil(return_.clone()),
3638            ),
3639            ListReturn::Nil(NilListReturn::block(
3640                Vec::<crate::plan::Step>::new(),
3641                return_,
3642            )),
3643        );
3644    }
3645
3646    #[test]
3647    fn list_return_case_rejects_mismatched_item_families() {
3648        assert_eq!(
3649            ListReturn::try_bool_case(
3650                BoolExpr::value(true),
3651                ListReturn::expr(ListExpr::value(
3652                    vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3653                    ValueType::Int,
3654                )),
3655                ListReturn::expr(ListExpr::value(
3656                    vec![crate::plan::Expr::string(StringExpr::value("wrong".into()))],
3657                    ValueType::String,
3658                )),
3659            ),
3660            None,
3661        );
3662        assert_eq!(
3663            ListReturn::try_int_case(
3664                IntExpr::value(1.into()),
3665                vec![(
3666                    BigInt::from(1),
3667                    ListReturn::expr(ListExpr::value(
3668                        vec![crate::plan::Expr::string(StringExpr::value("wrong".into()))],
3669                        ValueType::String,
3670                    )),
3671                )],
3672                ListReturn::expr(ListExpr::value(
3673                    vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3674                    ValueType::Int,
3675                )),
3676            ),
3677            None,
3678        );
3679        assert_eq!(
3680            ListReturn::try_int_case(
3681                IntExpr::value(1.into()),
3682                vec![(
3683                    BigInt::from(1),
3684                    ListReturn::expr(ListExpr::value(
3685                        Vec::new(),
3686                        ValueType::List(Box::new(ValueType::String)),
3687                    )),
3688                )],
3689                ListReturn::expr(ListExpr::value(
3690                    Vec::new(),
3691                    ValueType::Tuple(vec![ValueType::Int])
3692                )),
3693            ),
3694            None,
3695        );
3696        assert_eq!(
3697            ListReturn::try_int_case(
3698                IntExpr::value(1.into()),
3699                vec![(
3700                    BigInt::from(1),
3701                    ListReturn::expr(ListExpr::value(
3702                        Vec::new(),
3703                        ValueType::Function(Box::new(FunctionType::new(
3704                            Vec::new(),
3705                            ValueType::Bool
3706                        ))),
3707                    )),
3708                )],
3709                ListReturn::expr(ListExpr::value(
3710                    Vec::new(),
3711                    ValueType::List(Box::new(ValueType::String)),
3712                )),
3713            ),
3714            None,
3715        );
3716        assert_eq!(
3717            ListReturn::try_int_case(
3718                IntExpr::value(1.into()),
3719                vec![(
3720                    BigInt::from(1),
3721                    ListReturn::expr(ListExpr::value(
3722                        Vec::new(),
3723                        ValueType::Tuple(vec![ValueType::Int])
3724                    )),
3725                )],
3726                ListReturn::expr(ListExpr::value(
3727                    Vec::new(),
3728                    ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Bool))),
3729                )),
3730            ),
3731            None,
3732        );
3733    }
3734
3735    #[test]
3736    fn return_body_kind_accessor_exposes_exact_shape() {
3737        let expression = ListExpr::value(
3738            vec![crate::plan::Expr::int(IntExpr::value(1.into()))],
3739            ValueType::Int,
3740        )
3741        .into_int()
3742        .expect("int list");
3743        let body = IntListReturn::expr(expression.clone());
3744        assert_eq!(body.kind(), &ReturnBodyKind::Expr(expression));
3745    }
3746
3747    #[test]
3748    fn list_return_case_helpers_preserve_all_item_families() {
3749        let item_types = vec![
3750            ValueType::Parameter(crate::plan::TypeParameterId(0)),
3751            ValueType::Int,
3752            ValueType::Float,
3753            ValueType::String,
3754            ValueType::BitArray,
3755            ValueType::UtfCodepoint,
3756            ValueType::Custom(custom_type()),
3757            ValueType::External(external_type("Token")),
3758            ValueType::Bool,
3759            ValueType::Nil,
3760            ValueType::Tuple(vec![ValueType::Int]),
3761            ValueType::List(Box::new(ValueType::Parameter(TypeParameterId(1)))),
3762            ValueType::List(Box::new(ValueType::String)),
3763            ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Bool))),
3764        ];
3765
3766        for item_type in item_types {
3767            let true_ = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3768            let false_ = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3769            let bool_case = ListReturn::try_bool_case(BoolExpr::value(true), true_, false_);
3770            assert_eq!(
3771                bool_case.as_ref().map(list_return_item_type),
3772                Some(item_type.clone())
3773            );
3774
3775            let branch = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3776            let fallback = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3777            let int_case = ListReturn::try_int_case(
3778                IntExpr::value(1.into()),
3779                vec![(BigInt::from(1), branch)],
3780                fallback,
3781            );
3782            assert_eq!(
3783                int_case.as_ref().map(list_return_item_type),
3784                Some(item_type.clone())
3785            );
3786
3787            let branch = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3788            let fallback = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3789            let float_case =
3790                ListReturn::try_float_case(FloatExpr::value(1.5), vec![(1.5, branch)], fallback);
3791            assert_eq!(
3792                float_case.as_ref().map(list_return_item_type),
3793                Some(item_type.clone()),
3794            );
3795
3796            let branch = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3797            let fallback = ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone()));
3798            let string_case = ListReturn::try_string_case(
3799                StringExpr::value("one".into()),
3800                vec![("one".into(), branch)],
3801                fallback,
3802            );
3803            assert_eq!(
3804                string_case.as_ref().map(list_return_item_type),
3805                Some(item_type.clone()),
3806            );
3807
3808            let block = ListReturn::try_block(
3809                Vec::<crate::plan::Step>::new(),
3810                ListReturn::expr(ListExpr::value(Vec::new(), item_type.clone())),
3811            );
3812            assert_eq!(list_return_item_type(&block), item_type);
3813        }
3814    }
3815
3816    #[test]
3817    fn list_return_case_helpers_reject_clause_mismatch_for_all_item_families() {
3818        fn empty_return(item_type: ValueType) -> ListReturn {
3819            ListReturn::expr(ListExpr::value(Vec::new(), item_type))
3820        }
3821
3822        let item_types = vec![
3823            ValueType::Parameter(crate::plan::TypeParameterId(0)),
3824            ValueType::Int,
3825            ValueType::Float,
3826            ValueType::String,
3827            ValueType::BitArray,
3828            ValueType::UtfCodepoint,
3829            ValueType::Custom(custom_type()),
3830            ValueType::External(external_type("Token")),
3831            ValueType::Bool,
3832            ValueType::Nil,
3833            ValueType::Tuple(vec![ValueType::Int]),
3834            ValueType::List(Box::new(ValueType::Parameter(TypeParameterId(1)))),
3835            ValueType::List(Box::new(ValueType::String)),
3836            ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Bool))),
3837        ];
3838
3839        for item_type in item_types {
3840            let mismatched_type = if item_type == ValueType::Int {
3841                ValueType::String
3842            } else {
3843                ValueType::Int
3844            };
3845
3846            assert_eq!(
3847                ListReturn::try_int_case(
3848                    IntExpr::value(1.into()),
3849                    vec![(BigInt::from(1), empty_return(mismatched_type.clone()))],
3850                    empty_return(item_type.clone()),
3851                ),
3852                None,
3853            );
3854            assert_eq!(
3855                ListReturn::try_float_case(
3856                    FloatExpr::value(1.5),
3857                    vec![(1.5, empty_return(mismatched_type.clone()))],
3858                    empty_return(item_type.clone()),
3859                ),
3860                None,
3861            );
3862            assert_eq!(
3863                ListReturn::try_string_case(
3864                    StringExpr::value("one".into()),
3865                    vec![("one".into(), empty_return(mismatched_type))],
3866                    empty_return(item_type),
3867                ),
3868                None,
3869            );
3870        }
3871    }
3872
3873    #[test]
3874    fn list_return_case_helpers_reject_nested_item_metadata_mismatch() {
3875        fn empty_return(item_type: ValueType) -> ListReturn {
3876            ListReturn::expr(ListExpr::value(Vec::new(), item_type))
3877        }
3878
3879        fn assert_case_helpers_reject(branch_type: ValueType, fallback_type: ValueType) {
3880            assert_eq!(
3881                ListReturn::try_bool_case(
3882                    BoolExpr::value(true),
3883                    empty_return(branch_type.clone()),
3884                    empty_return(fallback_type.clone()),
3885                ),
3886                None,
3887            );
3888            assert_eq!(
3889                ListReturn::try_int_case(
3890                    IntExpr::value(1.into()),
3891                    vec![(BigInt::from(1), empty_return(branch_type.clone()))],
3892                    empty_return(fallback_type.clone()),
3893                ),
3894                None,
3895            );
3896            assert_eq!(
3897                ListReturn::try_float_case(
3898                    FloatExpr::value(1.5),
3899                    vec![(1.5, empty_return(branch_type.clone()))],
3900                    empty_return(fallback_type.clone()),
3901                ),
3902                None,
3903            );
3904            assert_eq!(
3905                ListReturn::try_string_case(
3906                    StringExpr::value("one".into()),
3907                    vec![("one".into(), empty_return(branch_type))],
3908                    empty_return(fallback_type),
3909                ),
3910                None,
3911            );
3912        }
3913
3914        assert_case_helpers_reject(
3915            ValueType::Tuple(vec![ValueType::String]),
3916            ValueType::Tuple(vec![ValueType::Int]),
3917        );
3918        assert_case_helpers_reject(
3919            ValueType::List(Box::new(ValueType::String)),
3920            ValueType::List(Box::new(ValueType::Int)),
3921        );
3922        assert_case_helpers_reject(
3923            ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::String))),
3924            ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Int))),
3925        );
3926        assert_case_helpers_reject(
3927            ValueType::External(external_type("Left")),
3928            ValueType::External(external_type("Right")),
3929        );
3930    }
3931
3932    fn list_return_item_type(return_: &ListReturn) -> ValueType {
3933        match return_ {
3934            ListReturn::Generic { item_parameter, .. } => ValueType::Parameter(*item_parameter),
3935            ListReturn::Int(_) => ValueType::Int,
3936            ListReturn::Float(_) => ValueType::Float,
3937            ListReturn::String(_) => ValueType::String,
3938            ListReturn::BitArray(_) => ValueType::BitArray,
3939            ListReturn::UtfCodepoint(_) => ValueType::UtfCodepoint,
3940            ListReturn::Custom { item_type, .. } => ValueType::Custom(item_type.clone()),
3941            ListReturn::External { item_type, .. } => ValueType::External(item_type.clone()),
3942            ListReturn::Bool(_) => ValueType::Bool,
3943            ListReturn::Nil(_) => ValueType::Nil,
3944            ListReturn::Tuple { item_type, .. } => ValueType::Tuple(item_type.clone()),
3945            ListReturn::ParameterList { item_parameter, .. } => {
3946                ValueType::List(Box::new(ValueType::Parameter(*item_parameter)))
3947            }
3948            ListReturn::List { item_shape, .. } => {
3949                ValueType::List(Box::new(item_shape.value_type()))
3950            }
3951            ListReturn::Function { item_type, .. } => {
3952                ValueType::Function(Box::new(item_type.clone()))
3953            }
3954        }
3955    }
3956}