rain_lang/value/
lambda.rs1use smallvec::{smallvec, SmallVec};
6use crate::graph::region::Region;
7use super::{
8 ValId, ValueEnum, ValueData, Value, ValueDesc,
9 error::{ValueError, IncomparableRegions, RegionAlreadyFused, RegionError},
10 expr::SMALL_SEXPR_SIZE
11};
12
13pub const SMALL_RESULT_SIZE: usize = SMALL_SEXPR_SIZE;
15
16#[derive(Debug, Clone, PartialEq, Hash, Eq)]
18pub struct Lambda {
19 region: Region,
21 results: SmallVec<[ValId; SMALL_RESULT_SIZE]>
23}
24
25impl Lambda {
26 pub fn new(region: Region, results: SmallVec<[ValId; SMALL_RESULT_SIZE]>)
28 -> Result<Lambda, RegionError> {
29 {
31 let mut params = region.params_mut();
32 if params.fused() { return Err(RegionAlreadyFused.into()) }
33 for result in results.iter() {
35 let result_region = &result.data().region;
36 if !(result_region >= ®ion) {
37 let err = IncomparableRegions(
38 smallvec![region.downgrade(), result_region.clone()]
39 );
40 return Err(err.into())
41 }
42 }
43 params.fuse();
44 }
45 Ok(Lambda { region, results })
46 }
47 pub fn region(&self) -> &Region { &self.region }
49 pub fn results(&self) -> &[ValId] { &self.results }
51 pub fn dependencies(&self) -> std::slice::Iter<ValId> { self.results().iter() }
53}
54
55impl From<Lambda> for ValueEnum {
56 fn from(lambda: Lambda) -> ValueEnum { ValueEnum::Lambda(lambda) }
57}
58
59impl From<Lambda> for ValueData {
60 fn from(lambda: Lambda) -> ValueData {
61 let region = lambda.region().parent.clone();
62 ValueData::with_region(lambda.into(), region)
63 }
64}
65
66impl From<Lambda> for ValId {
67 fn from(lambda: Lambda) -> ValId {
68 ValId::try_new(ValueData::from(lambda)).expect("Impossible")
69 }
70}
71
72impl ValueDesc for Lambda {
73 type Err = ValueError;
74}
75
76impl Value for Lambda {}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::value::primitive::logical::Bool;
82 use crate::assert_jeq;
83
84 #[test]
85 fn invalid_nested_lambda_result_fails() {
86 let region = Region::new();
87 let nested_region = Region::new_in(region.downgrade());
88 let (iy, y) = nested_region.add_with_ty(Bool.into());
89 assert_eq!(iy, 0);
90 let err = Lambda::new(region.clone(), smallvec![y.clone()])
91 .expect_err("This is an invalid function");
92 match err {
93 RegionError::IncomparableRegions(err) => {
94 assert!(
95 err.0.as_slice() == &[region.downgrade(), nested_region.downgrade()]
96 || err.0.as_slice() == &[nested_region.downgrade(), region.downgrade()]
97 )
98 },
99 err => panic!("Wrong error {:?} (expected incomparable regions)", err)
100 }
101 }
102
103 #[test]
104 fn lambda_on_fused_region_fails() {
105 let region = Region::new();
106 { region.params_mut().fuse(); }
107 let t = ValId::from(true);
108 let err = Lambda::new(region.clone(), smallvec![t.clone()])
109 .expect_err("This function's region is invalid");
110 match err {
111 RegionError::RegionAlreadyFused(_) => {},
112 err => panic!("Wrong error {:?} (expected region already fused)", err)
113 }
114 }
115
116 #[test]
117 fn constant_bool_lambda() {
118 let region = Region::new();
119 let t = ValId::from(true);
120 let lambda = Lambda::new(region.clone(), smallvec![t.clone()])
121 .expect("This is a valid function");
122 assert_eq!(lambda.region(), ®ion);
123 assert_eq!(lambda.results().len(), 1);
124 assert_jeq!(lambda.results()[0], &t);
125 let lambda = ValId::from(lambda);
126 let _ = lambda;
128 }
129
130 #[test]
131 fn identity_bool_lambda() {
132 let region = Region::new();
133 let (_, x) = region.add_with_ty(Bool.into());
134 let lambda = Lambda::new(region.clone(), smallvec![x.clone()])
135 .expect("This is a valid function");
136 assert_eq!(lambda.region(), ®ion);
137 assert_eq!(lambda.results().len(), 1);
138 assert_eq!(lambda.results()[0], x);
139 let lambda = ValId::from(lambda);
140 let _ = lambda;
142 }
143}