1use std::fmt;
15use std::sync::Arc;
16
17use crate::jet::Jet;
18use crate::node::{DisconnectConstructible, NoDisconnect};
19use crate::types::{Context, Error, Final, Type};
20use crate::value::Word;
21
22use super::variable::new_name;
23
24#[derive(Debug)]
27pub struct Arrow<'brand> {
28 pub source: Type<'brand>,
30 pub target: Type<'brand>,
32 pub inference_context: Context<'brand>,
34}
35
36impl Clone for Arrow<'_> {
40 fn clone(&self) -> Self {
41 self.shallow_clone()
42 }
43}
44
45impl fmt::Display for Arrow<'_> {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f, "{} → {}", self.source, self.target)
48 }
49}
50
51#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
54pub struct FinalArrow {
55 pub source: Arc<Final>,
57 pub target: Arc<Final>,
59}
60
61impl fmt::Display for FinalArrow {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 write!(f, "{} → {}", self.source, self.target)
64 }
65}
66
67impl FinalArrow {
68 pub fn shallow_clone(&self) -> Self {
70 Self {
71 source: Arc::clone(&self.source),
72 target: Arc::clone(&self.target),
73 }
74 }
75}
76
77impl<'brand> Arrow<'brand> {
78 pub fn finalize(&self) -> Result<FinalArrow, Error> {
80 Ok(FinalArrow {
81 source: self.source.finalize()?,
82 target: self.target.finalize()?,
83 })
84 }
85
86 pub fn shallow_clone(&self) -> Self {
88 Self {
89 source: self.source.shallow_clone(),
90 target: self.target.shallow_clone(),
91 inference_context: self.inference_context.shallow_clone(),
92 }
93 }
94
95 fn for_case(lchild_arrow: Option<&Self>, rchild_arrow: Option<&Self>) -> Result<Self, Error> {
105 if let (Some(left), Some(right)) = (lchild_arrow, rchild_arrow) {
106 left.inference_context.check_eq(&right.inference_context)?;
107 }
108
109 let ctx = match (lchild_arrow, rchild_arrow) {
110 (Some(left), _) => left.inference_context.shallow_clone(),
111 (_, Some(right)) => right.inference_context.shallow_clone(),
112 (None, None) => panic!("called `for_case` with no children"),
113 };
114
115 let a = Type::free(&ctx, new_name("case_a_"));
116 let b = Type::free(&ctx, new_name("case_b_"));
117 let c = Type::free(&ctx, new_name("case_c_"));
118
119 let sum_a_b = Type::sum(&ctx, a.shallow_clone(), b.shallow_clone());
120 let prod_sum_a_b_c = Type::product(&ctx, sum_a_b, c.shallow_clone());
121
122 let target = Type::free(&ctx, String::new());
123 if let Some(lchild_arrow) = lchild_arrow {
124 ctx.bind_product(
125 &lchild_arrow.source,
126 &a,
127 &c,
128 "case combinator: left source = A × C",
129 )?;
130 ctx.unify(&target, &lchild_arrow.target, "").unwrap();
131 }
132 if let Some(rchild_arrow) = rchild_arrow {
133 ctx.bind_product(
134 &rchild_arrow.source,
135 &b,
136 &c,
137 "case combinator: left source = B × C",
138 )?;
139 ctx.unify(
140 &target,
141 &rchild_arrow.target,
142 "case combinator: left target = right target",
143 )?;
144 }
145
146 Ok(Self {
147 source: prod_sum_a_b_c,
148 target,
149 inference_context: ctx,
150 })
151 }
152
153 fn for_disconnect(lchild_arrow: &Self, rchild_arrow: &Self) -> Result<Self, Error> {
155 lchild_arrow
156 .inference_context
157 .check_eq(&rchild_arrow.inference_context)?;
158
159 let ctx = lchild_arrow.inference_context();
160 let a = Type::free(ctx, new_name("disconnect_a_"));
161 let b = Type::free(ctx, new_name("disconnect_b_"));
162 let c = rchild_arrow.source.shallow_clone();
163 let d = rchild_arrow.target.shallow_clone();
164
165 ctx.bind_product(
166 &lchild_arrow.source,
167 &Type::two_two_n(ctx, 8),
168 &a,
169 "disconnect combinator: left source = 2^256 × A",
170 )?;
171 ctx.bind_product(
172 &lchild_arrow.target,
173 &b,
174 &c,
175 "disconnect combinator: left target = B × C",
176 )?;
177
178 let prod_b_d = Type::product(ctx, b, d);
179
180 Ok(Self {
181 source: a,
182 target: prod_b_d,
183 inference_context: lchild_arrow.inference_context.shallow_clone(),
184 })
185 }
186
187 pub fn hidden(inference_context: &Context<'brand>) -> Self {
192 Self {
193 source: Type::free(inference_context, new_name("hidden_src_")),
194 target: Type::free(inference_context, new_name("hidden_tgt_")),
195 inference_context: inference_context.shallow_clone(),
196 }
197 }
198
199 pub fn program(inference_context: &Context<'brand>) -> Self {
201 Self {
202 source: Type::unit(inference_context),
203 target: Type::unit(inference_context),
204 inference_context: inference_context.shallow_clone(),
205 }
206 }
207
208 pub fn iden(inference_context: &Context<'brand>) -> Self {
209 let new = Type::free(inference_context, new_name("iden_src_"));
215 Self {
216 source: new.shallow_clone(),
217 target: new,
218 inference_context: inference_context.shallow_clone(),
219 }
220 }
221
222 pub fn unit(inference_context: &Context<'brand>) -> Self {
223 Self {
224 source: Type::free(inference_context, new_name("unit_src_")),
225 target: Type::unit(inference_context),
226 inference_context: inference_context.shallow_clone(),
227 }
228 }
229
230 pub fn injl(child: &Self) -> Self {
231 Self {
232 source: child.source.shallow_clone(),
233 target: Type::sum(
234 &child.inference_context,
235 child.target.shallow_clone(),
236 Type::free(&child.inference_context, new_name("injl_tgt_")),
237 ),
238 inference_context: child.inference_context.shallow_clone(),
239 }
240 }
241
242 pub fn injr(child: &Self) -> Self {
243 Self {
244 source: child.source.shallow_clone(),
245 target: Type::sum(
246 &child.inference_context,
247 Type::free(&child.inference_context, new_name("injr_tgt_")),
248 child.target.shallow_clone(),
249 ),
250 inference_context: child.inference_context.shallow_clone(),
251 }
252 }
253
254 pub fn take(child: &Self) -> Self {
255 Self {
256 source: Type::product(
257 &child.inference_context,
258 child.source.shallow_clone(),
259 Type::free(&child.inference_context, new_name("take_src_")),
260 ),
261 target: child.target.shallow_clone(),
262 inference_context: child.inference_context.shallow_clone(),
263 }
264 }
265
266 pub fn drop_(child: &Self) -> Self {
267 Self {
268 source: Type::product(
269 &child.inference_context,
270 Type::free(&child.inference_context, new_name("drop_src_")),
271 child.source.shallow_clone(),
272 ),
273 target: child.target.shallow_clone(),
274 inference_context: child.inference_context.shallow_clone(),
275 }
276 }
277
278 pub fn comp(left: &Self, right: &Self) -> Result<Self, Error> {
279 left.inference_context.check_eq(&right.inference_context)?;
280 left.inference_context.unify(
281 &left.target,
282 &right.source,
283 "comp combinator: left target = right source",
284 )?;
285 Ok(Self {
286 source: left.source.shallow_clone(),
287 target: right.target.shallow_clone(),
288 inference_context: left.inference_context.shallow_clone(),
289 })
290 }
291
292 pub fn case(left: &Self, right: &Self) -> Result<Self, Error> {
293 Self::for_case(Some(left), Some(right))
294 }
295
296 pub fn assertl(left: &Self) -> Result<Self, Error> {
297 Self::for_case(Some(left), None)
298 }
299
300 pub fn assertr(right: &Self) -> Result<Self, Error> {
301 Self::for_case(None, Some(right))
302 }
303
304 pub fn pair(left: &Self, right: &Self) -> Result<Self, Error> {
305 left.inference_context.check_eq(&right.inference_context)?;
306 left.inference_context.unify(
307 &left.source,
308 &right.source,
309 "pair combinator: left source = right source",
310 )?;
311 Ok(Self {
312 source: left.source.shallow_clone(),
313 target: Type::product(
314 &left.inference_context,
315 left.target.shallow_clone(),
316 right.target.shallow_clone(),
317 ),
318 inference_context: left.inference_context.shallow_clone(),
319 })
320 }
321
322 pub fn fail(inference_context: &Context<'brand>) -> Self {
323 Self {
324 source: Type::free(inference_context, new_name("fail_src_")),
325 target: Type::free(inference_context, new_name("fail_tgt_")),
326 inference_context: inference_context.shallow_clone(),
327 }
328 }
329
330 pub fn const_word(inference_context: &Context<'brand>, word: &Word) -> Self {
331 Self {
332 source: Type::unit(inference_context),
333 target: Type::two_two_n(inference_context, word.n()),
334 inference_context: inference_context.shallow_clone(),
335 }
336 }
337
338 pub fn jet(inference_context: &Context<'brand>, jet: &dyn Jet) -> Self {
339 inference_context.check_jet(jet);
340
341 Self {
342 source: jet.source_ty().to_type(inference_context),
343 target: jet.target_ty().to_type(inference_context),
344 inference_context: inference_context.shallow_clone(),
345 }
346 }
347
348 pub fn witness(inference_context: &Context<'brand>) -> Self {
349 Self {
350 source: Type::free(inference_context, new_name("witness_src_")),
351 target: Type::free(inference_context, new_name("witness_tgt_")),
352 inference_context: inference_context.shallow_clone(),
353 }
354 }
355
356 pub fn inference_context(&self) -> &Context<'brand> {
357 &self.inference_context
358 }
359}
360
361impl<'brand> DisconnectConstructible<'brand, Self> for Arrow<'brand> {
362 fn disconnect(left: &Self, right: &Self) -> Result<Self, Error> {
363 Self::for_disconnect(left, right)
364 }
365}
366
367impl<'brand> DisconnectConstructible<'brand, NoDisconnect> for Arrow<'brand> {
368 fn disconnect(left: &Self, _: &NoDisconnect) -> Result<Self, Error> {
369 let source = Type::free(&left.inference_context, "disc_src".into());
370 let target = Type::free(&left.inference_context, "disc_tgt".into());
371 Self::for_disconnect(
372 left,
373 &Self {
374 source,
375 target,
376 inference_context: left.inference_context.shallow_clone(),
377 },
378 )
379 }
380}
381
382impl<'brand> DisconnectConstructible<'brand, Option<&Self>> for Arrow<'brand> {
383 fn disconnect(left: &Self, right: &Option<&Self>) -> Result<Self, Error> {
384 match *right {
385 Some(right) => Self::disconnect(left, right),
386 None => Self::disconnect(left, &NoDisconnect),
387 }
388 }
389}