diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index 6f640034..79b36f9a 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -354,9 +354,29 @@ pub fn erase_opaque_type_operations( pub fn find_introduced_variables(air_tree: &AirTree) -> Vec { match air_tree { AirTree::Let { name, .. } => vec![name.clone()], + AirTree::SoftCastLet { name, .. } => vec![name.clone()], AirTree::TupleGuard { indices, .. } | AirTree::TupleClause { indices, .. } => { indices.iter().map(|(_, name)| name.clone()).collect() } + AirTree::PairGuard { + fst_name, snd_name, .. + } => fst_name + .into_iter() + .cloned() + .chain(snd_name.into_iter().cloned()) + .collect_vec(), + AirTree::PairAccessor { fst, snd, .. } => fst + .into_iter() + .cloned() + .chain(snd.into_iter().cloned()) + .collect_vec(), + AirTree::PairClause { + fst_name, snd_name, .. + } => fst_name + .into_iter() + .cloned() + .chain(snd_name.into_iter().cloned()) + .collect_vec(), AirTree::Fn { params, .. } => params.to_vec(), AirTree::ListAccessor { names, .. } => names.clone(), AirTree::ListExpose { @@ -913,17 +933,7 @@ pub fn unknown_data_to_type(term: Term, field_type: &Type) -> Term { .lambda("__list_data") .apply(Term::unlist_data().apply(term)), Some(UplcType::Bool) => Term::unwrap_bool_or(term, |result| result, &Term::Error.delay()), - Some(UplcType::Unit) => Term::equals_integer() - .apply(Term::integer(0.into())) - .apply(Term::fst_pair().apply(Term::var("__pair__"))) - .delayed_if_then_else( - Term::snd_pair() - .apply(Term::var("__pair__")) - .delayed_choose_list(Term::unit(), Term::Error), - Term::Error, - ) - .lambda("__pair__") - .apply(Term::unconstr_data().apply(term)), + Some(UplcType::Unit) => Term::unwrap_void_or(term, |result| result, &Term::Error.delay()), Some(UplcType::Data) | None => term, } @@ -948,7 +958,7 @@ pub fn softcast_data_to_type_otherwise( value.as_var("__val", |val| match uplc_type { None => Term::choose_data_constr(val, then_delayed, &otherwise_delayed).force(), - Some(UplcType::Data) => just_then, + Some(UplcType::Data) => just_then.lambda(name).apply(Term::Var(val)), Some(UplcType::Bls12_381MlResult) => { unreachable!("attempted to cast Data into Bls12_381MlResult ?!") @@ -1343,9 +1353,9 @@ pub fn list_access_to_uplc( &tail_name, acc.apply( Term::tail_list().apply(Term::var(tail_name.to_string())), - ) - .delay(), - ), + ), + ) + .delay(), ) .force() .lambda(tail_name) diff --git a/crates/aiken-lang/src/gen_uplc/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs index a5dc2673..a508efd7 100644 --- a/crates/aiken-lang/src/gen_uplc/tree.rs +++ b/crates/aiken-lang/src/gen_uplc/tree.rs @@ -8,7 +8,10 @@ use crate::{ use indexmap::IndexSet; use itertools::Itertools; use std::{borrow::BorrowMut, rc::Rc, slice::Iter}; -use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction}; +use uplc::{ + builder::{EXPECT_ON_LIST, INNER_EXPECT_ON_LIST}, + builtins::DefaultFunction, +}; #[derive(Clone, Debug, PartialEq, Copy)] pub enum Fields { @@ -1037,28 +1040,36 @@ impl AirTree { } pub fn expect_on_list2() -> AirTree { - let expect_on_list = AirTree::var( - ValueConstructor::public( - void(), - ValueConstructorVariant::ModuleFn { - name: EXPECT_ON_LIST.to_string(), - field_map: None, - module: "".to_string(), - arity: 1, - location: Span::empty(), - builtin: None, - }, - ), - EXPECT_ON_LIST, - "", - ); + let inner_expect_on_list = AirTree::local_var(INNER_EXPECT_ON_LIST, void()); let list_var = AirTree::local_var("__list_to_check", list(data())); - AirTree::call( - AirTree::local_var("__check_with", void()), - void(), - vec![list_var, expect_on_list], + AirTree::let_assignment( + INNER_EXPECT_ON_LIST, + AirTree::anon_func( + vec![ + INNER_EXPECT_ON_LIST.to_string(), + "__list_to_check".to_string(), + ], + AirTree::call( + AirTree::local_var("__check_with", void()), + void(), + vec![ + list_var.clone(), + AirTree::call( + inner_expect_on_list.clone(), + void(), + vec![inner_expect_on_list.clone()], + ), + ], + ), + false, + ), + AirTree::call( + inner_expect_on_list.clone(), + void(), + vec![inner_expect_on_list, list_var], + ), ) } diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index 780d0b7c..dd1f09b7 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -5221,6 +5221,7 @@ fn expect_head3_cast_data_no_tail() { false, ); } + #[test] fn expect_head_cast_data_no_tail() { let src = r#" @@ -5309,131 +5310,143 @@ fn expect_head_cast_data_with_tail() { assert_uplc( src, - Term::var("unwrap_a") - .choose_list( + Term::var("__val") + .choose_data( Term::var("expect[h,j,..]:List=a"), - Term::var("tail_1") - .choose_list( - Term::var("expect[h,j,..]:List=a"), - Term::equals_integer() - .apply(Term::var("h")) - .apply(Term::var("h")) - .delayed_if_then_else( - Term::equals_integer() - .apply(Term::var("j")) - .apply(Term::var("j")), - Term::bool(false), - ) - .lambda("_") - .apply( - Term::var("expect_on_list") - .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", - )), + Term::var("expect[h,j,..]:List=a"), + Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ]) + .choose_list( + Term::var("expect[h,j,..]:List=a"), + Term::var("__val") + .choose_data( + Term::var("expect[h,j,..]:List=a"), + Term::var("expect[h,j,..]:List=a"), + Term::var("expect[h,j,..]:List=a"), + Term::var("tail_1") + .choose_list( + Term::var("expect[h,j,..]:List=a"), + Term::var("__val") + .choose_data( + Term::var("expect[h,j,..]:List=a"), + Term::var("expect[h,j,..]:List=a"), + Term::var("expect[h,j,..]:List=a"), + Term::var("expect_on_list") + .apply(Term::tail_list().apply(Term::var("tail_2"))) + .apply( + Term::var("__list") + .choose_list( + Term::equals_integer() + .apply(Term::var("h")) + .apply(Term::var("h")) + .delayed_if_then_else( + Term::equals_integer() + .apply(Term::var("j")) + .apply(Term::var("j")), + Term::bool(false), + ), + Term::var("__head").choose_data( + Term::var( + "expect[h,j,..]:List=a", + ), + Term::var( + "expect[h,j,..]:List=a", + ), + Term::var( + "expect[h,j,..]:List=a", + ), + Term::var( + "__curried_expect_on_list", + ) + .apply( + Term::tail_list() + .apply(Term::var("__list")), + ) + .lambda("_") + .apply( + Term::un_i_data() + .apply(Term::var("__head")), + ), + Term::var( + "expect[h,j,..]:List=a", + ), ) - .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("tail_2")) - .apply( - Term::var("__val") - .choose_data( - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::un_i_data().apply(Term::var("__val")).delay(), - Term::var("expect[h,j,..]:List=a"), - ) - .force() - .lambda("__val") - .apply(Term::var("list_item")) - .lambda("list_item"), - ), - ) - .lambda("tail_2") - .apply(Term::tail_list().apply(Term::var("tail_1"))) - .lambda("j") - .apply( - Term::var("__val") - .choose_data( - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::un_i_data().apply(Term::var("__val")).delay(), - Term::var("expect[h,j,..]:List=a"), - ) - .force() - .lambda("__val") - .apply(Term::head_list().apply(Term::var("tail_1"))), - ) - .delay(), - ) - .force() - .lambda("tail_1") - .apply(Term::tail_list().apply(Term::var("unwrap_a"))) - .lambda("h") - .apply( - Term::var("__val") - .choose_data( - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::un_i_data().apply(Term::var("__val")).delay(), - Term::var("expect[h,j,..]:List=a"), - ) - .force() - .lambda("__val") - .apply(Term::head_list().apply(Term::var("unwrap_a"))), - ) - .delay(), - ) - .force() - .lambda("unwrap_a") - .apply( - Term::var("__val") - .choose_data( - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - Term::list_values(vec![ + .lambda("__head") + .apply(Term::head_list().apply(Term::var("__list"))), + ) + .lambda("__curried_expect_on_list") + .lambda("__list"), + ) + .lambda("expect_on_list") + .apply( + Term::var("expect_on_list") + .apply(Term::var("expect_on_list")) + .lambda("expect_on_list") + .apply( + Term::var("check_with") + .apply(Term::var("__list")) + .apply( + Term::var("expect_on_list") + .apply(Term::var( + "expect_on_list", + )), + ) + .lambda("__list") + .lambda("expect_on_list"), + ) + .lambda("check_with") + .lambda("__list"), + ) + .lambda("j") + .apply( + Term::un_i_data() + .apply(Term::var("__val")) + .delay(), + ), + Term::var("expect[h,j,..]:List=a"), + ) + .force() + .lambda("__val") + .apply(Term::head_list().apply(Term::var("tail_1"))) + .lambda("tail_2") + .apply(Term::tail_list().apply(Term::var("tail_1"))) + .delay(), + ) + .force() + .lambda("tail_1") + .apply(Term::tail_list().apply(Term::list_values(vec![ + Constant::Data(Data::integer(1.into())), + Constant::Data(Data::integer(2.into())), + Constant::Data(Data::integer(3.into())), + ]))) + .lambda("h") + .apply(Term::un_i_data().apply(Term::var("__val"))) + .delay(), + Term::var("expect[h,j,..]:List=a"), + ) + .force() + .lambda("__val") + .apply(Term::head_list().apply(Term::list_values(vec![ Constant::Data(Data::integer(1.into())), Constant::Data(Data::integer(2.into())), Constant::Data(Data::integer(3.into())), - ]) - .delay(), - Term::var("expect[h,j,..]:List=a"), - Term::var("expect[h,j,..]:List=a"), - ) - .force() - .lambda("__val") - .apply(Term::data(Data::list(vec![ - Data::integer(1.into()), - Data::integer(2.into()), - Data::integer(3.into()), - ]))), + ]))), + ) + .force() + .delay(), + Term::var("expect[h,j,..]:List=a"), + Term::var("expect[h,j,..]:List=a"), ) + .force() + .lambda("__val") + .apply(Term::data(Data::list(vec![ + Data::integer(1.into()), + Data::integer(2.into()), + Data::integer(3.into()), + ]))) .lambda("expect[h,j,..]:List=a") .apply( Term::Error diff --git a/crates/uplc/src/builder.rs b/crates/uplc/src/builder.rs index 3db4a1c2..ce677799 100644 --- a/crates/uplc/src/builder.rs +++ b/crates/uplc/src/builder.rs @@ -8,6 +8,7 @@ use std::rc::Rc; pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer"; pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer"; pub const EXPECT_ON_LIST: &str = "__expect_on_list"; +pub const INNER_EXPECT_ON_LIST: &str = "__inner_expect_on_list"; impl Term { // Terms @@ -632,6 +633,7 @@ impl Term { .delay(), otherwise.clone(), ) + .force() } /// Convert an arbitrary 'term' into a pair and pass it into a 'callback'.