feat: expects now print the line of code that failed
This commit is contained in:
		
							parent
							
								
									412945af3a
								
							
						
					
					
						commit
						355e38d6e2
					
				| 
						 | 
				
			
			@ -29,7 +29,7 @@ use crate::{
 | 
			
		|||
        find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
 | 
			
		||||
        get_generic_id_and_type, get_src_code_by_span, get_variant_name, monomorphize,
 | 
			
		||||
        pattern_has_conditions, wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction,
 | 
			
		||||
        SpecificClause, CONSTR_INDEX_MISMATCH,
 | 
			
		||||
        SpecificClause,
 | 
			
		||||
    },
 | 
			
		||||
    tipo::{
 | 
			
		||||
        ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +44,7 @@ use self::{
 | 
			
		|||
        cast_validator_args, constants_ir, convert_type_to_data, extract_constant,
 | 
			
		||||
        lookup_data_type_by_tipo, modify_cyclic_calls, modify_self_calls, rearrange_list_clauses,
 | 
			
		||||
        AssignmentProperties, ClauseProperties, CodeGenSpecialFuncs, CycleFunctionNames,
 | 
			
		||||
        DataTypeKey, FunctionAccessKey, HoistableFunction, Variant, CONSTR_NOT_EMPTY,
 | 
			
		||||
        LIST_NOT_EMPTY, TOO_MANY_ITEMS,
 | 
			
		||||
        DataTypeKey, FunctionAccessKey, HoistableFunction, Variant,
 | 
			
		||||
    },
 | 
			
		||||
    tree::{AirExpression, AirTree, TreePath},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +132,10 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
        air_tree_fun = wrap_validator_condition(air_tree_fun, self.tracing);
 | 
			
		||||
 | 
			
		||||
        let mut validator_args_tree = self.check_validator_args(&fun.arguments, true, air_tree_fun);
 | 
			
		||||
        let src_code = self.module_src.get(module_name).unwrap().clone();
 | 
			
		||||
 | 
			
		||||
        let mut validator_args_tree =
 | 
			
		||||
            self.check_validator_args(&fun.arguments, true, air_tree_fun, &src_code);
 | 
			
		||||
 | 
			
		||||
        validator_args_tree = AirTree::no_op().hoist_over(validator_args_tree);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +155,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
            air_tree_fun_other = wrap_validator_condition(air_tree_fun_other, self.tracing);
 | 
			
		||||
 | 
			
		||||
            let mut validator_args_tree_other =
 | 
			
		||||
                self.check_validator_args(&other.arguments, true, air_tree_fun_other);
 | 
			
		||||
                self.check_validator_args(&other.arguments, true, air_tree_fun_other, &src_code);
 | 
			
		||||
 | 
			
		||||
            validator_args_tree_other = AirTree::no_op().hoist_over(validator_args_tree_other);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -173,8 +175,11 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                };
 | 
			
		||||
 | 
			
		||||
            // Special Case with multi_validators
 | 
			
		||||
            self.special_functions.use_function(CONSTR_FIELDS_EXPOSER);
 | 
			
		||||
            self.special_functions.use_function(CONSTR_INDEX_EXPOSER);
 | 
			
		||||
            self.special_functions
 | 
			
		||||
                .use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string());
 | 
			
		||||
 | 
			
		||||
            self.special_functions
 | 
			
		||||
                .use_function_uplc(CONSTR_INDEX_EXPOSER.to_string());
 | 
			
		||||
 | 
			
		||||
            term = wrap_as_multi_validator(spend, mint, self.tracing, spend_name, mint_name);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -463,6 +468,22 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
                let air_value = self.build(value, module_name);
 | 
			
		||||
 | 
			
		||||
                let msg = get_src_code_by_span(module_name, location, &self.module_src);
 | 
			
		||||
 | 
			
		||||
                let msg_func_name = msg.split_whitespace().join("");
 | 
			
		||||
 | 
			
		||||
                self.special_functions.insert_new_function(
 | 
			
		||||
                    msg_func_name.clone(),
 | 
			
		||||
                    Term::string(msg),
 | 
			
		||||
                    string(),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                let msg_func = if self.tracing {
 | 
			
		||||
                    self.special_functions.use_function_tree(msg_func_name)
 | 
			
		||||
                } else {
 | 
			
		||||
                    AirTree::no_op()
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                self.assignment(
 | 
			
		||||
                    pattern,
 | 
			
		||||
                    air_value,
 | 
			
		||||
| 
						 | 
				
			
			@ -472,8 +493,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                        kind: *kind,
 | 
			
		||||
                        remove_unused: kind.is_let(),
 | 
			
		||||
                        full_check: !tipo.is_data() && value.tipo().is_data() && kind.is_expect(),
 | 
			
		||||
                        location: *location,
 | 
			
		||||
                        module_name: module_name.clone(),
 | 
			
		||||
                        msg_func,
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -514,8 +534,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                            kind: AssignmentKind::Let,
 | 
			
		||||
                            remove_unused: false,
 | 
			
		||||
                            full_check: false,
 | 
			
		||||
                            location: Span::empty(),
 | 
			
		||||
                            module_name: module_name.clone(),
 | 
			
		||||
                            msg_func: AirTree::no_op(),
 | 
			
		||||
                        },
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -621,10 +640,8 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                    }
 | 
			
		||||
 | 
			
		||||
                    let list_of_fields = AirTree::call(
 | 
			
		||||
                        AirTree::local_var(
 | 
			
		||||
                            self.special_functions.use_function(CONSTR_FIELDS_EXPOSER),
 | 
			
		||||
                            void(),
 | 
			
		||||
                        ),
 | 
			
		||||
                        self.special_functions
 | 
			
		||||
                            .use_function_tree(CONSTR_FIELDS_EXPOSER.to_string()),
 | 
			
		||||
                        list(data()),
 | 
			
		||||
                        vec![self.build(record, module_name)],
 | 
			
		||||
                    );
 | 
			
		||||
| 
						 | 
				
			
			@ -828,10 +845,8 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                    AirTree::local_var(name, int()),
 | 
			
		||||
                    int(),
 | 
			
		||||
                );
 | 
			
		||||
                let msg =
 | 
			
		||||
                    get_src_code_by_span(&props.module_name, &props.location, &self.module_src);
 | 
			
		||||
 | 
			
		||||
                AirTree::assert_bool(true, assignment.hoist_over(expect), msg)
 | 
			
		||||
                AirTree::assert_bool(true, assignment.hoist_over(expect), props.msg_func.clone())
 | 
			
		||||
            }
 | 
			
		||||
            Pattern::Var { name, .. } => {
 | 
			
		||||
                if props.full_check {
 | 
			
		||||
| 
						 | 
				
			
			@ -851,6 +866,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                            val,
 | 
			
		||||
                            &mut index_map,
 | 
			
		||||
                            pattern.location(),
 | 
			
		||||
                            props.msg_func,
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                        let assign_expect = AirTree::let_assignment("_", expect);
 | 
			
		||||
| 
						 | 
				
			
			@ -890,6 +906,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                            val,
 | 
			
		||||
                            &mut index_map,
 | 
			
		||||
                            pattern.location(),
 | 
			
		||||
                            props.msg_func,
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                        let assign_expect = AirTree::let_assignment("_", expect);
 | 
			
		||||
| 
						 | 
				
			
			@ -948,8 +965,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                                    kind: props.kind,
 | 
			
		||||
                                    remove_unused: true,
 | 
			
		||||
                                    full_check: props.full_check,
 | 
			
		||||
                                    location: props.location,
 | 
			
		||||
                                    module_name: props.module_name.clone(),
 | 
			
		||||
                                    msg_func: props.msg_func.clone(),
 | 
			
		||||
                                },
 | 
			
		||||
                            )
 | 
			
		||||
                        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -991,8 +1007,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                                kind: props.kind,
 | 
			
		||||
                                remove_unused: true,
 | 
			
		||||
                                full_check: props.full_check,
 | 
			
		||||
                                location: props.location,
 | 
			
		||||
                                module_name: props.module_name.clone(),
 | 
			
		||||
                                msg_func: props.msg_func.clone(),
 | 
			
		||||
                            },
 | 
			
		||||
                        )
 | 
			
		||||
                    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1005,9 +1020,15 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
 | 
			
		||||
 | 
			
		||||
                let list_access = if elements.is_empty() {
 | 
			
		||||
                    AirTree::list_empty(value)
 | 
			
		||||
                    AirTree::list_empty(value, props.msg_func)
 | 
			
		||||
                } else {
 | 
			
		||||
                    AirTree::list_access(names, tipo.clone(), tail.is_some(), tail.is_none(), value)
 | 
			
		||||
                    AirTree::list_access(
 | 
			
		||||
                        names,
 | 
			
		||||
                        tipo.clone(),
 | 
			
		||||
                        tail.is_some(),
 | 
			
		||||
                        value,
 | 
			
		||||
                        Some(props.msg_func),
 | 
			
		||||
                    )
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut sequence = vec![list_access];
 | 
			
		||||
| 
						 | 
				
			
			@ -1027,10 +1048,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                if tipo.is_bool() {
 | 
			
		||||
                    assert!(props.kind.is_expect());
 | 
			
		||||
 | 
			
		||||
                    let msg =
 | 
			
		||||
                        get_src_code_by_span(&props.module_name, &props.location, &self.module_src);
 | 
			
		||||
 | 
			
		||||
                    AirTree::assert_bool(name == "True", value, msg)
 | 
			
		||||
                    AirTree::assert_bool(name == "True", value, props.msg_func)
 | 
			
		||||
                } else if tipo.is_void() {
 | 
			
		||||
                    AirTree::let_assignment("_", value)
 | 
			
		||||
                } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1062,16 +1080,10 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
                            sequence.push(constructor_val);
 | 
			
		||||
 | 
			
		||||
                            let msg = get_src_code_by_span(
 | 
			
		||||
                                &props.module_name,
 | 
			
		||||
                                &props.location,
 | 
			
		||||
                                &self.module_src,
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            let assert_constr = AirTree::assert_constr_index(
 | 
			
		||||
                                index,
 | 
			
		||||
                                AirTree::local_var(&constructor_name, tipo.clone()),
 | 
			
		||||
                                msg,
 | 
			
		||||
                                props.msg_func.clone(),
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            sequence.push(assert_constr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1147,8 +1159,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                                        kind: props.kind,
 | 
			
		||||
                                        remove_unused: true,
 | 
			
		||||
                                        full_check: props.full_check,
 | 
			
		||||
                                        location: props.location,
 | 
			
		||||
                                        module_name: props.module_name.clone(),
 | 
			
		||||
                                        msg_func: props.msg_func.clone(),
 | 
			
		||||
                                    },
 | 
			
		||||
                                )
 | 
			
		||||
                            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1169,7 +1180,12 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                    if check_replaceable_opaque_type(tipo, &self.data_types) {
 | 
			
		||||
                        sequence.push(AirTree::let_assignment(&indices[0].1, value));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        sequence.push(AirTree::fields_expose(indices, props.full_check, value));
 | 
			
		||||
                        let msg = if props.full_check {
 | 
			
		||||
                            Some(props.msg_func)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            None
 | 
			
		||||
                        };
 | 
			
		||||
                        sequence.push(AirTree::fields_expose(indices, value, msg));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    sequence.append(
 | 
			
		||||
| 
						 | 
				
			
			@ -1237,8 +1253,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                                    kind: props.kind,
 | 
			
		||||
                                    remove_unused: true,
 | 
			
		||||
                                    full_check: props.full_check,
 | 
			
		||||
                                    location: props.location,
 | 
			
		||||
                                    module_name: props.module_name.clone(),
 | 
			
		||||
                                    msg_func: props.msg_func.clone(),
 | 
			
		||||
                                },
 | 
			
		||||
                            )
 | 
			
		||||
                        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1251,14 +1266,15 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
                let indices = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
 | 
			
		||||
 | 
			
		||||
                let msg = if props.full_check {
 | 
			
		||||
                    Some(props.msg_func)
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // This `value` is either value param that was passed in or
 | 
			
		||||
                // local var
 | 
			
		||||
                sequence.push(AirTree::tuple_access(
 | 
			
		||||
                    indices,
 | 
			
		||||
                    tipo.clone(),
 | 
			
		||||
                    props.full_check,
 | 
			
		||||
                    value,
 | 
			
		||||
                ));
 | 
			
		||||
                sequence.push(AirTree::tuple_access(indices, tipo.clone(), value, msg));
 | 
			
		||||
 | 
			
		||||
                sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec());
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1273,6 +1289,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
        value: AirTree,
 | 
			
		||||
        defined_data_types: &mut IndexMap<String, u64>,
 | 
			
		||||
        location: Span,
 | 
			
		||||
        msg_func: AirTree,
 | 
			
		||||
    ) -> AirTree {
 | 
			
		||||
        assert!(tipo.get_generic().is_none());
 | 
			
		||||
        let tipo = &convert_opaque_type(tipo, &self.data_types);
 | 
			
		||||
| 
						 | 
				
			
			@ -1298,8 +1315,8 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
            let tuple_access = AirTree::tuple_access(
 | 
			
		||||
                vec![fst_name.clone(), snd_name.clone()],
 | 
			
		||||
                inner_list_type.clone(),
 | 
			
		||||
                false,
 | 
			
		||||
                AirTree::local_var(&pair_name, inner_list_type.clone()),
 | 
			
		||||
                None,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let expect_fst = self.expect_type_assign(
 | 
			
		||||
| 
						 | 
				
			
			@ -1307,6 +1324,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                AirTree::local_var(fst_name, inner_pair_types[0].clone()),
 | 
			
		||||
                defined_data_types,
 | 
			
		||||
                location,
 | 
			
		||||
                msg_func.clone(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let expect_snd = self.expect_type_assign(
 | 
			
		||||
| 
						 | 
				
			
			@ -1314,6 +1332,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                AirTree::local_var(snd_name, inner_pair_types[1].clone()),
 | 
			
		||||
                defined_data_types,
 | 
			
		||||
                location,
 | 
			
		||||
                msg_func.clone(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let anon_func_body = AirTree::UnhoistedSequence(vec![
 | 
			
		||||
| 
						 | 
				
			
			@ -1385,6 +1404,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                    ),
 | 
			
		||||
                    defined_data_types,
 | 
			
		||||
                    location,
 | 
			
		||||
                    msg_func,
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                let anon_func_body = expect_item;
 | 
			
		||||
| 
						 | 
				
			
			@ -1447,8 +1467,8 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
            let tuple_access = AirTree::tuple_access(
 | 
			
		||||
                vec![fst_name.clone(), snd_name.clone()],
 | 
			
		||||
                tipo.clone(),
 | 
			
		||||
                false,
 | 
			
		||||
                AirTree::local_var(pair_name, tipo.clone()),
 | 
			
		||||
                None,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let expect_fst = self.expect_type_assign(
 | 
			
		||||
| 
						 | 
				
			
			@ -1456,6 +1476,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                AirTree::local_var(fst_name, tuple_inner_types[0].clone()),
 | 
			
		||||
                defined_data_types,
 | 
			
		||||
                location,
 | 
			
		||||
                msg_func.clone(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let expect_snd = self.expect_type_assign(
 | 
			
		||||
| 
						 | 
				
			
			@ -1463,6 +1484,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                AirTree::local_var(snd_name, tuple_inner_types[1].clone()),
 | 
			
		||||
                defined_data_types,
 | 
			
		||||
                location,
 | 
			
		||||
                msg_func,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            AirTree::UnhoistedSequence(vec![
 | 
			
		||||
| 
						 | 
				
			
			@ -1493,6 +1515,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                        AirTree::local_var(&tuple_index_name, arg.clone()),
 | 
			
		||||
                        defined_data_types,
 | 
			
		||||
                        location,
 | 
			
		||||
                        msg_func.clone(),
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    (
 | 
			
		||||
| 
						 | 
				
			
			@ -1510,8 +1533,8 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
            let tuple_access = AirTree::tuple_access(
 | 
			
		||||
                tuple_index_names,
 | 
			
		||||
                tipo.clone(),
 | 
			
		||||
                true,
 | 
			
		||||
                AirTree::local_var(tuple_name, tipo.clone()),
 | 
			
		||||
                Some(msg_func),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let mut tuple_expects = tuple_expect_items
 | 
			
		||||
| 
						 | 
				
			
			@ -1553,10 +1576,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
            let error_term = if self.tracing {
 | 
			
		||||
                AirTree::trace(
 | 
			
		||||
                    AirTree::local_var(
 | 
			
		||||
                        self.special_functions.use_function(CONSTR_INDEX_MISMATCH),
 | 
			
		||||
                        string(),
 | 
			
		||||
                    ),
 | 
			
		||||
                    msg_func.clone(),
 | 
			
		||||
                    tipo.clone(),
 | 
			
		||||
                    AirTree::error(tipo.clone(), false),
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -1590,6 +1610,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                                        AirTree::local_var(&arg_name, arg_tipo.clone()),
 | 
			
		||||
                                        defined_data_types,
 | 
			
		||||
                                        location,
 | 
			
		||||
                                        msg_func.clone(),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1610,16 +1631,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                            .collect_vec();
 | 
			
		||||
 | 
			
		||||
                        if assigns.is_empty() {
 | 
			
		||||
                            let empty = AirTree::fields_empty(AirTree::local_var(
 | 
			
		||||
                                format!("__constr_var_span_{}_{}", location.start, location.end),
 | 
			
		||||
                                tipo.clone(),
 | 
			
		||||
                            ));
 | 
			
		||||
 | 
			
		||||
                            assigns.insert(0, empty);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            let expose = AirTree::fields_expose(
 | 
			
		||||
                                indices,
 | 
			
		||||
                                true,
 | 
			
		||||
                            let empty = AirTree::fields_empty(
 | 
			
		||||
                                AirTree::local_var(
 | 
			
		||||
                                    format!(
 | 
			
		||||
                                        "__constr_var_span_{}_{}",
 | 
			
		||||
| 
						 | 
				
			
			@ -1627,6 +1639,21 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                                    ),
 | 
			
		||||
                                    tipo.clone(),
 | 
			
		||||
                                ),
 | 
			
		||||
                                msg_func.clone(),
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            assigns.insert(0, empty);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            let expose = AirTree::fields_expose(
 | 
			
		||||
                                indices,
 | 
			
		||||
                                AirTree::local_var(
 | 
			
		||||
                                    format!(
 | 
			
		||||
                                        "__constr_var_span_{}_{}",
 | 
			
		||||
                                        location.start, location.end
 | 
			
		||||
                                    ),
 | 
			
		||||
                                    tipo.clone(),
 | 
			
		||||
                                ),
 | 
			
		||||
                                Some(msg_func.clone()),
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            assigns.insert(0, expose);
 | 
			
		||||
| 
						 | 
				
			
			@ -2205,8 +2232,11 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                        defined_heads,
 | 
			
		||||
                        subject_tipo.clone(),
 | 
			
		||||
                        tail.is_some(),
 | 
			
		||||
                        false,
 | 
			
		||||
                        AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
 | 
			
		||||
                        // One special usage of list access here
 | 
			
		||||
                        // So for the msg we pass in empty string if tracing is on
 | 
			
		||||
                        // Since check_last_item is false this will never get added to the final uplc anyway
 | 
			
		||||
                        None,
 | 
			
		||||
                    )
 | 
			
		||||
                } else {
 | 
			
		||||
                    assert!(defined_tails.len() >= defined_heads.len());
 | 
			
		||||
| 
						 | 
				
			
			@ -2345,11 +2375,11 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                        } else {
 | 
			
		||||
                            AirTree::fields_expose(
 | 
			
		||||
                                indices,
 | 
			
		||||
                                false,
 | 
			
		||||
                                AirTree::local_var(
 | 
			
		||||
                                    props.clause_var_name.clone(),
 | 
			
		||||
                                    subject_tipo.clone(),
 | 
			
		||||
                                ),
 | 
			
		||||
                                None,
 | 
			
		||||
                            )
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2482,8 +2512,8 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                        AirTree::tuple_access(
 | 
			
		||||
                            names,
 | 
			
		||||
                            subject_tipo.clone(),
 | 
			
		||||
                            false,
 | 
			
		||||
                            AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
 | 
			
		||||
                            None,
 | 
			
		||||
                        ),
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -2668,17 +2698,39 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
        arguments: &[TypedArg],
 | 
			
		||||
        has_context: bool,
 | 
			
		||||
        body: AirTree,
 | 
			
		||||
        src_code: &str,
 | 
			
		||||
    ) -> AirTree {
 | 
			
		||||
        let checked_args = arguments
 | 
			
		||||
            .iter()
 | 
			
		||||
            .enumerate()
 | 
			
		||||
            .map(|(index, arg)| {
 | 
			
		||||
                let arg_name = arg.arg_name.get_variable_name().unwrap_or("_").to_string();
 | 
			
		||||
                let arg_span = arg.location;
 | 
			
		||||
 | 
			
		||||
                if !(has_context && index == arguments.len() - 1) && &arg_name != "_" {
 | 
			
		||||
                    let param = AirTree::local_var(&arg_name, data());
 | 
			
		||||
 | 
			
		||||
                    let actual_type = convert_opaque_type(&arg.tipo, &self.data_types);
 | 
			
		||||
 | 
			
		||||
                    let msg = src_code
 | 
			
		||||
                        .get(arg_span.start..arg_span.end)
 | 
			
		||||
                        .expect("Out of bounds span")
 | 
			
		||||
                        .to_string();
 | 
			
		||||
 | 
			
		||||
                    let msg_func_name = msg.split_whitespace().join("");
 | 
			
		||||
 | 
			
		||||
                    self.special_functions.insert_new_function(
 | 
			
		||||
                        msg_func_name.to_string(),
 | 
			
		||||
                        Term::string(msg),
 | 
			
		||||
                        string(),
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    let msg_func = if self.tracing {
 | 
			
		||||
                        self.special_functions.use_function_tree(msg_func_name)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        AirTree::no_op()
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    let assign = self.assignment(
 | 
			
		||||
                        &Pattern::Var {
 | 
			
		||||
                            location: Span::empty(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2691,8 +2743,7 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                            kind: AssignmentKind::Expect,
 | 
			
		||||
                            remove_unused: false,
 | 
			
		||||
                            full_check: true,
 | 
			
		||||
                            location: Span::empty(),
 | 
			
		||||
                            module_name: String::new(),
 | 
			
		||||
                            msg_func,
 | 
			
		||||
                        },
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3911,9 +3962,17 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                // tipo here refers to the list type while the actual return
 | 
			
		||||
                // type is nothing since this is an assignment over some expression
 | 
			
		||||
                tipo,
 | 
			
		||||
                check_last_item,
 | 
			
		||||
                is_expect,
 | 
			
		||||
            } => {
 | 
			
		||||
                let value = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let error_term = if self.tracing && is_expect {
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let list_id = self.id_gen.next();
 | 
			
		||||
| 
						 | 
				
			
			@ -3937,37 +3996,21 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                    .collect_vec();
 | 
			
		||||
 | 
			
		||||
                if !names_empty {
 | 
			
		||||
                    let error_term = if self.tracing {
 | 
			
		||||
                        Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                            self.special_functions.use_function(TOO_MANY_ITEMS),
 | 
			
		||||
                        ))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Term::Error
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    term = builder::list_access_to_uplc(
 | 
			
		||||
                        &names_types,
 | 
			
		||||
                        &id_list,
 | 
			
		||||
                        tail,
 | 
			
		||||
                        0,
 | 
			
		||||
                        term,
 | 
			
		||||
                        check_last_item,
 | 
			
		||||
                        is_expect && !tail,
 | 
			
		||||
                        true,
 | 
			
		||||
                        error_term,
 | 
			
		||||
                    )
 | 
			
		||||
                    .apply(value);
 | 
			
		||||
 | 
			
		||||
                    arg_stack.push(term);
 | 
			
		||||
                } else if check_last_item {
 | 
			
		||||
                    let trace_term = if self.tracing {
 | 
			
		||||
                        Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                            self.special_functions.use_function(LIST_NOT_EMPTY),
 | 
			
		||||
                        ))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Term::Error
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    term = value.delayed_choose_list(term, trace_term);
 | 
			
		||||
                } else if is_expect {
 | 
			
		||||
                    term = value.delayed_choose_list(term, error_term);
 | 
			
		||||
 | 
			
		||||
                    arg_stack.push(term);
 | 
			
		||||
                } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -4449,37 +4492,44 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
                arg_stack.push(term);
 | 
			
		||||
            }
 | 
			
		||||
            Air::AssertConstr { constr_index, msg } => {
 | 
			
		||||
            Air::AssertConstr { constr_index } => {
 | 
			
		||||
                let constr = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let trace_term = if self.tracing {
 | 
			
		||||
                    Term::Error.delayed_trace(Term::string(msg))
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                term = Term::equals_integer()
 | 
			
		||||
                    .apply(Term::integer(constr_index.into()))
 | 
			
		||||
                    .apply(
 | 
			
		||||
                        Term::var(self.special_functions.use_function(CONSTR_INDEX_EXPOSER))
 | 
			
		||||
                        Term::var(
 | 
			
		||||
                            self.special_functions
 | 
			
		||||
                                .use_function_uplc(CONSTR_INDEX_EXPOSER.to_string()),
 | 
			
		||||
                        )
 | 
			
		||||
                        .apply(constr),
 | 
			
		||||
                    )
 | 
			
		||||
                    .delayed_if_then_else(term, trace_term);
 | 
			
		||||
 | 
			
		||||
                arg_stack.push(term);
 | 
			
		||||
            }
 | 
			
		||||
            Air::AssertBool { is_true, msg } => {
 | 
			
		||||
            Air::AssertBool { is_true } => {
 | 
			
		||||
                let value = arg_stack.pop().unwrap();
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let trace_term = if self.tracing {
 | 
			
		||||
                    Term::Error.delayed_trace(Term::string(msg))
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                if is_true {
 | 
			
		||||
                    term = value.delayed_if_then_else(term, trace_term)
 | 
			
		||||
                } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -4504,7 +4554,10 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                {
 | 
			
		||||
                    subject
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::var(self.special_functions.use_function(CONSTR_INDEX_EXPOSER))
 | 
			
		||||
                    Term::var(
 | 
			
		||||
                        self.special_functions
 | 
			
		||||
                            .use_function_uplc(CONSTR_INDEX_EXPOSER.to_string()),
 | 
			
		||||
                    )
 | 
			
		||||
                    .apply(subject)
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4710,7 +4763,10 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                        unreachable!()
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Term::equals_integer().apply(checker).apply(
 | 
			
		||||
                            Term::var(self.special_functions.use_function(CONSTR_INDEX_EXPOSER))
 | 
			
		||||
                            Term::var(
 | 
			
		||||
                                self.special_functions
 | 
			
		||||
                                    .use_function_uplc(CONSTR_INDEX_EXPOSER.to_string()),
 | 
			
		||||
                            )
 | 
			
		||||
                            .apply(Term::var(subject_name)),
 | 
			
		||||
                        )
 | 
			
		||||
                    };
 | 
			
		||||
| 
						 | 
				
			
			@ -4850,13 +4906,18 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
                arg_stack.push(term);
 | 
			
		||||
            }
 | 
			
		||||
            Air::FieldsExpose {
 | 
			
		||||
                indices,
 | 
			
		||||
                check_last_item,
 | 
			
		||||
            } => {
 | 
			
		||||
            Air::FieldsExpose { indices, is_expect } => {
 | 
			
		||||
                let mut id_list = vec![];
 | 
			
		||||
 | 
			
		||||
                let value = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let error_term = if self.tracing && is_expect {
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
                let list_id = self.id_gen.next();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4875,43 +4936,33 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                    .collect_vec();
 | 
			
		||||
 | 
			
		||||
                if !indices.is_empty() {
 | 
			
		||||
                    let error_term = if self.tracing {
 | 
			
		||||
                        Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                            self.special_functions.use_function(TOO_MANY_ITEMS),
 | 
			
		||||
                        ))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Term::Error
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    term = builder::list_access_to_uplc(
 | 
			
		||||
                        &names_types,
 | 
			
		||||
                        &id_list,
 | 
			
		||||
                        false,
 | 
			
		||||
                        current_index,
 | 
			
		||||
                        term,
 | 
			
		||||
                        check_last_item,
 | 
			
		||||
                        is_expect,
 | 
			
		||||
                        false,
 | 
			
		||||
                        error_term,
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    term = term.apply(
 | 
			
		||||
                        Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
 | 
			
		||||
                        Term::var(
 | 
			
		||||
                            self.special_functions
 | 
			
		||||
                                .use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
 | 
			
		||||
                        )
 | 
			
		||||
                        .apply(value),
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    arg_stack.push(term);
 | 
			
		||||
                } else if check_last_item {
 | 
			
		||||
                    let trace_term = if self.tracing {
 | 
			
		||||
                        Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                            self.special_functions.use_function(CONSTR_NOT_EMPTY),
 | 
			
		||||
                        ))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Term::Error
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    term = Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
 | 
			
		||||
                } else if is_expect {
 | 
			
		||||
                    term = Term::var(
 | 
			
		||||
                        self.special_functions
 | 
			
		||||
                            .use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
 | 
			
		||||
                    )
 | 
			
		||||
                    .apply(value)
 | 
			
		||||
                        .delayed_choose_list(term, trace_term);
 | 
			
		||||
                    .delayed_choose_list(term, error_term);
 | 
			
		||||
 | 
			
		||||
                    arg_stack.push(term);
 | 
			
		||||
                } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -4920,35 +4971,38 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
            }
 | 
			
		||||
            Air::FieldsEmpty => {
 | 
			
		||||
                let value = arg_stack.pop().unwrap();
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let trace_term = if self.tracing {
 | 
			
		||||
                    Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                        self.special_functions.use_function(CONSTR_NOT_EMPTY),
 | 
			
		||||
                    ))
 | 
			
		||||
                let error_term = if self.tracing {
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                term = Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                term = Term::var(
 | 
			
		||||
                    self.special_functions
 | 
			
		||||
                        .use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
 | 
			
		||||
                )
 | 
			
		||||
                .apply(value)
 | 
			
		||||
                    .delayed_choose_list(term, trace_term);
 | 
			
		||||
                .delayed_choose_list(term, error_term);
 | 
			
		||||
 | 
			
		||||
                arg_stack.push(term);
 | 
			
		||||
            }
 | 
			
		||||
            Air::ListEmpty => {
 | 
			
		||||
                let value = arg_stack.pop().unwrap();
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let trace_term = if self.tracing {
 | 
			
		||||
                    Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                        self.special_functions.use_function(LIST_NOT_EMPTY),
 | 
			
		||||
                    ))
 | 
			
		||||
                let error_term = if self.tracing {
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                term = value.delayed_choose_list(term, trace_term);
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                term = value.delayed_choose_list(term, error_term);
 | 
			
		||||
 | 
			
		||||
                arg_stack.push(term);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -5095,7 +5149,10 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
                }
 | 
			
		||||
 | 
			
		||||
                term = term.lambda(format!("{tail_name_prefix}_0")).apply(
 | 
			
		||||
                    Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
 | 
			
		||||
                    Term::var(
 | 
			
		||||
                        self.special_functions
 | 
			
		||||
                            .use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
 | 
			
		||||
                    )
 | 
			
		||||
                    .apply(record),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5128,10 +5185,18 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
            Air::TupleAccessor {
 | 
			
		||||
                tipo,
 | 
			
		||||
                names,
 | 
			
		||||
                check_last_item,
 | 
			
		||||
                is_expect,
 | 
			
		||||
            } => {
 | 
			
		||||
                let inner_types = tipo.get_inner_types();
 | 
			
		||||
                let value = arg_stack.pop().unwrap();
 | 
			
		||||
 | 
			
		||||
                let error_term = if self.tracing && is_expect && !tipo.is_2_tuple() {
 | 
			
		||||
                    let msg = arg_stack.pop().unwrap();
 | 
			
		||||
                    Term::Error.delayed_trace(msg)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Term::Error
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut term = arg_stack.pop().unwrap();
 | 
			
		||||
                let list_id = self.id_gen.next();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5169,31 +5234,21 @@ impl<'a> CodeGenerator<'a> {
 | 
			
		|||
 | 
			
		||||
                    let names_types = names.into_iter().zip(inner_types).collect_vec();
 | 
			
		||||
 | 
			
		||||
                    let error_term = if self.tracing {
 | 
			
		||||
                        Term::Error.delayed_trace(Term::var(
 | 
			
		||||
                            self.special_functions.use_function(TOO_MANY_ITEMS),
 | 
			
		||||
                        ))
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Term::Error
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    term = builder::list_access_to_uplc(
 | 
			
		||||
                        &names_types,
 | 
			
		||||
                        &id_list,
 | 
			
		||||
                        false,
 | 
			
		||||
                        0,
 | 
			
		||||
                        term,
 | 
			
		||||
                        check_last_item,
 | 
			
		||||
                        is_expect,
 | 
			
		||||
                        false,
 | 
			
		||||
                        error_term,
 | 
			
		||||
                    )
 | 
			
		||||
                    .apply(value);
 | 
			
		||||
 | 
			
		||||
                    arg_stack.push(term);
 | 
			
		||||
                } else if check_last_item {
 | 
			
		||||
                    unreachable!("HOW DID YOU DO THIS");
 | 
			
		||||
                } else {
 | 
			
		||||
                    arg_stack.push(term);
 | 
			
		||||
                    unreachable!("HOW DID YOU DO THIS");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Air::Trace { .. } => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,11 +89,9 @@ pub enum Air {
 | 
			
		|||
    },
 | 
			
		||||
    AssertConstr {
 | 
			
		||||
        constr_index: usize,
 | 
			
		||||
        msg: String,
 | 
			
		||||
    },
 | 
			
		||||
    AssertBool {
 | 
			
		||||
        is_true: bool,
 | 
			
		||||
        msg: String,
 | 
			
		||||
    },
 | 
			
		||||
    // When
 | 
			
		||||
    When {
 | 
			
		||||
| 
						 | 
				
			
			@ -154,14 +152,14 @@ pub enum Air {
 | 
			
		|||
    // Field Access
 | 
			
		||||
    FieldsExpose {
 | 
			
		||||
        indices: Vec<(usize, String, Rc<Type>)>,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        is_expect: bool,
 | 
			
		||||
    },
 | 
			
		||||
    // ListAccess
 | 
			
		||||
    ListAccessor {
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
        names: Vec<String>,
 | 
			
		||||
        tail: bool,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        is_expect: bool,
 | 
			
		||||
    },
 | 
			
		||||
    ListExpose {
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +170,7 @@ pub enum Air {
 | 
			
		|||
    TupleAccessor {
 | 
			
		||||
        names: Vec<String>,
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        is_expect: bool,
 | 
			
		||||
    },
 | 
			
		||||
    // Misc.
 | 
			
		||||
    ErrorTerm {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ use crate::{
 | 
			
		|||
        AssignmentKind, DataType, Pattern, Span, TypedArg, TypedClause, TypedClauseGuard,
 | 
			
		||||
        TypedDataType, TypedPattern,
 | 
			
		||||
    },
 | 
			
		||||
    builtins::{bool, void},
 | 
			
		||||
    builtins::{bool, data, function, int, list, string, void},
 | 
			
		||||
    expr::TypedExpr,
 | 
			
		||||
    tipo::{PatternConstructor, TypeVar, ValueConstructor, ValueConstructorVariant},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -82,8 +82,7 @@ pub struct AssignmentProperties {
 | 
			
		|||
    pub kind: AssignmentKind,
 | 
			
		||||
    pub remove_unused: bool,
 | 
			
		||||
    pub full_check: bool,
 | 
			
		||||
    pub location: Span,
 | 
			
		||||
    pub module_name: String,
 | 
			
		||||
    pub msg_func: AirTree,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +192,7 @@ impl ClauseProperties {
 | 
			
		|||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct CodeGenSpecialFuncs {
 | 
			
		||||
    pub used_funcs: Vec<String>,
 | 
			
		||||
    pub key_to_func: IndexMap<String, Term<Name>>,
 | 
			
		||||
    pub key_to_func: IndexMap<String, (Term<Name>, Rc<Type>)>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CodeGenSpecialFuncs {
 | 
			
		||||
| 
						 | 
				
			
			@ -202,46 +201,30 @@ impl CodeGenSpecialFuncs {
 | 
			
		|||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            CONSTR_FIELDS_EXPOSER.to_string(),
 | 
			
		||||
            (
 | 
			
		||||
                Term::snd_pair()
 | 
			
		||||
                    .apply(Term::unconstr_data().apply(Term::var("__constr_var")))
 | 
			
		||||
                    .lambda("__constr_var"),
 | 
			
		||||
                function(vec![data()], list(data())),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            CONSTR_INDEX_EXPOSER.to_string(),
 | 
			
		||||
            (
 | 
			
		||||
                Term::fst_pair()
 | 
			
		||||
                    .apply(Term::unconstr_data().apply(Term::var("__constr_var")))
 | 
			
		||||
                    .lambda("__constr_var"),
 | 
			
		||||
                function(vec![data()], int()),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            TOO_MANY_ITEMS.to_string(),
 | 
			
		||||
            (
 | 
			
		||||
                Term::string("List/Tuple/Constr contains more items than expected"),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            LIST_NOT_EMPTY.to_string(),
 | 
			
		||||
            Term::string("Expected no items for List"),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            CONSTR_NOT_EMPTY.to_string(),
 | 
			
		||||
            Term::string("Expected no fields for Constr"),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            INCORRECT_BOOLEAN.to_string(),
 | 
			
		||||
            Term::string("Expected on incorrect Boolean variant"),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            INCORRECT_CONSTR.to_string(),
 | 
			
		||||
            Term::string("Expected on incorrect Constr variant"),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        key_to_func.insert(
 | 
			
		||||
            CONSTR_INDEX_MISMATCH.to_string(),
 | 
			
		||||
            Term::string("Constr index didn't match a type variant"),
 | 
			
		||||
                string(),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        CodeGenSpecialFuncs {
 | 
			
		||||
| 
						 | 
				
			
			@ -250,15 +233,26 @@ impl CodeGenSpecialFuncs {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn use_function(&mut self, func_name: &'static str) -> &'static str {
 | 
			
		||||
        if !self.used_funcs.contains(&func_name.to_string()) {
 | 
			
		||||
    pub fn use_function_tree(&mut self, func_name: String) -> AirTree {
 | 
			
		||||
        if !self.used_funcs.contains(&func_name) {
 | 
			
		||||
            self.used_funcs.push(func_name.to_string());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let tipo = self.key_to_func.get(&func_name).unwrap().1.clone();
 | 
			
		||||
 | 
			
		||||
        AirTree::local_var(func_name, tipo)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn use_function_uplc(&mut self, func_name: String) -> String {
 | 
			
		||||
        if !self.used_funcs.contains(&func_name) {
 | 
			
		||||
            self.used_funcs.push(func_name.to_string());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        func_name
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_function(&self, func_name: &String) -> Term<Name> {
 | 
			
		||||
        self.key_to_func[func_name].clone()
 | 
			
		||||
        self.key_to_func[func_name].0.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn apply_used_functions(&self, mut term: Term<Name>) -> Term<Name> {
 | 
			
		||||
| 
						 | 
				
			
			@ -267,6 +261,18 @@ impl CodeGenSpecialFuncs {
 | 
			
		|||
        }
 | 
			
		||||
        term
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn insert_new_function(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        func_name: String,
 | 
			
		||||
        function: Term<Name>,
 | 
			
		||||
        function_type: Rc<Type>,
 | 
			
		||||
    ) {
 | 
			
		||||
        if !self.key_to_func.contains_key(&func_name) {
 | 
			
		||||
            self.key_to_func
 | 
			
		||||
                .insert(func_name, (function, function_type));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for CodeGenSpecialFuncs {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,12 +127,12 @@ pub enum AirStatement {
 | 
			
		|||
    AssertConstr {
 | 
			
		||||
        constr_index: usize,
 | 
			
		||||
        constr: Box<AirTree>,
 | 
			
		||||
        msg: String,
 | 
			
		||||
        msg: Box<AirTree>,
 | 
			
		||||
    },
 | 
			
		||||
    AssertBool {
 | 
			
		||||
        is_true: bool,
 | 
			
		||||
        value: Box<AirTree>,
 | 
			
		||||
        msg: String,
 | 
			
		||||
        msg: Box<AirTree>,
 | 
			
		||||
    },
 | 
			
		||||
    // Clause Guards
 | 
			
		||||
    ClauseGuard {
 | 
			
		||||
| 
						 | 
				
			
			@ -154,16 +154,16 @@ pub enum AirStatement {
 | 
			
		|||
    // Field Access
 | 
			
		||||
    FieldsExpose {
 | 
			
		||||
        indices: Vec<(usize, String, Rc<Type>)>,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        record: Box<AirTree>,
 | 
			
		||||
        msg: Box<Option<AirTree>>,
 | 
			
		||||
    },
 | 
			
		||||
    // List Access
 | 
			
		||||
    ListAccessor {
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
        names: Vec<String>,
 | 
			
		||||
        tail: bool,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        list: Box<AirTree>,
 | 
			
		||||
        msg: Box<Option<AirTree>>,
 | 
			
		||||
    },
 | 
			
		||||
    ListExpose {
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
| 
						 | 
				
			
			@ -174,15 +174,17 @@ pub enum AirStatement {
 | 
			
		|||
    TupleAccessor {
 | 
			
		||||
        names: Vec<String>,
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        tuple: Box<AirTree>,
 | 
			
		||||
        msg: Box<Option<AirTree>>,
 | 
			
		||||
    },
 | 
			
		||||
    // Misc.
 | 
			
		||||
    FieldsEmpty {
 | 
			
		||||
        constr: Box<AirTree>,
 | 
			
		||||
        msg: Box<AirTree>,
 | 
			
		||||
    },
 | 
			
		||||
    ListEmpty {
 | 
			
		||||
        list: Box<AirTree>,
 | 
			
		||||
        msg: Box<AirTree>,
 | 
			
		||||
    },
 | 
			
		||||
    NoOp,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -494,22 +496,22 @@ impl AirTree {
 | 
			
		|||
            value: value.into(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    pub fn assert_constr_index(constr_index: usize, constr: AirTree, msg: String) -> AirTree {
 | 
			
		||||
    pub fn assert_constr_index(constr_index: usize, constr: AirTree, msg: AirTree) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::AssertConstr {
 | 
			
		||||
                constr_index,
 | 
			
		||||
                constr: constr.into(),
 | 
			
		||||
                msg,
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn assert_bool(is_true: bool, value: AirTree, msg: String) -> AirTree {
 | 
			
		||||
    pub fn assert_bool(is_true: bool, value: AirTree, msg: AirTree) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::AssertBool {
 | 
			
		||||
                is_true,
 | 
			
		||||
                value: value.into(),
 | 
			
		||||
                msg,
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -714,14 +716,14 @@ impl AirTree {
 | 
			
		|||
 | 
			
		||||
    pub fn fields_expose(
 | 
			
		||||
        indices: Vec<(usize, String, Rc<Type>)>,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        record: AirTree,
 | 
			
		||||
        msg: Option<AirTree>,
 | 
			
		||||
    ) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::FieldsExpose {
 | 
			
		||||
                indices,
 | 
			
		||||
                check_last_item,
 | 
			
		||||
                record: record.into(),
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -730,16 +732,16 @@ impl AirTree {
 | 
			
		|||
        names: Vec<String>,
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
        tail: bool,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        list: AirTree,
 | 
			
		||||
        msg: Option<AirTree>,
 | 
			
		||||
    ) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::ListAccessor {
 | 
			
		||||
                tipo,
 | 
			
		||||
                names,
 | 
			
		||||
                tail,
 | 
			
		||||
                check_last_item,
 | 
			
		||||
                list: list.into(),
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -761,15 +763,15 @@ impl AirTree {
 | 
			
		|||
    pub fn tuple_access(
 | 
			
		||||
        names: Vec<String>,
 | 
			
		||||
        tipo: Rc<Type>,
 | 
			
		||||
        check_last_item: bool,
 | 
			
		||||
        tuple: AirTree,
 | 
			
		||||
        msg: Option<AirTree>,
 | 
			
		||||
    ) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::TupleAccessor {
 | 
			
		||||
                names,
 | 
			
		||||
                tipo,
 | 
			
		||||
                check_last_item,
 | 
			
		||||
                tuple: tuple.into(),
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -804,17 +806,21 @@ impl AirTree {
 | 
			
		|||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn fields_empty(constr: AirTree) -> AirTree {
 | 
			
		||||
    pub fn fields_empty(constr: AirTree, msg: AirTree) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::FieldsEmpty {
 | 
			
		||||
                constr: constr.into(),
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn list_empty(list: AirTree) -> AirTree {
 | 
			
		||||
    pub fn list_empty(list: AirTree, msg: AirTree) -> AirTree {
 | 
			
		||||
        AirTree::Statement {
 | 
			
		||||
            statement: AirStatement::ListEmpty { list: list.into() },
 | 
			
		||||
            statement: AirStatement::ListEmpty {
 | 
			
		||||
                list: list.into(),
 | 
			
		||||
                msg: msg.into(),
 | 
			
		||||
            },
 | 
			
		||||
            hoisted_over: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -952,20 +958,18 @@ impl AirTree {
 | 
			
		|||
                    } => {
 | 
			
		||||
                        air_vec.push(Air::AssertConstr {
 | 
			
		||||
                            constr_index: *constr_index,
 | 
			
		||||
                            msg: msg.clone(),
 | 
			
		||||
                        });
 | 
			
		||||
                        constr.create_air_vec(air_vec);
 | 
			
		||||
                        msg.create_air_vec(air_vec);
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::AssertBool {
 | 
			
		||||
                        is_true,
 | 
			
		||||
                        value,
 | 
			
		||||
                        msg,
 | 
			
		||||
                    } => {
 | 
			
		||||
                        air_vec.push(Air::AssertBool {
 | 
			
		||||
                            is_true: *is_true,
 | 
			
		||||
                            msg: msg.clone(),
 | 
			
		||||
                        });
 | 
			
		||||
                        air_vec.push(Air::AssertBool { is_true: *is_true });
 | 
			
		||||
                        value.create_air_vec(air_vec);
 | 
			
		||||
                        msg.create_air_vec(air_vec);
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::ClauseGuard {
 | 
			
		||||
                        subject_name,
 | 
			
		||||
| 
						 | 
				
			
			@ -1005,29 +1009,35 @@ impl AirTree {
 | 
			
		|||
                    }
 | 
			
		||||
                    AirStatement::FieldsExpose {
 | 
			
		||||
                        indices,
 | 
			
		||||
                        check_last_item,
 | 
			
		||||
                        record,
 | 
			
		||||
                        msg,
 | 
			
		||||
                    } => {
 | 
			
		||||
                        air_vec.push(Air::FieldsExpose {
 | 
			
		||||
                            indices: indices.clone(),
 | 
			
		||||
                            check_last_item: *check_last_item,
 | 
			
		||||
                            is_expect: msg.is_some(),
 | 
			
		||||
                        });
 | 
			
		||||
                        record.create_air_vec(air_vec);
 | 
			
		||||
                        msg.iter().for_each(|msg| {
 | 
			
		||||
                            msg.create_air_vec(air_vec);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::ListAccessor {
 | 
			
		||||
                        tipo,
 | 
			
		||||
                        names,
 | 
			
		||||
                        tail,
 | 
			
		||||
                        check_last_item,
 | 
			
		||||
                        list,
 | 
			
		||||
                        msg,
 | 
			
		||||
                    } => {
 | 
			
		||||
                        air_vec.push(Air::ListAccessor {
 | 
			
		||||
                            tipo: tipo.clone(),
 | 
			
		||||
                            names: names.clone(),
 | 
			
		||||
                            tail: *tail,
 | 
			
		||||
                            check_last_item: *check_last_item,
 | 
			
		||||
                            is_expect: msg.is_some(),
 | 
			
		||||
                        });
 | 
			
		||||
                        list.create_air_vec(air_vec);
 | 
			
		||||
                        msg.iter().for_each(|msg| {
 | 
			
		||||
                            msg.create_air_vec(air_vec);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::ListExpose {
 | 
			
		||||
                        tipo,
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,26 +1053,31 @@ impl AirTree {
 | 
			
		|||
                    AirStatement::TupleAccessor {
 | 
			
		||||
                        names,
 | 
			
		||||
                        tipo,
 | 
			
		||||
                        check_last_item,
 | 
			
		||||
                        tuple,
 | 
			
		||||
                        msg,
 | 
			
		||||
                    } => {
 | 
			
		||||
                        air_vec.push(Air::TupleAccessor {
 | 
			
		||||
                            names: names.clone(),
 | 
			
		||||
                            tipo: tipo.clone(),
 | 
			
		||||
                            check_last_item: *check_last_item,
 | 
			
		||||
                            is_expect: msg.is_some(),
 | 
			
		||||
                        });
 | 
			
		||||
                        tuple.create_air_vec(air_vec);
 | 
			
		||||
                        msg.iter().for_each(|msg| {
 | 
			
		||||
                            msg.create_air_vec(air_vec);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::NoOp => {
 | 
			
		||||
                        air_vec.push(Air::NoOp);
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::FieldsEmpty { constr } => {
 | 
			
		||||
                    AirStatement::FieldsEmpty { constr, msg } => {
 | 
			
		||||
                        air_vec.push(Air::FieldsEmpty);
 | 
			
		||||
                        constr.create_air_vec(air_vec);
 | 
			
		||||
                        msg.create_air_vec(air_vec);
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::ListEmpty { list } => {
 | 
			
		||||
                    AirStatement::ListEmpty { list, msg } => {
 | 
			
		||||
                        air_vec.push(Air::ListEmpty);
 | 
			
		||||
                        list.create_air_vec(air_vec);
 | 
			
		||||
                        msg.create_air_vec(air_vec);
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                exp.create_air_vec(air_vec);
 | 
			
		||||
| 
						 | 
				
			
			@ -1527,7 +1542,7 @@ impl AirTree {
 | 
			
		|||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                AirStatement::NoOp => {}
 | 
			
		||||
                AirStatement::FieldsEmpty { constr } => {
 | 
			
		||||
                AirStatement::FieldsEmpty { constr, .. } => {
 | 
			
		||||
                    constr.do_traverse_tree_with(
 | 
			
		||||
                        tree_path,
 | 
			
		||||
                        current_depth + 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -1536,7 +1551,7 @@ impl AirTree {
 | 
			
		|||
                        apply_with_func_last,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                AirStatement::ListEmpty { list } => {
 | 
			
		||||
                AirStatement::ListEmpty { list, .. } => {
 | 
			
		||||
                    list.do_traverse_tree_with(
 | 
			
		||||
                        tree_path,
 | 
			
		||||
                        current_depth + 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -1997,7 +2012,7 @@ impl AirTree {
 | 
			
		|||
                    }
 | 
			
		||||
                    AirStatement::DefineFunc { .. } => unreachable!(),
 | 
			
		||||
                    AirStatement::DefineCyclicFuncs { .. } => unreachable!(),
 | 
			
		||||
                    AirStatement::FieldsEmpty { constr } => {
 | 
			
		||||
                    AirStatement::FieldsEmpty { constr, .. } => {
 | 
			
		||||
                        if *index == 0 {
 | 
			
		||||
                            constr.as_mut().do_find_air_tree_node(tree_path_iter)
 | 
			
		||||
                        } else if *index == 1 {
 | 
			
		||||
| 
						 | 
				
			
			@ -2006,7 +2021,7 @@ impl AirTree {
 | 
			
		|||
                            panic!("Tree Path index outside tree children nodes")
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    AirStatement::ListEmpty { list } => {
 | 
			
		||||
                    AirStatement::ListEmpty { list, .. } => {
 | 
			
		||||
                        if *index == 0 {
 | 
			
		||||
                            list.as_mut().do_find_air_tree_node(tree_path_iter)
 | 
			
		||||
                        } else if *index == 1 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue