1pub mod air;
2pub mod builder;
3pub mod decision_tree;
4pub mod interner;
5pub mod stick_break_set;
6pub mod tree;
7
8use self::{
9 air::Air,
10 builder::{
11 AssignmentProperties, CodeGenSpecialFuncs, CycleFunctionNames, HoistableFunction, Variant,
12 cast_validator_args, convert_type_to_data, extract_constant, modify_cyclic_calls,
13 modify_self_calls,
14 },
15 tree::{AirTree, TreePath},
16};
17use crate::{
18 IdGenerator,
19 ast::{
20 AssignmentKind, BinOp, Bls12_381Point, Curve, DataTypeKey, DecoratorKind,
21 FunctionAccessKey, Pattern, Span, TraceLevel, Tracing, TypedArg, TypedDataType,
22 TypedFunction, TypedPattern, TypedValidator, UnOp,
23 },
24 builtins::PRELUDE,
25 expr::TypedExpr,
26 gen_uplc::{
27 air::ExpectLevel,
28 builder::{
29 CodeGenFunction, erase_opaque_type_operations, get_generic_variant_name,
30 get_src_code_by_span, known_data_to_type, monomorphize, wrap_validator_condition,
31 },
32 },
33 line_numbers::LineNumbers,
34 plutus_version::PlutusVersion,
35 tipo::{
36 ModuleValueConstructor, PatternConstructor, Type, TypeInfo, TypeVar, ValueConstructor,
37 ValueConstructorVariant, check_replaceable_opaque_type, convert_opaque_type,
38 find_and_replace_generics, get_generic_id_and_type, lookup_data_type_by_tipo,
39 },
40};
41use builder::{
42 DISCARDED, get_constr_index_variant, introduce_name, introduce_pattern, pop_pattern,
43 softcast_data_to_type_otherwise, unknown_data_to_type,
44};
45use decision_tree::{Assigned, CaseTest, DecisionTree, TreeGen, get_tipo_by_path};
46use indexmap::IndexMap;
47use interner::AirInterner;
48use itertools::Itertools;
49use petgraph::{Graph, algo};
50use std::{collections::HashMap, rc::Rc};
51use stick_break_set::{Builtins, TreeSet};
52use tree::Fields;
53use uplc::{
54 ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType},
55 builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST},
56 builtins::DefaultFunction,
57 machine::cost_model::ExBudget,
58 optimize::{aiken_optimize_and_intern, interner::CodeGenInterner, shrinker::NO_INLINE},
59};
60
61type Otherwise = Option<AirTree>;
62
63const DELAY_ERROR: fn() -> AirTree =
64 || AirTree::anon_func(vec![], AirTree::error(Type::void(), false), true);
65
66fn expect_decoder_function_name(tipo: &Type, has_otherwise: bool) -> String {
67 let mut name = "__expect".to_string();
68 push_type_identity(&mut name, tipo);
69
70 if has_otherwise {
71 name.push_str("_otherwise");
72 }
73
74 name
75}
76
77fn push_type_identity(name: &mut String, tipo: &Type) {
78 match tipo {
79 Type::App {
80 module,
81 name: type_name,
82 args,
83 ..
84 } => {
85 name.push_str("_app");
86 push_key_segment(name, module);
87 push_key_segment(name, type_name);
88 push_key_count(name, args.len());
89
90 for arg in args {
91 push_type_identity(name, arg);
92 }
93 }
94 Type::Fn { args, ret, .. } => {
95 name.push_str("_fn");
96 push_key_count(name, args.len());
97
98 for arg in args {
99 push_type_identity(name, arg);
100 }
101
102 push_type_identity(name, ret);
103 }
104 Type::Var { tipo, .. } => {
105 let tipo = tipo.borrow();
106
107 match &*tipo {
108 TypeVar::Link { tipo } => push_type_identity(name, tipo),
109 TypeVar::Unbound { id } => {
110 unreachable!(
111 "expect decoder key requires a bound type, found unbound variable {id}"
112 )
113 }
114 TypeVar::Generic { id } => {
115 unreachable!(
116 "expect decoder key requires a concrete type, found generic variable {id}"
117 )
118 }
119 }
120 }
121 Type::Tuple { elems, .. } => {
122 name.push_str("_tuple");
123 push_key_count(name, elems.len());
124
125 for elem in elems {
126 push_type_identity(name, elem);
127 }
128 }
129 Type::Pair { fst, snd, .. } => {
130 name.push_str("_pair");
131 push_type_identity(name, fst);
132 push_type_identity(name, snd);
133 }
134 }
135}
136
137fn push_key_segment(name: &mut String, segment: &str) {
138 name.push('_');
139 name.push_str(&segment.len().to_string());
140 name.push('_');
141 name.push_str(&hex::encode(segment));
142}
143
144fn push_key_count(name: &mut String, count: usize) {
145 name.push('_');
146 name.push_str(&count.to_string());
147}
148
149#[derive(Clone)]
150pub struct CodeGenerator<'a> {
151 #[allow(dead_code)]
152 plutus_version: PlutusVersion,
153 functions: IndexMap<&'a FunctionAccessKey, &'a TypedFunction>,
155 constants: IndexMap<&'a FunctionAccessKey, &'a TypedExpr>,
156 data_types: IndexMap<&'a DataTypeKey, &'a TypedDataType>,
157 module_types: IndexMap<&'a str, &'a TypeInfo>,
158 module_src: IndexMap<&'a str, &'a (String, LineNumbers)>,
159 tracing: TraceLevel,
161 defined_functions: IndexMap<FunctionAccessKey, ()>,
163 special_functions: CodeGenSpecialFuncs,
164 code_gen_functions: IndexMap<String, CodeGenFunction>,
165 cyclic_functions:
166 IndexMap<(FunctionAccessKey, Variant), (CycleFunctionNames, usize, FunctionAccessKey)>,
167 interner: AirInterner,
169 id_gen: IdGenerator,
170}
171
172impl<'a> CodeGenerator<'a> {
173 pub fn data_types(&self) -> &IndexMap<&'a DataTypeKey, &'a TypedDataType> {
174 &self.data_types
175 }
176
177 pub fn new(
178 plutus_version: PlutusVersion,
179 functions: IndexMap<&'a FunctionAccessKey, &'a TypedFunction>,
180 constants: IndexMap<&'a FunctionAccessKey, &'a TypedExpr>,
181 data_types: IndexMap<&'a DataTypeKey, &'a TypedDataType>,
182 module_types: IndexMap<&'a str, &'a TypeInfo>,
183 module_src: IndexMap<&'a str, &'a (String, LineNumbers)>,
184 tracing: Tracing,
185 ) -> Self {
186 CodeGenerator {
187 plutus_version,
188 functions,
189 constants,
190 data_types,
191 module_types,
192 module_src,
193 tracing: tracing.trace_level(true),
194 defined_functions: IndexMap::new(),
195 special_functions: CodeGenSpecialFuncs::new(),
196 code_gen_functions: IndexMap::new(),
197 cyclic_functions: IndexMap::new(),
198 interner: AirInterner::new(),
199 id_gen: IdGenerator::new(),
200 }
201 }
202
203 pub fn reset(&mut self, reset_special_functions: bool) {
204 self.code_gen_functions = IndexMap::new();
205 self.defined_functions = IndexMap::new();
206 self.cyclic_functions = IndexMap::new();
207 self.interner = AirInterner::new();
208 self.id_gen = IdGenerator::new();
209 if reset_special_functions {
210 self.special_functions = CodeGenSpecialFuncs::new();
211 }
212 }
213
214 pub fn generate(&mut self, validator: &TypedValidator, module_name: &str) -> Program<Name> {
215 let context_name = "__context__".to_string();
216 let context_name_interned = introduce_name(&mut self.interner, &context_name);
217 validator.params.iter().for_each(|arg| {
218 arg.get_variable_name()
219 .iter()
220 .for_each(|arg_name| self.interner.intern(arg_name.to_string()))
221 });
222
223 let air_tree_fun = wrap_validator_condition(
224 self.build(&validator.into_script_context_handler(), module_name, &[]),
225 self.tracing,
226 );
227
228 let air_tree_fun = AirTree::anon_func(vec![context_name_interned], air_tree_fun, true);
229
230 let validator_args_tree = AirTree::no_op(air_tree_fun);
231
232 let full_tree = self.hoist_functions_to_validator(validator_args_tree);
233
234 let full_vec = full_tree.to_vec();
237
238 let term = self.uplc_code_gen(full_vec);
239
240 let term = cast_validator_args(term, &validator.params, &self.interner, &self.data_types);
241
242 self.interner.pop_text(context_name);
243 validator.params.iter().for_each(|arg| {
244 arg.get_variable_name()
245 .iter()
246 .for_each(|arg_name| self.interner.pop_text(arg_name.to_string()))
247 });
248
249 self.finalize(term)
250 }
251
252 pub fn generate_raw(
253 &mut self,
254 body: &TypedExpr,
255 args: &[TypedArg],
256 module_name: &str,
257 ) -> Program<Name> {
258 args.iter().for_each(|arg| {
259 arg.get_variable_name()
260 .iter()
261 .for_each(|arg_name| self.interner.intern(arg_name.to_string()))
262 });
263
264 let mut air_tree = self.build(body, module_name, &[]);
265
266 air_tree = AirTree::no_op(air_tree);
267
268 let full_tree = self.hoist_functions_to_validator(air_tree);
269
270 let full_vec = full_tree.to_vec();
272
273 let mut term = self.uplc_code_gen(full_vec);
274
275 term = if args.is_empty() {
276 term
277 } else {
278 cast_validator_args(term, args, &self.interner, &self.data_types)
279 };
280
281 args.iter().for_each(|arg| {
282 arg.get_variable_name()
283 .iter()
284 .for_each(|arg_name| self.interner.pop_text(arg_name.to_string()))
285 });
286
287 self.finalize(term)
288 }
289
290 fn new_program<T>(&self, term: Term<T>) -> Program<T> {
291 let version = match self.plutus_version {
292 PlutusVersion::V1 | PlutusVersion::V2 => (1, 0, 0),
293 PlutusVersion::V3 => (1, 1, 0),
294 };
295
296 Program { version, term }
297 }
298
299 fn finalize(&mut self, mut term: Term<Name>) -> Program<Name> {
300 term = self.special_functions.apply_used_functions(term);
301
302 let program = aiken_optimize_and_intern(self.new_program(term));
303
304 self.reset(true);
312
313 program
314 }
315
316 fn build(
319 &mut self,
320 body: &TypedExpr,
321 module_build_name: &str,
322 context: &[TypedExpr],
323 ) -> AirTree {
324 if !context.is_empty() {
325 let TypedExpr::Assignment {
326 location,
327 tipo,
328 value,
329 pattern,
330 kind,
331 comment,
332 } = body
333 else {
334 panic!("Dangling expressions without an assignment")
335 };
336
337 let air_value = self.build(value, module_build_name, &[]);
338
339 let otherwise_delayed = {
340 let msg = match (self.tracing, kind) {
341 (TraceLevel::Silent, _) | (_, AssignmentKind::Let { .. }) => "".to_string(),
342 (TraceLevel::Compact, _) => {
343 match comment.as_ref().and_then(|s| s.split(":").next()) {
344 None => "".to_string(),
345 Some(label) => format!("<expected> {label}"),
346 }
347 }
348 (TraceLevel::Verbose, _) => match comment.as_ref() {
349 None => get_src_code_by_span(module_build_name, location, &self.module_src),
350 Some(comment) => format!("<expected> {comment}"),
351 },
352 };
353
354 let msg_func_name = msg.split_whitespace().join("");
355
356 if msg_func_name.is_empty() {
357 None
358 } else {
359 self.special_functions.insert_new_function(
360 msg_func_name.clone(),
361 Term::Error.delayed_trace(Term::string(msg)).delay(),
362 Type::void(),
363 );
364
365 Some(self.special_functions.use_function_tree(msg_func_name))
366 }
367 };
368
369 introduce_pattern(&mut self.interner, pattern);
371
372 let (then, context) = context.split_first().unwrap();
373
374 let then = self.build(then, module_build_name, context);
375
376 let tree = self.assignment(
377 pattern,
378 air_value,
379 then,
380 tipo,
381 AssignmentProperties {
382 value_type: value.tipo(),
383 kind: *kind,
384 remove_unused: kind.is_let(),
385 full_check: !tipo.is_data() && value.tipo().is_data() && kind.is_expect(),
386 otherwise: otherwise_delayed,
387 },
388 );
389
390 pop_pattern(&mut self.interner, pattern);
392
393 tree
394 } else {
395 match body {
396 TypedExpr::Assignment { .. } => {
397 panic!("Reached assignment with no dangling expressions")
398 }
399 TypedExpr::UInt { value, .. } => AirTree::int(value),
400 TypedExpr::String { value, .. } => AirTree::string(value),
401 TypedExpr::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()),
402 TypedExpr::Sequence { expressions, .. }
403 | TypedExpr::Pipeline { expressions, .. } => {
404 let (expr, dangling_expressions) = expressions
405 .split_first()
406 .expect("Sequence or Pipeline should have at least one expression");
407 self.build(expr, module_build_name, dangling_expressions)
408 }
409
410 TypedExpr::Var {
411 constructor, name, ..
412 } => match constructor.variant {
413 ValueConstructorVariant::LocalVariable { .. } => {
414 if name != CONSTR_INDEX_EXPOSER && name != CONSTR_FIELDS_EXPOSER {
415 AirTree::var(
416 constructor.clone(),
417 self.interner.lookup_interned(name),
418 "",
419 )
420 } else {
421 AirTree::var(constructor.clone(), name, "")
422 }
423 }
424 _ => AirTree::var(constructor.clone(), name, ""),
425 },
426
427 TypedExpr::Fn { args, body, .. } => {
428 let params = args
429 .iter()
430 .map(|arg| {
431 arg.get_variable_name()
432 .map(|arg| introduce_name(&mut self.interner, &arg.to_string()))
433 .unwrap_or_else(|| DISCARDED.to_string())
434 })
435 .collect_vec();
436
437 let anon =
438 AirTree::anon_func(params, self.build(body, module_build_name, &[]), false);
439
440 args.iter()
441 .filter_map(|arg| arg.get_variable_name())
442 .for_each(|arg| {
443 self.interner.pop_text(arg.to_string());
444 });
445
446 anon
447 }
448
449 TypedExpr::List {
450 tipo,
451 elements,
452 tail,
453 ..
454 } => AirTree::list(
455 elements
456 .iter()
457 .map(|elem| self.build(elem, module_build_name, &[]))
458 .collect_vec(),
459 tipo.clone(),
460 tail.as_ref()
461 .map(|tail| self.build(tail, module_build_name, &[])),
462 ),
463
464 TypedExpr::Call {
465 tipo, fun, args, ..
466 } => match fun.as_ref() {
467 TypedExpr::Var {
468 constructor:
469 ValueConstructor {
470 variant:
471 ValueConstructorVariant::Record {
472 name: constr_name, ..
473 },
474 tipo: constr_tipo,
475 ..
476 },
477 ..
478 }
479 | TypedExpr::ModuleSelect {
480 constructor:
481 ModuleValueConstructor::Record {
482 name: constr_name,
483 tipo: constr_tipo,
484 ..
485 },
486 ..
487 } => {
488 let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
489 .unwrap_or_else(||
490 panic!(
491 "Creating a record of type {:?} with no record definition. Known definitions: {:?}",
492 tipo.to_pretty(0),
493 self.data_types.keys()
494 )
495 );
496
497 let err = &format!("Missing constr variant {constr_name}");
498 let (constr_index, _) =
499 get_constr_index_variant(&data_type, constr_name).expect(err);
500
501 let constr_args = args
502 .iter()
503 .zip(constr_tipo.arg_types().unwrap())
504 .map(|(arg, tipo)| {
505 if tipo.is_data() {
506 AirTree::cast_to_data(
507 self.build(&arg.value, module_build_name, &[]),
508 arg.value.tipo(),
509 )
510 } else {
511 self.build(&arg.value, module_build_name, &[])
512 }
513 })
514 .collect_vec();
515
516 let index = if data_type
517 .decorators
518 .iter()
519 .any(|dec| matches!(dec.kind, DecoratorKind::List))
520 {
521 None
522 } else {
523 Some(constr_index)
524 };
525
526 AirTree::create_constr(index, constr_tipo.clone(), constr_args)
527 }
528
529 TypedExpr::Var {
530 constructor:
531 ValueConstructor {
532 variant: ValueConstructorVariant::ModuleFn { builtin, .. },
533 ..
534 },
535 ..
536 } => {
537 let fun_arg_types = fun
538 .tipo()
539 .arg_types()
540 .expect("Expected a function type with arguments");
541
542 assert!(args.len() == fun_arg_types.len());
543
544 let func_args = args
545 .iter()
546 .zip(fun_arg_types)
547 .map(|(arg, arg_tipo)| {
548 let mut arg_val = self.build(&arg.value, module_build_name, &[]);
549 if arg_tipo.is_data() && !arg.value.tipo().is_data() {
550 arg_val = AirTree::cast_to_data(arg_val, arg.value.tipo())
551 }
552 arg_val
553 })
554 .collect_vec();
555
556 if let Some(func) = builtin {
557 AirTree::builtin(*func, tipo.clone(), func_args)
558 } else {
559 AirTree::call(
560 self.build(fun.as_ref(), module_build_name, &[]),
561 tipo.clone(),
562 func_args,
563 )
564 }
565 }
566
567 TypedExpr::ModuleSelect {
568 module_name,
569 constructor: ModuleValueConstructor::Fn { name, .. },
570 ..
571 } => {
572 let type_info = self.module_types.get(module_name.as_str()).unwrap();
573 let value = type_info.values.get(name).unwrap();
574
575 let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant
576 else {
577 unreachable!("Missing module function definition")
578 };
579
580 let fun_arg_types = fun
581 .tipo()
582 .arg_types()
583 .expect("Expected a function type with arguments");
584
585 assert!(args.len() == fun_arg_types.len());
586
587 let func_args = args
588 .iter()
589 .zip(fun_arg_types)
590 .map(|(arg, arg_tipo)| {
591 let mut arg_val = self.build(&arg.value, module_build_name, &[]);
592
593 if arg_tipo.is_data() && !arg.value.tipo().is_data() {
594 arg_val = AirTree::cast_to_data(arg_val, arg.value.tipo())
595 }
596 arg_val
597 })
598 .collect_vec();
599
600 if let Some(func) = builtin {
601 AirTree::builtin(*func, tipo.clone(), func_args)
602 } else {
603 AirTree::call(
604 self.build(fun.as_ref(), module_build_name, &[]),
605 tipo.clone(),
606 func_args,
607 )
608 }
609 }
610 _ => {
611 let fun_arg_types = fun
612 .tipo()
613 .arg_types()
614 .expect("Expected a function type with arguments");
615
616 assert!(args.len() == fun_arg_types.len());
617
618 let func_args = args
619 .iter()
620 .zip(fun_arg_types)
621 .map(|(arg, arg_tipo)| {
622 let mut arg_val = self.build(&arg.value, module_build_name, &[]);
623 if arg_tipo.is_data() && !arg.value.tipo().is_data() {
624 arg_val = AirTree::cast_to_data(arg_val, arg.value.tipo())
625 }
626 arg_val
627 })
628 .collect_vec();
629
630 AirTree::call(
631 self.build(fun.as_ref(), module_build_name, &[]),
632 tipo.clone(),
633 func_args,
634 )
635 }
636 },
637 TypedExpr::BinOp {
638 name,
639 left,
640 right,
641 tipo,
642 ..
643 } => AirTree::binop(
644 *name,
645 tipo.clone(),
646 self.build(left, module_build_name, &[]),
647 self.build(right, module_build_name, &[]),
648 left.tipo(),
649 right.tipo(),
650 ),
651
652 TypedExpr::Trace {
653 tipo, then, text, ..
654 } => AirTree::trace(
655 self.build(text, module_build_name, &[]),
656 tipo.clone(),
657 self.build(then, module_build_name, &[]),
658 ),
659
660 TypedExpr::When {
661 subject,
662 clauses,
663 tipo,
664 ..
665 } => {
666 if clauses.is_empty() {
667 unreachable!("We should have one clause at least")
668 } else if clauses.len() == 1 {
669 let subject_val = self.build(subject, module_build_name, &[]);
670
671 let last_clause = &clauses[0];
672
673 introduce_pattern(&mut self.interner, &last_clause.pattern);
675
676 let clause_then = self.build(&last_clause.then, module_build_name, &[]);
677
678 let subject_type = subject.tipo();
679
680 let tree = self.assignment(
681 &last_clause.pattern,
682 subject_val,
683 clause_then,
684 &subject_type,
685 AssignmentProperties {
686 value_type: subject.tipo(),
687 kind: AssignmentKind::let_(),
688 remove_unused: false,
689 full_check: false,
690 otherwise: None,
691 },
692 );
693
694 pop_pattern(&mut self.interner, &last_clause.pattern);
696
697 tree
698 } else {
699 let subject_name = format!(
700 "__subject_var_span_{}_{}",
701 subject.location().start,
702 subject.location().end
703 );
704
705 self.interner.intern(subject_name.clone());
706
707 let subject_name_interned = self.interner.lookup_interned(&subject_name);
708
709 let wild_card = TypedPattern::Discard {
710 name: "".to_string(),
711 location: Span::empty(),
712 };
713
714 let tree_gen =
715 TreeGen::new(&mut self.interner, &self.data_types, &wild_card);
716
717 let tree = tree_gen.build_tree(&subject.tipo(), clauses);
718
719 let stick_set = TreeSet::new();
720
721 let clauses = self.handle_decision_tree(
722 &subject_name_interned,
723 subject.tipo(),
724 tipo.clone(),
725 module_build_name,
726 tree,
727 stick_set,
728 );
729
730 self.interner.pop_text(subject_name);
731
732 AirTree::let_assignment(
733 subject_name_interned,
734 self.build(subject, module_build_name, &[]),
735 clauses,
736 )
737 }
738 }
739
740 TypedExpr::If {
741 branches,
742 final_else,
743 tipo,
744 ..
745 } => {
746 branches.iter().rfold(
747 self.build(final_else, module_build_name, &[]),
748 |acc, branch| {
749 let condition = self.build(&branch.condition, module_build_name, &[]);
750
751 match &branch.is {
752 Some((pattern, tipo)) => {
753 introduce_pattern(&mut self.interner, pattern);
754 self.interner.intern("acc_var".to_string());
755
756 let body = self.build(&branch.body, module_build_name, &[]);
757
758 let acc_var =
759 self.interner.lookup_interned(&"acc_var".to_string());
760
761 let tree = AirTree::let_assignment(
762 &acc_var,
763 AirTree::anon_func(vec![], acc, true),
765 self.assignment(
766 pattern,
767 condition,
768 body,
769 tipo,
770 AssignmentProperties {
771 value_type: branch.condition.tipo(),
772 kind: AssignmentKind::Expect { backpassing: () },
773 remove_unused: false,
774 full_check: true,
775 otherwise: Some(AirTree::local_var(
776 &acc_var,
777 tipo.clone(),
778 )),
779 },
780 ),
781 );
782
783 pop_pattern(&mut self.interner, pattern);
784 self.interner.pop_text("acc_var".to_string());
785
786 tree
787 }
788 None => AirTree::if_branch(
789 tipo.clone(),
790 condition,
791 self.build(&branch.body, module_build_name, &[]),
792 acc,
793 ),
794 }
795 },
796 )
797 }
798 TypedExpr::RecordAccess {
799 tipo,
800 index,
801 record,
802 ..
803 } => {
804 assert!(
805 !record.tipo().is_pair(),
806 "illegal record access on a Pair. This should have been a pair-index access."
807 );
808
809 if check_replaceable_opaque_type(&record.tipo(), &self.data_types) {
810 self.build(record, module_build_name, &[])
811 } else {
812 let function_name = format!("__access_index_{}", *index);
813
814 if self.code_gen_functions.get(&function_name).is_none() {
815 let mut body = AirTree::local_var("__fields", Type::list(Type::data()));
816
817 for _ in 0..*index {
818 body = AirTree::builtin(
819 DefaultFunction::TailList,
820 Type::list(Type::data()),
821 vec![body],
822 )
823 }
824
825 body = AirTree::builtin(
826 DefaultFunction::HeadList,
827 Type::data(),
828 vec![body],
829 );
830
831 self.code_gen_functions.insert(
832 function_name.clone(),
833 CodeGenFunction::Function {
834 body,
835 params: vec!["__fields".to_string()],
836 },
837 );
838 }
839
840 let err =
841 format!("Missing record data type for type: {:#?}", record.tipo());
842
843 let record_data_type =
844 lookup_data_type_by_tipo(self.data_types(), &record.tipo())
845 .expect(&err);
846
847 let list_of_fields = if record_data_type
848 .decorators
849 .iter()
850 .any(|dec| matches!(dec.kind, DecoratorKind::List))
851 {
852 self.build(record, module_build_name, &[])
853 } else {
854 AirTree::call(
855 self.special_functions
856 .use_function_tree(CONSTR_FIELDS_EXPOSER.to_string()),
857 Type::list(Type::data()),
858 vec![self.build(record, module_build_name, &[])],
859 )
860 };
861
862 AirTree::index_access(function_name, tipo.clone(), list_of_fields)
863 }
864 }
865
866 TypedExpr::ModuleSelect {
867 tipo,
868 module_name,
869 constructor,
870 ..
871 } => match constructor {
872 ModuleValueConstructor::Record {
873 name,
874 arity,
875 tipo,
876 field_map,
877 ..
878 } => {
879 let val_constructor = {
880 let data_type = lookup_data_type_by_tipo(&self.data_types, tipo);
881
882 ValueConstructor::public(
883 tipo.clone(),
884 ValueConstructorVariant::Record {
885 name: name.clone(),
886 arity: *arity,
887 field_map: field_map.clone(),
888 location: Span::empty(),
889 module: module_name.clone(),
890 constructors_count: data_type
891 .expect("Created a module type without a definition?")
892 .constructors
893 .len()
894 as u16,
895 },
896 )
897 };
898
899 AirTree::var(val_constructor, name, "")
900 }
901 ModuleValueConstructor::Fn { name, module, .. } => {
902 let func = self.functions.get(&FunctionAccessKey {
903 module_name: if module_name == PRELUDE {
912 String::new()
913 } else {
914 module_name.clone()
915 },
916 function_name: name.clone(),
917 });
918
919 let type_info = self.module_types.get(module_name.as_str()).unwrap();
920
921 let value = type_info.values.get(name).unwrap();
922
923 if let Some(_func) = func {
924 AirTree::var(
925 ValueConstructor::public(tipo.clone(), value.variant.clone()),
926 format!("{module}_{name}"),
927 "",
928 )
929 } else {
930 let ValueConstructorVariant::ModuleFn {
931 builtin: Some(builtin),
932 ..
933 } = &value.variant
934 else {
935 unreachable!("Didn't find the function definition.")
936 };
937
938 AirTree::builtin(*builtin, tipo.clone(), vec![])
939 }
940 }
941 ModuleValueConstructor::Constant { module, name, .. } => {
942 let type_info = self.module_types.get(module_name.as_str()).unwrap();
943
944 let value = type_info.values.get(name).unwrap();
945
946 AirTree::var(
947 ValueConstructor::public(tipo.clone(), value.variant.clone()),
948 format!("{module}_{name}"),
949 "",
950 )
951 }
952 },
953
954 TypedExpr::Pair { tipo, fst, snd, .. } => AirTree::pair(
955 self.build(fst, module_build_name, &[]),
956 self.build(snd, module_build_name, &[]),
957 tipo.clone(),
958 ),
959
960 TypedExpr::Tuple { tipo, elems, .. } => AirTree::tuple(
961 elems
962 .iter()
963 .map(|elem| self.build(elem, module_build_name, &[]))
964 .collect_vec(),
965 tipo.clone(),
966 ),
967
968 TypedExpr::TupleIndex {
969 index, tuple, tipo, ..
970 } => {
971 if tuple.tipo().is_pair() {
972 AirTree::pair_index(
973 *index,
974 tipo.clone(),
975 self.build(tuple, module_build_name, &[]),
976 )
977 } else {
978 let function_name = format!("__access_index_{}", *index);
979
980 if self.code_gen_functions.get(&function_name).is_none() {
981 let mut body = AirTree::local_var("__fields", Type::list(Type::data()));
982
983 for _ in 0..*index {
984 body = AirTree::builtin(
985 DefaultFunction::TailList,
986 Type::list(Type::data()),
987 vec![body],
988 )
989 }
990
991 body = AirTree::builtin(
992 DefaultFunction::HeadList,
993 Type::data(),
994 vec![body],
995 );
996
997 self.code_gen_functions.insert(
998 function_name.clone(),
999 CodeGenFunction::Function {
1000 body,
1001 params: vec!["__fields".to_string()],
1002 },
1003 );
1004 }
1005
1006 AirTree::index_access(
1007 function_name,
1008 tipo.clone(),
1009 self.build(tuple, module_build_name, &[]),
1010 )
1011 }
1012 }
1013
1014 TypedExpr::ErrorTerm { tipo, .. } => AirTree::error(tipo.clone(), false),
1015
1016 TypedExpr::RecordUpdate {
1017 tipo, spread, args, ..
1018 } => {
1019 let mut index_types = vec![];
1020 let mut update_args = vec![];
1021
1022 let mut highest_index = 0;
1023
1024 for arg in args
1025 .iter()
1026 .sorted_by(|arg1, arg2| arg1.index.cmp(&arg2.index))
1027 {
1028 let arg_val = self.build(&arg.value, module_build_name, &[]);
1029
1030 if arg.index > highest_index {
1031 highest_index = arg.index;
1032 }
1033
1034 index_types.push((arg.index, arg.value.tipo()));
1035 update_args.push(arg_val);
1036 }
1037
1038 AirTree::record_update(
1039 index_types,
1040 highest_index,
1041 tipo.clone(),
1042 self.build(spread, module_build_name, &[]),
1043 update_args,
1044 )
1045 }
1046 TypedExpr::UnOp { value, op, .. } => {
1047 AirTree::unop(*op, self.build(value, module_build_name, &[]))
1048 }
1049 TypedExpr::CurvePoint { point, .. } => AirTree::curve(*point.as_ref()),
1050 }
1051 }
1052 }
1053
1054 pub fn assignment(
1055 &mut self,
1056 pattern: &TypedPattern,
1057 value: AirTree,
1058 then: AirTree,
1059 tipo: &Rc<Type>,
1060 props: AssignmentProperties,
1061 ) -> AirTree {
1062 assert!(
1063 match &value {
1064 AirTree::Var { name, .. } if props.kind.is_let() => {
1065 name != DISCARDED
1066 }
1067 _ => true,
1068 },
1069 "No discard expressions or let bindings should be in the tree at this point."
1070 );
1071
1072 let assign_casted_value = |name, value, then| {
1074 if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
1075 if let Some(otherwise) = props.otherwise.as_ref() {
1076 AirTree::soft_cast_assignment(
1077 name,
1078 tipo.clone(),
1079 value,
1080 then,
1081 otherwise.clone(),
1082 )
1083 } else {
1084 AirTree::let_assignment(
1085 name,
1086 AirTree::cast_from_data(value, tipo.clone(), true),
1087 then,
1088 )
1089 }
1090 } else if !props.value_type.is_data() && tipo.is_data() {
1091 AirTree::let_assignment(
1092 name,
1093 AirTree::cast_to_data(value, props.value_type.clone()),
1094 then,
1095 )
1096 } else {
1097 AirTree::let_assignment(name, value, then)
1098 }
1099 };
1100
1101 let otherwise = match &props.otherwise {
1102 Some(x) => x.clone(),
1103 None => DELAY_ERROR(),
1105 };
1106
1107 match pattern {
1108 Pattern::Int {
1109 value: expected_int,
1110 location,
1111 ..
1112 } => {
1113 let name = format!(
1114 "__expected_by_{}_span_{}_{}",
1115 expected_int, location.start, location.end
1116 );
1117
1118 let expect = AirTree::binop(
1119 BinOp::Eq,
1120 Type::bool(),
1121 AirTree::int(expected_int),
1122 AirTree::local_var(&name, Type::int()),
1123 Type::int(),
1124 Type::int(),
1125 );
1126
1127 assign_casted_value(
1128 name,
1129 value,
1130 AirTree::assert_bool(true, expect, then, otherwise),
1131 )
1132 }
1133
1134 Pattern::ByteArray {
1135 value: expected_bytes,
1136 location,
1137 ..
1138 } => {
1139 let name = format!("__expected_bytes_span_{}_{}", location.start, location.end);
1140
1141 let expect = AirTree::binop(
1142 BinOp::Eq,
1143 Type::bool(),
1144 AirTree::byte_array(expected_bytes.clone()),
1145 AirTree::local_var(&name, Type::byte_array()),
1146 Type::byte_array(),
1147 Type::byte_array(),
1148 );
1149
1150 assign_casted_value(
1151 name,
1152 value,
1153 AirTree::assert_bool(true, expect, then, otherwise),
1154 )
1155 }
1156
1157 Pattern::Var { name, .. } => {
1158 let name = self.interner.lookup_interned(name);
1159
1160 if props.full_check {
1161 let mut index_map = IndexMap::new();
1162
1163 let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types, true);
1164
1165 let val = AirTree::local_var(&name, tipo.clone());
1166
1167 if non_opaque_tipo.is_primitive() {
1168 assign_casted_value(name.clone(), value, then)
1169 } else {
1170 assign_casted_value(
1171 name,
1172 value,
1173 self.expect_type_assign(
1174 &non_opaque_tipo,
1175 val,
1176 &mut index_map,
1177 pattern.location(),
1178 then,
1179 props.otherwise.clone(),
1180 ),
1181 )
1182 }
1183 } else {
1184 assign_casted_value(name.clone(), value, then)
1185 }
1186 }
1187
1188 Pattern::Assign { name, pattern, .. } => {
1189 let name = self.interner.lookup_interned(name);
1190
1191 let inner_pattern = self.assignment(
1192 pattern,
1193 AirTree::local_var(&name, tipo.clone()),
1194 then,
1195 tipo,
1196 AssignmentProperties {
1197 value_type: tipo.clone(),
1198 kind: props.kind,
1199 remove_unused: props.remove_unused,
1200 full_check: props.full_check,
1201 otherwise: props.otherwise.clone(),
1202 },
1203 );
1204
1205 assign_casted_value(name, value, inner_pattern)
1206 }
1207
1208 Pattern::Discard { name, .. } => {
1209 if props.full_check {
1210 let name = format!("__discard_expect_{name}");
1211
1212 let name_interned = introduce_name(&mut self.interner, &name);
1213
1214 let mut index_map = IndexMap::new();
1215
1216 let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types, true);
1217
1218 let val = AirTree::local_var(&name_interned, tipo.clone());
1219
1220 let tree = if non_opaque_tipo.is_primitive() {
1221 assign_casted_value(name_interned, value, then)
1222 } else {
1223 assign_casted_value(
1224 name_interned,
1225 value,
1226 self.expect_type_assign(
1227 &non_opaque_tipo,
1228 val,
1229 &mut index_map,
1230 pattern.location(),
1231 then,
1232 props.otherwise.clone(),
1233 ),
1234 )
1235 };
1236
1237 self.interner.pop_text(name);
1238
1239 tree
1240 } else if !props.remove_unused {
1241 assign_casted_value(name.clone(), value, then)
1243 } else {
1244 then
1245 }
1246 }
1247
1248 Pattern::List { elements, tail, .. } => {
1249 assert!(tipo.is_list());
1250 assert!(props.kind.is_expect());
1251
1252 let list_elem_types = tipo.get_inner_types();
1253
1254 let list_elem_type = list_elem_types
1255 .first()
1256 .unwrap_or_else(|| unreachable!("No list element type?"));
1257
1258 let mut elems = vec![];
1259
1260 let then = match tail {
1262 None => then,
1263 Some(tail) => {
1264 let (tail_name, tail_name_interned) = match tail.as_ref() {
1265 Pattern::Var { name, .. } => {
1266 (None, self.interner.lookup_interned(name))
1267 }
1268 Pattern::Assign { .. } => {
1270 todo!("Has this ever been reached before?")
1271 }
1272 Pattern::Discard { name, .. } => {
1273 if props.full_check {
1274 (
1275 Some(format!("__discard_{name}_tail")),
1276 introduce_name(
1277 &mut self.interner,
1278 &format!("__discard_{name}_tail"),
1279 ),
1280 )
1281 } else {
1282 (None, DISCARDED.to_string())
1283 }
1284 }
1285 _ => unreachable!(),
1286 };
1287
1288 let val = AirTree::local_var(&tail_name_interned, tipo.clone());
1289
1290 let then = if tail_name_interned != DISCARDED {
1291 self.assignment(
1292 tail,
1293 val,
1294 then,
1295 tipo,
1296 AssignmentProperties {
1297 value_type: tipo.clone(),
1298 kind: props.kind,
1299 remove_unused: true,
1303 full_check: props.full_check,
1304 otherwise: props.otherwise.clone(),
1305 },
1306 )
1307 } else {
1308 then
1309 };
1310
1311 elems.push(tail_name_interned);
1312
1313 if let Some(tail_name) = tail_name {
1314 self.interner.pop_text(tail_name);
1315 }
1316
1317 then
1318 }
1319 };
1320
1321 let then = elements
1322 .iter()
1323 .enumerate()
1324 .rfold(then, |then, (index, elem)| {
1325 let (elem_name, elem_name_interned) = match elem {
1326 Pattern::Var { name, .. } => {
1327 (None, self.interner.lookup_interned(name))
1328 }
1329 Pattern::Assign { name, .. } => {
1330 (None, self.interner.lookup_interned(name))
1331 }
1332 Pattern::Discard { name, .. } => {
1333 if props.full_check {
1334 (
1335 Some(format!("__discard_{name}_{index}")),
1336 introduce_name(
1337 &mut self.interner,
1338 &format!("__discard_{name}_{index}"),
1339 ),
1340 )
1341 } else {
1342 (None, DISCARDED.to_string())
1343 }
1344 }
1345 _ => {
1346 let name = format!(
1347 "elem_{}_span_{}_{}",
1348 index,
1349 elem.location().start,
1350 elem.location().end
1351 );
1352 let interned = introduce_name(&mut self.interner, &name);
1353
1354 (Some(name), interned)
1355 }
1356 };
1357
1358 let val = AirTree::local_var(&elem_name_interned, list_elem_type.clone());
1359
1360 let then = if elem_name_interned != DISCARDED {
1361 self.assignment(
1362 elem,
1363 val,
1364 then,
1365 list_elem_type,
1366 AssignmentProperties {
1367 value_type: list_elem_type.clone(),
1368 kind: props.kind,
1369 remove_unused: true,
1370 full_check: props.full_check,
1371 otherwise: props.otherwise.clone(),
1372 },
1373 )
1374 } else {
1375 then
1376 };
1377
1378 elems.push(elem_name_interned);
1379
1380 if let Some(elem_name) = elem_name {
1381 self.interner.pop_text(elem_name);
1382 }
1383
1384 then
1385 });
1386
1387 elems.reverse();
1388
1389 let name = format!(
1390 "__List_span_{}_{}",
1391 pattern.location().start,
1392 pattern.location().end
1393 );
1394
1395 let name_interned = introduce_name(&mut self.interner, &name);
1396
1397 let casted_var = AirTree::local_var(&name_interned, tipo.clone());
1398
1399 let tree = if elements.is_empty() {
1400 assign_casted_value(
1401 name_interned,
1402 value,
1403 AirTree::list_empty(casted_var, then, otherwise),
1404 )
1405 } else {
1406 assign_casted_value(
1407 name_interned,
1408 value,
1409 AirTree::list_access(
1410 elems,
1411 tipo.clone(),
1412 tail.is_some(),
1413 casted_var,
1414 if props.full_check {
1415 ExpectLevel::Full
1416 } else {
1417 ExpectLevel::Items
1418 },
1419 then,
1420 otherwise,
1421 ),
1422 )
1423 };
1424
1425 self.interner.pop_text(name);
1426
1427 tree
1428 }
1429
1430 Pattern::Pair {
1431 fst,
1432 snd,
1433 location: _,
1434 } => {
1435 let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
1436
1437 for (index, arg) in tipo.get_inner_types().iter().enumerate() {
1438 let field_type = arg.clone();
1439 type_map.insert(index, field_type);
1440 }
1441
1442 assert!(type_map.len() == 2);
1443
1444 let mut fields = vec![];
1445
1446 let then = [fst, snd]
1447 .iter()
1448 .enumerate()
1449 .rfold(then, |then, (field_index, arg)| {
1450 let (field_name, field_name_interned) = match arg.as_ref() {
1451 Pattern::Var { name, .. } => {
1452 (None, self.interner.lookup_interned(name))
1453 }
1454 Pattern::Assign { name, .. } => {
1455 (None, self.interner.lookup_interned(name))
1456 }
1457 Pattern::Discard { name, .. } => {
1458 if props.full_check {
1459 (
1460 Some(format!("__discard_{name}_{field_index}")),
1461 introduce_name(
1462 &mut self.interner,
1463 &format!("__discard_{name}_{field_index}"),
1464 ),
1465 )
1466 } else {
1467 (None, DISCARDED.to_string())
1468 }
1469 }
1470 _ => {
1471 let name = format!(
1472 "field_{}_span_{}_{}",
1473 field_index,
1474 arg.location().start,
1475 arg.location().end
1476 );
1477 let interned = introduce_name(&mut self.interner, &name);
1478
1479 (Some(name), interned)
1480 }
1481 };
1482
1483 let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
1484 unreachable!("Missing type for field {} of Pair", field_index,)
1485 });
1486
1487 let val = AirTree::local_var(&field_name_interned, arg_type.clone());
1488
1489 let then = if field_name_interned != DISCARDED {
1490 self.assignment(
1491 arg,
1492 val,
1493 then,
1494 arg_type,
1495 AssignmentProperties {
1496 value_type: arg_type.clone(),
1497 kind: props.kind,
1498 remove_unused: true,
1499 full_check: props.full_check,
1500 otherwise: props.otherwise.clone(),
1501 },
1502 )
1503 } else {
1504 then
1505 };
1506
1507 fields.push((field_index, field_name_interned, arg_type.clone()));
1508
1509 if let Some(field_name) = field_name {
1510 self.interner.pop_text(field_name);
1511 }
1512
1513 then
1514 });
1515
1516 fields.reverse();
1517
1518 let constructor_name = format!(
1521 "Pair_span_{}_{}",
1522 pattern.location().start,
1523 pattern.location().end
1524 );
1525
1526 let constructor_name_interned =
1527 introduce_name(&mut self.interner, &constructor_name);
1528
1529 let local_value = AirTree::local_var(&constructor_name_interned, tipo.clone());
1530
1531 let then = AirTree::pair_access(
1532 fields
1533 .first()
1534 .map(|x| {
1535 if x.1 == DISCARDED {
1536 None
1537 } else {
1538 Some(x.1.clone())
1539 }
1540 })
1541 .unwrap(),
1542 fields
1543 .last()
1544 .map(|x| {
1545 if x.1 == DISCARDED {
1546 None
1547 } else {
1548 Some(x.1.clone())
1549 }
1550 })
1551 .unwrap(),
1552 tipo.clone(),
1553 local_value,
1554 props.full_check,
1555 then,
1556 otherwise,
1557 );
1558
1559 let tree = assign_casted_value(constructor_name_interned, value, then);
1560
1561 self.interner.pop_text(constructor_name);
1562
1563 tree
1564 }
1565
1566 Pattern::Constructor {
1567 constructor: PatternConstructor::Record { name, .. },
1568 ..
1569 } if tipo.is_bool() => {
1570 assert!(props.kind.is_expect());
1571
1572 let name_var = format!(
1573 "__Bool_{}_{}",
1574 pattern.location().start,
1575 pattern.location().end
1576 );
1577
1578 let local_var = AirTree::local_var(&name_var, tipo.clone());
1579
1580 assign_casted_value(
1581 name_var,
1582 value,
1583 AirTree::assert_bool(name == "True", local_var, then, otherwise),
1584 )
1585 }
1586
1587 Pattern::Constructor { .. } if tipo.is_void() => {
1588 assign_casted_value(DISCARDED.to_string(), value, then)
1591 }
1592
1593 Pattern::Constructor {
1594 arguments,
1595 constructor: PatternConstructor::Record { name, field_map },
1596 tipo: constr_tipo,
1597 ..
1598 } => {
1599 let field_map = field_map.clone();
1601
1602 let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
1603
1604 for (index, arg) in constr_tipo
1605 .arg_types()
1606 .expect("Mismatched type")
1607 .iter()
1608 .enumerate()
1609 {
1610 let field_type = arg.clone();
1611
1612 type_map.insert(index, field_type);
1613 }
1614
1615 assert!(
1616 type_map.len() >= arguments.len(),
1617 "type map len: {}, arguments len: {}; for constructor {:?}",
1618 type_map.len(),
1619 arguments.len(),
1620 name,
1621 );
1622
1623 let mut fields = vec![];
1624
1625 let then = arguments
1626 .iter()
1627 .enumerate()
1628 .rfold(then, |then, (index, arg)| {
1629 let label = arg.label.clone().unwrap_or_default();
1630
1631 let field_index = if let Some(field_map) = &field_map {
1632 *field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index)
1633 } else {
1634 index
1635 };
1636
1637 let (field_name, field_name_interned) = match &arg.value {
1638 Pattern::Var { name, .. } => {
1639 (None, self.interner.lookup_interned(name))
1640 }
1641 Pattern::Assign { name, .. } => {
1642 (None, self.interner.lookup_interned(name))
1643 }
1644 Pattern::Discard { name, .. } => {
1645 if props.full_check {
1646 (
1647 Some(format!("__discard_{name}_{index}")),
1648 introduce_name(
1649 &mut self.interner,
1650 &format!("__discard_{name}_{index}"),
1651 ),
1652 )
1653 } else {
1654 (None, DISCARDED.to_string())
1655 }
1656 }
1657 _ => {
1658 let name = format!(
1659 "field_{}_span_{}_{}",
1660 field_index,
1661 arg.value.location().start,
1662 arg.value.location().end
1663 );
1664 let interned = introduce_name(&mut self.interner, &name);
1665
1666 (Some(name), interned)
1667 }
1668 };
1669
1670 let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
1671 unreachable!(
1672 "Missing type for field {} of constr {}",
1673 field_index, name
1674 )
1675 });
1676
1677 let val = AirTree::local_var(&field_name_interned, arg_type.clone());
1678
1679 let then = if field_name_interned != DISCARDED {
1680 self.assignment(
1681 &arg.value,
1682 val,
1683 then,
1684 arg_type,
1685 AssignmentProperties {
1686 value_type: arg_type.clone(),
1687 kind: props.kind,
1688 remove_unused: true,
1689 full_check: props.full_check,
1690 otherwise: props.otherwise.clone(),
1691 },
1692 )
1693 } else {
1694 then
1695 };
1696
1697 fields.push((field_index, field_name_interned, arg_type.clone()));
1698
1699 if let Some(field_name) = field_name {
1700 self.interner.pop_text(field_name);
1701 }
1702
1703 then
1704 });
1705
1706 fields.reverse();
1707
1708 let constructor_name = format!(
1711 "__constructor_{}_span_{}_{}",
1712 name,
1713 pattern.location().start,
1714 pattern.location().end
1715 );
1716
1717 let subject_name = format!(
1718 "__subject_{}_span_{}_{}",
1719 name,
1720 pattern.location().start,
1721 pattern.location().end
1722 );
1723
1724 let constructor_name_interned =
1725 introduce_name(&mut self.interner, &constructor_name);
1726
1727 let subject_name_interned = introduce_name(&mut self.interner, &subject_name);
1728
1729 let local_value = AirTree::local_var(&constructor_name_interned, tipo.clone());
1730
1731 let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
1732 .unwrap_or_else(|| unreachable!("Failed to find definition for {}", name));
1733
1734 let list_decorator = data_type
1735 .decorators
1736 .iter()
1737 .any(|dec| matches!(dec.kind, DecoratorKind::List));
1738
1739 let then = if check_replaceable_opaque_type(tipo, &self.data_types) {
1740 AirTree::let_assignment(&fields[0].1, local_value.clone(), then)
1741 } else {
1742 AirTree::fields_expose(
1743 fields,
1744 local_value.clone(),
1745 props.full_check,
1746 then,
1747 otherwise.clone(),
1748 list_decorator,
1749 )
1750 };
1751
1752 let then = if props.kind.is_expect()
1753 && !list_decorator
1754 && (data_type.constructors.len() > 1
1755 || props.full_check
1756 || data_type.is_never())
1758 {
1759 let (index, _) =
1760 get_constr_index_variant(&data_type, name).unwrap_or_else(|| {
1761 panic!("Found constructor type {name} with 0 matching constructors")
1762 });
1763
1764 AirTree::when(
1765 &subject_name_interned,
1766 Type::void(),
1767 tipo.clone(),
1768 local_value,
1769 AirTree::clause(
1770 &subject_name_interned,
1771 AirTree::int(index),
1772 tipo.clone(),
1773 then,
1774 otherwise,
1775 ),
1776 )
1777 } else {
1778 assert!(
1779 data_type.constructors.len() == 1 || data_type.is_never(),
1780 "attempted let-assignment on a type with more or less than 1 constructor: \nis_expect? {}\nfull_check? {}\ndata_type={data_type:#?}\n{}",
1781 props.kind.is_expect(),
1782 props.full_check,
1783 name,
1784 );
1785
1786 then
1787 };
1788
1789 let tree = assign_casted_value(constructor_name_interned, value, then);
1790
1791 self.interner.pop_text(constructor_name);
1792 self.interner.pop_text(subject_name);
1793
1794 tree
1795 }
1796
1797 Pattern::Tuple {
1798 elems, location, ..
1799 } => {
1800 let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
1801
1802 for (index, arg) in tipo.get_inner_types().iter().enumerate() {
1803 let field_type = arg.clone();
1804 type_map.insert(index, field_type);
1805 }
1806
1807 assert!(type_map.len() == elems.len());
1808
1809 let mut fields = vec![];
1810
1811 let then = elems.iter().enumerate().rfold(then, |then, (index, arg)| {
1812 let (tuple_name, tuple_name_interned) = match &arg {
1813 Pattern::Var { name, .. } => (None, self.interner.lookup_interned(name)),
1814 Pattern::Assign { name, .. } => (None, self.interner.lookup_interned(name)),
1815 Pattern::Discard { name, .. } => {
1816 if props.full_check {
1817 (
1818 Some(format!("__discard_{name}_{index}")),
1819 introduce_name(
1820 &mut self.interner,
1821 &format!("__discard_{name}_{index}"),
1822 ),
1823 )
1824 } else {
1825 (None, DISCARDED.to_string())
1826 }
1827 }
1828 _ => {
1829 let name = format!(
1830 "tuple_{}_span_{}_{}",
1831 index,
1832 arg.location().start,
1833 arg.location().end
1834 );
1835
1836 let interned = introduce_name(&mut self.interner, &name);
1837
1838 (Some(name), interned)
1839 }
1840 };
1841
1842 let arg_type = type_map.get(&index).unwrap_or_else(|| {
1843 unreachable!(
1844 "Missing type for tuple index {} of tuple_span_{}_{}",
1845 index, location.start, location.end
1846 )
1847 });
1848
1849 let val = AirTree::local_var(&tuple_name_interned, arg_type.clone());
1850
1851 let then = if DISCARDED != tuple_name_interned {
1852 self.assignment(
1853 arg,
1854 val,
1855 then,
1856 arg_type,
1857 AssignmentProperties {
1858 value_type: arg_type.clone(),
1859 kind: props.kind,
1860 remove_unused: true,
1861 full_check: props.full_check,
1862 otherwise: props.otherwise.clone(),
1863 },
1864 )
1865 } else {
1866 then
1867 };
1868
1869 fields.push(tuple_name_interned);
1870
1871 if let Some(tuple_name) = tuple_name {
1872 self.interner.pop_text(tuple_name);
1873 }
1874
1875 then
1876 });
1877
1878 fields.reverse();
1879
1880 let name = format!(
1883 "__Tuple_span_{}_{}",
1884 pattern.location().start,
1885 pattern.location().end
1886 );
1887
1888 let name_interned = introduce_name(&mut self.interner, &name);
1889
1890 let local_var = AirTree::local_var(&name_interned, tipo.clone());
1891
1892 let tree = assign_casted_value(
1893 name_interned,
1894 value,
1895 AirTree::tuple_access(
1896 fields,
1897 tipo.clone(),
1898 local_var,
1899 props.full_check,
1900 then,
1901 otherwise,
1902 ),
1903 );
1904
1905 self.interner.pop_text(name);
1906
1907 tree
1908 }
1909 }
1910 }
1911
1912 pub fn expect_type_assign(
1913 &mut self,
1914 tipo: &Rc<Type>,
1915 value: AirTree,
1916 defined_data_types: &mut IndexMap<String, u64>,
1917 location: Span,
1918 then: AirTree,
1919 otherwise: Otherwise,
1920 ) -> AirTree {
1921 assert!(
1922 tipo.get_generic_id().is_none(),
1923 "left-hand side of expect is generic: {}",
1924 tipo.to_pretty(0)
1925 );
1926 let tipo = &convert_opaque_type(tipo, &self.data_types, true);
1929
1930 let uplc_type = tipo.get_uplc_type();
1931
1932 match uplc_type {
1933 Some(
1936 UplcType::Integer
1937 | UplcType::String
1938 | UplcType::Bool
1939 | UplcType::ByteString
1940 | UplcType::Unit
1941 | UplcType::Bls12_381G1Element
1942 | UplcType::Bls12_381G2Element
1943 | UplcType::Bls12_381MlResult
1944 | UplcType::Data,
1945 ) => then,
1946
1947 Some(UplcType::List(_)) if tipo.is_map() => {
1949 assert!(!tipo.get_inner_types().is_empty());
1950
1951 let inner_list_type = &tipo.get_inner_types()[0];
1952 let inner_pair_types = inner_list_type.get_inner_types();
1953
1954 assert!(inner_pair_types.len() == 2);
1955
1956 let map_name = format!("__map_span_{}_{}", location.start, location.end);
1957 let pair_name = format!("__pair_span_{}_{}", location.start, location.end);
1958 let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end);
1959 let snd_name = format!("__pair_snd_span_{}_{}", location.start, location.end);
1960 let curried_expect_on_list = "__curried_expect_on_list".to_string();
1961 let list = "__list".to_string();
1962
1963 let map_name_interned = introduce_name(&mut self.interner, &map_name);
1964 let pair_name_interned = introduce_name(&mut self.interner, &pair_name);
1965 let fst_name_interned = introduce_name(&mut self.interner, &fst_name);
1966 let snd_name_interned = introduce_name(&mut self.interner, &snd_name);
1967 let curried_expect_on_list_interned =
1968 introduce_name(&mut self.interner, &curried_expect_on_list);
1969 let list_interned = introduce_name(&mut self.interner, &list);
1970
1971 let expect_snd = self.expect_type_assign(
1972 &inner_pair_types[1],
1973 AirTree::local_var(snd_name_interned.clone(), inner_pair_types[1].clone()),
1974 defined_data_types,
1975 location,
1976 AirTree::call(
1977 AirTree::local_var(&curried_expect_on_list_interned, Type::void()),
1978 Type::void(),
1979 vec![AirTree::builtin(
1980 DefaultFunction::TailList,
1981 Type::list(Type::data()),
1982 vec![AirTree::local_var(&list_interned, tipo.clone())],
1983 )],
1984 ),
1985 otherwise.clone(),
1986 );
1987
1988 let expect_fst = self.expect_type_assign(
1989 &inner_pair_types[0],
1990 AirTree::local_var(fst_name_interned.clone(), inner_pair_types[0].clone()),
1991 defined_data_types,
1992 location,
1993 expect_snd,
1994 otherwise.clone(),
1995 );
1996
1997 let unwrap_function = AirTree::anon_func(
1998 vec![list_interned.clone(), curried_expect_on_list_interned],
1999 AirTree::list_empty(
2000 AirTree::local_var(&list_interned, tipo.clone()),
2001 then,
2002 AirTree::anon_func(
2003 vec![],
2004 AirTree::let_assignment(
2005 &pair_name_interned,
2006 AirTree::builtin(
2007 DefaultFunction::HeadList,
2008 Type::pair(Type::data(), Type::data()),
2009 vec![AirTree::local_var(list_interned, tipo.clone())],
2010 ),
2011 AirTree::pair_access(
2012 Some(fst_name_interned),
2013 Some(snd_name_interned),
2014 inner_list_type.clone(),
2015 AirTree::local_var(
2016 &pair_name_interned,
2017 inner_list_type.clone(),
2018 ),
2019 true,
2020 expect_fst,
2021 otherwise.unwrap_or_else(DELAY_ERROR),
2022 ),
2023 ),
2024 true,
2025 ),
2026 ),
2027 false,
2028 );
2029
2030 let function = self.code_gen_functions.get(EXPECT_ON_LIST);
2031
2032 if function.is_none() {
2034 let expect_list_func = AirTree::expect_on_list2();
2035 self.code_gen_functions.insert(
2036 EXPECT_ON_LIST.to_string(),
2037 CodeGenFunction::Function {
2038 body: expect_list_func,
2039 params: vec!["__list_to_check".to_string(), "__check_with".to_string()],
2040 },
2041 );
2042 }
2043
2044 if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) {
2045 *counter += 1
2046 } else {
2047 defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1);
2048 }
2049
2050 let func_call = AirTree::call(
2051 AirTree::var(
2052 ValueConstructor::public(
2053 Type::void(),
2054 ValueConstructorVariant::ModuleFn {
2055 name: EXPECT_ON_LIST.to_string(),
2056 field_map: None,
2057 module: "".to_string(),
2058 arity: 1,
2059 location,
2060 builtin: None,
2061 },
2062 ),
2063 EXPECT_ON_LIST,
2064 "",
2065 ),
2066 Type::void(),
2067 vec![
2068 AirTree::local_var(&map_name_interned, tipo.clone()),
2069 unwrap_function,
2070 ],
2071 );
2072
2073 let tree = AirTree::let_assignment(map_name_interned, value, func_call);
2074
2075 self.interner.pop_text(map_name);
2076 self.interner.pop_text(pair_name);
2077 self.interner.pop_text(fst_name);
2078 self.interner.pop_text(snd_name);
2079 self.interner.pop_text(curried_expect_on_list);
2080 self.interner.pop_text(list);
2081
2082 tree
2083 }
2084 Some(UplcType::List(_)) if tipo.is_tuple() => {
2086 let tuple_inner_types = tipo.get_inner_types();
2087
2088 assert!(!tuple_inner_types.is_empty());
2089
2090 let tuple_name = format!("__tuple_span_{}_{}", location.start, location.end);
2091
2092 let tuple_name_interned = introduce_name(&mut self.interner, &tuple_name);
2093
2094 let mut tuple_expect_items = vec![];
2095
2096 let then =
2097 tuple_inner_types
2098 .iter()
2099 .enumerate()
2100 .rfold(then, |then, (index, arg)| {
2101 let tuple_index_name = format!(
2102 "__tuple_index_{}_span_{}_{}",
2103 index, location.start, location.end
2104 );
2105
2106 let tuple_index_name_interned =
2107 introduce_name(&mut self.interner, &tuple_index_name);
2108
2109 let expect_tuple_item = self.expect_type_assign(
2110 arg,
2111 AirTree::local_var(&tuple_index_name_interned, arg.clone()),
2112 defined_data_types,
2113 location,
2114 then,
2115 otherwise.clone(),
2116 );
2117
2118 tuple_expect_items.push(tuple_index_name_interned);
2119
2120 self.interner.pop_text(tuple_index_name);
2121
2122 expect_tuple_item
2123 });
2124
2125 tuple_expect_items.reverse();
2126
2127 let tuple_access = AirTree::tuple_access(
2128 tuple_expect_items,
2129 tipo.clone(),
2130 AirTree::local_var(&tuple_name_interned, tipo.clone()),
2131 true,
2132 then,
2133 otherwise.unwrap_or_else(DELAY_ERROR),
2134 );
2135
2136 let tree = AirTree::let_assignment(tuple_name_interned, value, tuple_access);
2137
2138 self.interner.pop_text(tuple_name);
2139
2140 tree
2141 }
2142 Some(UplcType::List(_)) => {
2144 assert!(!tipo.get_inner_types().is_empty());
2145
2146 let inner_list_type = &tipo.get_inner_types()[0];
2147
2148 if inner_list_type.is_data() {
2149 then
2150 } else {
2151 let list_name = format!("__list_span_{}_{}", location.start, location.end);
2152 let item_name = format!("__item_span_{}_{}", location.start, location.end);
2153 let list = "__list".to_string();
2154 let curried_func = "__curried_expect_on_list".to_string();
2155
2156 let list_name_interned = introduce_name(&mut self.interner, &list_name);
2157 let item_name_interned = introduce_name(&mut self.interner, &item_name);
2158 let list_interned = introduce_name(&mut self.interner, &list);
2159 let curried_func_interned = introduce_name(&mut self.interner, &curried_func);
2160
2161 let unwrap_function = AirTree::anon_func(
2162 vec![list_interned.clone(), curried_func_interned.clone()],
2163 AirTree::list_empty(
2164 AirTree::local_var(&list_interned, tipo.clone()),
2165 then,
2166 AirTree::anon_func(
2167 vec![],
2168 AirTree::let_assignment(
2169 &item_name_interned,
2170 AirTree::builtin(
2171 DefaultFunction::HeadList,
2172 Type::data(),
2173 vec![AirTree::local_var(&list_interned, tipo.clone())],
2174 ),
2175 AirTree::soft_cast_assignment(
2176 &item_name_interned,
2177 inner_list_type.clone(),
2178 AirTree::local_var(&item_name_interned, Type::data()),
2179 self.expect_type_assign(
2180 inner_list_type,
2181 AirTree::local_var(
2182 &item_name_interned,
2183 inner_list_type.clone(),
2184 ),
2185 defined_data_types,
2186 location,
2187 AirTree::call(
2188 AirTree::local_var(
2189 curried_func_interned,
2190 Type::void(),
2191 ),
2192 Type::void(),
2193 vec![AirTree::builtin(
2194 DefaultFunction::TailList,
2195 Type::list(Type::data()),
2196 vec![AirTree::local_var(
2197 list_interned,
2198 tipo.clone(),
2199 )],
2200 )],
2201 ),
2202 otherwise.clone(),
2203 ),
2204 otherwise.unwrap_or_else(DELAY_ERROR),
2205 ),
2206 ),
2207 true,
2208 ),
2209 ),
2210 false,
2211 );
2212
2213 let function = self.code_gen_functions.get(EXPECT_ON_LIST);
2214
2215 if function.is_none() {
2216 let expect_list_func = AirTree::expect_on_list2();
2217 self.code_gen_functions.insert(
2218 EXPECT_ON_LIST.to_string(),
2219 CodeGenFunction::Function {
2220 body: expect_list_func,
2221 params: vec![
2222 "__list_to_check".to_string(),
2223 "__check_with".to_string(),
2224 ],
2225 },
2226 );
2227 }
2228
2229 if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) {
2230 *counter += 1
2231 } else {
2232 defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1);
2233 }
2234
2235 let func_call = AirTree::call(
2236 AirTree::var(
2237 ValueConstructor::public(
2238 Type::void(),
2239 ValueConstructorVariant::ModuleFn {
2240 name: EXPECT_ON_LIST.to_string(),
2241 field_map: None,
2242 module: "".to_string(),
2243 arity: 1,
2244 location,
2245 builtin: None,
2246 },
2247 ),
2248 EXPECT_ON_LIST,
2249 "",
2250 ),
2251 Type::void(),
2252 vec![
2253 AirTree::local_var(&list_name_interned, tipo.clone()),
2254 unwrap_function,
2255 ],
2256 );
2257
2258 let tree = AirTree::let_assignment(list_name_interned, value, func_call);
2259
2260 self.interner.pop_text(list_name);
2261 self.interner.pop_text(item_name);
2262 self.interner.pop_text(list);
2263 self.interner.pop_text(curried_func);
2264
2265 tree
2266 }
2267 }
2268 Some(UplcType::Pair(_, _)) => {
2270 let tuple_inner_types = tipo.get_inner_types();
2271
2272 assert!(tuple_inner_types.len() == 2);
2273
2274 let pair_name = format!("__pair_span_{}_{}", location.start, location.end);
2275 let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end);
2276 let snd_name = format!("__pair_snd_span_{}_{}", location.start, location.end);
2277
2278 let pair_name_interned = introduce_name(&mut self.interner, &pair_name);
2279 let fst_name_interned = introduce_name(&mut self.interner, &fst_name);
2280 let snd_name_interned = introduce_name(&mut self.interner, &snd_name);
2281
2282 let expect_snd = self.expect_type_assign(
2283 &tuple_inner_types[1],
2284 AirTree::local_var(snd_name_interned.clone(), tuple_inner_types[1].clone()),
2285 defined_data_types,
2286 location,
2287 then,
2288 otherwise.clone(),
2289 );
2290
2291 let expect_fst = self.expect_type_assign(
2292 &tuple_inner_types[0],
2293 AirTree::local_var(fst_name_interned.clone(), tuple_inner_types[0].clone()),
2294 defined_data_types,
2295 location,
2296 expect_snd,
2297 otherwise.clone(),
2298 );
2299
2300 let pair_access = AirTree::pair_access(
2301 Some(fst_name_interned),
2302 Some(snd_name_interned),
2303 tipo.clone(),
2304 AirTree::local_var(&pair_name_interned, tipo.clone()),
2305 true,
2306 expect_fst,
2307 otherwise.unwrap_or_else(DELAY_ERROR),
2308 );
2309
2310 let tree = AirTree::let_assignment(pair_name_interned, value, pair_access);
2311
2312 self.interner.pop_text(pair_name);
2313 self.interner.pop_text(fst_name);
2314 self.interner.pop_text(snd_name);
2315
2316 tree
2317 }
2318
2319 None => {
2321 let data_type =
2322 lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| {
2323 unreachable!("We need a data type definition for type {:#?}", tipo)
2324 });
2325
2326 assert!(data_type.typed_parameters.len() == tipo.arg_types().unwrap().len());
2327
2328 let mono_types: IndexMap<u64, Rc<Type>> = if !data_type.typed_parameters.is_empty()
2329 {
2330 data_type
2331 .typed_parameters
2332 .iter()
2333 .zip(tipo.arg_types().unwrap())
2334 .flat_map(|item| get_generic_id_and_type(item.0, &item.1))
2335 .collect()
2336 } else {
2337 IndexMap::new()
2338 };
2339
2340 let data_type_name = expect_decoder_function_name(tipo, otherwise.is_some());
2341 let function = self.code_gen_functions.get(&data_type_name);
2342
2343 if function.is_none() && defined_data_types.get(&data_type_name).is_none() {
2345 defined_data_types.insert(data_type_name.clone(), 1);
2346
2347 let var_then = AirTree::call(
2348 AirTree::local_var("then_delayed", Type::void()),
2349 Type::void(),
2350 vec![],
2351 );
2352
2353 let otherwise_delayed = otherwise
2354 .as_ref()
2355 .map(|_| AirTree::local_var("otherwise_delayed", Type::void()));
2356
2357 let is_never = data_type.is_never();
2358
2359 let list_decorator = data_type
2360 .decorators
2361 .iter()
2362 .any(|dec| matches!(dec.kind, DecoratorKind::List));
2363
2364 let constr_clauses = data_type.constructors.iter().enumerate().rfold(
2365 otherwise_delayed.clone().unwrap_or_else(DELAY_ERROR),
2366 |acc, (index, constr)| {
2367 if is_never && index == 0 {
2373 return acc;
2374 }
2375
2376 let index = if let Some(tag) =
2377 constr.decorators.iter().find_map(|d| match &d.kind {
2378 DecoratorKind::Tag { value, .. } => Some(value),
2379 _ => None,
2380 }) {
2381 *tag
2382 } else {
2383 index
2384 };
2385
2386 let mut constr_args = vec![];
2387
2388 let constr_then = constr.arguments.iter().enumerate().rfold(
2389 var_then.clone(),
2390 |then, (index, arg)| {
2391 let arg_name =
2392 arg.label.clone().unwrap_or(format!("__field_{index}"));
2393
2394 let arg_tipo =
2395 find_and_replace_generics(&arg.tipo, &mono_types);
2396
2397 constr_args.push((index, arg_name.clone(), arg_tipo.clone()));
2398
2399 self.expect_type_assign(
2400 &arg_tipo.clone(),
2401 AirTree::local_var(arg_name, arg_tipo),
2402 defined_data_types,
2403 location,
2404 then,
2405 otherwise_delayed.clone(),
2406 )
2407 },
2408 );
2409 constr_args.reverse();
2410
2411 let then = if constr_args.is_empty() {
2412 AirTree::fields_empty(
2413 AirTree::local_var(
2414 format!(
2415 "__constr_var_span_{}_{}",
2416 location.start, location.end
2417 ),
2418 tipo.clone(),
2419 ),
2420 constr_then,
2421 otherwise_delayed.clone().unwrap_or_else(DELAY_ERROR),
2422 list_decorator,
2423 )
2424 } else {
2425 AirTree::fields_expose(
2426 constr_args,
2427 AirTree::local_var(
2428 format!(
2429 "__constr_var_span_{}_{}",
2430 location.start, location.end
2431 ),
2432 tipo.clone(),
2433 ),
2434 true,
2435 constr_then,
2436 otherwise_delayed.clone().unwrap_or_else(DELAY_ERROR),
2437 list_decorator,
2438 )
2439 };
2440
2441 if list_decorator {
2442 AirTree::anon_func(vec![], then, true)
2443 } else {
2444 AirTree::anon_func(
2445 vec![],
2446 AirTree::clause(
2447 format!(
2448 "__subject_span_{}_{}",
2449 location.start, location.end
2450 ),
2451 AirTree::int(index),
2452 tipo.clone(),
2453 then,
2454 acc,
2455 ),
2456 true,
2457 )
2458 }
2459 },
2460 );
2461
2462 let when_expr = AirTree::when(
2463 format!("__subject_span_{}_{}", location.start, location.end),
2464 Type::void(),
2465 tipo.clone(),
2466 AirTree::local_var(
2467 format!("__constr_var_span_{}_{}", location.start, location.end),
2468 tipo.clone(),
2469 ),
2470 AirTree::call(constr_clauses, Type::void(), vec![]),
2471 );
2472
2473 let func_body = AirTree::let_assignment(
2474 format!("__constr_var_span_{}_{}", location.start, location.end),
2475 AirTree::local_var("__param_0", tipo.clone()),
2476 when_expr,
2477 );
2478
2479 let code_gen_func = CodeGenFunction::Function {
2480 body: func_body,
2481 params: if otherwise.is_some() {
2482 vec![
2483 "__param_0".to_string(),
2484 "then_delayed".to_string(),
2485 "otherwise_delayed".to_string(),
2486 ]
2487 } else {
2488 vec!["__param_0".to_string(), "then_delayed".to_string()]
2489 },
2490 };
2491
2492 self.code_gen_functions
2493 .insert(data_type_name.clone(), code_gen_func);
2494 } else if defined_data_types.get(&data_type_name).is_none() {
2495 defined_data_types.insert(data_type_name.to_string(), 1);
2496 }
2497
2498 let args = if let Some(otherwise) = otherwise {
2499 vec![value, AirTree::anon_func(vec![], then, true), otherwise]
2500 } else {
2501 vec![value, AirTree::anon_func(vec![], then, true)]
2502 };
2503
2504 let module_fn = ValueConstructorVariant::ModuleFn {
2505 name: data_type_name.to_string(),
2506 field_map: None,
2507 module: "".to_string(),
2508 arity: args.len(),
2509 location,
2510 builtin: None,
2511 };
2512
2513 let func_var = AirTree::var(
2514 ValueConstructor::public(tipo.clone(), module_fn),
2515 data_type_name,
2516 "",
2517 );
2518
2519 AirTree::call(func_var, Type::void(), args)
2520 }
2521 }
2522 }
2523
2524 fn handle_decision_tree(
2525 &mut self,
2526 subject_name: &String,
2527 subject_tipo: Rc<Type>,
2528 return_tipo: Rc<Type>,
2529 module_build_name: &str,
2530 tree: decision_tree::DecisionTree<'_>,
2531 mut stick_set: TreeSet,
2532 ) -> AirTree {
2533 match tree {
2534 DecisionTree::Switch {
2535 path,
2536 mut cases,
2537 default,
2538 } => {
2539 let current_tipo = get_tipo_by_path(subject_tipo.clone(), &path);
2541 let builtins_path = Builtins::new_from_path(subject_tipo.clone(), path);
2542 let current_subject_name = if builtins_path.is_empty() {
2543 subject_name.clone()
2544 } else {
2545 format!("{subject_name}_{builtins_path}")
2546 };
2547
2548 let builtins_to_add = stick_set.diff_union_builtins(builtins_path.clone());
2550
2551 let prev_builtins = Builtins {
2553 vec: builtins_path.vec[0..(builtins_path.len() - builtins_to_add.len())]
2554 .to_vec(),
2555 };
2556
2557 let prev_subject_name = if prev_builtins.is_empty() {
2558 subject_name.clone()
2559 } else {
2560 format!("{subject_name}_{prev_builtins}")
2561 };
2562 let prev_tipo = prev_builtins
2563 .vec
2564 .last()
2565 .map_or(subject_tipo.clone(), |last| last.tipo());
2566
2567 let data_type = lookup_data_type_by_tipo(&self.data_types, ¤t_tipo);
2568
2569 let last_clause = if data_type
2570 .as_ref()
2571 .is_none_or(|d| d.constructors.len() != cases.len())
2572 {
2573 *default.unwrap()
2574 } else {
2575 cases.pop().unwrap().1
2576 };
2577
2578 let last_clause = self.handle_decision_tree(
2579 subject_name,
2580 subject_tipo.clone(),
2581 return_tipo.clone(),
2582 module_build_name,
2583 last_clause,
2584 stick_set.clone(),
2585 );
2586
2587 let test_subject_name = if data_type.is_some() {
2588 format!("{}_index", current_subject_name.clone(),)
2589 } else {
2590 current_subject_name.clone()
2591 };
2592
2593 let clauses = cases.into_iter().rfold(last_clause, |acc, (case, then)| {
2594 let case_air = self.handle_decision_tree(
2595 subject_name,
2596 subject_tipo.clone(),
2597 return_tipo.clone(),
2598 module_build_name,
2599 then,
2600 stick_set.clone(),
2601 );
2602
2603 AirTree::clause(
2604 test_subject_name.clone(),
2605 case.get_air_pattern(current_tipo.clone()),
2606 current_tipo.clone(),
2607 case_air,
2608 AirTree::anon_func(vec![], acc, true),
2609 )
2610 });
2611
2612 let when_air_clauses = AirTree::when(
2613 test_subject_name,
2614 return_tipo.clone(),
2615 current_tipo.clone(),
2616 AirTree::local_var(current_subject_name, current_tipo.clone()),
2617 clauses,
2618 );
2619
2620 builtins_to_add.produce_air(prev_subject_name, prev_tipo, when_air_clauses)
2621 }
2622 DecisionTree::ListSwitch {
2623 path,
2624 cases,
2625 tail_cases,
2626 default,
2627 } => {
2628 let current_tipo = get_tipo_by_path(subject_tipo.clone(), &path);
2630 let builtins_path = Builtins::new_from_path(subject_tipo.clone(), path);
2631 let current_subject_name = if builtins_path.is_empty() {
2632 subject_name.clone()
2633 } else {
2634 format!("{subject_name}_{builtins_path}")
2635 };
2636
2637 let builtins_to_add = stick_set.diff_union_builtins(builtins_path.clone());
2639
2640 let prev_builtins = Builtins {
2642 vec: builtins_path.vec[0..(builtins_path.len() - builtins_to_add.len())]
2643 .to_vec(),
2644 };
2645
2646 let prev_subject_name = if prev_builtins.is_empty() {
2647 subject_name.clone()
2648 } else {
2649 format!("{subject_name}_{prev_builtins}")
2650 };
2651 let prev_tipo = prev_builtins
2652 .vec
2653 .last()
2654 .map_or(subject_tipo.clone(), |last| last.tipo());
2655
2656 let longest_pattern = cases.iter().chain(tail_cases.iter()).fold(
2657 0,
2658 |longest, (case, _)| match case {
2659 CaseTest::List(i) => {
2660 if longest < *i {
2661 *i
2662 } else {
2663 longest
2664 }
2665 }
2666 CaseTest::ListWithTail(i) => {
2667 if longest < *i {
2668 *i - 1
2669 } else {
2670 longest
2671 }
2672 }
2673 _ => unreachable!(),
2674 },
2675 );
2676
2677 let last_pattern = if tail_cases.is_empty() {
2678 *default.as_ref().unwrap().clone()
2679 } else {
2680 let tree = tail_cases.last().unwrap();
2681
2682 tree.1.clone()
2683 };
2684
2685 let builtins_for_pattern = builtins_path.merge(Builtins::new_from_list_case(
2686 CaseTest::List(longest_pattern),
2687 ));
2688
2689 stick_set.diff_union_builtins(builtins_for_pattern.clone());
2690
2691 let last_pattern = self.handle_decision_tree(
2692 subject_name,
2693 subject_tipo.clone(),
2694 return_tipo.clone(),
2695 module_build_name,
2696 last_pattern,
2697 stick_set.clone(),
2698 );
2699
2700 let list_clauses = (0..=longest_pattern).rev().with_position().fold(
2701 (builtins_for_pattern, last_pattern),
2702 |(mut builtins_for_pattern, acc), list_item| match list_item {
2703 itertools::Position::First(index) | itertools::Position::Only(index) => {
2704 let (_, tree) = cases
2705 .iter()
2706 .chain(tail_cases.iter())
2707 .find(|x| match x.0 {
2708 CaseTest::List(i) => i == index,
2709 CaseTest::ListWithTail(i) => i <= index,
2710 _ => unreachable!(),
2711 })
2712 .cloned()
2713 .unwrap_or_else(|| {
2714 (CaseTest::Wild, *default.as_ref().unwrap().clone())
2715 });
2716
2717 let tail_name = if builtins_for_pattern.is_empty() {
2718 subject_name.clone()
2719 } else {
2720 format!("{subject_name}_{builtins_for_pattern}")
2721 };
2722
2723 let then = self.handle_decision_tree(
2724 subject_name,
2725 subject_tipo.clone(),
2726 return_tipo.clone(),
2727 module_build_name,
2728 tree,
2729 stick_set.clone(),
2730 );
2731
2732 let acc = AirTree::list_clause(
2733 tail_name.clone(),
2734 subject_tipo.clone(),
2735 then,
2736 AirTree::anon_func(vec![], acc, true),
2737 None,
2738 );
2739
2740 builtins_for_pattern.pop();
2741
2742 (builtins_for_pattern, acc)
2743 }
2744
2745 itertools::Position::Middle(index) | itertools::Position::Last(index) => {
2746 let (_, tree) = cases
2747 .iter()
2748 .chain(tail_cases.iter())
2749 .find(|x| match x.0 {
2750 CaseTest::List(i) => i == index,
2751 CaseTest::ListWithTail(i) => i <= index,
2752 _ => unreachable!(),
2753 })
2754 .cloned()
2755 .unwrap_or_else(|| {
2756 (CaseTest::Wild, *default.as_ref().unwrap().clone())
2757 });
2758
2759 let tail_name = if builtins_for_pattern.is_empty() {
2760 subject_name.clone()
2761 } else {
2762 format!("{subject_name}_{builtins_for_pattern}")
2763 };
2764
2765 let next_tail_name = Some(format!("{tail_name}_tail"));
2768
2769 let then = self.handle_decision_tree(
2770 subject_name,
2771 subject_tipo.clone(),
2772 return_tipo.clone(),
2773 module_build_name,
2774 tree,
2775 stick_set.clone(),
2776 );
2777
2778 let acc = AirTree::list_clause(
2779 tail_name.clone(),
2780 subject_tipo.clone(),
2781 then,
2782 AirTree::anon_func(vec![], acc, true),
2783 next_tail_name.map(|next| (tail_name, next)),
2784 );
2785
2786 builtins_for_pattern.pop();
2790
2791 (builtins_for_pattern, acc)
2792 }
2793 },
2794 );
2795
2796 let when_list_cases = AirTree::when(
2797 current_subject_name.clone(),
2798 return_tipo.clone(),
2799 current_tipo.clone(),
2800 AirTree::local_var(current_subject_name, current_tipo.clone()),
2801 list_clauses.1,
2802 );
2803
2804 builtins_to_add.produce_air(prev_subject_name, prev_tipo, when_list_cases)
2805 }
2806 DecisionTree::HoistedLeaf(name, args) => {
2807 let air_args = args
2808 .iter()
2809 .map(|item| {
2810 let current_tipo = get_tipo_by_path(subject_tipo.clone(), &item.path);
2811
2812 (
2813 current_tipo.clone(),
2814 AirTree::local_var(item.assigned.clone(), current_tipo),
2815 )
2816 })
2817 .collect_vec();
2818
2819 let then = AirTree::call(
2820 AirTree::local_var(
2821 name,
2822 Type::function(
2823 air_args.iter().map(|i| i.0.clone()).collect_vec(),
2824 return_tipo.clone(),
2825 ),
2826 ),
2827 Type::void(),
2828 air_args.into_iter().map(|i| i.1).collect_vec(),
2829 );
2830
2831 handle_assigns(subject_name, subject_tipo, &args, &mut stick_set, then)
2832 }
2833 DecisionTree::HoistThen {
2834 name,
2835 assigns,
2836 pattern,
2837 then,
2838 } => {
2839 let assign = AirTree::let_assignment(
2840 name,
2841 AirTree::anon_func(
2842 assigns
2843 .iter()
2844 .map(|i| introduce_name(&mut self.interner, &i.assigned))
2845 .collect_vec(),
2846 self.build(then, module_build_name, &[]),
2849 true,
2850 ),
2851 self.handle_decision_tree(
2852 subject_name,
2853 subject_tipo,
2854 return_tipo,
2855 module_build_name,
2856 *pattern,
2857 stick_set,
2858 ),
2859 );
2860
2861 assigns.into_iter().for_each(|x| {
2862 self.interner.pop_text(x.assigned);
2863 });
2864
2865 assign
2866 }
2867 }
2868 }
2869
2870 fn hoist_functions_to_validator(&mut self, mut air_tree: AirTree) -> AirTree {
2871 let mut functions_to_hoist = IndexMap::new();
2872 let mut used_functions = vec![];
2873 let mut defined_functions = vec![];
2874 let mut hoisted_functions = vec![];
2875 let mut validator_hoistable;
2876
2877 air_tree.traverse_tree_with(&mut |air_tree: &mut AirTree, _| {
2879 erase_opaque_type_operations(air_tree, &self.data_types);
2880 });
2881
2882 self.find_function_vars_and_depth(
2883 &mut air_tree,
2884 &mut functions_to_hoist,
2885 &mut used_functions,
2886 &mut TreePath::new(),
2887 0,
2888 Fields::FirstField,
2889 );
2890
2891 validator_hoistable = used_functions.clone();
2892
2893 while let Some((key, variant_name)) = used_functions.pop() {
2894 defined_functions.push((key.clone(), variant_name.clone()));
2895
2896 let function_variants = functions_to_hoist
2897 .get(&key)
2898 .unwrap_or_else(|| panic!("Missing Function Definition"));
2899
2900 let (tree_path, function) = function_variants
2901 .get(&variant_name)
2902 .unwrap_or_else(|| panic!("Missing Function Variant Definition"));
2903
2904 match function {
2905 HoistableFunction::Function { body, deps, params } => {
2906 let mut hoist_body = body.clone();
2907 let mut hoist_deps = deps.clone();
2908 let params = params.clone();
2909 let tree_path = tree_path.clone();
2910
2911 self.define_dependent_functions(
2912 &mut hoist_body,
2913 &mut functions_to_hoist,
2914 &mut used_functions,
2915 &defined_functions,
2916 &mut hoist_deps,
2917 tree_path,
2918 );
2919
2920 let function_variants = functions_to_hoist
2921 .get_mut(&key)
2922 .unwrap_or_else(|| panic!("Missing Function Definition"));
2923
2924 let (_, function) = function_variants
2925 .get_mut(&variant_name)
2926 .expect("Missing Function Variant Definition");
2927
2928 *function = HoistableFunction::Function {
2929 body: hoist_body,
2930 deps: hoist_deps,
2931 params,
2932 };
2933 }
2934 HoistableFunction::Link(_) => todo!("Deal with Link later"),
2935 _ => unreachable!(),
2936 }
2937 }
2938 validator_hoistable.dedup();
2939
2940 let inputs = functions_to_hoist
2945 .iter()
2946 .flat_map(|(function_name, val)| {
2947 val.into_iter()
2948 .map(|(variant, (_, function))| {
2949 if let HoistableFunction::Function { deps, .. } = function {
2950 ((function_name.clone(), variant.clone()), deps)
2951 } else {
2952 todo!("Deal with Link later")
2953 }
2954 })
2955 .collect_vec()
2956 })
2957 .collect_vec();
2958
2959 let capacity = inputs.len();
2960
2961 let mut graph = Graph::<(), ()>::with_capacity(capacity, capacity * 5);
2962
2963 let mut indices = HashMap::with_capacity(capacity);
2964 let mut values = HashMap::with_capacity(capacity);
2965
2966 for (value, _) in &inputs {
2967 let index = graph.add_node(());
2968
2969 indices.insert(value.clone(), index);
2970
2971 values.insert(index, value.clone());
2972 }
2973
2974 for (value, deps) in inputs {
2975 if let Some(from_index) = indices.get(&value) {
2976 let deps = deps.iter().filter_map(|dep| indices.get(dep));
2977
2978 for to_index in deps {
2979 graph.add_edge(*from_index, *to_index, ());
2980 }
2981 }
2982 }
2983
2984 let strong_connections = algo::tarjan_scc(&graph);
2985
2986 for (index, connections) in strong_connections.into_iter().enumerate() {
2987 if connections.len() < 2 {
2989 continue;
2990 }
2991
2992 let cyclic_function_names = connections
2993 .iter()
2994 .map(|index| values.get(index).unwrap())
2995 .collect_vec();
2996
2997 let function_key = FunctionAccessKey {
2999 function_name: format!("__cyclic_function_{index}"),
3000 module_name: "".to_string(),
3001 };
3002
3003 let mut path = TreePath::new();
3004 let mut cycle_of_functions = vec![];
3005 let mut cycle_deps = vec![];
3006
3007 let function_list = cyclic_function_names
3008 .iter()
3009 .map(|(key, variant)| {
3010 format!(
3011 "{}{}{}",
3012 key.module_name,
3013 key.function_name,
3014 if variant.is_empty() {
3015 "".to_string()
3016 } else {
3017 format!("_{variant}")
3018 }
3019 )
3020 })
3021 .collect_vec();
3022
3023 for (index, (func_name, variant)) in cyclic_function_names.iter().enumerate() {
3026 self.cyclic_functions.insert(
3027 (func_name.clone(), variant.clone()),
3028 (function_list.clone(), index, function_key.clone()),
3029 );
3030
3031 let (tree_path, func) = functions_to_hoist
3032 .get_mut(func_name)
3033 .expect("Missing Function Definition")
3034 .get_mut(variant)
3035 .expect("Missing Function Variant Definition");
3036
3037 match func {
3038 HoistableFunction::Function { params, body, deps } => {
3039 cycle_of_functions.push((params.clone(), body.clone()));
3040 cycle_deps.push(deps.clone());
3041 }
3042
3043 _ => unreachable!(),
3044 }
3045
3046 if !path.was_set() {
3047 path = tree_path.clone();
3048 } else {
3049 path = path.common_ancestor(tree_path);
3050 }
3051
3052 *func = HoistableFunction::CyclicLink(function_key.clone());
3055 }
3056
3057 let cyclic_function = HoistableFunction::CyclicFunction {
3058 functions: cycle_of_functions,
3059 deps: cycle_deps
3060 .into_iter()
3061 .flatten()
3062 .dedup()
3063 .filter(|dependency| {
3065 !cyclic_function_names.iter().any(|(func_name, variant)| {
3066 func_name == &dependency.0 && variant == &dependency.1
3067 })
3068 })
3069 .collect_vec(),
3070 };
3071
3072 let mut cyclic_map = IndexMap::new();
3073 cyclic_map.insert("".to_string(), (path, cyclic_function));
3074
3075 functions_to_hoist.insert(function_key, cyclic_map);
3076 }
3077
3078 let mut sorted_function_vec: Vec<(FunctionAccessKey, String)> = vec![];
3081
3082 let functions_to_hoist_cloned = functions_to_hoist.clone();
3083
3084 let mut sorting_attempts: u64 = 0;
3085 while let Some((generic_func, variant)) = validator_hoistable.pop() {
3086 assert!(
3087 sorting_attempts < 5_000_000_000,
3088 "Sorting dependency attempts exceeded"
3089 );
3090
3091 let function_variants = functions_to_hoist_cloned
3092 .get(&generic_func)
3093 .unwrap_or_else(|| panic!("Missing Function Definition"));
3094
3095 let (_, function) = function_variants
3096 .get(&variant)
3097 .unwrap_or_else(|| panic!("Missing Function Variant Definition"));
3098
3099 match function {
3100 HoistableFunction::Function { deps, .. } => {
3101 for (dep_generic_func, dep_variant) in deps.iter() {
3102 if !(dep_generic_func == &generic_func && dep_variant == &variant) {
3103 validator_hoistable
3104 .insert(0, (dep_generic_func.clone(), dep_variant.clone()));
3105
3106 sorted_function_vec.retain(|(generic_func, variant)| {
3107 !(generic_func == dep_generic_func && variant == dep_variant)
3108 });
3109 }
3110 }
3111
3112 for (dep_key, dep_variant) in deps {
3114 let (func_tree_path, _) = functions_to_hoist
3115 .get(&generic_func)
3116 .unwrap()
3117 .get(&variant)
3118 .unwrap()
3119 .clone();
3120
3121 let (dep_path, _) = functions_to_hoist
3122 .get_mut(dep_key)
3123 .unwrap()
3124 .get_mut(dep_variant)
3125 .unwrap();
3126
3127 *dep_path = func_tree_path.common_ancestor(dep_path);
3128 }
3129 sorted_function_vec.push((generic_func, variant));
3130 }
3131 HoistableFunction::Link(_) => todo!("Deal with Link later"),
3132 HoistableFunction::CyclicLink(cyclic_name) => {
3133 validator_hoistable.insert(0, (cyclic_name.clone(), "".to_string()));
3134
3135 sorted_function_vec.retain(|(generic_func, variant)| {
3136 !(generic_func == cyclic_name && variant.is_empty())
3137 });
3138
3139 let (func_tree_path, _) = functions_to_hoist
3140 .get(&generic_func)
3141 .unwrap()
3142 .get(&variant)
3143 .unwrap()
3144 .clone();
3145
3146 let (dep_path, _) = functions_to_hoist
3147 .get_mut(cyclic_name)
3148 .unwrap()
3149 .get_mut("")
3150 .unwrap();
3151
3152 *dep_path = func_tree_path.common_ancestor(dep_path);
3153 }
3154 HoistableFunction::CyclicFunction { deps, .. } => {
3155 for (dep_generic_func, dep_variant) in deps.iter() {
3156 if !(dep_generic_func == &generic_func && dep_variant == &variant) {
3157 validator_hoistable
3158 .insert(0, (dep_generic_func.clone(), dep_variant.clone()));
3159
3160 sorted_function_vec.retain(|(generic_func, variant)| {
3161 !(generic_func == dep_generic_func && variant == dep_variant)
3162 });
3163 }
3164 }
3165
3166 for (dep_key, dep_variant) in deps {
3168 let (func_tree_path, _) = functions_to_hoist
3169 .get(&generic_func)
3170 .unwrap()
3171 .get(&variant)
3172 .unwrap()
3173 .clone();
3174
3175 let (dep_path, _) = functions_to_hoist
3176 .get_mut(dep_key)
3177 .unwrap()
3178 .get_mut(dep_variant)
3179 .unwrap();
3180
3181 *dep_path = func_tree_path.common_ancestor(dep_path);
3182 }
3183 sorted_function_vec.push((generic_func, variant));
3184 }
3185 }
3186
3187 sorting_attempts += 1;
3188 }
3189 sorted_function_vec.dedup();
3190
3191 for (key, variant) in sorted_function_vec {
3193 if hoisted_functions
3194 .iter()
3195 .any(|(func_key, func_variant)| func_key == &key && func_variant == &variant)
3196 {
3197 continue;
3198 }
3199
3200 let function_variants = functions_to_hoist
3201 .get(&key)
3202 .unwrap_or_else(|| panic!("Missing Function Definition"));
3203
3204 let (tree_path, function) = function_variants
3205 .get(&variant)
3206 .unwrap_or_else(|| panic!("Missing Function Variant Definition"));
3207
3208 self.hoist_function(
3209 &mut air_tree,
3210 tree_path,
3211 function,
3212 (&key, &variant),
3213 &functions_to_hoist,
3214 &mut hoisted_functions,
3215 );
3216 }
3217
3218 air_tree
3219 }
3220
3221 fn hoist_function(
3222 &mut self,
3223 air_tree: &mut AirTree,
3224 tree_path: &TreePath,
3225 function: &HoistableFunction,
3226 key_var: (&FunctionAccessKey, &String),
3227 functions_to_hoist: &IndexMap<
3228 FunctionAccessKey,
3229 IndexMap<String, (TreePath, HoistableFunction)>,
3230 >,
3231 hoisted_functions: &mut Vec<(FunctionAccessKey, String)>,
3232 ) {
3233 match function {
3234 HoistableFunction::Function {
3235 body,
3236 deps: func_deps,
3237 params,
3238 } => {
3239 let mut body = body.clone();
3240
3241 let (key, variant) = key_var;
3242
3243 let is_recursive = func_deps
3245 .iter()
3246 .any(|(dep_key, dep_variant)| dep_key == key && dep_variant == variant);
3247
3248 let func_params = params;
3250
3251 let deps = (tree_path, func_deps.clone());
3252
3253 let recursive_nonstatics = if is_recursive {
3254 modify_self_calls(&mut body, key, variant, func_params)
3255 } else {
3256 func_params.clone()
3257 };
3258
3259 let node_to_edit = air_tree.find_air_tree_node(tree_path);
3260
3261 let defined_function = AirTree::define_func(
3262 &key.function_name,
3263 &key.module_name,
3264 variant,
3265 func_params.clone(),
3266 is_recursive,
3267 recursive_nonstatics,
3268 body,
3269 node_to_edit.clone(),
3270 );
3271
3272 let defined_dependencies = self.hoist_dependent_functions(
3273 deps,
3274 (key, variant),
3275 hoisted_functions,
3276 functions_to_hoist,
3277 defined_function,
3278 );
3279
3280 *node_to_edit = defined_dependencies;
3282
3283 hoisted_functions.push((key.clone(), variant.clone()));
3284 }
3285 HoistableFunction::CyclicFunction {
3286 functions,
3287 deps: func_deps,
3288 } => {
3289 let (key, variant) = key_var;
3290
3291 let deps = (tree_path, func_deps.clone());
3292
3293 let mut functions = functions.clone();
3294
3295 for (_, body) in functions.iter_mut() {
3296 modify_cyclic_calls(body, key, &self.cyclic_functions);
3297 }
3298
3299 let node_to_edit = air_tree.find_air_tree_node(tree_path);
3300
3301 let cyclic_func = AirTree::define_cyclic_func(
3302 &key.function_name,
3303 &key.module_name,
3304 variant,
3305 functions,
3306 node_to_edit.clone(),
3307 );
3308
3309 let defined_dependencies = self.hoist_dependent_functions(
3310 deps,
3311 (key, variant),
3312 hoisted_functions,
3313 functions_to_hoist,
3314 cyclic_func,
3315 );
3316
3317 *node_to_edit = defined_dependencies;
3319
3320 hoisted_functions.push((key.clone(), variant.clone()));
3321 }
3322 HoistableFunction::Link(_) => {
3323 todo!("This should probably be unreachable when I get to it")
3324 }
3325 HoistableFunction::CyclicLink(_) => {
3326 unreachable!("Sorted functions should not contain cyclic links")
3327 }
3328 }
3329 }
3330
3331 fn hoist_dependent_functions(
3332 &mut self,
3333 deps: (&TreePath, Vec<(FunctionAccessKey, String)>),
3334 func_key_variant: (&FunctionAccessKey, &Variant),
3335 hoisted_functions: &mut Vec<(FunctionAccessKey, String)>,
3336 functions_to_hoist: &IndexMap<
3337 FunctionAccessKey,
3338 IndexMap<String, (TreePath, HoistableFunction)>,
3339 >,
3340 air_tree: AirTree,
3341 ) -> AirTree {
3342 let (key, variant) = func_key_variant;
3343 let (func_path, func_deps) = deps;
3344
3345 let mut deps_vec = func_deps;
3346 let mut sorted_dep_vec = vec![];
3347
3348 while let Some(dep) = deps_vec.pop() {
3349 let function_variants = functions_to_hoist
3350 .get(&dep.0)
3351 .unwrap_or_else(|| panic!("Missing Function Definition"));
3352
3353 let (_, function) = function_variants
3354 .get(&dep.1)
3355 .unwrap_or_else(|| panic!("Missing Function Variant Definition"));
3356
3357 match function {
3358 HoistableFunction::Function { deps, .. } => {
3359 for (dep_generic_func, dep_variant) in deps.iter() {
3360 if !(dep_generic_func == &dep.0 && dep_variant == &dep.1) {
3361 sorted_dep_vec.retain(|(generic_func, variant)| {
3362 !(generic_func == dep_generic_func && variant == dep_variant)
3363 });
3364
3365 deps_vec.insert(0, (dep_generic_func.clone(), dep_variant.clone()));
3366 }
3367 }
3368
3369 sorted_dep_vec.push((dep.0.clone(), dep.1.clone()));
3370 }
3371 HoistableFunction::CyclicFunction { deps, .. } => {
3372 for (dep_generic_func, dep_variant) in deps.iter() {
3373 if !(dep_generic_func == &dep.0 && dep_variant == &dep.1) {
3374 sorted_dep_vec.retain(|(generic_func, variant)| {
3375 !(generic_func == dep_generic_func && variant == dep_variant)
3376 });
3377
3378 deps_vec.insert(0, (dep_generic_func.clone(), dep_variant.clone()));
3379 }
3380 }
3381 sorted_dep_vec.push((dep.0.clone(), dep.1.clone()));
3382 }
3383 HoistableFunction::Link(_) => todo!("Deal with Link later"),
3384 HoistableFunction::CyclicLink(cyclic_func) => {
3385 sorted_dep_vec.retain(|(generic_func, variant)| {
3386 !(generic_func == cyclic_func && variant.is_empty())
3387 });
3388
3389 deps_vec.insert(0, (cyclic_func.clone(), "".to_string()));
3390 }
3391 }
3392 }
3393
3394 sorted_dep_vec.dedup();
3395
3396 sorted_dep_vec
3397 .into_iter()
3398 .fold(air_tree, |then, (dep_key, dep_variant)| {
3399 if
3400 hoisted_functions
3403 .iter()
3404 .any(|(generic, variant)| generic == &dep_key && variant == &dep_variant)
3405 || (&dep_key == key && &dep_variant == variant)
3406 {
3407 return then;
3408 }
3409
3410 let dependency = functions_to_hoist
3411 .get(&dep_key)
3412 .unwrap_or_else(|| panic!("Missing Function Definition"));
3413
3414 let (dep_path, dep_function) = dependency
3415 .get(&dep_variant)
3416 .unwrap_or_else(|| panic!("Missing Function Variant Definition"));
3417
3418 if &dep_path.common_ancestor(func_path) == func_path {
3422 match dep_function.clone() {
3423 HoistableFunction::Function {
3424 body: mut dep_air_tree,
3425 deps: dependency_deps,
3426 params: dependent_params,
3427 } => {
3428 let is_dependent_recursive = dependency_deps
3429 .iter()
3430 .any(|(key, variant)| &dep_key == key && &dep_variant == variant);
3431
3432 let recursive_nonstatics = if is_dependent_recursive {
3433 modify_self_calls(
3434 &mut dep_air_tree,
3435 &dep_key,
3436 &dep_variant,
3437 &dependent_params,
3438 )
3439 } else {
3440 dependent_params.clone()
3441 };
3442
3443 hoisted_functions.push((dep_key.clone(), dep_variant.clone()));
3444
3445 AirTree::define_func(
3446 &dep_key.function_name,
3447 &dep_key.module_name,
3448 &dep_variant,
3449 dependent_params,
3450 is_dependent_recursive,
3451 recursive_nonstatics,
3452 dep_air_tree,
3453 then,
3454 )
3455 }
3456 HoistableFunction::CyclicFunction { functions, .. } => {
3457 let mut functions = functions.clone();
3458
3459 for (_, body) in functions.iter_mut() {
3460 modify_cyclic_calls(body, &dep_key, &self.cyclic_functions);
3461 }
3462
3463 hoisted_functions.push((dep_key.clone(), dep_variant.clone()));
3464
3465 AirTree::define_cyclic_func(
3466 &dep_key.function_name,
3467 &dep_key.module_name,
3468 &dep_variant,
3469 functions,
3470 then,
3471 )
3472 }
3473 HoistableFunction::Link(_) => unreachable!(),
3474 HoistableFunction::CyclicLink(_) => unreachable!(),
3475 }
3476 } else {
3477 then
3478 }
3479 })
3480 }
3481
3482 fn define_dependent_functions(
3483 &mut self,
3484 air_tree: &mut AirTree,
3485 function_usage: &mut IndexMap<
3486 FunctionAccessKey,
3487 IndexMap<String, (TreePath, HoistableFunction)>,
3488 >,
3489 used_functions: &mut Vec<(FunctionAccessKey, String)>,
3490 defined_functions: &[(FunctionAccessKey, String)],
3491 current_function_deps: &mut Vec<(FunctionAccessKey, String)>,
3492 mut function_tree_path: TreePath,
3493 ) {
3494 let Some((depth, index)) = function_tree_path.pop() else {
3495 return;
3496 };
3497
3498 function_tree_path.push(depth, index);
3499
3500 self.find_function_vars_and_depth(
3501 air_tree,
3502 function_usage,
3503 current_function_deps,
3504 &mut function_tree_path,
3505 depth + 1,
3506 Fields::FirstField,
3507 );
3508
3509 for (generic_function_key, variant_name) in current_function_deps.iter() {
3510 if !used_functions
3511 .iter()
3512 .any(|(key, name)| key == generic_function_key && name == variant_name)
3513 && !defined_functions
3514 .iter()
3515 .any(|(key, name)| key == generic_function_key && name == variant_name)
3516 {
3517 used_functions.push((generic_function_key.clone(), variant_name.clone()));
3518 }
3519 }
3520 }
3521
3522 fn find_function_vars_and_depth(
3523 &mut self,
3524 air_tree: &mut AirTree,
3525 function_usage: &mut IndexMap<
3526 FunctionAccessKey,
3527 IndexMap<String, (TreePath, HoistableFunction)>,
3528 >,
3529 dependency_functions: &mut Vec<(FunctionAccessKey, String)>,
3530 path: &mut TreePath,
3531 current_depth: usize,
3532 depth_index: Fields,
3533 ) {
3534 air_tree.traverse_tree_with_path(
3535 path,
3536 current_depth,
3537 depth_index,
3538 &mut |air_tree, tree_path| {
3539 if let AirTree::Var {
3540 constructor,
3541 variant_name,
3542 ..
3543 } = air_tree
3544 {
3545 let ValueConstructorVariant::ModuleFn {
3546 name: func_name,
3547 module,
3548 builtin: None,
3549 ..
3550 } = &constructor.variant
3551 else {
3552 return;
3553 };
3554
3555 let function_var_tipo = &constructor.tipo;
3556
3557 let generic_function_key = FunctionAccessKey {
3558 module_name: module.clone(),
3559 function_name: func_name.clone(),
3560 };
3561
3562 let function_def = self.functions.get(&generic_function_key);
3563
3564 let Some(function_def) = function_def else {
3565 let code_gen_func = self
3566 .code_gen_functions
3567 .get(&generic_function_key.function_name)
3568 .unwrap_or_else(|| {
3569 panic!(
3570 "Missing function definition for {}. Known functions: {:?}",
3571 generic_function_key.function_name,
3572 self.functions.keys(),
3573 )
3574 });
3575
3576 if !dependency_functions
3577 .iter()
3578 .any(|(key, name)| key == &generic_function_key && name.is_empty())
3579 {
3580 dependency_functions
3581 .push((generic_function_key.clone(), "".to_string()));
3582 }
3583
3584 if let Some(func_variants) = function_usage.get_mut(&generic_function_key) {
3586 let (path, _) = func_variants.get_mut("").unwrap();
3587 *path = path.common_ancestor(tree_path);
3588 } else {
3589 let CodeGenFunction::Function { body, params } = code_gen_func else {
3591 unreachable!()
3592 };
3593
3594 let mut function_variant_path = IndexMap::new();
3595
3596 let mut body = AirTree::no_op(body.clone());
3597
3598 body.traverse_tree_with(&mut |air_tree, _| {
3599 erase_opaque_type_operations(air_tree, &self.data_types);
3600 });
3601
3602 function_variant_path.insert(
3603 "".to_string(),
3604 (
3605 tree_path.clone(),
3606 HoistableFunction::Function {
3607 body,
3608 deps: vec![],
3609 params: params.clone(),
3610 },
3611 ),
3612 );
3613
3614 function_usage.insert(generic_function_key, function_variant_path);
3615 }
3616 return;
3617 };
3618
3619 let mut function_var_types = function_var_tipo
3620 .arg_types()
3621 .unwrap_or_else(|| panic!("Expected a function tipo with arg types"));
3622
3623 function_var_types.push(
3624 function_var_tipo
3625 .return_type()
3626 .unwrap_or_else(|| panic!("Should have return type")),
3627 );
3628
3629 let mut function_def_types = function_def
3630 .arguments
3631 .iter()
3632 .map(|arg| convert_opaque_type(&arg.tipo, &self.data_types, true))
3633 .collect_vec();
3634
3635 function_def_types.push(convert_opaque_type(
3636 &function_def.return_type,
3637 &self.data_types,
3638 true,
3639 ));
3640
3641 let mono_types: IndexMap<u64, Rc<Type>> = if !function_def_types.is_empty() {
3642 function_def_types
3643 .iter()
3644 .zip(function_var_types.iter())
3645 .flat_map(|(func_tipo, var_tipo)| {
3646 get_generic_id_and_type(func_tipo, var_tipo)
3647 })
3648 .collect()
3649 } else {
3650 IndexMap::new()
3651 };
3652
3653 let variant = mono_types
3655 .iter()
3656 .map(|(_, tipo)| get_generic_variant_name(tipo))
3657 .join("");
3658
3659 variant_name.clone_from(&variant);
3660
3661 if !dependency_functions
3662 .iter()
3663 .any(|(key, name)| key == &generic_function_key && name == &variant)
3664 {
3665 dependency_functions.push((generic_function_key.clone(), variant.clone()));
3666 }
3667
3668 if let Some(func_variants) = function_usage.get_mut(&generic_function_key) {
3669 if let Some((path, _)) = func_variants.get_mut(&variant) {
3670 *path = path.common_ancestor(tree_path);
3671 } else {
3672 let args = function_def.arguments.clone();
3673
3674 let params = args
3675 .iter()
3676 .map(|arg| {
3677 arg.arg_name
3678 .get_variable_name()
3679 .map(|arg| {
3680 introduce_name(&mut self.interner, &arg.to_string())
3681 })
3682 .unwrap_or_else(|| DISCARDED.to_string())
3683 })
3684 .collect_vec();
3685
3686 let mut function_air_tree_body = AirTree::no_op(self.build(
3687 &function_def.body,
3688 &generic_function_key.module_name,
3689 &[],
3690 ));
3691
3692 function_air_tree_body.traverse_tree_with(&mut |air_tree, _| {
3693 erase_opaque_type_operations(air_tree, &self.data_types);
3694 monomorphize(air_tree, &mono_types);
3695 });
3696
3697 args.iter().for_each(|arg| {
3698 arg.arg_name.get_variable_name().iter().for_each(|arg| {
3699 self.interner.pop_text(arg.to_string());
3700 })
3701 });
3702
3703 func_variants.insert(
3704 variant,
3705 (
3706 tree_path.clone(),
3707 HoistableFunction::Function {
3708 body: function_air_tree_body,
3709 deps: vec![],
3710 params,
3711 },
3712 ),
3713 );
3714 }
3715 } else {
3716 let args = function_def.arguments.clone();
3717
3718 let params = args
3719 .iter()
3720 .map(|arg| {
3721 arg.arg_name
3722 .get_variable_name()
3723 .map(|arg| introduce_name(&mut self.interner, &arg.to_string()))
3724 .unwrap_or_else(|| DISCARDED.to_string())
3725 })
3726 .collect_vec();
3727
3728 let mut function_air_tree_body = AirTree::no_op(self.build(
3729 &function_def.body,
3730 &generic_function_key.module_name,
3731 &[],
3732 ));
3733
3734 function_air_tree_body.traverse_tree_with(&mut |air_tree, _| {
3735 erase_opaque_type_operations(air_tree, &self.data_types);
3736 monomorphize(air_tree, &mono_types);
3737 });
3738
3739 let mut function_variant_path = IndexMap::new();
3740
3741 args.iter().for_each(|arg| {
3742 arg.arg_name
3743 .get_variable_name()
3744 .iter()
3745 .for_each(|arg| self.interner.pop_text(arg.to_string()))
3746 });
3747
3748 function_variant_path.insert(
3749 variant,
3750 (
3751 tree_path.clone(),
3752 HoistableFunction::Function {
3753 body: function_air_tree_body,
3754 deps: vec![],
3755 params,
3756 },
3757 ),
3758 );
3759
3760 function_usage.insert(generic_function_key, function_variant_path);
3761 }
3762 }
3763 },
3764 );
3765 }
3766
3767 fn uplc_code_gen(&mut self, mut ir_stack: Vec<Air>) -> Term<Name> {
3768 let mut arg_stack: Vec<Term<Name>> = vec![];
3769
3770 while let Some(air_element) = ir_stack.pop() {
3771 let arg = self.gen_uplc(air_element, &mut arg_stack);
3772 if let Some(arg) = arg {
3773 arg_stack.push(arg);
3774 }
3775 }
3776 assert!(arg_stack.len() == 1, "Expected one term on the stack");
3777 arg_stack.pop().unwrap()
3778 }
3779
3780 fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec<Term<Name>>) -> Option<Term<Name>> {
3781 match ir {
3782 Air::Int { value } => Some(Term::integer(value.parse().unwrap())),
3783 Air::String { value } => Some(Term::string(value)),
3784 Air::ByteArray { bytes } => Some(Term::byte_string(bytes)),
3785 Air::Bool { value } => Some(Term::bool(value)),
3786 Air::CurvePoint { point, .. } => match point {
3787 Curve::Bls12_381(Bls12_381Point::G1(g1)) => Some(Term::bls12_381_g1(g1)),
3788 Curve::Bls12_381(Bls12_381Point::G2(g2)) => Some(Term::bls12_381_g2(g2)),
3789 },
3790 Air::Var {
3791 name,
3792 constructor,
3793 variant_name,
3794 } => match &constructor.variant {
3795 ValueConstructorVariant::LocalVariable { .. } => Some(Term::Var(
3796 Name {
3797 text: name,
3798 unique: 0.into(),
3799 }
3800 .into(),
3801 )),
3802 ValueConstructorVariant::ModuleConstant { module, name, .. } => {
3803 let access_key = FunctionAccessKey {
3804 module_name: module.clone(),
3805 function_name: name.clone(),
3806 };
3807
3808 let definition = self
3809 .constants
3810 .get(&access_key)
3811 .unwrap_or_else(|| panic!("unknown constant {module}.{name}"));
3812
3813 let mut value =
3814 AirTree::no_op(self.build(definition, &access_key.module_name, &[]));
3815
3816 value.traverse_tree_with(&mut |air_tree, _| {
3817 erase_opaque_type_operations(air_tree, &self.data_types);
3818 });
3819
3820 value = self.hoist_functions_to_validator(value);
3821
3822 let term = self.uplc_code_gen(value.to_vec());
3823
3824 let mut program =
3825 self.new_program(self.special_functions.apply_used_functions(term));
3826
3827 let mut interner = CodeGenInterner::new();
3828
3829 interner.program(&mut program);
3830
3831 let eval_program: Program<NamedDeBruijn> =
3832 program.clean_up_no_inlines().try_into().unwrap();
3833
3834 Some(
3835 eval_program
3836 .eval(ExBudget::max())
3837 .result()
3838 .unwrap_or_else(|e| panic!("Failed to evaluate constant: {e:#?}"))
3839 .try_into()
3840 .unwrap(),
3841 )
3842 }
3843 ValueConstructorVariant::ModuleFn {
3844 name: func_name,
3845 module,
3846 builtin,
3847 ..
3848 } => {
3849 if let Some(func) = builtin {
3850 return self.gen_uplc(
3851 Air::Builtin {
3852 count: 0,
3853 func: *func,
3854 tipo: constructor.tipo,
3855 },
3856 arg_stack,
3857 );
3858 }
3859
3860 if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&(
3861 FunctionAccessKey {
3862 module_name: module.clone(),
3863 function_name: func_name.clone(),
3864 },
3865 variant_name.clone(),
3866 )) {
3867 let cyclic_var_name = if cyclic_name.module_name.is_empty() {
3868 cyclic_name.function_name.to_string()
3869 } else {
3870 format!("{}_{}", cyclic_name.module_name, cyclic_name.function_name)
3871 };
3872
3873 let index_name = names[*index].clone();
3874
3875 let mut arg_var = Term::var(index_name.clone());
3876
3877 for name in names.iter().rev() {
3878 arg_var = arg_var.lambda(name);
3879 }
3880
3881 let term = Term::var(cyclic_var_name).apply(arg_var);
3882
3883 Some(term)
3884 } else {
3885 let name = if !module.is_empty() {
3886 format!("{module}_{func_name}{variant_name}")
3887 } else {
3888 format!("{func_name}{variant_name}")
3889 };
3890
3891 Some(Term::Var(
3892 Name {
3893 text: name,
3894 unique: 0.into(),
3895 }
3896 .into(),
3897 ))
3898 }
3899 }
3900 ValueConstructorVariant::Record {
3901 name: constr_name, ..
3902 } => {
3903 if constructor.tipo.is_bool() {
3904 Some(Term::bool(constr_name == "True"))
3905 } else if constructor.tipo.is_void() {
3906 Some(Term::Constant(UplcConstant::Unit.into()))
3907 } else if constructor.is_pair() {
3908 let args = constructor.tipo.arg_types().unwrap();
3909 let mut args = args.iter();
3910 let arg_left = args.next().unwrap();
3911 let arg_right = args.next().unwrap();
3912 Some(
3913 Term::mk_pair_data()
3914 .apply(convert_type_to_data(
3915 Term::var("left".to_string()),
3916 arg_left,
3917 &self.data_types,
3918 ))
3919 .apply(convert_type_to_data(
3920 Term::var("right".to_string()),
3921 arg_right,
3922 &self.data_types,
3923 ))
3924 .lambda("right".to_string())
3925 .lambda("left".to_string()),
3926 )
3927 } else {
3928 let data_type = crate::tipo::lookup_data_type_by_tipo(
3929 &self.data_types,
3930 &constructor.tipo,
3931 )
3932 .unwrap_or_else(|| {
3933 panic!(
3934 "could not find data-type definition for {} within known set: {:?}",
3935 constructor.tipo.to_pretty(0),
3936 self.data_types.keys()
3937 )
3938 });
3939
3940 let (constr_index, constr_type) =
3941 get_constr_index_variant(&data_type, constr_name).unwrap();
3942
3943 let list_decorator = data_type
3944 .decorators
3945 .iter()
3946 .any(|dec| matches!(dec.kind, DecoratorKind::List));
3947
3948 let mut term = Term::empty_list();
3949
3950 if constr_type.arguments.is_empty() {
3951 if !list_decorator {
3952 term = Term::constr_data()
3953 .apply(Term::integer(constr_index.into()))
3954 .apply(term);
3955 }
3956
3957 let mut program = self.new_program(term);
3958
3959 let mut interner = CodeGenInterner::new();
3960
3961 interner.program(&mut program);
3962
3963 let eval_program: Program<NamedDeBruijn> =
3964 program.clean_up_no_inlines().try_into().unwrap();
3965
3966 let evaluated_term: Term<NamedDeBruijn> = eval_program
3967 .eval(ExBudget::default())
3968 .result()
3969 .expect("Evaluated a constant record and got an error");
3970
3971 term = evaluated_term.try_into().unwrap();
3972 } else {
3973 for (index, arg) in constructor
3974 .tipo
3975 .arg_types()
3976 .unwrap()
3977 .iter()
3978 .enumerate()
3979 .rev()
3980 {
3981 term = Term::mk_cons()
3982 .apply(convert_type_to_data(
3983 Term::var(format!("arg_{index}")),
3984 arg,
3985 &self.data_types,
3986 ))
3987 .apply(term);
3988 }
3989 if !list_decorator {
3990 term = Term::constr_data()
3991 .apply(Term::integer(constr_index.into()))
3992 .apply(term);
3993 }
3994
3995 for (index, _) in constr_type.arguments.iter().enumerate().rev() {
3996 term = term.lambda(format!("arg_{index}"))
3997 }
3998 }
3999 Some(term)
4000 }
4001 }
4002 },
4003 Air::Void => Some(Term::Constant(UplcConstant::Unit.into())),
4004 Air::List { count, tipo, tail } => {
4005 let mut args = vec![];
4006
4007 for _ in 0..count {
4008 let arg = arg_stack.pop().unwrap();
4009 args.push(arg);
4010 }
4011 let mut constants = vec![];
4012 for arg in &args {
4013 let maybe_const = extract_constant(arg);
4014 if let Some(c) = maybe_const {
4015 constants.push(c);
4016 }
4017 }
4018
4019 if constants.len() == args.len() && !tail {
4020 let list = if tipo.is_map() {
4021 let mut convert_keys = vec![];
4022 let mut convert_values = vec![];
4023 for constant in constants {
4024 match constant.as_ref() {
4025 UplcConstant::ProtoPair(_, _, fst, snd) => {
4026 convert_keys.push(fst.clone());
4027 convert_values.push(snd.clone());
4028 }
4029 _ => unreachable!(),
4030 }
4031 }
4032
4033 let convert_keys = builder::convert_constants_to_data(convert_keys);
4034 let convert_values = builder::convert_constants_to_data(convert_values);
4035
4036 Term::Constant(
4037 UplcConstant::ProtoList(
4038 UplcType::Pair(UplcType::Data.into(), UplcType::Data.into()),
4039 convert_keys
4040 .into_iter()
4041 .zip(convert_values)
4042 .map(|(key, value)| {
4043 UplcConstant::ProtoPair(
4044 UplcType::Data,
4045 UplcType::Data,
4046 key.into(),
4047 value.into(),
4048 )
4049 })
4050 .collect_vec(),
4051 )
4052 .into(),
4053 )
4054 } else {
4055 Term::Constant(
4056 UplcConstant::ProtoList(
4057 UplcType::Data,
4058 builder::convert_constants_to_data(constants),
4059 )
4060 .into(),
4061 )
4062 };
4063
4064 Some(list)
4065 } else {
4066 let mut term = if tail {
4067 args.pop().unwrap()
4068 } else if tipo.is_map() {
4069 Term::empty_map()
4070 } else {
4071 Term::empty_list()
4072 };
4073
4074 let list_element_type = tipo.get_inner_types()[0].clone();
4076
4077 for arg in args.into_iter().rev() {
4078 let list_item = if tipo.is_map() {
4079 arg
4080 } else {
4081 builder::convert_type_to_data(arg, &list_element_type, &self.data_types)
4082 };
4083 term = Term::mk_cons().apply(list_item).apply(term);
4084 }
4085 Some(term)
4086 }
4087 }
4088 Air::ListAccessor {
4089 names,
4090 tail,
4091 tipo,
4095 expect_level,
4096 } => {
4097 let value = arg_stack.pop().unwrap();
4098
4099 let mut term = arg_stack.pop().unwrap();
4100
4101 let otherwise = if matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items) {
4102 arg_stack.pop().unwrap()
4103 } else {
4104 Term::Error.delay()
4105 };
4106
4107 let list_id = self.id_gen.next();
4108
4109 let mut id_list = vec![];
4110 id_list.push(list_id);
4111
4112 names.iter().for_each(|_| {
4113 id_list.push(self.id_gen.next());
4114 });
4115
4116 let names_types = tipo
4117 .get_inner_types()
4118 .into_iter()
4119 .cycle()
4120 .take(names.len())
4121 .zip(names)
4122 .zip(id_list)
4123 .map(|((tipo, name), id)| (name, tipo, id))
4124 .collect_vec();
4125
4126 term = builder::list_access_to_uplc(
4127 &names_types,
4128 tail,
4129 term,
4130 true,
4131 expect_level,
4132 otherwise,
4133 &self.data_types,
4134 )
4135 .apply(value);
4136
4137 Some(term)
4138 }
4139 Air::Fn {
4140 params,
4141 allow_inline,
4142 } => {
4143 let mut term = arg_stack.pop().unwrap();
4144
4145 for param in params.iter().rev() {
4146 term = term.lambda(param);
4147 }
4148 term = if allow_inline {
4149 term
4150 } else {
4151 term.lambda(NO_INLINE)
4152 };
4153
4154 if params.is_empty() {
4155 Some(term.delay())
4156 } else {
4157 Some(term)
4158 }
4159 }
4160 Air::Call { count, .. } => {
4161 if count >= 1 {
4162 let mut term = arg_stack.pop().unwrap();
4163 for _ in 0..count {
4164 let arg = arg_stack.pop().unwrap();
4165
4166 term = term.apply(arg);
4167 }
4168 Some(term)
4169 } else {
4170 let term = arg_stack.pop().unwrap();
4171 match term.pierce_no_inlines_ref() {
4172 Term::Var(_) => Some(term.force()),
4173 Term::Delay(inner_term) => Some(inner_term.as_ref().clone()),
4174 Term::Apply { .. } => Some(term.force()),
4175 _ => unreachable!(
4176 "Shouldn't call anything other than var or apply\n{:#?}",
4177 term
4178 ),
4179 }
4180 }
4181 }
4182 Air::Builtin { func, tipo, count } => {
4183 let mut arg_vec = vec![];
4184 for _ in 0..count {
4185 arg_vec.push(arg_stack.pop().unwrap());
4186 }
4187
4188 let ret_tipo = match tipo.as_ref() {
4189 Type::Fn { ret, .. } => ret,
4190 _ => &tipo,
4192 };
4193
4194 let term = match &func {
4195 DefaultFunction::IfThenElse
4196 | DefaultFunction::ChooseUnit
4197 | DefaultFunction::Trace
4198 | DefaultFunction::ChooseList
4199 | DefaultFunction::ChooseData
4200 | DefaultFunction::MkCons
4201 | DefaultFunction::UnConstrData => {
4202 builder::special_case_builtin(&func, tipo, count, arg_vec, &self.data_types)
4203 }
4204 DefaultFunction::FstPair | DefaultFunction::SndPair => {
4205 builder::undata_builtin(&func, count, ret_tipo, arg_vec, &self.data_types)
4206 }
4207 DefaultFunction::HeadList if !tipo.is_pair() => {
4208 builder::undata_builtin(&func, count, ret_tipo, arg_vec, &self.data_types)
4209 }
4210 _ => {
4211 let mut term: Term<Name> = func.into();
4212
4213 term = builder::apply_builtin_forces(term, func.force_count());
4214
4215 if func.arg_is_unit() {
4216 term = term.apply(Term::unit())
4217 } else {
4218 for arg in arg_vec {
4219 term = term.apply(arg.clone());
4220 }
4221 }
4222
4223 term
4224 }
4225 };
4226
4227 Some(term)
4228 }
4229 Air::BinOp {
4230 name: mut op,
4231 left_tipo,
4233 right_tipo,
4234 ..
4235 } => {
4236 let mut left = arg_stack.pop().unwrap();
4237 let mut right = arg_stack.pop().unwrap();
4238
4239 let uplc_type = left_tipo.get_uplc_type();
4240
4241 if !left.is_constant() && right.is_constant() {
4244 if op.is_symmetric() {
4246 std::mem::swap(&mut left, &mut right);
4247 } else if matches!(op, BinOp::SubInt)
4249 && let Some(minus_right) = right.try_negate()
4250 {
4251 right = left;
4252 left = minus_right;
4253 op = BinOp::AddInt;
4254 }
4255 }
4256
4257 let term = match op {
4258 BinOp::And => left.delayed_if_then_else(right, Term::bool(false)),
4259 BinOp::Or => left.delayed_if_then_else(Term::bool(true), right),
4260 BinOp::Eq | BinOp::NotEq => {
4261 let builtin = match &uplc_type {
4262 Some(UplcType::Integer) => Term::equals_integer(),
4263 Some(UplcType::String) => Term::equals_string(),
4264 Some(UplcType::ByteString) => Term::equals_bytestring(),
4265 Some(UplcType::Bls12_381G1Element) => Term::bls12_381_g1_equal(),
4266 Some(UplcType::Bls12_381G2Element) => Term::bls12_381_g2_equal(),
4267 Some(UplcType::Bool | UplcType::Unit) => Term::unit(),
4268 Some(UplcType::List(_) | UplcType::Pair(_, _) | UplcType::Data)
4269 | None => Term::equals_data(),
4270 Some(UplcType::Bls12_381MlResult) => {
4271 panic!("ML Result equality is not supported")
4272 }
4273 };
4274
4275 let binop_eq = match uplc_type {
4276 Some(UplcType::Bool) => {
4277 if matches!(op, BinOp::Eq) {
4278 if left.is_true() {
4279 right
4280 } else if left.is_false() {
4281 right.if_then_else(Term::bool(false), Term::bool(true))
4282 } else {
4283 left.delayed_if_then_else(
4284 right.clone(),
4285 right.if_then_else(Term::bool(false), Term::bool(true)),
4286 )
4287 }
4288 } else {
4289 if left.is_true() {
4290 right.if_then_else(Term::bool(false), Term::bool(true))
4291 } else if left.is_false() {
4292 right
4293 } else {
4294 left.delayed_if_then_else(
4295 right
4296 .clone()
4297 .if_then_else(Term::bool(false), Term::bool(true)),
4298 right.clone(),
4299 )
4300 }
4301 }
4302 }
4303 Some(UplcType::List(_)) if left_tipo.is_map() => builtin
4304 .apply(Term::map_data().apply(left))
4305 .apply(Term::map_data().apply(right)),
4306 Some(UplcType::List(_)) => builtin
4307 .apply(Term::list_data().apply(left))
4308 .apply(Term::list_data().apply(right)),
4309 Some(UplcType::Pair(_, _)) => {
4310 builtin
4311 .apply(Term::map_data().apply(
4312 Term::mk_cons().apply(left).apply(Term::empty_map()),
4313 ))
4314 .apply(Term::map_data().apply(
4315 Term::mk_cons().apply(right).apply(Term::empty_map()),
4316 ))
4317 }
4318 Some(
4319 UplcType::Data
4320 | UplcType::Bls12_381G1Element
4321 | UplcType::Bls12_381G2Element
4322 | UplcType::Bls12_381MlResult
4323 | UplcType::Integer
4324 | UplcType::String
4325 | UplcType::ByteString,
4326 ) => builtin.apply(left).apply(right),
4327
4328 None => {
4329 let mut left = left;
4330 let mut right = right;
4331
4332 let left_data_type =
4333 lookup_data_type_by_tipo(&self.data_types, &left_tipo);
4334
4335 let right_data_type =
4336 lookup_data_type_by_tipo(&self.data_types, &right_tipo);
4337
4338 if left_data_type
4339 .map(|d| {
4340 d.decorators
4341 .iter()
4342 .any(|dec| matches!(dec.kind, DecoratorKind::List))
4343 })
4344 .unwrap_or(false)
4345 {
4346 left = Term::list_data().apply(left)
4347 }
4348
4349 if right_data_type
4350 .map(|d| {
4351 d.decorators
4352 .iter()
4353 .any(|dec| matches!(dec.kind, DecoratorKind::List))
4354 })
4355 .unwrap_or(false)
4356 {
4357 right = Term::list_data().apply(right)
4358 }
4359
4360 builtin.apply(left).apply(right)
4361 }
4362 Some(UplcType::Unit) => {
4363 left.choose_unit(right.choose_unit(Term::bool(true)))
4364 }
4365 };
4366
4367 if !left_tipo.is_bool() && matches!(op, BinOp::NotEq) {
4368 binop_eq.if_then_else(Term::bool(false), Term::bool(true))
4369 } else {
4370 binop_eq
4371 }
4372 }
4373 BinOp::LtInt => Term::Builtin(DefaultFunction::LessThanInteger)
4374 .apply(left)
4375 .apply(right),
4376 BinOp::LtEqInt => Term::Builtin(DefaultFunction::LessThanEqualsInteger)
4377 .apply(left)
4378 .apply(right),
4379 BinOp::GtEqInt => Term::Builtin(DefaultFunction::LessThanEqualsInteger)
4380 .apply(right)
4381 .apply(left),
4382 BinOp::GtInt => Term::Builtin(DefaultFunction::LessThanInteger)
4383 .apply(right)
4384 .apply(left),
4385 BinOp::AddInt => Term::add_integer().apply(left).apply(right),
4386 BinOp::SubInt => Term::Builtin(DefaultFunction::SubtractInteger)
4387 .apply(left)
4388 .apply(right),
4389 BinOp::MultInt => Term::Builtin(DefaultFunction::MultiplyInteger)
4390 .apply(left)
4391 .apply(right),
4392 BinOp::DivInt => Term::Builtin(DefaultFunction::DivideInteger)
4393 .apply(left)
4394 .apply(right),
4395 BinOp::ModInt => Term::Builtin(DefaultFunction::ModInteger)
4396 .apply(left)
4397 .apply(right),
4398 };
4399 Some(term)
4400 }
4401 Air::DefineFunc {
4402 func_name,
4403 module_name,
4404 variant_name,
4405 variant,
4406 } => {
4407 let func_name = if module_name.is_empty() {
4408 format!("{func_name}{variant_name}")
4409 } else {
4410 format!("{module_name}_{func_name}{variant_name}")
4411 };
4412
4413 match variant {
4414 air::FunctionVariants::Standard(params) => {
4415 let mut func_body = arg_stack.pop().unwrap();
4416
4417 let term = arg_stack.pop().unwrap();
4418
4419 if params.is_empty() {
4420 func_body = func_body.delay();
4421 }
4422
4423 let func_body = params
4424 .into_iter()
4425 .rfold(func_body, |term, arg| term.lambda(arg))
4426 .lambda(NO_INLINE);
4427
4428 Some(term.lambda(func_name).apply(func_body))
4429 }
4430 air::FunctionVariants::Recursive {
4431 params,
4432 recursive_nonstatic_params,
4433 } => {
4434 let mut func_body = arg_stack.pop().unwrap();
4435
4436 let term = arg_stack.pop().unwrap();
4437
4438 let no_statics = recursive_nonstatic_params == params;
4439
4440 if recursive_nonstatic_params.is_empty() || params.is_empty() {
4441 func_body = func_body.delay();
4442 }
4443
4444 let func_body = recursive_nonstatic_params
4445 .iter()
4446 .rfold(func_body, |term, arg| term.lambda(arg));
4447
4448 let func_body = func_body.lambda(func_name.clone());
4449
4450 if no_statics {
4451 Some(
4453 term.lambda(func_name.clone())
4454 .apply(
4455 Term::var(func_name.clone())
4456 .apply(Term::var(func_name.clone())),
4457 )
4458 .lambda(func_name)
4459 .apply(func_body.lambda(NO_INLINE)),
4460 )
4461 } else {
4462 let mut recursive_func_body =
4466 Term::var(&func_name).apply(Term::var(&func_name));
4467
4468 if recursive_nonstatic_params.is_empty() {
4469 recursive_func_body = recursive_func_body.force();
4470 }
4471
4472 for param in recursive_nonstatic_params.into_iter() {
4477 recursive_func_body = recursive_func_body.apply(Term::var(param));
4478 }
4479
4480 let mut outer_func_body =
4482 recursive_func_body.lambda(&func_name).apply(func_body);
4483
4484 outer_func_body = params
4486 .clone()
4487 .into_iter()
4488 .rfold(outer_func_body, |term, arg| term.lambda(arg));
4489
4490 Some(
4492 term.lambda(&func_name)
4493 .apply(outer_func_body.lambda(NO_INLINE)),
4494 )
4495 }
4496 }
4497 air::FunctionVariants::Cyclic(contained_functions) => {
4498 let mut cyclic_functions = vec![];
4499
4500 for params in contained_functions {
4501 let func_body = arg_stack.pop().unwrap();
4502
4503 cyclic_functions.push((params, func_body));
4504 }
4505 let mut term = arg_stack.pop().unwrap();
4506
4507 let mut cyclic_body = Term::var("__chooser");
4508
4509 for (params, func_body) in cyclic_functions.into_iter() {
4510 let mut function = func_body;
4511 if params.is_empty() {
4512 function = function.delay();
4513 } else {
4514 for param in params.iter().rev() {
4515 function = function.lambda(param);
4516 }
4517 }
4518
4519 cyclic_body = cyclic_body.apply(function)
4527 }
4528
4529 term = term
4530 .lambda(&func_name)
4531 .apply(Term::var(&func_name).apply(Term::var(&func_name)))
4532 .lambda(&func_name)
4533 .apply(
4534 cyclic_body
4535 .lambda("__chooser")
4536 .lambda(func_name)
4537 .lambda(NO_INLINE),
4538 );
4539
4540 Some(term)
4541 }
4542 }
4543 }
4544
4545 Air::Let { name } => {
4546 let arg = arg_stack.pop().unwrap();
4547
4548 let mut term = arg_stack.pop().unwrap();
4549
4550 term = term.lambda(name).apply(arg);
4551
4552 Some(term)
4553 }
4554 Air::CastFromData { tipo, full_cast } => {
4555 let mut term = arg_stack.pop().unwrap();
4556
4557 term = if full_cast {
4558 unknown_data_to_type(term, &tipo, &self.data_types)
4559 } else {
4560 known_data_to_type(term, &tipo, &self.data_types)
4561 };
4562
4563 if extract_constant(term.pierce_no_inlines_ref()).is_some() {
4564 let mut program = self.new_program(term);
4565
4566 let mut interner = CodeGenInterner::new();
4567
4568 interner.program(&mut program);
4569
4570 let eval_program: Program<NamedDeBruijn> =
4571 program.clean_up_no_inlines().try_into().unwrap();
4572
4573 let evaluated_term: Term<NamedDeBruijn> = eval_program
4574 .eval(ExBudget::default())
4575 .result()
4576 .expect("Evaluated on unwrapping a data constant and got an error");
4577
4578 term = evaluated_term.try_into().unwrap();
4579 }
4580
4581 Some(term)
4582 }
4583 Air::CastToData { tipo } => {
4584 let mut term = arg_stack.pop().unwrap();
4585
4586 if extract_constant(term.pierce_no_inlines_ref()).is_some() {
4587 term = builder::convert_type_to_data(term, &tipo, &self.data_types);
4588
4589 let mut program = self.new_program(term);
4590
4591 let mut interner = CodeGenInterner::new();
4592
4593 interner.program(&mut program);
4594
4595 let eval_program: Program<NamedDeBruijn> =
4596 program.clean_up_no_inlines().try_into().unwrap();
4597
4598 let evaluated_term: Term<NamedDeBruijn> = eval_program
4599 .eval(ExBudget::default())
4600 .result()
4601 .expect("Evaluated on wrapping a constant into data and got an error");
4602
4603 term = evaluated_term.try_into().unwrap();
4604 } else {
4605 term = builder::convert_type_to_data(term, &tipo, &self.data_types);
4606 }
4607
4608 Some(term)
4609 }
4610 Air::AssertBool { is_true } => {
4611 let value = arg_stack.pop().unwrap();
4612
4613 let mut term = arg_stack.pop().unwrap();
4614 let otherwise = arg_stack.pop().unwrap();
4615
4616 if is_true {
4617 term = value.if_then_else(term.delay(), otherwise).force()
4618 } else {
4619 term = value.if_then_else(otherwise, term.delay()).force()
4620 }
4621 Some(term)
4622 }
4623 Air::When {
4624 subject_name,
4625 subject_tipo: tipo,
4627 ..
4628 } => {
4629 let subject = arg_stack.pop().unwrap();
4630
4631 let uplc_type = tipo.get_uplc_type();
4632
4633 let subject = match uplc_type {
4634 Some(
4635 UplcType::Bool
4636 | UplcType::Integer
4637 | UplcType::String
4638 | UplcType::ByteString
4639 | UplcType::Unit
4640 | UplcType::List(_)
4641 | UplcType::Pair(_, _)
4642 | UplcType::Bls12_381G1Element
4643 | UplcType::Bls12_381G2Element
4644 | UplcType::Bls12_381MlResult,
4645 ) => subject,
4646
4647 Some(UplcType::Data) => subject,
4648
4649 None => {
4650 let data_type = lookup_data_type_by_tipo(&self.data_types, &tipo)
4651 .expect("Found constr with no data type?");
4652
4653 let list_decorator = data_type
4654 .decorators
4655 .iter()
4656 .any(|dec| matches!(dec.kind, DecoratorKind::List));
4657
4658 if list_decorator {
4659 subject
4660 } else {
4661 Term::var(CONSTR_INDEX_EXPOSER).apply(subject)
4662 }
4663 }
4664 };
4665
4666 let mut term = arg_stack.pop().unwrap();
4667
4668 term = term.lambda(subject_name).apply(subject);
4669
4670 Some(term)
4671 }
4672 Air::Clause {
4673 subject_tipo: tipo,
4674 subject_name,
4675 } => {
4676 let clause = arg_stack.pop().unwrap();
4678
4679 let body = arg_stack.pop().unwrap();
4681
4682 let term = arg_stack.pop().unwrap();
4685
4686 assert!(matches!(term, Term::Delay(_) | Term::Var(_)));
4687
4688 let other_clauses = term.clone();
4689
4690 let body = if tipo.is_bool() {
4691 if matches!(clause, Term::Constant(boolean) if matches!(boolean.as_ref(), UplcConstant::Bool(true)))
4692 {
4693 Term::var(subject_name)
4694 .if_then_else(body.delay(), other_clauses)
4695 .force()
4696 } else {
4697 Term::var(subject_name)
4698 .if_then_else(other_clauses, body.delay())
4699 .force()
4700 }
4701 } else {
4702 let uplc_type = tipo.get_uplc_type();
4703
4704 let condition = match uplc_type {
4705 Some(
4706 UplcType::Bool
4707 | UplcType::Unit
4708 | UplcType::List(_)
4709 | UplcType::Pair(_, _)
4710 | UplcType::Bls12_381MlResult,
4711 ) => unreachable!("{:#?}", tipo),
4712 Some(UplcType::Data) => unimplemented!(),
4713 Some(UplcType::Integer) => Term::equals_integer()
4714 .apply(clause)
4715 .apply(Term::var(subject_name)),
4716 Some(UplcType::String) => Term::equals_string()
4717 .apply(clause)
4718 .apply(Term::var(subject_name)),
4719 Some(UplcType::ByteString) => Term::equals_bytestring()
4720 .apply(clause)
4721 .apply(Term::var(subject_name)),
4722 Some(UplcType::Bls12_381G1Element) => Term::bls12_381_g1_equal()
4723 .apply(clause)
4724 .apply(Term::var(subject_name)),
4725 Some(UplcType::Bls12_381G2Element) => Term::bls12_381_g2_equal()
4726 .apply(clause)
4727 .apply(Term::var(subject_name)),
4728 None => Term::equals_integer()
4729 .apply(clause)
4730 .apply(Term::var(subject_name)),
4731 };
4732
4733 condition.delay_true_if_then_else(body, other_clauses)
4734 };
4735
4736 Some(body)
4737 }
4738 Air::ListClause {
4739 tail_name,
4740 next_tail_name,
4741 ..
4742 } => {
4743 let body = arg_stack.pop().unwrap();
4745 let mut term = arg_stack.pop().unwrap();
4746
4747 assert!(matches!(term, Term::Delay(_)));
4748
4749 term = if let Some((current_tail, next_tail_name)) = next_tail_name {
4750 term.force()
4751 .lambda(next_tail_name)
4752 .apply(Term::tail_list().apply(Term::var(current_tail.clone())))
4753 .delay()
4754 } else {
4755 term
4756 };
4757
4758 term = Term::var(tail_name).delay_empty_choose_list(body, term);
4759
4760 Some(term)
4761 }
4762 Air::If { .. } => {
4763 let condition = arg_stack.pop().unwrap();
4764 let then = arg_stack.pop().unwrap();
4765 let mut term = arg_stack.pop().unwrap();
4766
4767 term = condition.delayed_if_then_else(then, term);
4768
4769 Some(term)
4770 }
4771 Air::Constr { tag, count, tipo } => {
4772 let mut arg_vec = vec![];
4773 for _ in 0..count {
4774 arg_vec.push(arg_stack.pop().unwrap());
4775 }
4776
4777 let mut term = Term::empty_list();
4778
4779 for (index, arg) in arg_vec.iter().enumerate().rev() {
4780 term = Term::mk_cons()
4781 .apply(builder::convert_type_to_data(
4782 arg.clone(),
4783 &tipo.arg_types().unwrap()[index],
4784 &self.data_types,
4785 ))
4786 .apply(term);
4787 }
4788
4789 if let Some(constr_index) = tag {
4790 term = Term::constr_data()
4791 .apply(Term::integer(constr_index.into()))
4792 .apply(term);
4793 }
4794
4795 if arg_vec.iter().all(|item| {
4796 let maybe_const = extract_constant(item.pierce_no_inlines_ref());
4797 maybe_const.is_some()
4798 }) {
4799 let mut program = self.new_program(term);
4800
4801 let mut interner = CodeGenInterner::new();
4802
4803 interner.program(&mut program);
4804
4805 let eval_program: Program<NamedDeBruijn> =
4806 program.clean_up_no_inlines().try_into().unwrap();
4807
4808 let evaluated_term: Term<NamedDeBruijn> = eval_program
4809 .eval(ExBudget::default())
4810 .result()
4811 .expect("Evaluated a constant record with args and got an error");
4812
4813 term = evaluated_term.try_into().unwrap();
4814 }
4815
4816 Some(term)
4817 }
4818 Air::FieldsExpose {
4819 indices,
4820 is_expect,
4821 list_decorator,
4822 } => {
4823 let mut id_list = vec![];
4824
4825 let mut value = arg_stack.pop().unwrap();
4826
4827 let mut term = arg_stack.pop().unwrap();
4828
4829 let otherwise = if is_expect {
4830 arg_stack.pop().unwrap()
4831 } else {
4832 Term::Error.delay()
4833 };
4834
4835 let list_id = self.id_gen.next();
4836
4837 id_list.push(list_id);
4838
4839 indices.iter().for_each(|_| {
4840 id_list.push(self.id_gen.next());
4841 });
4842
4843 let names_types = indices
4844 .iter()
4845 .cloned()
4846 .zip(id_list)
4847 .map(|(item, id)| (item.1, item.2, id))
4848 .collect_vec();
4849
4850 let named_indices = names_types
4851 .iter()
4852 .skip_while(|(name, _, _)| name == DISCARDED)
4853 .collect_vec();
4854
4855 if !named_indices.is_empty() || is_expect {
4856 term = builder::list_access_to_uplc(
4857 &names_types,
4858 false,
4859 term,
4860 false,
4861 is_expect.into(),
4862 otherwise,
4863 &self.data_types,
4864 );
4865
4866 if !list_decorator {
4867 value = Term::var(CONSTR_FIELDS_EXPOSER).apply(value);
4868 }
4869
4870 term = term.apply(value);
4871
4872 Some(term)
4873 } else {
4874 Some(term)
4875 }
4876 }
4877 Air::FieldsEmpty { list_decorator } => {
4878 let mut value = arg_stack.pop().unwrap();
4879
4880 let mut term = arg_stack.pop().unwrap();
4881 let otherwise = arg_stack.pop().unwrap();
4882
4883 if !list_decorator {
4884 value = Term::var(CONSTR_FIELDS_EXPOSER).apply(value)
4885 }
4886
4887 term = value.choose_list(term.delay(), otherwise).force();
4888
4889 Some(term)
4890 }
4891 Air::ListEmpty => {
4892 let value = arg_stack.pop().unwrap();
4893
4894 let mut term = arg_stack.pop().unwrap();
4895 let otherwise = arg_stack.pop().unwrap();
4896
4897 term = value.choose_list(term.delay(), otherwise).force();
4898
4899 Some(term)
4900 }
4901 Air::Tuple { count, tipo } => {
4902 let mut args = vec![];
4903
4904 let tuple_sub_types = tipo.get_inner_types();
4905
4906 for _ in 0..count {
4907 let arg = arg_stack.pop().unwrap();
4908 args.push(arg);
4909 }
4910 let mut constants = vec![];
4911 for arg in &args {
4912 let maybe_const = extract_constant(arg);
4913 if let Some(c) = maybe_const {
4914 constants.push(c);
4915 }
4916 }
4917
4918 if constants.len() == args.len() {
4919 let data_constants = builder::convert_constants_to_data(constants);
4920
4921 let term = Term::Constant(
4922 UplcConstant::ProtoList(UplcType::Data, data_constants).into(),
4923 );
4924 Some(term)
4925 } else {
4926 let mut term = Term::empty_list();
4927 for (arg, tipo) in args.into_iter().zip(tuple_sub_types).rev() {
4928 term = Term::mk_cons()
4929 .apply(builder::convert_type_to_data(arg, &tipo, &self.data_types))
4930 .apply(term);
4931 }
4932 Some(term)
4933 }
4934 }
4935 Air::Pair { tipo } => {
4936 let fst = arg_stack.pop().unwrap();
4937 let snd = arg_stack.pop().unwrap();
4938
4939 match (extract_constant(&fst), extract_constant(&snd)) {
4940 (Some(fst), Some(snd)) => {
4941 let mut pair_fields = builder::convert_constants_to_data(vec![fst, snd]);
4942 let term = Term::Constant(
4943 UplcConstant::ProtoPair(
4944 UplcType::Data,
4945 UplcType::Data,
4946 pair_fields.remove(0).into(),
4947 pair_fields.remove(0).into(),
4948 )
4949 .into(),
4950 );
4951 Some(term)
4952 }
4953 _ => {
4954 let term = Term::mk_pair_data()
4955 .apply(builder::convert_type_to_data(
4956 fst,
4957 &tipo.get_inner_types()[0],
4958 &self.data_types,
4959 ))
4960 .apply(builder::convert_type_to_data(
4961 snd,
4962 &tipo.get_inner_types()[1],
4963 &self.data_types,
4964 ));
4965
4966 Some(term)
4967 }
4968 }
4969 }
4970 Air::RecordUpdate {
4971 highest_index,
4972 indices,
4973 tipo,
4974 } => {
4975 let tail_name_prefix = "__tail_index";
4976
4977 let data_type =
4978 lookup_data_type_by_tipo(&self.data_types, &tipo).unwrap_or_else(|| {
4979 panic!("Attempted record update on an unknown type!\ntype: {tipo:#?}")
4980 });
4981
4982 assert!(
4983 !data_type.is_never(),
4984 "Attempted record update on a Never type.",
4985 );
4986
4987 let list_decorator = data_type
4988 .decorators
4989 .iter()
4990 .any(|dec| matches!(dec.kind, DecoratorKind::List));
4991
4992 let constructor_field_count = data_type.constructors[0].arguments.len();
4993 let mut record = arg_stack.pop().unwrap();
4994
4995 let mut args = IndexMap::new();
4996 let mut unchanged_field_indices = vec![];
4997 unchanged_field_indices.push(0);
5001 let mut prev_index = 0;
5002
5003 for (index, tipo) in indices
5004 .into_iter()
5005 .sorted_by(|(index1, _), (index2, _)| index1.cmp(index2))
5006 {
5007 let arg = arg_stack.pop().unwrap();
5008 args.insert(index, (tipo.clone(), arg));
5009
5010 for field_index in (prev_index + 1)..index {
5011 unchanged_field_indices.push(field_index);
5012 }
5013 prev_index = index;
5014 }
5015
5016 unchanged_field_indices.push(prev_index + 1);
5017
5018 let mut term = Term::var(format!("{tail_name_prefix}_{}", highest_index + 1));
5019
5020 for current_index in (0..(highest_index + 1)).rev() {
5021 let tail_name = format!("{tail_name_prefix}_{current_index}");
5022
5023 if let Some((tipo, arg)) = args.get(¤t_index) {
5024 term = Term::mk_cons()
5025 .apply(builder::convert_type_to_data(
5026 arg.clone(),
5027 tipo,
5028 &self.data_types,
5029 ))
5030 .apply(term);
5031 } else {
5032 term = Term::mk_cons()
5033 .apply(Term::head_list().apply(Term::var(tail_name)))
5034 .apply(term);
5035 }
5036 }
5037
5038 if !list_decorator {
5039 term = Term::constr_data()
5040 .apply(Term::integer(0.into()))
5041 .apply(term);
5042 }
5043
5044 if unchanged_field_indices.len() > 1 {
5045 let (prev_index, rest_list) = unchanged_field_indices
5046 .split_last()
5047 .unwrap_or_else(|| panic!("WHAT HAPPENED"));
5048
5049 let mut prev_index = *prev_index;
5050
5051 for index in rest_list.iter().rev() {
5052 let index = *index;
5053 let suffix_tail = format!("{tail_name_prefix}_{prev_index}");
5054 let tail = format!("{tail_name_prefix}_{index}");
5055
5056 let mut tail_list = Term::var(tail);
5057
5058 if index < prev_index {
5059 tail_list = tail_list.repeat_tail_list(prev_index - index);
5060
5061 if prev_index == constructor_field_count {
5062 term = term.lambda(suffix_tail).apply(Term::empty_list());
5063 } else {
5064 term = term.lambda(suffix_tail).apply(tail_list);
5065 }
5066 }
5067 prev_index = index;
5068 }
5069 }
5070
5071 if !list_decorator {
5072 record = Term::var(CONSTR_FIELDS_EXPOSER).apply(record)
5073 }
5074
5075 term = term.lambda(format!("{tail_name_prefix}_0")).apply(record);
5076
5077 Some(term)
5078 }
5079 Air::UnOp { op } => {
5080 let value = arg_stack.pop().unwrap();
5081
5082 let term = match op {
5083 UnOp::Not => value.if_then_else(Term::bool(false), Term::bool(true)),
5084 UnOp::Negate => {
5085 if let Term::Constant(c) = &value {
5086 if let UplcConstant::Integer(i) = c.as_ref() {
5087 Term::integer(-i)
5088 } else {
5089 Term::subtract_integer()
5090 .apply(Term::integer(0.into()))
5091 .apply(value)
5092 }
5093 } else {
5094 Term::subtract_integer()
5095 .apply(Term::integer(0.into()))
5096 .apply(value)
5097 }
5098 }
5099 };
5100
5101 Some(term)
5102 }
5103 Air::TupleAccessor {
5104 tipo,
5105 names,
5106 is_expect,
5107 } => {
5108 let inner_types = tipo.get_inner_types();
5109 let value = arg_stack.pop().unwrap();
5110
5111 let mut term = arg_stack.pop().unwrap();
5112 let otherwise = if is_expect {
5113 arg_stack.pop().unwrap()
5114 } else {
5115 Term::Error.delay()
5116 };
5117 let list_id = self.id_gen.next();
5118
5119 let mut id_list = vec![];
5120 id_list.push(list_id);
5121
5122 names.iter().for_each(|_| {
5123 id_list.push(self.id_gen.next());
5124 });
5125
5126 let names_types = names
5127 .into_iter()
5128 .zip(inner_types)
5129 .zip(id_list)
5130 .map(|((name, tipo), id)| (name, tipo, id))
5131 .collect_vec();
5132
5133 term = builder::list_access_to_uplc(
5134 &names_types,
5135 false,
5136 term,
5137 false,
5138 is_expect.into(),
5139 otherwise,
5140 &self.data_types,
5141 )
5142 .apply(value);
5143
5144 Some(term)
5145 }
5146 Air::PairAccessor {
5147 fst,
5148 snd,
5149 tipo,
5150 is_expect,
5151 } => {
5152 let inner_types = tipo.get_inner_types();
5153 let value = arg_stack.pop().unwrap();
5154
5155 let mut term = arg_stack.pop().unwrap();
5156 let otherwise = if is_expect {
5157 arg_stack.pop().unwrap()
5158 } else {
5159 Term::Error.delay()
5160 };
5161
5162 let list_id = self.id_gen.next();
5163
5164 if let Some(name) = snd {
5165 let value = Term::snd_pair().apply(Term::var(format!("__pair_{list_id}")));
5166 term = if is_expect {
5167 if otherwise == Term::Error.delay() {
5168 term.lambda(name).apply(unknown_data_to_type(
5169 value,
5170 &inner_types[1],
5171 &self.data_types,
5172 ))
5173 } else {
5174 softcast_data_to_type_otherwise(
5175 value,
5176 &name,
5177 &inner_types[1],
5178 term,
5179 otherwise.clone(),
5180 &self.data_types,
5181 )
5182 }
5183 } else {
5184 term.lambda(name).apply(known_data_to_type(
5185 value,
5186 &inner_types[1],
5187 &self.data_types,
5188 ))
5189 }
5190 }
5191
5192 if let Some(name) = fst {
5193 let value = Term::fst_pair().apply(Term::var(format!("__pair_{list_id}")));
5194 term = if is_expect {
5195 if otherwise == Term::Error.delay() {
5196 term.lambda(name).apply(unknown_data_to_type(
5197 value,
5198 &inner_types[0],
5199 &self.data_types,
5200 ))
5201 } else {
5202 softcast_data_to_type_otherwise(
5203 value,
5204 &name,
5205 &inner_types[0],
5206 term,
5207 otherwise,
5208 &self.data_types,
5209 )
5210 }
5211 } else {
5212 term.lambda(name).apply(known_data_to_type(
5213 value,
5214 &inner_types[0],
5215 &self.data_types,
5216 ))
5217 }
5218 }
5219
5220 term = term.lambda(format!("__pair_{list_id}")).apply(value);
5221
5222 Some(term)
5223 }
5224 Air::Trace { .. } => {
5225 let text = arg_stack.pop().unwrap();
5226
5227 let term = arg_stack.pop().unwrap();
5228
5229 let term = term.delayed_trace(text);
5230
5231 Some(term)
5232 }
5233 Air::ErrorTerm { validator, .. } => {
5234 if validator {
5235 Some(Term::Error.apply(Term::Error.force()))
5236 } else {
5237 Some(Term::Error)
5238 }
5239 }
5240
5241 Air::NoOp => None,
5242 Air::SoftCastLet { name, tipo } => {
5243 let value = arg_stack.pop().unwrap();
5244 let then = arg_stack.pop().unwrap();
5245 let otherwise = arg_stack.pop().unwrap();
5246
5247 if otherwise == Term::Error.delay() {
5248 Some(then.lambda(name).apply(unknown_data_to_type(
5249 value,
5250 &tipo,
5251 &self.data_types,
5252 )))
5253 } else {
5254 Some(softcast_data_to_type_otherwise(
5255 value,
5256 &name,
5257 &tipo,
5258 then,
5259 otherwise,
5260 &self.data_types,
5261 ))
5262 }
5263 }
5264 Air::ExtractField { tipo } => {
5265 let arg = arg_stack.pop().unwrap();
5266
5267 Some(known_data_to_type(
5268 Term::head_list().apply(arg),
5269 &tipo,
5270 &self.data_types,
5271 ))
5272 }
5273 }
5274 }
5275}
5276
5277fn handle_assigns(
5278 subject_name: &String,
5279 subject_tipo: Rc<Type>,
5280 assigns: &[Assigned],
5281 stick_set: &mut TreeSet,
5282 then: AirTree,
5283) -> AirTree {
5284 match assigns {
5285 [] => then,
5286 [assign, rest @ ..] => {
5287 let Assigned { path, assigned } = assign;
5288
5289 let current_tipo = get_tipo_by_path(subject_tipo.clone(), path);
5290 let builtins_path = Builtins::new_from_path(subject_tipo.clone(), path.clone());
5291 let current_subject_name = if builtins_path.is_empty() {
5292 subject_name.clone()
5293 } else {
5294 format!("{subject_name}_{builtins_path}")
5295 };
5296
5297 let builtins_to_add = stick_set.diff_union_builtins(builtins_path.clone());
5299
5300 let prev_builtins = Builtins {
5302 vec: builtins_path.vec[0..(builtins_path.len() - builtins_to_add.len())].to_vec(),
5303 };
5304
5305 let prev_subject_name = if prev_builtins.is_empty() {
5306 subject_name.clone()
5307 } else {
5308 format!("{subject_name}_{prev_builtins}")
5309 };
5310 let prev_tipo = prev_builtins
5311 .vec
5312 .last()
5313 .map_or(subject_tipo.clone(), |last| last.tipo());
5314
5315 let assignment = AirTree::let_assignment(
5316 assigned,
5317 AirTree::local_var(current_subject_name, current_tipo),
5318 handle_assigns(subject_name, subject_tipo, rest, stick_set, then),
5319 );
5320
5321 builtins_to_add.produce_air(prev_subject_name, prev_tipo, assignment)
5322 }
5323 }
5324}