Skip to main content

geam_core/plan/module/expression/
arg.rs

1use super::{Expr, ExprKind, GenericExpr, TupleExpr};
2use crate::plan::ParamLocal;
3
4#[derive(Debug, Clone, PartialEq)]
5pub struct CallArg {
6    value: Expr,
7}
8
9#[derive(Debug, Clone, PartialEq)]
10pub(crate) struct CaptureArg {
11    local: ParamLocal,
12}
13
14#[cfg_attr(test, derive(Debug, PartialEq))]
15pub(crate) enum CallArgStorage<'a> {
16    Stored,
17    PotentiallyUninhabited(PotentiallyUninhabitedCallArg<'a>),
18}
19
20#[cfg_attr(test, derive(Debug, PartialEq))]
21pub(crate) enum PotentiallyUninhabitedCallArg<'a> {
22    Generic(&'a GenericExpr),
23    Tuple(&'a TupleExpr),
24    Custom(&'a super::CustomExpr),
25}
26
27impl CallArg {
28    pub(crate) fn new(value: Expr) -> Self {
29        Self { value }
30    }
31
32    pub(crate) fn value(&self) -> &Expr {
33        &self.value
34    }
35
36    pub(crate) fn storage(&self) -> CallArgStorage<'_> {
37        match self.value.kind() {
38            ExprKind::Generic(value) => CallArgStorage::PotentiallyUninhabited(
39                PotentiallyUninhabitedCallArg::Generic(value),
40            ),
41            ExprKind::Tuple(value) => {
42                CallArgStorage::PotentiallyUninhabited(PotentiallyUninhabitedCallArg::Tuple(value))
43            }
44            ExprKind::Custom(value) => {
45                CallArgStorage::PotentiallyUninhabited(PotentiallyUninhabitedCallArg::Custom(value))
46            }
47            ExprKind::Int(_)
48            | ExprKind::Float(_)
49            | ExprKind::String(_)
50            | ExprKind::BitArray(_)
51            | ExprKind::UtfCodepoint(_)
52            | ExprKind::External(_)
53            | ExprKind::Bool(_)
54            | ExprKind::Nil(_)
55            | ExprKind::List(_)
56            | ExprKind::Function(_) => CallArgStorage::Stored,
57        }
58    }
59
60    #[cfg(test)]
61    pub(crate) fn parameter_shape(&self) -> crate::plan::ValueShape {
62        self.value.shape().clone()
63    }
64}
65
66impl CaptureArg {
67    pub(crate) fn new(local: ParamLocal) -> Self {
68        Self { local }
69    }
70
71    pub(crate) fn local(&self) -> &ParamLocal {
72        &self.local
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::{CallArg, CallArgStorage, CaptureArg, PotentiallyUninhabitedCallArg};
79    use crate::plan::{
80        CustomConstructorRefinement, CustomExpr, CustomLocal, CustomLocalId, CustomTypeName,
81        CustomValueShape, Expr, FunctionExpr, FunctionReference, FunctionShape, IntExpr, ListExpr,
82        TupleExpr, TypeParameterId, ValueShape, monomorphic_function_instantiation,
83    };
84    use num_bigint::BigInt;
85
86    #[test]
87    fn call_arguments_own_expressions_and_capture_arguments_own_typed_locals() {
88        let value = Expr::int(IntExpr::value(BigInt::from(1)));
89        let local = crate::plan::ParamLocal::int(crate::plan::IntLocalId(2));
90
91        assert_eq!(CallArg::new(value.clone()).value(), &value);
92        assert_eq!(CaptureArg::new(local.clone()).local(), &local);
93        assert_eq!(CallArg::new(value).parameter_shape(), ValueShape::Int);
94    }
95
96    #[test]
97    fn call_argument_storage_distinguishes_stored_values() {
98        let list = CallArg::new(Expr::list(
99            ListExpr::try_value(
100                Vec::new(),
101                crate::plan::ValueType::Parameter(TypeParameterId(0)),
102            )
103            .expect("an empty parameter list has no mismatching element"),
104        ));
105        let function_shape = FunctionShape::new(vec![ValueShape::Int], ValueShape::Int);
106        let function = CallArg::new(Expr::function(FunctionExpr::reference(
107            FunctionReference::new(monomorphic_function_instantiation(
108                0,
109                function_shape.clone(),
110            )),
111        )));
112
113        assert_eq!(list.storage(), CallArgStorage::Stored);
114        assert_eq!(function.storage(), CallArgStorage::Stored);
115    }
116
117    #[test]
118    fn potentially_uninhabited_arguments_keep_their_typed_source() {
119        let parameter = TypeParameterId(0);
120        let generic = crate::plan::GenericExpr::panic(
121            parameter,
122            crate::plan::PanicExpr::panic_at(None, crate::plan::PanicSite::unknown()),
123        );
124        let argument = CallArg::new(Expr::generic(generic.clone()));
125
126        assert_eq!(
127            argument.storage(),
128            CallArgStorage::PotentiallyUninhabited(PotentiallyUninhabitedCallArg::Generic(
129                &generic,
130            )),
131        );
132
133        let tuple = TupleExpr::value(
134            vec![Expr::generic(generic)],
135            vec![crate::plan::ValueType::Parameter(parameter)],
136        );
137        let argument = CallArg::new(Expr::tuple(tuple.clone()));
138        assert_eq!(
139            argument.storage(),
140            CallArgStorage::PotentiallyUninhabited(PotentiallyUninhabitedCallArg::Tuple(&tuple)),
141        );
142
143        let custom = CustomExpr::local_get(
144            CustomLocal::from_shape(
145                CustomLocalId(0),
146                CustomValueShape::new(
147                    CustomTypeName::new("geam".into(), "main".into(), "Boxed".into()),
148                    vec![ValueShape::Parameter(parameter)],
149                    CustomConstructorRefinement::Exact(0),
150                ),
151            ),
152            "boxed".into(),
153        );
154        let argument = CallArg::new(Expr::custom(custom.clone()));
155        assert_eq!(
156            argument.storage(),
157            CallArgStorage::PotentiallyUninhabited(PotentiallyUninhabitedCallArg::Custom(&custom)),
158        );
159    }
160}