Skip to main content

geam_core/runtime/value/
function.rs

1use super::CaptureValue;
2use crate::plan::FunctionType;
3
4use crate::plan::execution::function::{
5    BitArrayFunctionId, BoolFunctionId, CustomFunctionId, ExternalFunctionId, FloatFunctionId,
6    FunctionFunctionId, GenericCallableId, IntFunctionId, NeverFunctionId, NilFunctionId,
7    RuntimeListFunctionId, StringFunctionId, TupleFunctionId, UtfCodepointFunctionId,
8};
9#[cfg(test)]
10use crate::plan::execution::function::{
11    CoreRuntimeFunctionId, FunctionReturnFamily, RuntimeFunctionId,
12};
13use crate::plan::execution::graph::ParamLocal;
14use crate::plan::execution::type_::CustomConstructorId;
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct FunctionValue {
18    kind: FunctionValueKind,
19}
20
21#[derive(Debug, Clone, PartialEq)]
22pub(crate) enum FunctionValueKind {
23    Generic(GenericFunctionValue),
24    Never(NeverFunctionValue),
25    Int(IntFunctionValue),
26    Float(FloatFunctionValue),
27    String(StringFunctionValue),
28    BitArray(BitArrayFunctionValue),
29    UtfCodepoint(UtfCodepointFunctionValue),
30    Custom(CustomFunctionValue),
31    External(ExternalFunctionValue),
32    Bool(BoolFunctionValue),
33    Nil(NilFunctionValue),
34    Tuple(TupleFunctionValue),
35    List(ListFunctionValue),
36    Function(FunctionFunctionValue),
37}
38
39#[derive(Debug, Clone, PartialEq)]
40pub(crate) struct GenericFunctionValue {
41    target: GenericCallableId,
42    params: Vec<ParamLocal>,
43    captures: Vec<CaptureValue>,
44    type_: FunctionType,
45}
46
47#[derive(Debug, Clone, PartialEq)]
48pub(crate) struct NeverFunctionValue {
49    runtime_id: NeverFunctionId,
50    params: Vec<ParamLocal>,
51    captures: Vec<CaptureValue>,
52    type_: FunctionType,
53}
54
55#[derive(Debug, Clone, PartialEq)]
56pub(crate) struct IntFunctionValue {
57    runtime_id: IntFunctionId,
58    params: Vec<ParamLocal>,
59    captures: Vec<CaptureValue>,
60    type_: FunctionType,
61}
62
63#[derive(Debug, Clone, PartialEq)]
64pub(crate) struct FloatFunctionValue {
65    runtime_id: FloatFunctionId,
66    params: Vec<ParamLocal>,
67    captures: Vec<CaptureValue>,
68    type_: FunctionType,
69}
70
71#[derive(Debug, Clone, PartialEq)]
72pub(crate) struct StringFunctionValue {
73    runtime_id: StringFunctionId,
74    params: Vec<ParamLocal>,
75    captures: Vec<CaptureValue>,
76    type_: FunctionType,
77}
78
79#[derive(Debug, Clone, PartialEq)]
80pub(crate) struct BitArrayFunctionValue {
81    runtime_id: BitArrayFunctionId,
82    params: Vec<ParamLocal>,
83    captures: Vec<CaptureValue>,
84    type_: FunctionType,
85}
86
87#[derive(Debug, Clone, PartialEq)]
88pub(crate) struct UtfCodepointFunctionValue {
89    runtime_id: UtfCodepointFunctionId,
90    params: Vec<ParamLocal>,
91    captures: Vec<CaptureValue>,
92    type_: FunctionType,
93}
94
95#[derive(Debug, Clone, PartialEq)]
96pub(crate) struct CustomFunctionValue {
97    target: CustomFunctionValueTarget,
98    params: Vec<ParamLocal>,
99    captures: Vec<CaptureValue>,
100    type_: FunctionType,
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub(crate) enum CustomFunctionValueTarget {
105    Function(CustomFunctionId),
106    Constructor(CustomConstructorId),
107}
108
109#[derive(Debug, Clone, PartialEq)]
110pub(crate) struct ExternalFunctionValue {
111    runtime_id: ExternalFunctionId,
112    params: Vec<ParamLocal>,
113    captures: Vec<CaptureValue>,
114    type_: FunctionType,
115}
116
117#[derive(Debug, Clone, PartialEq)]
118pub(crate) struct BoolFunctionValue {
119    runtime_id: BoolFunctionId,
120    params: Vec<ParamLocal>,
121    captures: Vec<CaptureValue>,
122    type_: FunctionType,
123}
124
125#[derive(Debug, Clone, PartialEq)]
126pub(crate) struct NilFunctionValue {
127    runtime_id: NilFunctionId,
128    params: Vec<ParamLocal>,
129    captures: Vec<CaptureValue>,
130    type_: FunctionType,
131}
132
133#[derive(Debug, Clone, PartialEq)]
134pub(crate) struct TupleFunctionValue {
135    runtime_id: TupleFunctionId,
136    params: Vec<ParamLocal>,
137    captures: Vec<CaptureValue>,
138    type_: FunctionType,
139}
140
141#[derive(Debug, Clone, PartialEq)]
142pub(crate) struct ListFunctionValue {
143    runtime_id: RuntimeListFunctionId,
144    params: Vec<ParamLocal>,
145    captures: Vec<CaptureValue>,
146    type_: FunctionType,
147}
148
149#[derive(Debug, Clone, PartialEq)]
150pub(crate) struct FunctionFunctionValue {
151    runtime_id: FunctionFunctionId,
152    params: Vec<ParamLocal>,
153    captures: Vec<CaptureValue>,
154    type_: FunctionType,
155}
156
157impl FunctionValue {
158    pub(crate) fn from_kind(kind: FunctionValueKind) -> Self {
159        Self { kind }
160    }
161
162    pub fn type_(&self) -> FunctionType {
163        match &self.kind {
164            FunctionValueKind::Generic(value) => value.type_(),
165            FunctionValueKind::Never(value) => value.type_(),
166            FunctionValueKind::Int(value) => value.type_(),
167            FunctionValueKind::Float(value) => value.type_(),
168            FunctionValueKind::String(value) => value.type_(),
169            FunctionValueKind::BitArray(value) => value.type_(),
170            FunctionValueKind::UtfCodepoint(value) => value.type_(),
171            FunctionValueKind::Custom(value) => value.type_(),
172            FunctionValueKind::External(value) => value.type_(),
173            FunctionValueKind::Bool(value) => value.type_(),
174            FunctionValueKind::Nil(value) => value.type_(),
175            FunctionValueKind::Tuple(value) => value.type_(),
176            FunctionValueKind::List(value) => value.type_(),
177            FunctionValueKind::Function(value) => value.type_(),
178        }
179    }
180
181    #[cfg(test)]
182    pub(crate) fn new(
183        runtime_id: RuntimeFunctionId,
184        params: Vec<ParamLocal>,
185        type_: FunctionType,
186    ) -> Self {
187        let kind = match runtime_id {
188            RuntimeFunctionId::Core(runtime_id) => match runtime_id {
189                CoreRuntimeFunctionId::Never(runtime_id) => FunctionValueKind::Never(
190                    NeverFunctionValue::from_evaluated(runtime_id, params, Vec::new(), type_),
191                ),
192                CoreRuntimeFunctionId::Int(runtime_id) => FunctionValueKind::Int(
193                    IntFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
194                ),
195                CoreRuntimeFunctionId::Float(runtime_id) => FunctionValueKind::Float(
196                    FloatFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
197                ),
198                CoreRuntimeFunctionId::String(runtime_id) => FunctionValueKind::String(
199                    StringFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
200                ),
201                CoreRuntimeFunctionId::BitArray(runtime_id) => FunctionValueKind::BitArray(
202                    BitArrayFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
203                ),
204                CoreRuntimeFunctionId::UtfCodepoint(runtime_id) => {
205                    FunctionValueKind::UtfCodepoint(UtfCodepointFunctionValue::new_with_captures(
206                        runtime_id,
207                        params,
208                        Vec::new(),
209                        type_,
210                    ))
211                }
212                CoreRuntimeFunctionId::Custom(id) => {
213                    FunctionValueKind::Custom(CustomFunctionValue::new_with_captures(
214                        CustomFunctionValueTarget::Function(id),
215                        params,
216                        Vec::new(),
217                        type_,
218                    ))
219                }
220                CoreRuntimeFunctionId::Bool(runtime_id) => FunctionValueKind::Bool(
221                    BoolFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
222                ),
223                CoreRuntimeFunctionId::Nil(runtime_id) => FunctionValueKind::Nil(
224                    NilFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
225                ),
226                CoreRuntimeFunctionId::Tuple { id, return_type } => {
227                    let _ = return_type;
228                    FunctionValueKind::Tuple(TupleFunctionValue::from_evaluated(
229                        id,
230                        params,
231                        Vec::new(),
232                        type_,
233                    ))
234                }
235                CoreRuntimeFunctionId::List(id) => FunctionValueKind::List(
236                    ListFunctionValue::new_with_captures(id, params, Vec::new(), type_),
237                ),
238                CoreRuntimeFunctionId::Function { id, return_type } => {
239                    let _ = return_type;
240                    FunctionValueKind::Function(FunctionFunctionValue::from_evaluated(
241                        id.runtime_id(),
242                        params,
243                        Vec::new(),
244                        type_,
245                    ))
246                }
247            },
248            RuntimeFunctionId::External(runtime_id) => FunctionValueKind::External(
249                ExternalFunctionValue::new_with_captures(runtime_id, params, Vec::new(), type_),
250            ),
251        };
252
253        Self { kind }
254    }
255
256    #[cfg(test)]
257    pub(crate) fn kind(&self) -> &FunctionValueKind {
258        &self.kind
259    }
260}
261
262impl FunctionValueKind {
263    #[cfg(test)]
264    pub(crate) fn family(&self) -> FunctionReturnFamily {
265        match self {
266            Self::Generic(_) => FunctionReturnFamily::Generic,
267            Self::Never(_) => FunctionReturnFamily::Never,
268            Self::Int(_) => FunctionReturnFamily::Int,
269            Self::Float(_) => FunctionReturnFamily::Float,
270            Self::String(_) => FunctionReturnFamily::String,
271            Self::BitArray(_) => FunctionReturnFamily::BitArray,
272            Self::UtfCodepoint(_) => FunctionReturnFamily::UtfCodepoint,
273            Self::Custom(_) => FunctionReturnFamily::Custom,
274            Self::External(_) => FunctionReturnFamily::External,
275            Self::Bool(_) => FunctionReturnFamily::Bool,
276            Self::Nil(_) => FunctionReturnFamily::Nil,
277            Self::Tuple(_) => FunctionReturnFamily::Tuple,
278            Self::List(_) => FunctionReturnFamily::List,
279            Self::Function(_) => FunctionReturnFamily::Function,
280        }
281    }
282}
283
284impl GenericFunctionValue {
285    pub(crate) fn from_evaluated(
286        target: GenericCallableId,
287        params: Vec<ParamLocal>,
288        captures: Vec<CaptureValue>,
289        type_: FunctionType,
290    ) -> Self {
291        Self {
292            target,
293            params,
294            captures,
295            type_,
296        }
297    }
298
299    pub(crate) fn type_(&self) -> FunctionType {
300        self.type_.clone()
301    }
302}
303
304impl NeverFunctionValue {
305    pub(crate) fn from_evaluated(
306        runtime_id: NeverFunctionId,
307        params: Vec<ParamLocal>,
308        captures: Vec<CaptureValue>,
309        type_: FunctionType,
310    ) -> Self {
311        Self {
312            runtime_id,
313            params,
314            captures,
315            type_,
316        }
317    }
318
319    pub(crate) fn type_(&self) -> FunctionType {
320        self.type_.clone()
321    }
322}
323
324impl IntFunctionValue {
325    #[cfg(test)]
326    pub(crate) fn new(
327        runtime_id: IntFunctionId,
328        params: Vec<ParamLocal>,
329        type_: FunctionType,
330    ) -> Self {
331        Self::new_with_captures(runtime_id, params, Vec::new(), type_)
332    }
333
334    pub(crate) fn new_with_captures(
335        runtime_id: IntFunctionId,
336        params: Vec<ParamLocal>,
337        captures: Vec<CaptureValue>,
338        type_: FunctionType,
339    ) -> Self {
340        Self {
341            runtime_id,
342            params,
343            captures,
344            type_,
345        }
346    }
347
348    pub(crate) fn type_(&self) -> FunctionType {
349        self.type_.clone()
350    }
351}
352
353impl FloatFunctionValue {
354    pub(crate) fn new_with_captures(
355        runtime_id: FloatFunctionId,
356        params: Vec<ParamLocal>,
357        captures: Vec<CaptureValue>,
358        type_: FunctionType,
359    ) -> Self {
360        Self {
361            runtime_id,
362            params,
363            captures,
364            type_,
365        }
366    }
367
368    pub(crate) fn type_(&self) -> FunctionType {
369        self.type_.clone()
370    }
371}
372
373impl StringFunctionValue {
374    pub(crate) fn new_with_captures(
375        runtime_id: StringFunctionId,
376        params: Vec<ParamLocal>,
377        captures: Vec<CaptureValue>,
378        type_: FunctionType,
379    ) -> Self {
380        Self {
381            runtime_id,
382            params,
383            captures,
384            type_,
385        }
386    }
387
388    pub(crate) fn type_(&self) -> FunctionType {
389        self.type_.clone()
390    }
391}
392
393impl BitArrayFunctionValue {
394    pub(crate) fn new_with_captures(
395        runtime_id: BitArrayFunctionId,
396        params: Vec<ParamLocal>,
397        captures: Vec<CaptureValue>,
398        type_: FunctionType,
399    ) -> Self {
400        Self {
401            runtime_id,
402            params,
403            captures,
404            type_,
405        }
406    }
407
408    pub(crate) fn type_(&self) -> FunctionType {
409        self.type_.clone()
410    }
411}
412
413impl UtfCodepointFunctionValue {
414    pub(crate) fn new_with_captures(
415        runtime_id: UtfCodepointFunctionId,
416        params: Vec<ParamLocal>,
417        captures: Vec<CaptureValue>,
418        type_: FunctionType,
419    ) -> Self {
420        Self {
421            runtime_id,
422            params,
423            captures,
424            type_,
425        }
426    }
427
428    pub(crate) fn type_(&self) -> FunctionType {
429        self.type_.clone()
430    }
431}
432
433impl CustomFunctionValue {
434    pub(crate) fn new_with_captures(
435        target: CustomFunctionValueTarget,
436        params: Vec<ParamLocal>,
437        captures: Vec<CaptureValue>,
438        type_: FunctionType,
439    ) -> Self {
440        Self {
441            target,
442            params,
443            captures,
444            type_,
445        }
446    }
447
448    pub(crate) fn type_(&self) -> FunctionType {
449        self.type_.clone()
450    }
451}
452
453impl ExternalFunctionValue {
454    pub(crate) fn new_with_captures(
455        runtime_id: ExternalFunctionId,
456        params: Vec<ParamLocal>,
457        captures: Vec<CaptureValue>,
458        type_: FunctionType,
459    ) -> Self {
460        Self {
461            runtime_id,
462            params,
463            captures,
464            type_,
465        }
466    }
467
468    pub(crate) fn type_(&self) -> FunctionType {
469        self.type_.clone()
470    }
471}
472
473impl BoolFunctionValue {
474    pub(crate) fn new_with_captures(
475        runtime_id: BoolFunctionId,
476        params: Vec<ParamLocal>,
477        captures: Vec<CaptureValue>,
478        type_: FunctionType,
479    ) -> Self {
480        Self {
481            runtime_id,
482            params,
483            captures,
484            type_,
485        }
486    }
487
488    pub(crate) fn type_(&self) -> FunctionType {
489        self.type_.clone()
490    }
491}
492
493impl NilFunctionValue {
494    pub(crate) fn new_with_captures(
495        runtime_id: NilFunctionId,
496        params: Vec<ParamLocal>,
497        captures: Vec<CaptureValue>,
498        type_: FunctionType,
499    ) -> Self {
500        Self {
501            runtime_id,
502            params,
503            captures,
504            type_,
505        }
506    }
507
508    pub(crate) fn type_(&self) -> FunctionType {
509        self.type_.clone()
510    }
511}
512
513impl TupleFunctionValue {
514    pub(crate) fn from_evaluated(
515        runtime_id: TupleFunctionId,
516        params: Vec<ParamLocal>,
517        captures: Vec<CaptureValue>,
518        type_: FunctionType,
519    ) -> Self {
520        Self {
521            runtime_id,
522            params,
523            captures,
524            type_,
525        }
526    }
527
528    pub(crate) fn type_(&self) -> FunctionType {
529        self.type_.clone()
530    }
531}
532
533impl ListFunctionValue {
534    pub(crate) fn new_with_captures(
535        runtime_id: RuntimeListFunctionId,
536        params: Vec<ParamLocal>,
537        captures: Vec<CaptureValue>,
538        type_: FunctionType,
539    ) -> Self {
540        Self {
541            runtime_id,
542            params,
543            captures,
544            type_,
545        }
546    }
547
548    pub(crate) fn type_(&self) -> FunctionType {
549        self.type_.clone()
550    }
551}
552
553impl FunctionFunctionValue {
554    pub(crate) fn from_evaluated(
555        runtime_id: FunctionFunctionId,
556        params: Vec<ParamLocal>,
557        captures: Vec<CaptureValue>,
558        type_: FunctionType,
559    ) -> Self {
560        Self {
561            runtime_id,
562            params,
563            captures,
564            type_,
565        }
566    }
567
568    pub(crate) fn type_(&self) -> FunctionType {
569        self.type_.clone()
570    }
571}
572
573impl From<GenericFunctionValue> for FunctionValue {
574    fn from(value: GenericFunctionValue) -> Self {
575        Self {
576            kind: FunctionValueKind::Generic(value),
577        }
578    }
579}
580
581impl From<NeverFunctionValue> for FunctionValue {
582    fn from(value: NeverFunctionValue) -> Self {
583        Self {
584            kind: FunctionValueKind::Never(value),
585        }
586    }
587}
588
589impl From<IntFunctionValue> for FunctionValue {
590    fn from(value: IntFunctionValue) -> Self {
591        Self {
592            kind: FunctionValueKind::Int(value),
593        }
594    }
595}
596
597impl From<FloatFunctionValue> for FunctionValue {
598    fn from(value: FloatFunctionValue) -> Self {
599        Self {
600            kind: FunctionValueKind::Float(value),
601        }
602    }
603}
604
605impl From<StringFunctionValue> for FunctionValue {
606    fn from(value: StringFunctionValue) -> Self {
607        Self {
608            kind: FunctionValueKind::String(value),
609        }
610    }
611}
612
613impl From<BitArrayFunctionValue> for FunctionValue {
614    fn from(value: BitArrayFunctionValue) -> Self {
615        Self {
616            kind: FunctionValueKind::BitArray(value),
617        }
618    }
619}
620
621impl From<UtfCodepointFunctionValue> for FunctionValue {
622    fn from(value: UtfCodepointFunctionValue) -> Self {
623        Self {
624            kind: FunctionValueKind::UtfCodepoint(value),
625        }
626    }
627}
628
629impl From<CustomFunctionValue> for FunctionValue {
630    fn from(value: CustomFunctionValue) -> Self {
631        Self {
632            kind: FunctionValueKind::Custom(value),
633        }
634    }
635}
636
637impl From<ExternalFunctionValue> for FunctionValue {
638    fn from(value: ExternalFunctionValue) -> Self {
639        Self {
640            kind: FunctionValueKind::External(value),
641        }
642    }
643}
644
645impl From<BoolFunctionValue> for FunctionValue {
646    fn from(value: BoolFunctionValue) -> Self {
647        Self {
648            kind: FunctionValueKind::Bool(value),
649        }
650    }
651}
652
653impl From<NilFunctionValue> for FunctionValue {
654    fn from(value: NilFunctionValue) -> Self {
655        Self {
656            kind: FunctionValueKind::Nil(value),
657        }
658    }
659}
660
661impl From<TupleFunctionValue> for FunctionValue {
662    fn from(value: TupleFunctionValue) -> Self {
663        Self {
664            kind: FunctionValueKind::Tuple(value),
665        }
666    }
667}
668
669impl From<ListFunctionValue> for FunctionValue {
670    fn from(value: ListFunctionValue) -> Self {
671        Self {
672            kind: FunctionValueKind::List(value),
673        }
674    }
675}
676
677impl From<FunctionFunctionValue> for FunctionValue {
678    fn from(value: FunctionFunctionValue) -> Self {
679        Self {
680            kind: FunctionValueKind::Function(value),
681        }
682    }
683}
684
685#[cfg(test)]
686mod tests {
687    use super::{FunctionValue, FunctionValueKind, GenericFunctionValue};
688    use crate::host::{
689        ExternalTestProfile, ExternalTestRunState, HostCall, HostCallCompletion, HostCallError,
690        HostExternalBinding, HostExternalSchema, HostExternalStorage, HostExternalStore,
691        HostExternalType, HostProvider, HostProviderModule, HostProviderSet,
692    };
693    use crate::plan::execution::function::{FunctionReturnFamily, GenericCallableId};
694    use crate::plan::execution::runtime::RuntimeExecutionPlan;
695    use crate::plan::{
696        CustomType, CustomTypeName, ExternalType, ExternalTypeName, FunctionType, TypeParameterId,
697        ValueType,
698    };
699    use crate::{
700        HostModule, HostedExecution, ModuleSource, PackageSource, compile_typed_host_program,
701        plan_host_program,
702    };
703    use ecow::EcoString;
704
705    struct ResourceSchema;
706
707    struct ResourceProvider;
708
709    struct ResourceStorage;
710
711    type HostResource = HostExternalType<ResourceSchema>;
712
713    impl HostExternalSchema for ResourceSchema {
714        const PACKAGE: &'static str = "application";
715        const MODULE: &'static str = "main";
716        const NAME: &'static str = "Resource";
717        const PARAMETER_COUNT: usize = 0;
718    }
719
720    impl HostExternalStorage<ExternalTestProfile, ResourceSchema> for ResourceStorage {
721        type Payload = ();
722
723        fn store(
724            stores: &<ExternalTestProfile as crate::HostProfile>::ExternalStores,
725        ) -> &HostExternalStore<Self::Payload> {
726            &stores.units
727        }
728
729        fn source_equal(
730            _: &crate::host::HostExternalEquality<'_>,
731            _: &Self::Payload,
732            _: &Self::Payload,
733        ) -> bool {
734            true
735        }
736
737        fn source_hash(_: &crate::host::HostExternalHashing<'_>, _: &Self::Payload) -> u64 {
738            0
739        }
740
741        fn inspect(_: &crate::host::HostExternalInspection<'_>, _: &Self::Payload) -> EcoString {
742            "Resource".into()
743        }
744    }
745
746    impl HostProvider<ExternalTestProfile> for ResourceProvider {
747        type State = ();
748
749        fn project(state: &mut ExternalTestRunState) -> &mut Self::State {
750            &mut state.provider
751        }
752    }
753
754    impl HostExternalBinding<ExternalTestProfile, ResourceSchema> for ResourceProvider {
755        type Storage = ResourceStorage;
756    }
757
758    fn external_main<'call>(
759        mut call: HostCall<'call, ExternalTestProfile, ResourceProvider, HostResource>,
760    ) -> Result<HostCallCompletion<'call, HostResource>, HostCallError> {
761        let _ = call.state();
762        let resource = call.create_external(());
763        Ok(call.return_value(resource))
764    }
765
766    #[test]
767    fn resource_fixture_source_hash_is_exact() {
768        let retained_hash = |_: &crate::runtime::StoredRuntimeValue| 7;
769        let hashing = crate::host::HostExternalHashing::new(&retained_hash);
770
771        assert_eq!(
772            <ResourceStorage as HostExternalStorage<ExternalTestProfile, ResourceSchema>>::source_hash(
773                &hashing,
774                &(),
775            ),
776            0,
777        );
778    }
779
780    #[test]
781    fn function_value_preserves_every_lowered_return_family() {
782        let cases = [
783            (
784                "pub fn main() -> value { panic }",
785                ValueType::Parameter(TypeParameterId(0)),
786                FunctionReturnFamily::Never,
787            ),
788            (
789                "pub fn main() -> Int { 1 }",
790                ValueType::Int,
791                FunctionReturnFamily::Int,
792            ),
793            (
794                "pub fn main() -> Float { 1.0 }",
795                ValueType::Float,
796                FunctionReturnFamily::Float,
797            ),
798            (
799                "pub fn main() -> String { \"one\" }",
800                ValueType::String,
801                FunctionReturnFamily::String,
802            ),
803            (
804                "pub fn main() -> BitArray { <<1>> }",
805                ValueType::BitArray,
806                FunctionReturnFamily::BitArray,
807            ),
808            (
809                "fn value() -> UtfCodepoint { let assert <<value:utf8_codepoint>> = <<65>> value } pub fn main() { value() }",
810                ValueType::UtfCodepoint,
811                FunctionReturnFamily::UtfCodepoint,
812            ),
813            (
814                "pub type Boxed { Boxed(Int) } pub fn main() -> Boxed { Boxed(1) }",
815                boxed_type(),
816                FunctionReturnFamily::Custom,
817            ),
818            (
819                "pub fn main() -> Bool { True }",
820                ValueType::Bool,
821                FunctionReturnFamily::Bool,
822            ),
823            (
824                "pub fn main() -> Nil { Nil }",
825                ValueType::Nil,
826                FunctionReturnFamily::Nil,
827            ),
828            (
829                "pub fn main() -> #(Int) { #(1) }",
830                ValueType::Tuple(vec![ValueType::Int]),
831                FunctionReturnFamily::Tuple,
832            ),
833            (
834                "pub fn main() -> List(Int) { [] }",
835                ValueType::List(Box::new(ValueType::Int)),
836                FunctionReturnFamily::List,
837            ),
838            (
839                "pub fn main() -> fn() -> Int { fn() { 1 } }",
840                ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Int))),
841                FunctionReturnFamily::Function,
842            ),
843        ];
844
845        for (source, return_type, family) in cases {
846            let plan = crate::runtime::plan_src(source);
847            let value = FunctionValue::new(
848                plan.main_runtime(),
849                Vec::new(),
850                FunctionType::new(Vec::new(), return_type.clone()),
851            );
852
853            assert_eq!(value.type_(), FunctionType::new(Vec::new(), return_type));
854            assert_eq!(value.kind().family(), family);
855        }
856    }
857
858    #[test]
859    fn function_value_from_preserves_every_evaluated_return_family() {
860        let cases = [
861            (
862                "pub fn main() -> value { panic }",
863                ValueType::Parameter(TypeParameterId(0)),
864            ),
865            ("pub fn main() -> Int { 1 }", ValueType::Int),
866            ("pub fn main() -> Float { 1.0 }", ValueType::Float),
867            ("pub fn main() -> String { \"one\" }", ValueType::String),
868            ("pub fn main() -> BitArray { <<1>> }", ValueType::BitArray),
869            (
870                "fn value() -> UtfCodepoint { let assert <<value:utf8_codepoint>> = <<65>> value } pub fn main() { value() }",
871                ValueType::UtfCodepoint,
872            ),
873            (
874                "pub type Boxed { Boxed(Int) } pub fn main() -> Boxed { Boxed(1) }",
875                boxed_type(),
876            ),
877            ("pub fn main() -> Bool { True }", ValueType::Bool),
878            ("pub fn main() -> Nil { Nil }", ValueType::Nil),
879            (
880                "pub fn main() -> #(Int) { #(1) }",
881                ValueType::Tuple(vec![ValueType::Int]),
882            ),
883            (
884                "pub fn main() -> List(Int) { [] }",
885                ValueType::List(Box::new(ValueType::Int)),
886            ),
887            (
888                "pub fn main() -> fn() -> Int { fn() { 1 } }",
889                ValueType::Function(Box::new(FunctionType::new(Vec::new(), ValueType::Int))),
890            ),
891        ];
892
893        for (source, return_type) in cases {
894            let plan = crate::runtime::plan_src(source);
895            let value = FunctionValue::new(
896                plan.main_runtime(),
897                Vec::new(),
898                FunctionType::new(Vec::new(), return_type.clone()),
899            );
900            assert_eq!(clone_through_family(&value), value);
901        }
902
903        let generic = GenericFunctionValue::from_evaluated(
904            GenericCallableId::Function {
905                template: 0,
906                substitution: Box::new([]),
907            },
908            Vec::new(),
909            Vec::new(),
910            FunctionType::new(
911                vec![ValueType::Parameter(crate::plan::TypeParameterId(0))],
912                ValueType::Parameter(crate::plan::TypeParameterId(0)),
913            ),
914        );
915        let value = FunctionValue::from(generic.clone());
916        assert_eq!(value.kind().family(), FunctionReturnFamily::Generic);
917        assert_eq!(clone_through_family(&value), value);
918        assert_eq!(FunctionValue::from(generic), value);
919    }
920
921    #[test]
922    fn external_function_value_preserves_its_runtime_family_and_type() {
923        let provider = HostProviderModule::<ExternalTestProfile>::new("application", "main")
924            .expect("provider module should be valid")
925            .with_external_type::<ResourceProvider, ResourceSchema>()
926            .expect("external type should be valid")
927            .with_scoped_function::<ResourceProvider, (), HostResource, _>(
928                "resource",
929                external_main,
930            )
931            .expect("external resource function should be valid");
932        let source = r#"
933@external(erlang, "host", "Resource")
934pub type Resource
935
936@external(erlang, "host", "resource")
937fn resource() -> Resource
938
939pub type Wrapped {
940  Wrapped(value: Resource)
941}
942
943fn unwrap(value: Wrapped) -> Resource {
944  value.value
945}
946
947fn resources() -> List(Resource) {
948  [resource()]
949}
950
951fn resource_provider() -> fn() -> Resource {
952  resource
953}
954
955fn resources_provider() -> fn() -> List(Resource) {
956  resources
957}
958
959pub fn main() -> Resource {
960  let selected_resource = #(resource).0
961  let selected_resources = #(resources).0
962  let selected_resource_provider = #(resource_provider).0
963  let selected_resources_provider = #(resources_provider).0
964  let assert True = selected_resource == resource
965  let assert True = selected_resources == resources
966  let assert True = selected_resource_provider == resource_provider
967  let assert True = selected_resources_provider == resources_provider
968  let first = unwrap(Wrapped(resource()))
969  let assert True = first == resource()
970  first
971}
972"#;
973        let typed = compile_typed_host_program(
974            "application",
975            "main",
976            [PackageSource::new(
977                "application",
978                Vec::<&str>::new(),
979                [ModuleSource::new("main", "main.gleam", source)],
980            )],
981            HostProviderSet::with_providers(
982                Vec::<HostModule<ExternalTestProfile>>::new(),
983                [provider],
984            )
985            .expect("provider module should be unique"),
986        )
987        .expect("external main should compile");
988        let plan = plan_host_program(typed).expect("external main should plan");
989        let execution =
990            HostedExecution::try_from_module_plan(plan).expect("external main should seal");
991        let external_type = ExternalType::new(
992            ExternalTypeName::new("application".into(), "main".into(), "Resource".into()),
993            Vec::new(),
994        );
995        let function_type =
996            FunctionType::new(Vec::new(), ValueType::External(external_type.clone()));
997        let value = FunctionValue::new(
998            RuntimeExecutionPlan::main_runtime(&execution),
999            Vec::new(),
1000            function_type.clone(),
1001        );
1002
1003        assert_eq!(value.type_(), function_type);
1004        assert_eq!(value.kind().family(), FunctionReturnFamily::External);
1005        assert_eq!(clone_through_family(&value), value);
1006
1007        let returned = execution
1008            .run_main(&mut ExternalTestRunState::default(), &mut Vec::new())
1009            .expect("external main should execute");
1010        assert_eq!(returned.inspect().to_string(), "Resource");
1011        assert_eq!(returned.value_type(), ValueType::External(external_type));
1012    }
1013
1014    fn clone_through_family(value: &FunctionValue) -> FunctionValue {
1015        match value.kind() {
1016            FunctionValueKind::Generic(value) => FunctionValue::from(value.clone()),
1017            FunctionValueKind::Never(value) => FunctionValue::from(value.clone()),
1018            FunctionValueKind::Int(value) => FunctionValue::from(value.clone()),
1019            FunctionValueKind::Float(value) => FunctionValue::from(value.clone()),
1020            FunctionValueKind::String(value) => FunctionValue::from(value.clone()),
1021            FunctionValueKind::BitArray(value) => FunctionValue::from(value.clone()),
1022            FunctionValueKind::UtfCodepoint(value) => FunctionValue::from(value.clone()),
1023            FunctionValueKind::Custom(value) => FunctionValue::from(value.clone()),
1024            FunctionValueKind::External(value) => FunctionValue::from(value.clone()),
1025            FunctionValueKind::Bool(value) => FunctionValue::from(value.clone()),
1026            FunctionValueKind::Nil(value) => FunctionValue::from(value.clone()),
1027            FunctionValueKind::Tuple(value) => FunctionValue::from(value.clone()),
1028            FunctionValueKind::List(value) => FunctionValue::from(value.clone()),
1029            FunctionValueKind::Function(value) => FunctionValue::from(value.clone()),
1030        }
1031    }
1032
1033    fn boxed_type() -> ValueType {
1034        ValueType::Custom(CustomType::new(
1035            CustomTypeName::new("geam".into(), "main".into(), "Boxed".into()),
1036            Vec::new(),
1037        ))
1038    }
1039}