1use crate::dag::{InternalSharing, PostOrderIterItem};
4use crate::jet::Jet;
5use crate::types::{self, arrow::Arrow};
6use crate::{encode, BitIter, BitWriter, Cmr, FailEntropy, RedeemNode, Value, Word};
7
8use std::io;
9use std::marker::PhantomData;
10use std::sync::Arc;
11
12use super::{
13 Commit, CommitData, CommitNode, Converter, Inner, Marker, NoDisconnect, NoWitness, Node,
14 Redeem, RedeemData,
15};
16use super::{CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible};
17
18#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
23pub enum ConstructId {}
24
25#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
26pub struct Construct<J> {
27 never: std::convert::Infallible,
29 phantom: std::marker::PhantomData<J>,
31}
32
33impl<J: Jet> Marker for Construct<J> {
34 type CachedData = ConstructData<J>;
35 type Witness = Option<Value>;
36 type Disconnect = Option<Arc<ConstructNode<J>>>;
37 type SharingId = ConstructId;
38 type Jet = J;
39
40 fn compute_sharing_id(_: Cmr, _: &ConstructData<J>) -> Option<ConstructId> {
41 None
42 }
43}
44
45pub type ConstructNode<J> = Node<Construct<J>>;
46
47impl<J: Jet> ConstructNode<J> {
48 pub fn arrow(&self) -> &Arrow {
50 self.data.arrow()
51 }
52
53 pub fn set_arrow_to_program(&self) -> Result<(), types::Error> {
55 let ctx = self.data.inference_context();
56 let unit_ty = types::Type::unit(ctx);
57 ctx.unify(
58 &self.arrow().source,
59 &unit_ty,
60 "setting root source to unit",
61 )?;
62 ctx.unify(
63 &self.arrow().target,
64 &unit_ty,
65 "setting root target to unit",
66 )?;
67 Ok(())
68 }
69
70 pub fn finalize_types(&self) -> Result<Arc<CommitNode<J>>, crate::Error> {
77 self.set_arrow_to_program()?;
78 self.finalize_types_non_program()
79 }
80
81 pub fn finalize_types_non_program(&self) -> Result<Arc<CommitNode<J>>, crate::Error> {
85 struct FinalizeTypes<J: Jet>(PhantomData<J>);
86
87 impl<J: Jet> Converter<Construct<J>, Commit<J>> for FinalizeTypes<J> {
88 type Error = crate::Error;
89 fn convert_witness(
90 &mut self,
91 _: &PostOrderIterItem<&ConstructNode<J>>,
92 _: &Option<Value>,
93 ) -> Result<NoWitness, Self::Error> {
94 Ok(NoWitness)
95 }
96
97 fn convert_disconnect(
98 &mut self,
99 _: &PostOrderIterItem<&ConstructNode<J>>,
100 _: Option<&Arc<CommitNode<J>>>,
101 _: &Option<Arc<ConstructNode<J>>>,
102 ) -> Result<NoDisconnect, Self::Error> {
103 Ok(NoDisconnect)
104 }
105
106 fn convert_data(
107 &mut self,
108 data: &PostOrderIterItem<&ConstructNode<J>>,
109 inner: Inner<&Arc<CommitNode<J>>, J, &NoDisconnect, &NoWitness>,
110 ) -> Result<Arc<CommitData<J>>, Self::Error> {
111 let converted_data = inner.map(|node| node.cached_data());
112 CommitData::new(&data.node.data.arrow, converted_data)
113 .map(Arc::new)
114 .map_err(crate::Error::from)
115 }
116 }
117
118 self.convert::<InternalSharing, _, _>(&mut FinalizeTypes(PhantomData))
119 }
120
121 pub fn finalize_unpruned(&self) -> Result<Arc<RedeemNode<J>>, crate::Error> {
134 struct Finalizer<J>(PhantomData<J>);
135
136 impl<J: Jet> Converter<Construct<J>, Redeem<J>> for Finalizer<J> {
137 type Error = crate::Error;
138
139 fn convert_witness(
140 &mut self,
141 data: &PostOrderIterItem<&ConstructNode<J>>,
142 wit: &Option<Value>,
143 ) -> Result<Value, Self::Error> {
144 if let Some(ref wit) = wit {
145 Ok(wit.shallow_clone())
146 } else {
147 let ty = data.node.arrow().target.finalize()?;
163 Ok(Value::zero(&ty))
164 }
165 }
166
167 fn convert_disconnect(
168 &mut self,
169 _: &PostOrderIterItem<&ConstructNode<J>>,
170 maybe_converted: Option<&Arc<RedeemNode<J>>>,
171 _: &Option<Arc<ConstructNode<J>>>,
172 ) -> Result<Arc<RedeemNode<J>>, Self::Error> {
173 if let Some(child) = maybe_converted {
174 Ok(Arc::clone(child))
175 } else {
176 Err(crate::Error::DisconnectRedeemTime)
177 }
178 }
179
180 fn convert_data(
181 &mut self,
182 data: &PostOrderIterItem<&ConstructNode<J>>,
183 inner: Inner<&Arc<RedeemNode<J>>, J, &Arc<RedeemNode<J>>, &Value>,
184 ) -> Result<Arc<RedeemData<J>>, Self::Error> {
185 let converted_data = inner
186 .map(|node| node.cached_data())
187 .map_disconnect(|node| node.cached_data())
188 .map_witness(Value::shallow_clone);
189 Ok(Arc::new(RedeemData::new(
190 data.node.arrow().finalize()?,
191 converted_data,
192 )))
193 }
194 }
195
196 self.convert::<InternalSharing, _, _>(&mut Finalizer(PhantomData))
197 }
198
199 pub fn finalize_pruned(
212 &self,
213 env: &J::Environment,
214 ) -> Result<Arc<RedeemNode<J>>, crate::Error> {
215 let unpruned = self.finalize_unpruned()?;
216 unpruned.prune(env).map_err(crate::Error::Execution)
217 }
218
219 pub fn decode<I: Iterator<Item = u8>>(
229 mut bits: BitIter<I>,
230 ) -> Result<Arc<Self>, crate::decode::Error> {
231 let res = crate::decode::decode_expression(&mut bits)?;
232 bits.close()?;
233 Ok(res)
234 }
235
236 pub fn encode<W: io::Write>(&self, w: &mut BitWriter<W>) -> io::Result<usize> {
238 let program_bits = encode::encode_program(self, w)?;
239 w.flush_all()?;
240 Ok(program_bits)
241 }
242}
243
244#[derive(Clone, Debug)]
245pub struct ConstructData<J> {
246 arrow: Arrow,
247 phantom: PhantomData<J>,
251}
252
253impl<J: Jet> ConstructData<J> {
254 pub fn new(arrow: Arrow) -> Self {
256 ConstructData {
257 arrow,
258 phantom: PhantomData,
259 }
260 }
261
262 pub fn arrow(&self) -> &Arrow {
264 &self.arrow
265 }
266}
267
268impl<J> CoreConstructible for ConstructData<J> {
269 fn iden(inference_context: &types::Context) -> Self {
270 ConstructData {
271 arrow: Arrow::iden(inference_context),
272 phantom: PhantomData,
273 }
274 }
275
276 fn unit(inference_context: &types::Context) -> Self {
277 ConstructData {
278 arrow: Arrow::unit(inference_context),
279 phantom: PhantomData,
280 }
281 }
282
283 fn injl(child: &Self) -> Self {
284 ConstructData {
285 arrow: Arrow::injl(&child.arrow),
286 phantom: PhantomData,
287 }
288 }
289
290 fn injr(child: &Self) -> Self {
291 ConstructData {
292 arrow: Arrow::injr(&child.arrow),
293 phantom: PhantomData,
294 }
295 }
296
297 fn take(child: &Self) -> Self {
298 ConstructData {
299 arrow: Arrow::take(&child.arrow),
300 phantom: PhantomData,
301 }
302 }
303
304 fn drop_(child: &Self) -> Self {
305 ConstructData {
306 arrow: Arrow::drop_(&child.arrow),
307 phantom: PhantomData,
308 }
309 }
310
311 fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
312 Ok(ConstructData {
313 arrow: Arrow::comp(&left.arrow, &right.arrow)?,
314 phantom: PhantomData,
315 })
316 }
317
318 fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
319 Ok(ConstructData {
320 arrow: Arrow::case(&left.arrow, &right.arrow)?,
321 phantom: PhantomData,
322 })
323 }
324
325 fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error> {
326 Ok(ConstructData {
327 arrow: Arrow::assertl(&left.arrow, right)?,
328 phantom: PhantomData,
329 })
330 }
331
332 fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error> {
333 Ok(ConstructData {
334 arrow: Arrow::assertr(left, &right.arrow)?,
335 phantom: PhantomData,
336 })
337 }
338
339 fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
340 Ok(ConstructData {
341 arrow: Arrow::pair(&left.arrow, &right.arrow)?,
342 phantom: PhantomData,
343 })
344 }
345
346 fn fail(inference_context: &types::Context, entropy: FailEntropy) -> Self {
347 ConstructData {
348 arrow: Arrow::fail(inference_context, entropy),
349 phantom: PhantomData,
350 }
351 }
352
353 fn const_word(inference_context: &types::Context, word: Word) -> Self {
354 ConstructData {
355 arrow: Arrow::const_word(inference_context, word),
356 phantom: PhantomData,
357 }
358 }
359
360 fn inference_context(&self) -> &types::Context {
361 self.arrow.inference_context()
362 }
363}
364
365impl<J: Jet> DisconnectConstructible<Option<Arc<ConstructNode<J>>>> for ConstructData<J> {
366 fn disconnect(
367 left: &Self,
368 right: &Option<Arc<ConstructNode<J>>>,
369 ) -> Result<Self, types::Error> {
370 let right = right.as_ref();
371 Ok(ConstructData {
372 arrow: Arrow::disconnect(&left.arrow, &right.map(|n| n.arrow()))?,
373 phantom: PhantomData,
374 })
375 }
376}
377
378impl<J> WitnessConstructible<Option<Value>> for ConstructData<J> {
379 fn witness(inference_context: &types::Context, _witness: Option<Value>) -> Self {
380 ConstructData {
381 arrow: Arrow::witness(inference_context, NoWitness),
382 phantom: PhantomData,
383 }
384 }
385}
386
387impl<J: Jet> JetConstructible<J> for ConstructData<J> {
388 fn jet(inference_context: &types::Context, jet: J) -> Self {
389 ConstructData {
390 arrow: Arrow::jet(inference_context, jet),
391 phantom: PhantomData,
392 }
393 }
394}
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399 use crate::jet::Core;
400 use crate::types::Final;
401 use crate::Value;
402
403 #[test]
404 fn occurs_check_error() {
405 let ctx = types::Context::new();
406 let iden = Arc::<ConstructNode<Core>>::iden(&ctx);
407 let node = Arc::<ConstructNode<Core>>::disconnect(&iden, &Some(Arc::clone(&iden))).unwrap();
408
409 assert!(matches!(
410 node.finalize_types_non_program(),
411 Err(crate::Error::Type(types::Error::OccursCheck { .. })),
412 ));
413 }
414
415 #[test]
416 fn occurs_check_2() {
417 let ctx = types::Context::new();
418 let iden = Arc::<ConstructNode<Core>>::iden(&ctx);
420 let injr = Arc::<ConstructNode<Core>>::injr(&iden);
421 let pair = Arc::<ConstructNode<Core>>::pair(&injr, &iden).unwrap();
422 let drop = Arc::<ConstructNode<Core>>::drop_(&pair);
423
424 let case1 = Arc::<ConstructNode<Core>>::case(&drop, &drop).unwrap();
425 let case2 = Arc::<ConstructNode<Core>>::case(&case1, &case1).unwrap();
426
427 let comp1 = Arc::<ConstructNode<Core>>::comp(&case2, &case2).unwrap();
428 let comp2 = Arc::<ConstructNode<Core>>::comp(&comp1, &case1).unwrap();
429
430 assert!(matches!(
431 comp2.finalize_types_non_program(),
432 Err(crate::Error::Type(types::Error::OccursCheck { .. })),
433 ));
434 }
435
436 #[test]
437 fn occurs_check_3() {
438 let ctx = types::Context::new();
439 let wit = Arc::<ConstructNode<Core>>::witness(&ctx, None);
441 let drop = Arc::<ConstructNode<Core>>::drop_(&wit);
442
443 let comp1 = Arc::<ConstructNode<Core>>::comp(&drop, &drop).unwrap();
444 let comp2 = Arc::<ConstructNode<Core>>::comp(&comp1, &comp1).unwrap();
445 let comp3 = Arc::<ConstructNode<Core>>::comp(&comp2, &comp2).unwrap();
446 let comp4 = Arc::<ConstructNode<Core>>::comp(&comp3, &comp3).unwrap();
447 let comp5 = Arc::<ConstructNode<Core>>::comp(&comp4, &comp4).unwrap();
448
449 let case = Arc::<ConstructNode<Core>>::case(&comp5, &comp4).unwrap();
450 let drop2 = Arc::<ConstructNode<Core>>::drop_(&case);
451 let case2 = Arc::<ConstructNode<Core>>::case(&drop2, &case).unwrap();
452 let comp6 = Arc::<ConstructNode<Core>>::comp(&case2, &case2).unwrap();
453 let case3 = Arc::<ConstructNode<Core>>::case(&comp6, &comp6).unwrap();
454
455 let comp7 = Arc::<ConstructNode<Core>>::comp(&case3, &case3).unwrap();
456 let comp8 = Arc::<ConstructNode<Core>>::comp(&comp7, &comp7).unwrap();
457
458 assert!(matches!(
459 comp8.finalize_types_non_program(),
460 Err(crate::Error::Type(types::Error::OccursCheck { .. })),
461 ));
462 }
463
464 #[test]
465 fn type_check_error() {
466 let ctx = types::Context::new();
467 let unit = Arc::<ConstructNode<Core>>::unit(&ctx);
468 let case = Arc::<ConstructNode<Core>>::case(&unit, &unit).unwrap();
469
470 assert!(matches!(
471 Arc::<ConstructNode<Core>>::disconnect(&case, &Some(unit)),
472 Err(types::Error::Bind { .. }),
473 ));
474 }
475
476 #[test]
477 fn scribe() {
478 let ctx = types::Context::new();
482 let unit = Arc::<ConstructNode<Core>>::unit(&ctx);
483 let bit0 = Arc::<ConstructNode<Core>>::const_word(&ctx, Word::u1(0));
484 let bit1 = Arc::<ConstructNode<Core>>::const_word(&ctx, Word::u1(1));
485
486 assert_eq!(
487 unit.cmr(),
488 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::unit()).cmr()
489 );
490 assert_eq!(
491 bit0.cmr(),
492 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::u1(0)).cmr()
493 );
494 assert_eq!(
495 bit1.cmr(),
496 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::u1(1)).cmr()
497 );
498 assert_eq!(
499 Arc::<ConstructNode<Core>>::const_word(&ctx, Word::u2(1)).cmr(),
500 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::u2(1)).cmr()
501 );
502 assert_eq!(
503 Arc::<ConstructNode<Core>>::injl(&bit0).cmr(),
504 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::left(Value::u1(0), Final::unit()))
505 .cmr()
506 );
507 assert_eq!(
508 Arc::<ConstructNode<Core>>::injr(&bit1).cmr(),
509 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::right(Final::unit(), Value::u1(1)))
510 .cmr()
511 );
512 assert_eq!(
513 Arc::<ConstructNode<Core>>::pair(&unit, &unit)
514 .unwrap()
515 .cmr(),
516 Arc::<ConstructNode<Core>>::scribe(&ctx, &Value::product(Value::unit(), Value::unit()))
517 .cmr()
518 );
519 }
520
521 #[test]
522 fn regression_286_1() {
523 let ctx = types::Context::new();
526 let cmr = Cmr::from_byte_array([0xde; 32]);
527
528 let u0 = Arc::<ConstructNode<Core>>::unit(&ctx);
529 let i1 = Arc::<ConstructNode<Core>>::injl(&u0);
530 let i2 = Arc::<ConstructNode<Core>>::injr(&i1);
531 let i3 = Arc::<ConstructNode<Core>>::injr(&i2);
532 let i4 = Arc::<ConstructNode<Core>>::injl(&i3);
533 let u5 = Arc::<ConstructNode<Core>>::unit(&ctx);
534 let i6 = Arc::<ConstructNode<Core>>::injl(&u5);
535 let i7 = Arc::<ConstructNode<Core>>::injr(&i6);
536 let p8 = Arc::<ConstructNode<Core>>::pair(&i4, &i7).unwrap();
537 let u9 = Arc::<ConstructNode<Core>>::unit(&ctx);
538 let a10 = Arc::<ConstructNode<Core>>::assertr(cmr, &u9).unwrap();
539 let u11 = Arc::<ConstructNode<Core>>::unit(&ctx);
540 let a12 = Arc::<ConstructNode<Core>>::assertr(cmr, &u11).unwrap();
541 let a13 = Arc::<ConstructNode<Core>>::assertl(&a12, cmr).unwrap();
542 let c14 = Arc::<ConstructNode<Core>>::case(&a10, &a13).unwrap();
543 let c15 = Arc::<ConstructNode<Core>>::comp(&p8, &c14).unwrap();
544
545 let finalized: Arc<CommitNode<_>> = c15.finalize_types().unwrap();
546 let prog = finalized.encode_to_vec();
547 assert_eq!(
549 hex::DisplayHex::as_hex(&prog).to_string(),
550 "dc920a28812b6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f243090e00b10e00680",
551 );
552
553 let prog = BitIter::from(prog);
554 let decode = CommitNode::<Core>::decode(prog).unwrap();
555
556 assert_eq!(finalized, decode);
558 }
559
560 #[test]
561 fn regression_286_2() {
562 use crate::types::Error as TypeError;
563 use crate::Error;
564
565 let ctx = types::Context::new();
573
574 let w0 = Arc::<ConstructNode<Core>>::witness(&ctx, None);
575 let i1 = Arc::<ConstructNode<Core>>::iden(&ctx);
576 let d2 = Arc::<ConstructNode<Core>>::drop_(&i1);
577 let i3 = Arc::<ConstructNode<Core>>::iden(&ctx);
578 let i4 = Arc::<ConstructNode<Core>>::iden(&ctx);
579 let t5 = Arc::<ConstructNode<Core>>::take(&i4);
580 let ca6 = Arc::<ConstructNode<Core>>::case(&i3, &t5).unwrap();
581 let ca7 = Arc::<ConstructNode<Core>>::case(&d2, &ca6).unwrap();
582 let c8 = Arc::<ConstructNode<Core>>::comp(&w0, &ca7).unwrap();
583 let u9 = Arc::<ConstructNode<Core>>::unit(&ctx);
584 let c10 = Arc::<ConstructNode<Core>>::comp(&c8, &u9).unwrap();
585
586 let err = c10.finalize_types().unwrap_err();
588 assert!(matches!(err, Error::Type(TypeError::OccursCheck { .. })));
589 }
590}