change: traverse_with_tree now has a boolean to determine when with is called
fix: Opaque types are now properly handled in code gen (i.e. code gen functions, in datums/redeemers, in from data casts) chore: add specific nested opaque type tests to code gen
This commit is contained in:
		
							parent
							
								
									c6f764d2db
								
							
						
					
					
						commit
						084b900b2a
					
				|  | @ -23,10 +23,10 @@ use crate::{ | ||||||
|     builtins::{bool, data, int, void}, |     builtins::{bool, data, int, void}, | ||||||
|     expr::TypedExpr, |     expr::TypedExpr, | ||||||
|     gen_uplc::builder::{ |     gen_uplc::builder::{ | ||||||
|         convert_opaque_type, erase_opaque_type_operations, find_and_replace_generics, |         check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations, | ||||||
|         find_list_clause_or_default_first, get_arg_type_name, get_generic_id_and_type, |         find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name, | ||||||
|         get_variant_name, monomorphize, pattern_has_conditions, wrap_as_multi_validator, |         get_generic_id_and_type, get_variant_name, monomorphize, pattern_has_conditions, | ||||||
|         wrap_validator_condition, CodeGenFunction, SpecificClause, |         wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction, SpecificClause, | ||||||
|     }, |     }, | ||||||
|     tipo::{ |     tipo::{ | ||||||
|         ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, |         ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, | ||||||
|  | @ -539,7 +539,13 @@ impl<'a> CodeGenerator<'a> { | ||||||
|                 index, |                 index, | ||||||
|                 record, |                 record, | ||||||
|                 .. |                 .. | ||||||
|             } => AirTree::record_access(*index, tipo.clone(), self.build(record)), |             } => { | ||||||
|  |                 if check_replaceable_opaque_type(&record.tipo(), &self.data_types) { | ||||||
|  |                     self.build(record) | ||||||
|  |                 } else { | ||||||
|  |                     AirTree::record_access(*index, tipo.clone(), self.build(record)) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             TypedExpr::ModuleSelect { |             TypedExpr::ModuleSelect { | ||||||
|                 tipo, |                 tipo, | ||||||
|  | @ -1013,7 +1019,11 @@ impl<'a> CodeGenerator<'a> { | ||||||
| 
 | 
 | ||||||
|                     // This `value` is either value param that was passed in or
 |                     // This `value` is either value param that was passed in or
 | ||||||
|                     // local var
 |                     // local var
 | ||||||
|                     sequence.push(AirTree::fields_expose(indices, props.full_check, value)); |                     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)); | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                     sequence.append( |                     sequence.append( | ||||||
|                         &mut fields |                         &mut fields | ||||||
|  | @ -1116,6 +1126,7 @@ impl<'a> CodeGenerator<'a> { | ||||||
|         location: Span, |         location: Span, | ||||||
|     ) -> AirTree { |     ) -> AirTree { | ||||||
|         assert!(tipo.get_generic().is_none()); |         assert!(tipo.get_generic().is_none()); | ||||||
|  |         let tipo = &convert_opaque_type(tipo, &self.data_types); | ||||||
| 
 | 
 | ||||||
|         if tipo.is_primitive() { |         if tipo.is_primitive() { | ||||||
|             // Since we would return void anyway and ignore then we can just return value here and ignore
 |             // Since we would return void anyway and ignore then we can just return value here and ignore
 | ||||||
|  | @ -2158,11 +2169,25 @@ impl<'a> CodeGenerator<'a> { | ||||||
| 
 | 
 | ||||||
|                     let mut air_fields = fields.into_iter().map(|(_, _, _, val)| val).collect_vec(); |                     let mut air_fields = fields.into_iter().map(|(_, _, _, val)| val).collect_vec(); | ||||||
| 
 | 
 | ||||||
|                     let field_assign = AirTree::fields_expose( |                     let field_assign = | ||||||
|                         indices, |                         if check_replaceable_opaque_type(subject_tipo, &self.data_types) { | ||||||
|                         false, |                             AirTree::let_assignment( | ||||||
|                         AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()), |                                 &indices[0].1, | ||||||
|                     ); |                                 AirTree::local_var( | ||||||
|  |                                     props.clause_var_name.clone(), | ||||||
|  |                                     subject_tipo.clone(), | ||||||
|  |                                 ), | ||||||
|  |                             ) | ||||||
|  |                         } else { | ||||||
|  |                             AirTree::fields_expose( | ||||||
|  |                                 indices, | ||||||
|  |                                 false, | ||||||
|  |                                 AirTree::local_var( | ||||||
|  |                                     props.clause_var_name.clone(), | ||||||
|  |                                     subject_tipo.clone(), | ||||||
|  |                                 ), | ||||||
|  |                             ) | ||||||
|  |                         }; | ||||||
| 
 | 
 | ||||||
|                     let mut sequence = vec![field_assign]; |                     let mut sequence = vec![field_assign]; | ||||||
| 
 | 
 | ||||||
|  | @ -2530,9 +2555,12 @@ impl<'a> CodeGenerator<'a> { | ||||||
|         let mut validator_hoistable; |         let mut validator_hoistable; | ||||||
| 
 | 
 | ||||||
|         // TODO change subsequent tree traversals to be more like a stream.
 |         // TODO change subsequent tree traversals to be more like a stream.
 | ||||||
|         air_tree.traverse_tree_with(&mut |air_tree: &mut AirTree, _| { |         air_tree.traverse_tree_with( | ||||||
|             erase_opaque_type_operations(air_tree, &self.data_types); |             &mut |air_tree: &mut AirTree, _| { | ||||||
|         }); |                 erase_opaque_type_operations(air_tree, &self.data_types); | ||||||
|  |             }, | ||||||
|  |             true, | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         self.find_function_vars_and_depth( |         self.find_function_vars_and_depth( | ||||||
|             &mut air_tree, |             &mut air_tree, | ||||||
|  | @ -2964,7 +2992,8 @@ impl<'a> CodeGenerator<'a> { | ||||||
| 
 | 
 | ||||||
|                     let function_def = self.functions.get(&generic_function_key); |                     let function_def = self.functions.get(&generic_function_key); | ||||||
| 
 | 
 | ||||||
|                     let Some(function_def) = function_def else { |                     let Some(function_def) = function_def | ||||||
|  |                     else { | ||||||
|                         let code_gen_func = self |                         let code_gen_func = self | ||||||
|                             .code_gen_functions |                             .code_gen_functions | ||||||
|                             .get(&generic_function_key.function_name) |                             .get(&generic_function_key.function_name) | ||||||
|  | @ -2988,12 +3017,21 @@ impl<'a> CodeGenerator<'a> { | ||||||
| 
 | 
 | ||||||
|                             let mut function_variant_path = IndexMap::new(); |                             let mut function_variant_path = IndexMap::new(); | ||||||
| 
 | 
 | ||||||
|  |                             let mut body = body.clone(); | ||||||
|  | 
 | ||||||
|  |                             body.traverse_tree_with( | ||||||
|  |                                 &mut |air_tree, _| { | ||||||
|  |                                     erase_opaque_type_operations(air_tree, &self.data_types); | ||||||
|  |                                 }, | ||||||
|  |                                 true, | ||||||
|  |                             ); | ||||||
|  | 
 | ||||||
|                             function_variant_path.insert( |                             function_variant_path.insert( | ||||||
|                                 "".to_string(), |                                 "".to_string(), | ||||||
|                                 ( |                                 ( | ||||||
|                                     tree_path.clone(), |                                     tree_path.clone(), | ||||||
|                                     UserFunction::Function { |                                     UserFunction::Function { | ||||||
|                                         body: body.clone(), |                                         body, | ||||||
|                                         deps: vec![], |                                         deps: vec![], | ||||||
|                                         params: params.clone(), |                                         params: params.clone(), | ||||||
|                                     }, |                                     }, | ||||||
|  | @ -3067,10 +3105,13 @@ impl<'a> CodeGenerator<'a> { | ||||||
| 
 | 
 | ||||||
|                             let mut function_air_tree_body = self.build(&function_def.body); |                             let mut function_air_tree_body = self.build(&function_def.body); | ||||||
| 
 | 
 | ||||||
|                             function_air_tree_body.traverse_tree_with(&mut |air_tree, _| { |                             function_air_tree_body.traverse_tree_with( | ||||||
|                                 erase_opaque_type_operations(air_tree, &self.data_types); |                                 &mut |air_tree, _| { | ||||||
|                                 monomorphize(air_tree, &mono_types); |                                     erase_opaque_type_operations(air_tree, &self.data_types); | ||||||
|                             }); |                                     monomorphize(air_tree, &mono_types); | ||||||
|  |                                 }, | ||||||
|  |                                 true, | ||||||
|  |                             ); | ||||||
| 
 | 
 | ||||||
|                             func_variants.insert( |                             func_variants.insert( | ||||||
|                                 variant, |                                 variant, | ||||||
|  | @ -3093,10 +3134,13 @@ impl<'a> CodeGenerator<'a> { | ||||||
| 
 | 
 | ||||||
|                         let mut function_air_tree_body = self.build(&function_def.body); |                         let mut function_air_tree_body = self.build(&function_def.body); | ||||||
| 
 | 
 | ||||||
|                         function_air_tree_body.traverse_tree_with(&mut |air_tree, _| { |                         function_air_tree_body.traverse_tree_with( | ||||||
|                             erase_opaque_type_operations(air_tree, &self.data_types); |                             &mut |air_tree, _| { | ||||||
|                             monomorphize(air_tree, &mono_types); |                                 erase_opaque_type_operations(air_tree, &self.data_types); | ||||||
|                         }); |                                 monomorphize(air_tree, &mono_types); | ||||||
|  |                             }, | ||||||
|  |                             true, | ||||||
|  |                         ); | ||||||
| 
 | 
 | ||||||
|                         let mut function_variant_path = IndexMap::new(); |                         let mut function_variant_path = IndexMap::new(); | ||||||
| 
 | 
 | ||||||
|  | @ -3116,6 +3160,7 @@ impl<'a> CodeGenerator<'a> { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|  |             true, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -542,37 +542,14 @@ pub fn erase_opaque_type_operations( | ||||||
|     air_tree: &mut AirTree, |     air_tree: &mut AirTree, | ||||||
|     data_types: &IndexMap<DataTypeKey, &TypedDataType>, |     data_types: &IndexMap<DataTypeKey, &TypedDataType>, | ||||||
| ) { | ) { | ||||||
|     if let AirTree::Expression(e) = air_tree { |     if let AirTree::Expression(AirExpression::Constr { tipo, args, .. }) = air_tree { | ||||||
|         match e { |         if check_replaceable_opaque_type(tipo, data_types) { | ||||||
|             AirExpression::Constr { tipo, args, .. } => { |             let arg = args.pop().unwrap(); | ||||||
|                 if check_replaceable_opaque_type(tipo, data_types) { |             if let AirTree::Expression(AirExpression::CastToData { value, .. }) = arg { | ||||||
|                     let arg = args.pop().unwrap(); |                 *air_tree = *value; | ||||||
|                     if let AirTree::Expression(AirExpression::CastToData { value, .. }) = arg { |             } else { | ||||||
|                         *air_tree = *value; |                 *air_tree = arg; | ||||||
|                     } else { |  | ||||||
|                         *air_tree = arg; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             AirExpression::RecordAccess { record, .. } => { |  | ||||||
|                 if check_replaceable_opaque_type(&record.return_type(), data_types) { |  | ||||||
|                     *air_tree = (**record).clone(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             _ => {} |  | ||||||
|         } |  | ||||||
|     } else if let AirTree::Statement { |  | ||||||
|         statement: AirStatement::FieldsExpose { |  | ||||||
|             record, indices, .. |  | ||||||
|         }, |  | ||||||
|         hoisted_over: Some(hoisted_over), |  | ||||||
|     } = air_tree |  | ||||||
|     { |  | ||||||
|         if check_replaceable_opaque_type(&record.return_type(), data_types) { |  | ||||||
|             let name = indices[0].1.clone(); |  | ||||||
|             *air_tree = AirTree::let_assignment(name, (**record).clone()) |  | ||||||
|                 .hoist_over((**hoisted_over).clone()) |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -720,17 +697,20 @@ pub fn modify_self_calls( | ||||||
|     // TODO: this would be a lot simpler if each `Var`, `Let`, function argument, etc. had a unique identifier
 |     // TODO: this would be a lot simpler if each `Var`, `Let`, function argument, etc. had a unique identifier
 | ||||||
|     // rather than just a name; this would let us track if the Var passed to itself was the same value as the method argument
 |     // rather than just a name; this would let us track if the Var passed to itself was the same value as the method argument
 | ||||||
|     let mut shadowed_parameters: HashMap<String, TreePath> = HashMap::new(); |     let mut shadowed_parameters: HashMap<String, TreePath> = HashMap::new(); | ||||||
|     body.traverse_tree_with(&mut |air_tree: &mut AirTree, tree_path| { |     body.traverse_tree_with( | ||||||
|         identify_recursive_static_params( |         &mut |air_tree: &mut AirTree, tree_path| { | ||||||
|             air_tree, |             identify_recursive_static_params( | ||||||
|             tree_path, |                 air_tree, | ||||||
|             func_params, |                 tree_path, | ||||||
|             func_key, |                 func_params, | ||||||
|             variant, |                 func_key, | ||||||
|             &mut shadowed_parameters, |                 variant, | ||||||
|             &mut potential_recursive_statics, |                 &mut shadowed_parameters, | ||||||
|         ); |                 &mut potential_recursive_statics, | ||||||
|     }); |             ); | ||||||
|  |         }, | ||||||
|  |         false, | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     // Find the index of any recursively static parameters,
 |     // Find the index of any recursively static parameters,
 | ||||||
|     // so we can remove them from the call-site of each recursive call
 |     // so we can remove them from the call-site of each recursive call
 | ||||||
|  | @ -742,35 +722,38 @@ pub fn modify_self_calls( | ||||||
|         .collect(); |         .collect(); | ||||||
| 
 | 
 | ||||||
|     // Modify any self calls to remove recursive static parameters and append `self` as a parameter for the recursion
 |     // Modify any self calls to remove recursive static parameters and append `self` as a parameter for the recursion
 | ||||||
|     body.traverse_tree_with(&mut |air_tree: &mut AirTree, _| { |     body.traverse_tree_with( | ||||||
|         if let AirTree::Expression(AirExpression::Call { func, args, .. }) = air_tree { |         &mut |air_tree: &mut AirTree, _| { | ||||||
|             if let AirTree::Expression(AirExpression::Var { |             if let AirTree::Expression(AirExpression::Call { func, args, .. }) = air_tree { | ||||||
|                 constructor: |                 if let AirTree::Expression(AirExpression::Var { | ||||||
|                     ValueConstructor { |                     constructor: | ||||||
|                         variant: ValueConstructorVariant::ModuleFn { name, module, .. }, |                         ValueConstructor { | ||||||
|                         .. |                             variant: ValueConstructorVariant::ModuleFn { name, module, .. }, | ||||||
|                     }, |                             .. | ||||||
|                 variant_name, |                         }, | ||||||
|                 .. |                     variant_name, | ||||||
|             }) = func.as_ref() |                     .. | ||||||
|             { |                 }) = func.as_ref() | ||||||
|                 if name == &func_key.function_name |  | ||||||
|                     && module == &func_key.module_name |  | ||||||
|                     && variant == variant_name |  | ||||||
|                 { |                 { | ||||||
|                     // Remove any static-recursive-parameters, because they'll be bound statically
 |                     if name == &func_key.function_name | ||||||
|                     // above the recursive part of the function
 |                         && module == &func_key.module_name | ||||||
|                     // note: assumes that static_recursive_params is sorted
 |                         && variant == variant_name | ||||||
|                     for arg in recursive_static_indexes.iter().rev() { |                     { | ||||||
|                         args.remove(*arg); |                         // Remove any static-recursive-parameters, because they'll be bound statically
 | ||||||
|  |                         // above the recursive part of the function
 | ||||||
|  |                         // note: assumes that static_recursive_params is sorted
 | ||||||
|  |                         for arg in recursive_static_indexes.iter().rev() { | ||||||
|  |                             args.remove(*arg); | ||||||
|  |                         } | ||||||
|  |                         let mut new_args = vec![func.as_ref().clone()]; | ||||||
|  |                         new_args.append(args); | ||||||
|  |                         *args = new_args; | ||||||
|                     } |                     } | ||||||
|                     let mut new_args = vec![func.as_ref().clone()]; |  | ||||||
|                     new_args.append(args); |  | ||||||
|                     *args = new_args; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         }, | ||||||
|     }); |         true, | ||||||
|  |     ); | ||||||
|     let recursive_nonstatics = func_params |     let recursive_nonstatics = func_params | ||||||
|         .iter() |         .iter() | ||||||
|         .filter(|p| !potential_recursive_statics.contains(p)) |         .filter(|p| !potential_recursive_statics.contains(p)) | ||||||
|  |  | ||||||
|  | @ -1362,9 +1362,13 @@ impl AirTree { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn traverse_tree_with(&mut self, with: &mut impl FnMut(&mut AirTree, &TreePath)) { |     pub fn traverse_tree_with( | ||||||
|  |         &mut self, | ||||||
|  |         with: &mut impl FnMut(&mut AirTree, &TreePath), | ||||||
|  |         apply_with_last: bool, | ||||||
|  |     ) { | ||||||
|         let mut tree_path = TreePath::new(); |         let mut tree_path = TreePath::new(); | ||||||
|         self.do_traverse_tree_with(&mut tree_path, 0, 0, with); |         self.do_traverse_tree_with(&mut tree_path, 0, 0, with, apply_with_last); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn traverse_tree_with_path( |     pub fn traverse_tree_with_path( | ||||||
|  | @ -1373,8 +1377,9 @@ impl AirTree { | ||||||
|         current_depth: usize, |         current_depth: usize, | ||||||
|         depth_index: usize, |         depth_index: usize, | ||||||
|         with: &mut impl FnMut(&mut AirTree, &TreePath), |         with: &mut impl FnMut(&mut AirTree, &TreePath), | ||||||
|  |         apply_with_last: bool, | ||||||
|     ) { |     ) { | ||||||
|         self.do_traverse_tree_with(path, current_depth, depth_index, with); |         self.do_traverse_tree_with(path, current_depth, depth_index, with, apply_with_last); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn do_traverse_tree_with( |     fn do_traverse_tree_with( | ||||||
|  | @ -1383,6 +1388,7 @@ impl AirTree { | ||||||
|         current_depth: usize, |         current_depth: usize, | ||||||
|         depth_index: usize, |         depth_index: usize, | ||||||
|         with: &mut impl FnMut(&mut AirTree, &TreePath), |         with: &mut impl FnMut(&mut AirTree, &TreePath), | ||||||
|  |         apply_with_last: bool, | ||||||
|     ) { |     ) { | ||||||
|         let mut index_count = IndexCounter::new(); |         let mut index_count = IndexCounter::new(); | ||||||
|         tree_path.push(current_depth, depth_index); |         tree_path.push(current_depth, depth_index); | ||||||
|  | @ -1395,6 +1401,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::DefineFunc { func_body, .. } => { |                 AirStatement::DefineFunc { func_body, .. } => { | ||||||
|  | @ -1403,6 +1410,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::AssertConstr { constr, .. } => { |                 AirStatement::AssertConstr { constr, .. } => { | ||||||
|  | @ -1411,6 +1419,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::AssertBool { value, .. } => { |                 AirStatement::AssertBool { value, .. } => { | ||||||
|  | @ -1419,6 +1428,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::ClauseGuard { pattern, .. } => { |                 AirStatement::ClauseGuard { pattern, .. } => { | ||||||
|  | @ -1427,6 +1437,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::ListClauseGuard { .. } => {} |                 AirStatement::ListClauseGuard { .. } => {} | ||||||
|  | @ -1437,6 +1448,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::ListAccessor { list, .. } => { |                 AirStatement::ListAccessor { list, .. } => { | ||||||
|  | @ -1445,6 +1457,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::ListExpose { .. } => {} |                 AirStatement::ListExpose { .. } => {} | ||||||
|  | @ -1454,6 +1467,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::NoOp => {} |                 AirStatement::NoOp => {} | ||||||
|  | @ -1463,6 +1477,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirStatement::ListEmpty { list } => { |                 AirStatement::ListEmpty { list } => { | ||||||
|  | @ -1471,12 +1486,15 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         with(self, tree_path); |         if !apply_with_last { | ||||||
|  |             with(self, tree_path); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         match self { |         match self { | ||||||
|             AirTree::Statement { |             AirTree::Statement { | ||||||
|  | @ -1488,6 +1506,7 @@ impl AirTree { | ||||||
|                     current_depth + 1, |                     current_depth + 1, | ||||||
|                     index_count.next_number(), |                     index_count.next_number(), | ||||||
|                     with, |                     with, | ||||||
|  |                     apply_with_last, | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             AirTree::Expression(e) => match e { |             AirTree::Expression(e) => match e { | ||||||
|  | @ -1498,6 +1517,7 @@ impl AirTree { | ||||||
|                             current_depth + 1, |                             current_depth + 1, | ||||||
|                             index_count.next_number(), |                             index_count.next_number(), | ||||||
|                             with, |                             with, | ||||||
|  |                             apply_with_last, | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -1508,6 +1528,7 @@ impl AirTree { | ||||||
|                             current_depth + 1, |                             current_depth + 1, | ||||||
|                             index_count.next_number(), |                             index_count.next_number(), | ||||||
|                             with, |                             with, | ||||||
|  |                             apply_with_last, | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -1517,6 +1538,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     for arg in args { |                     for arg in args { | ||||||
|  | @ -1525,6 +1547,7 @@ impl AirTree { | ||||||
|                             current_depth + 1, |                             current_depth + 1, | ||||||
|                             index_count.next_number(), |                             index_count.next_number(), | ||||||
|                             with, |                             with, | ||||||
|  |                             apply_with_last, | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -1534,6 +1557,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::Builtin { args, .. } => { |                 AirExpression::Builtin { args, .. } => { | ||||||
|  | @ -1543,6 +1567,7 @@ impl AirTree { | ||||||
|                             current_depth + 1, |                             current_depth + 1, | ||||||
|                             index_count.next_number(), |                             index_count.next_number(), | ||||||
|                             with, |                             with, | ||||||
|  |                             apply_with_last, | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -1552,6 +1577,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     right.do_traverse_tree_with( |                     right.do_traverse_tree_with( | ||||||
|  | @ -1559,6 +1585,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::UnOp { arg, .. } => { |                 AirExpression::UnOp { arg, .. } => { | ||||||
|  | @ -1567,6 +1594,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::CastFromData { value, .. } => { |                 AirExpression::CastFromData { value, .. } => { | ||||||
|  | @ -1575,6 +1603,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::CastToData { value, .. } => { |                 AirExpression::CastToData { value, .. } => { | ||||||
|  | @ -1583,6 +1612,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::When { |                 AirExpression::When { | ||||||
|  | @ -1593,6 +1623,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     clauses.do_traverse_tree_with( |                     clauses.do_traverse_tree_with( | ||||||
|  | @ -1600,6 +1631,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::Clause { |                 AirExpression::Clause { | ||||||
|  | @ -1613,6 +1645,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     then.do_traverse_tree_with( |                     then.do_traverse_tree_with( | ||||||
|  | @ -1620,6 +1653,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     otherwise.do_traverse_tree_with( |                     otherwise.do_traverse_tree_with( | ||||||
|  | @ -1627,6 +1661,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::ListClause { |                 AirExpression::ListClause { | ||||||
|  | @ -1637,6 +1672,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     otherwise.do_traverse_tree_with( |                     otherwise.do_traverse_tree_with( | ||||||
|  | @ -1644,6 +1680,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::WrapClause { then, otherwise } => { |                 AirExpression::WrapClause { then, otherwise } => { | ||||||
|  | @ -1652,6 +1689,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     otherwise.do_traverse_tree_with( |                     otherwise.do_traverse_tree_with( | ||||||
|  | @ -1659,6 +1697,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::TupleClause { |                 AirExpression::TupleClause { | ||||||
|  | @ -1669,6 +1708,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     otherwise.do_traverse_tree_with( |                     otherwise.do_traverse_tree_with( | ||||||
|  | @ -1676,6 +1716,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::Finally { pattern, then } => { |                 AirExpression::Finally { pattern, then } => { | ||||||
|  | @ -1684,6 +1725,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     then.do_traverse_tree_with( |                     then.do_traverse_tree_with( | ||||||
|  | @ -1691,6 +1733,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::If { |                 AirExpression::If { | ||||||
|  | @ -1704,6 +1747,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     then.do_traverse_tree_with( |                     then.do_traverse_tree_with( | ||||||
|  | @ -1711,6 +1755,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     otherwise.do_traverse_tree_with( |                     otherwise.do_traverse_tree_with( | ||||||
|  | @ -1718,6 +1763,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::Constr { args, .. } => { |                 AirExpression::Constr { args, .. } => { | ||||||
|  | @ -1727,6 +1773,7 @@ impl AirTree { | ||||||
|                             current_depth + 1, |                             current_depth + 1, | ||||||
|                             index_count.next_number(), |                             index_count.next_number(), | ||||||
|                             with, |                             with, | ||||||
|  |                             apply_with_last, | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -1736,6 +1783,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                     for arg in args { |                     for arg in args { | ||||||
|                         arg.do_traverse_tree_with( |                         arg.do_traverse_tree_with( | ||||||
|  | @ -1743,6 +1791,7 @@ impl AirTree { | ||||||
|                             current_depth + 1, |                             current_depth + 1, | ||||||
|                             index_count.next_number(), |                             index_count.next_number(), | ||||||
|                             with, |                             with, | ||||||
|  |                             apply_with_last, | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -1752,6 +1801,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::TupleIndex { tuple, .. } => { |                 AirExpression::TupleIndex { tuple, .. } => { | ||||||
|  | @ -1760,6 +1810,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 AirExpression::Trace { msg, then, .. } => { |                 AirExpression::Trace { msg, then, .. } => { | ||||||
|  | @ -1768,6 +1819,7 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|                     then.do_traverse_tree_with( |                     then.do_traverse_tree_with( | ||||||
|  | @ -1775,12 +1827,18 @@ impl AirTree { | ||||||
|                         current_depth + 1, |                         current_depth + 1, | ||||||
|                         index_count.next_number(), |                         index_count.next_number(), | ||||||
|                         with, |                         with, | ||||||
|  |                         apply_with_last, | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|                 _ => {} |                 _ => {} | ||||||
|             }, |             }, | ||||||
|             a => unreachable!("GOT THIS {:#?}", a), |             a => unreachable!("GOT THIS {:#?}", a), | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if apply_with_last { | ||||||
|  |             with(self, tree_path); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         tree_path.pop(); |         tree_path.pop(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5077,3 +5077,268 @@ fn list_clause_with_assign2() { | ||||||
|         false, |         false, | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn opaque_value_in_datum() { | ||||||
|  |     let src = r#" | ||||||
|  |       opaque type Value { | ||||||
|  |         inner: Dict<Dict<Int>> | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       opaque type Dict<v> { | ||||||
|  |         inner: List<(ByteArray, v)> | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       type Dat { | ||||||
|  |           c: Int, | ||||||
|  |           a: Value | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       
 | ||||||
|  |       validator { | ||||||
|  |         fn spend(dat: Dat, red: Data, ctx: Data) { | ||||||
|  |           let val = dat.a 
 | ||||||
|  | 
 | ||||||
|  |           expect [(_, amount)] = val.inner.inner | ||||||
|  | 
 | ||||||
|  |           let final_amount = [(#"AA", 4)] |> Dict | ||||||
|  | 
 | ||||||
|  |           final_amount == amount | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |   "#;
 | ||||||
|  | 
 | ||||||
|  |     assert_uplc( | ||||||
|  |         src, | ||||||
|  |         Term::tail_list() | ||||||
|  |             .apply(Term::var("val")) | ||||||
|  |             .delayed_choose_list( | ||||||
|  |                 Term::equals_data() | ||||||
|  |                     .apply(Term::map_data().apply(Term::var("final_amount"))) | ||||||
|  |                     .apply(Term::map_data().apply(Term::var("amount"))) | ||||||
|  |                     .lambda("final_amount") | ||||||
|  |                     .apply(Term::map_values(vec![Constant::ProtoPair( | ||||||
|  |                         Type::Data, | ||||||
|  |                         Type::Data, | ||||||
|  |                         Constant::Data(Data::bytestring(vec![170])).into(), | ||||||
|  |                         Constant::Data(Data::integer(4.into())).into(), | ||||||
|  |                     )])) | ||||||
|  |                     .lambda("amount") | ||||||
|  |                     .apply( | ||||||
|  |                         Term::unmap_data().apply(Term::snd_pair().apply(Term::var("tuple_item_0"))), | ||||||
|  |                     ), | ||||||
|  |                 Term::Error.trace(Term::string( | ||||||
|  |                     "List/Tuple/Constr contains more items than expected", | ||||||
|  |                 )), | ||||||
|  |             ) | ||||||
|  |             .lambda("tuple_item_0") | ||||||
|  |             .apply(Term::head_list().apply(Term::var("val"))) | ||||||
|  |             .lambda("val") | ||||||
|  |             .apply( | ||||||
|  |                 Term::unmap_data().apply( | ||||||
|  |                     Term::var(CONSTR_GET_FIELD) | ||||||
|  |                         .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("dat"))) | ||||||
|  |                         .apply(Term::integer(1.into())), | ||||||
|  |                 ), | ||||||
|  |             ) | ||||||
|  |             .delayed_if_else(Term::unit(), Term::Error) | ||||||
|  |             .lambda("_") | ||||||
|  |             .apply( | ||||||
|  |                 Term::equals_integer() | ||||||
|  |                     .apply(Term::integer(0.into())) | ||||||
|  |                     .apply(Term::var("subject")) | ||||||
|  |                     .delayed_if_else( | ||||||
|  |                         Term::tail_list() | ||||||
|  |                             .apply(Term::var("tail_1")) | ||||||
|  |                             .delayed_choose_list( | ||||||
|  |                                 Term::unit().lambda("_").apply( | ||||||
|  |                                     Term::var("expect_on_list").apply(Term::var("a")).apply( | ||||||
|  |                                         Term::var("expect_on_list") | ||||||
|  |                                             .apply(Term::var("pair_snd_outer")) | ||||||
|  |                                             .apply( | ||||||
|  |                                                 Term::un_i_data() | ||||||
|  |                                                     .apply( | ||||||
|  |                                                         Term::snd_pair().apply(Term::var("pair")), | ||||||
|  |                                                     ) | ||||||
|  |                                                     .lambda("pair_fst") | ||||||
|  |                                                     .apply(Term::un_b_data().apply( | ||||||
|  |                                                         Term::fst_pair().apply(Term::var("pair")), | ||||||
|  |                                                     )) | ||||||
|  |                                                     .lambda("pair"), | ||||||
|  |                                             ) | ||||||
|  |                                             .lambda("pair_snd_outer") | ||||||
|  |                                             .apply(Term::unmap_data().apply( | ||||||
|  |                                                 Term::snd_pair().apply(Term::var("pair_outer")), | ||||||
|  |                                             )) | ||||||
|  |                                             .lambda("pair_fst_outer") | ||||||
|  |                                             .apply(Term::un_b_data().apply( | ||||||
|  |                                                 Term::fst_pair().apply(Term::var("pair_outer")), | ||||||
|  |                                             )) | ||||||
|  |                                             .lambda("pair_outer"), | ||||||
|  |                                     ), | ||||||
|  |                                 ), | ||||||
|  |                                 Term::Error.trace(Term::string( | ||||||
|  |                                     "List/Tuple/Constr contains more items than expected", | ||||||
|  |                                 )), | ||||||
|  |                             ) | ||||||
|  |                             .lambda("a") | ||||||
|  |                             .apply( | ||||||
|  |                                 Term::unmap_data() | ||||||
|  |                                     .apply(Term::head_list().apply(Term::var("tail_1"))), | ||||||
|  |                             ) | ||||||
|  |                             .lambda("tail_1") | ||||||
|  |                             .apply(Term::tail_list().apply(Term::var("dat_fields"))) | ||||||
|  |                             .lambda("c") | ||||||
|  |                             .apply( | ||||||
|  |                                 Term::un_i_data() | ||||||
|  |                                     .apply(Term::head_list().apply(Term::var("dat_fields"))), | ||||||
|  |                             ) | ||||||
|  |                             .lambda("dat_fields") | ||||||
|  |                             .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("param_0"))), | ||||||
|  |                         Term::Error | ||||||
|  |                             .trace(Term::string("Constr index did not match any type variant")), | ||||||
|  |                     ) | ||||||
|  |                     .lambda("subject") | ||||||
|  |                     .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("param_0"))) | ||||||
|  |                     .lambda("param_0") | ||||||
|  |                     .lambda("expect_on_list") | ||||||
|  |                     .apply( | ||||||
|  |                         Term::var("expect_on_list") | ||||||
|  |                             .apply(Term::var("expect_on_list")) | ||||||
|  |                             .apply(Term::var("list_to_check")) | ||||||
|  |                             .lambda("expect_on_list") | ||||||
|  |                             .apply( | ||||||
|  |                                 Term::var("list_to_check") | ||||||
|  |                                     .delayed_choose_list( | ||||||
|  |                                         Term::unit(), | ||||||
|  |                                         Term::var("expect_on_list") | ||||||
|  |                                             .apply(Term::var("expect_on_list")) | ||||||
|  |                                             .apply( | ||||||
|  |                                                 Term::tail_list().apply(Term::var("list_to_check")), | ||||||
|  |                                             ) | ||||||
|  |                                             .lambda("_") | ||||||
|  |                                             .apply(Term::var("check_with").apply( | ||||||
|  |                                                 Term::head_list().apply(Term::var("list_to_check")), | ||||||
|  |                                             )), | ||||||
|  |                                     ) | ||||||
|  |                                     .lambda("list_to_check") | ||||||
|  |                                     .lambda("expect_on_list"), | ||||||
|  |                             ) | ||||||
|  |                             .lambda("check_with") | ||||||
|  |                             .lambda("list_to_check"), | ||||||
|  |                     ) | ||||||
|  |                     .apply(Term::var("dat")), | ||||||
|  |             ) | ||||||
|  |             .lambda("ctx") | ||||||
|  |             .lambda("red") | ||||||
|  |             .lambda("dat") | ||||||
|  |             .constr_get_field() | ||||||
|  |             .constr_fields_exposer() | ||||||
|  |             .constr_index_exposer(), | ||||||
|  |         false, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn opaque_value_in_test() { | ||||||
|  |     let src = r#" | ||||||
|  |         pub opaque type Value { | ||||||
|  |           inner: Dict<Dict<Int>> | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         pub opaque type Dict<v> { | ||||||
|  |           inner: List<(ByteArray, v)> | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         pub type Dat { | ||||||
|  |           c: Int, | ||||||
|  |           a: Value | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         pub fn dat_new() -> Dat { | ||||||
|  |           let v = Value { inner: Dict { inner: [("", [(#"aa", 4)] |> Dict)] } } | ||||||
|  |           Dat { | ||||||
|  |             c: 0, 
 | ||||||
|  |             a: v | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         
 | ||||||
|  |         test spend() { | ||||||
|  |           let dat = dat_new() | ||||||
|  | 
 | ||||||
|  |           let val = dat.a 
 | ||||||
|  | 
 | ||||||
|  |           expect [(_, amount)] = val.inner.inner | ||||||
|  | 
 | ||||||
|  |           let final_amount = [(#"AA", 4)] |> Dict | ||||||
|  | 
 | ||||||
|  |           final_amount == amount  
 | ||||||
|  |         } | ||||||
|  |   "#;
 | ||||||
|  | 
 | ||||||
|  |     assert_uplc( | ||||||
|  |         src, | ||||||
|  |         Term::tail_list() | ||||||
|  |             .apply(Term::var("val")) | ||||||
|  |             .delayed_choose_list( | ||||||
|  |                 Term::equals_data() | ||||||
|  |                     .apply(Term::map_data().apply(Term::var("final_amount"))) | ||||||
|  |                     .apply(Term::map_data().apply(Term::var("amount"))) | ||||||
|  |                     .lambda("final_amount") | ||||||
|  |                     .apply(Term::map_values(vec![Constant::ProtoPair( | ||||||
|  |                         Type::Data, | ||||||
|  |                         Type::Data, | ||||||
|  |                         Constant::Data(Data::bytestring(vec![170])).into(), | ||||||
|  |                         Constant::Data(Data::integer(4.into())).into(), | ||||||
|  |                     )])) | ||||||
|  |                     .lambda("amount") | ||||||
|  |                     .apply( | ||||||
|  |                         Term::unmap_data().apply(Term::snd_pair().apply(Term::var("tuple_item_0"))), | ||||||
|  |                     ), | ||||||
|  |                 Term::Error.trace(Term::string( | ||||||
|  |                     "List/Tuple/Constr contains more items than expected", | ||||||
|  |                 )), | ||||||
|  |             ) | ||||||
|  |             .lambda("tuple_item_0") | ||||||
|  |             .apply(Term::head_list().apply(Term::var("val"))) | ||||||
|  |             .lambda("val") | ||||||
|  |             .apply( | ||||||
|  |                 Term::unmap_data().apply( | ||||||
|  |                     Term::var(CONSTR_GET_FIELD) | ||||||
|  |                         .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("dat"))) | ||||||
|  |                         .apply(Term::integer(1.into())), | ||||||
|  |                 ), | ||||||
|  |             ) | ||||||
|  |             .lambda("dat") | ||||||
|  |             .apply(Term::Constant( | ||||||
|  |                 Constant::Data(Data::constr( | ||||||
|  |                     0, | ||||||
|  |                     vec![ | ||||||
|  |                         Data::integer(0.into()), | ||||||
|  |                         Data::map(vec![( | ||||||
|  |                             Data::bytestring(vec![]), | ||||||
|  |                             Data::map(vec![(Data::bytestring(vec![170]), Data::integer(4.into()))]), | ||||||
|  |                         )]), | ||||||
|  |                     ], | ||||||
|  |                 )) | ||||||
|  |                 .into(), | ||||||
|  |             )) | ||||||
|  |             .lambda("v") | ||||||
|  |             .apply(Term::map_values(vec![Constant::ProtoPair( | ||||||
|  |                 Type::Data, | ||||||
|  |                 Type::Data, | ||||||
|  |                 Constant::Data(Data::bytestring(vec![])).into(), | ||||||
|  |                 Constant::Data(Data::map(vec![( | ||||||
|  |                     Data::bytestring(vec![170]), | ||||||
|  |                     Data::integer(4.into()), | ||||||
|  |                 )])) | ||||||
|  |                 .into(), | ||||||
|  |             )])) | ||||||
|  |             .constr_get_field() | ||||||
|  |             .constr_fields_exposer() | ||||||
|  |             .constr_index_exposer(), | ||||||
|  |         false, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 microproofs
						microproofs