geam_core/plan/module/expression/
arg.rs1use 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}