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}