From 3356e2ecd04bc728d51873a2827efab84638a50c Mon Sep 17 00:00:00 2001 From: microproofs Date: Sun, 14 May 2023 17:33:01 -0400 Subject: [PATCH] fix: nested constrs with a single index was ignoring fields --- CHANGELOG.md | 20 +- crates/aiken-lang/src/gen_uplc.rs | 3 + crates/aiken-project/src/tests/gen_uplc.rs | 261 +++++++++++++++++++-- 3 files changed, 258 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb2ea57..a2e8dd90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,26 @@ # Changelog +## next - 2023-MM-DD + +### Added + +- **aiken-lang**: Added some optimization tests +- **aiken-lang**: Added an Aiken to uplc conversion tests on validators +- **aiken-lang**: Added some uplc builder functions for builtin creation +- **aiken-lang**: Added optimization where identity functions called on an arg + are reduced to just the arg. + +### Fixed + +- **aiken-lang**: Fix for nested constructors where the type had a single + constructor. The fields exposed were not being added to the Air. + ## v1.0.4.alpha - 2023-05-09 ### Added - **aiken-lang**: ChooseUnit builtin uses a more efficient way of handling the first arg (unit) by just assigning to lambda -- **aiken-lang**: Added some optimization tests -- **aiken-lang**: Added an Aiken to uplc conversion tests on validators -- **aiken-lang**: Added some uplc builder functions for builtin creation -- **aiken-lang**: Added optimization where identity functions called on an arg - are reduced to just the arg. ### Fixed diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index ba451f9b..5002d80b 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -1283,6 +1283,7 @@ impl<'a> CodeGenerator<'a> { }) .sorted_by(|item1, item2| item1.2.cmp(&item2.2)) .collect::>(); + let indices = arguments_index .iter() .map(|(label, var_name, index)| { @@ -1562,6 +1563,8 @@ impl<'a> CodeGenerator<'a> { empty_stack, ); } + } else { + pattern_stack.merge_child(when_stack); } Some(constr_var_name) diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index 095f1f93..13321f76 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -9,7 +9,7 @@ use aiken_lang::{ }; use uplc::{ ast::{Constant, Data, DeBruijn, Name, Program, Term, Type}, - builder::CONSTR_GET_FIELD, + builder::{CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER}, machine::cost_model::ExBudget, optimize, }; @@ -1407,18 +1407,18 @@ fn when_tuple_deconstruction() { src, Term::equals_integer() .apply(Term::integer(0.into())) - .apply(Term::var("constr_index_exposer").apply(Term::var("dat"))) + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("dat"))) .if_else( Term::equals_integer() .apply(Term::integer(0.into())) - .apply(Term::var("constr_index_exposer").apply(Term::var("red"))) + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("red"))) .if_else( Term::equals_integer() .apply( Term::un_i_data().apply( - Term::var("constr_get_field") + Term::var(CONSTR_GET_FIELD) .apply( - Term::var("constr_fields_exposer") + Term::var(CONSTR_FIELDS_EXPOSER) .apply(Term::var("a")), ) .apply(Term::integer(0.into())), @@ -1431,7 +1431,7 @@ fn when_tuple_deconstruction() { .apply(Term::head_list().apply(Term::var("red_constr_fields"))), ) .lambda("red_constr_fields") - .apply(Term::var("constr_fields_exposer").apply(Term::var("red"))) + .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("red"))) .delay(), Term::var("other_clauses"), ) @@ -1439,7 +1439,7 @@ fn when_tuple_deconstruction() { .lambda("a") .apply(Term::head_list().apply(Term::var("dat_constr_fields"))) .lambda("dat_constr_fields") - .apply(Term::var("constr_fields_exposer").apply(Term::var("dat"))) + .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("dat"))) .delay(), Term::var("other_clauses"), ) @@ -1482,14 +1482,14 @@ fn when_tuple_deconstruction() { ) .lambda("dat_constr_fields") .apply( - Term::var("constr_fields_exposer") + Term::var(CONSTR_FIELDS_EXPOSER) .apply(Term::var("dat")), ), Term::equals_integer() .apply(Term::integer(1.into())) .apply(Term::var("subject")) .delayed_if_else( - Term::var("constr_fields_exposer") + Term::var(CONSTR_FIELDS_EXPOSER) .apply(Term::var("dat")) .delayed_choose_list( Term::unit(), @@ -1500,7 +1500,7 @@ fn when_tuple_deconstruction() { ), ) .lambda("subject") - .apply(Term::var("constr_index_exposer").apply(Term::var("dat"))) + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("dat"))) .lambda("dat"), ) .lambda("expect_Thing") @@ -1524,7 +1524,7 @@ fn when_tuple_deconstruction() { ) .lambda("field_1_constr_fields") .apply( - Term::var("constr_fields_exposer") + Term::var(CONSTR_FIELDS_EXPOSER) .apply(Term::var("field_1")), ), Term::Error.trace(Term::string( @@ -1533,7 +1533,7 @@ fn when_tuple_deconstruction() { ) .lambda("subject") .apply( - Term::var("constr_index_exposer").apply(Term::var("field_1")), + Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("field_1")), ) .lambda("field_1"), ) @@ -1562,14 +1562,14 @@ fn when_tuple_deconstruction() { )) .lambda("red_constr_fields") .apply( - Term::var("constr_fields_exposer") + Term::var(CONSTR_FIELDS_EXPOSER) .apply(Term::var("red")), ), Term::equals_integer() .apply(Term::integer(1.into())) .apply(Term::var("subject")) .delayed_if_else( - Term::var("constr_fields_exposer") + Term::var(CONSTR_FIELDS_EXPOSER) .apply(Term::var("red")) .delayed_choose_list( Term::unit(), @@ -1580,7 +1580,7 @@ fn when_tuple_deconstruction() { ), ) .lambda("subject") - .apply(Term::var("constr_index_exposer").apply(Term::var("red"))) + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("red"))) .lambda("red"), ) .apply(Term::var("red")), @@ -1589,13 +1589,13 @@ fn when_tuple_deconstruction() { .lambda("ctx") .lambda("red") .lambda("dat") - .lambda("constr_get_field") + .lambda(CONSTR_GET_FIELD) .apply( - Term::var("constr_get_field") - .apply(Term::var("constr_get_field")) + Term::var(CONSTR_GET_FIELD) + .apply(Term::var(CONSTR_GET_FIELD)) .apply(Term::integer(0.into())), ) - .lambda("constr_get_field") + .lambda(CONSTR_GET_FIELD) .apply( Term::equals_integer() .apply(Term::var("__wanted_arg".to_string())) @@ -1621,13 +1621,232 @@ fn when_tuple_deconstruction() { .lambda("__current_arg_number") .lambda(CONSTR_GET_FIELD), ) - .lambda("constr_fields_exposer") + .lambda(CONSTR_FIELDS_EXPOSER) .apply( Term::snd_pair() .apply(Term::unconstr_data().apply(Term::var("x"))) .lambda("x"), ) - .lambda("constr_index_exposer") + .lambda(CONSTR_INDEX_EXPOSER) + .apply( + Term::fst_pair() + .apply(Term::unconstr_data().apply(Term::var("x"))) + .lambda("x"), + ), + false, + ); +} + +#[test] +fn generic_validator_type_test() { + let error_string = "List/Tuple/Constr contains more items than expected"; + let src = r#" + type A { + NoA + SomeA(Void, x) + } + + type B { + something: Void, + } + + validator { + fn err_example(r: A, _ctx: Data) -> Bool { + when r is { + NoA -> + False + SomeA(_, B(something)) -> + something == Void + } + } + } + "#; + + assert_uplc( + src, + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply(Term::var("subject")) + .delayed_if_else( + Term::bool(false), + Term::choose_unit( + Term::var("something"), + Term::choose_unit(Term::unit(), Term::bool(true)), + ) + .lambda("something") + .apply( + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply( + Term::fst_pair().apply( + Term::unconstr_data() + .apply(Term::head_list().apply(Term::var("B_fields"))), + ), + ) + .delayed_if_else(Term::unit(), Term::Error), + ) + .lambda("B_fields") + .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("field_B"))) + .lambda("field_B") + .apply(Term::head_list().apply(Term::var("tail_1"))) + .lambda("tail_1") + .apply(Term::tail_list().apply(Term::var("r_fields"))) + .lambda("r_fields") + .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("r"))), + ) + .lambda("subject") + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("r"))) + .delayed_if_else(Term::unit(), Term::Error) + .lambda("r") + .apply( + Term::var("r").lambda("_").apply( + Term::var("__expect_A") + .lambda("__expect_A") + .apply( + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply(Term::var("subject")) + .delayed_if_else( + Term::var(CONSTR_FIELDS_EXPOSER) + .apply(Term::var("r")) + .delayed_choose_list( + Term::unit(), + Term::Error.trace(Term::string( + "Expected no fields for Constr", + )), + ), + Term::equals_integer() + .apply(Term::integer(1.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_B") + .apply(Term::var("field_B")), + ), + Term::Error + .trace(Term::string("List/Tuple/Constr contains more items than expected")), + ) + .lambda("field_B") + .apply(Term::head_list().apply(Term::var("tail_1"))) + .lambda("tail_1") + .apply( + Term::tail_list().apply(Term::var("r_fields")), + ) + .lambda("field_0") + .apply( + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply( + Term::fst_pair().apply( + Term::unconstr_data().apply( + Term::head_list().apply( + Term::var("r_fields"), + ), + ), + ), + ) + .delayed_if_else(Term::unit(), Term::Error), + ) + .lambda("r_fields") + .apply( + Term::var(CONSTR_FIELDS_EXPOSER) + .apply(Term::var("r")), + ), + Term::Error.trace(Term::string( + "Constr index did not match any type variant", + )), + ), + ) + .lambda("subject") + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("r"))) + .lambda("r"), + ) + .lambda("__expect_B") + .apply( + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply(Term::var("subject")) + .delayed_if_else( + Term::tail_list() + .apply(Term::var("B_fields")) + .delayed_choose_list( + Term::unit(), + Term::Error.trace(Term::string(error_string)), + ) + .lambda("something") + .apply( + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply( + Term::fst_pair().apply( + Term::unconstr_data().apply( + Term::head_list() + .apply(Term::var("B_fields")), + ), + ), + ) + .delayed_if_else(Term::unit(), Term::Error), + ) + .lambda("B_fields") + .apply( + Term::var(CONSTR_FIELDS_EXPOSER) + .apply(Term::var("field_B")), + ), + Term::Error.trace(Term::string( + "Constr index did not match any type variant", + )), + ) + .lambda("subject") + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("field_B"))) + .lambda("field_B"), + ) + .apply(Term::var("r")), + ), + ) + .lambda("_ctx") + .lambda("r") + .lambda(CONSTR_GET_FIELD) + .apply( + Term::var(CONSTR_GET_FIELD) + .apply(Term::var(CONSTR_GET_FIELD)) + .apply(Term::integer(0.into())), + ) + .lambda(CONSTR_GET_FIELD) + .apply( + Term::equals_integer() + .apply(Term::var("__wanted_arg".to_string())) + .apply(Term::var("__current_arg_number".to_string())) + .if_else( + Term::head_list(), + Term::var(CONSTR_GET_FIELD) + .apply(Term::var(CONSTR_GET_FIELD)) + .apply( + Term::add_integer() + .apply(Term::var("__current_arg_number")) + .apply(Term::integer(1.into())), + ) + .apply( + Term::tail_list().apply(Term::var("__current_list_of_constr_args")), + ) + .apply(Term::var("__wanted_arg")) + .lambda("__current_list_of_constr_args"), + ) + .apply(Term::var("__list_of_constr_args")) + .lambda("__wanted_arg") + .lambda("__list_of_constr_args") + .lambda("__current_arg_number") + .lambda(CONSTR_GET_FIELD), + ) + .lambda(CONSTR_FIELDS_EXPOSER) + .apply( + Term::snd_pair() + .apply(Term::unconstr_data().apply(Term::var("x"))) + .lambda("x"), + ) + .lambda(CONSTR_INDEX_EXPOSER) .apply( Term::fst_pair() .apply(Term::unconstr_data().apply(Term::var("x")))