diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 3a0555dd..7066499e 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -881,7 +881,7 @@ pub enum Located<'a> { Annotation(&'a Annotation), } -impl<'a> Located<'a> { +impl Located<'_> { pub fn definition_location(&self) -> Option> { match self { Self::Expression(expression) => expression.definition_location(), @@ -1996,7 +1996,7 @@ impl<'de> serde::Deserialize<'de> for Bls12_381Point { { struct FieldVisitor; - impl<'de> serde::de::Visitor<'de> for FieldVisitor { + impl serde::de::Visitor<'_> for FieldVisitor { type Value = Field; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { diff --git a/crates/aiken-lang/src/gen_uplc/decision_tree.rs b/crates/aiken-lang/src/gen_uplc/decision_tree.rs index 9c557166..ec885e61 100644 --- a/crates/aiken-lang/src/gen_uplc/decision_tree.rs +++ b/crates/aiken-lang/src/gen_uplc/decision_tree.rs @@ -3,7 +3,7 @@ use pretty::RcDoc; use std::{cmp::Ordering, fmt::Display, rc::Rc}; use indexmap::IndexMap; -use itertools::{Itertools, Position}; +use itertools::{Either, Itertools, Position}; use crate::{ ast::{DataTypeKey, Pattern, TypedClause, TypedDataType, TypedPattern}, @@ -12,10 +12,6 @@ use crate::{ use super::{interner::AirInterner, tree::AirTree}; -const PAIR_NEW_COLUMNS: usize = 2; - -const MIN_NEW_COLUMNS: usize = 1; - #[derive(Clone, Default, Copy)] struct Occurrence { passed_wild_card: bool, @@ -71,6 +67,26 @@ impl PartialEq for Path { impl Eq for Path {} +impl PartialOrd for Path { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Path { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Path::Pair(a), Path::Pair(b)) + | (Path::Tuple(a), Path::Tuple(b)) + | (Path::List(a), Path::List(b)) + | (Path::ListTail(a), Path::ListTail(b)) + | (Path::Constr(_, a), Path::Constr(_, b)) => a.cmp(b), + (Path::OpaqueConstr(_), Path::OpaqueConstr(_)) => Ordering::Equal, + _ => Ordering::Equal, + } + } +} + #[derive(Clone, Debug)] pub struct Assigned { pub path: Vec, @@ -568,7 +584,7 @@ impl<'a> DecisionTree<'a> { } } -impl<'a> Display for DecisionTree<'a> { +impl Display for DecisionTree<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_pretty()) } @@ -603,33 +619,86 @@ impl<'a, 'b> TreeGen<'a, 'b> { ) -> DecisionTree<'a> { let mut hoistables = IndexMap::new(); - let rows = clauses - .iter() - .enumerate() - .map(|(index, clause)| { - // Assigns are split out from patterns so they can be handled - // outside of the tree algorithm - let (assign, row_items) = - self.map_pattern_to_row(&clause.pattern, subject_tipo, vec![]); + let mut columns_added = vec![]; - self.interner.intern(format!("__clause_then_{}", index)); - let clause_then_name = self - .interner - .lookup_interned(&format!("__clause_then_{}", index)); + let rows = { + let rows_initial = clauses + .iter() + .enumerate() + .map(|(index, clause)| { + // Assigns are split out from patterns so they can be handled + // outside of the tree algorithm + let (assign, row_items) = + self.map_pattern_to_row(&clause.pattern, subject_tipo, vec![]); - hoistables.insert(clause_then_name.clone(), (vec![], &clause.then)); + self.interner.intern(format!("__clause_then_{}", index)); + let clause_then_name = self + .interner + .lookup_interned(&format!("__clause_then_{}", index)); - let row = Row { - assigns: assign.into_iter().collect_vec(), - columns: row_items, - then: clause_then_name, - }; + hoistables.insert(clause_then_name.clone(), (vec![], &clause.then)); - self.interner.pop_text(format!("__clause_then_{}", index)); + // Some good ol' mutation to track added columns per relevant path + // relevant path indicating a column that has a pattern to test at some point in + // one of the rows + row_items.iter().for_each(|col| { + if !columns_added.contains(&col.path) { + columns_added.push(col.path.clone()); + } + }); - row - }) - .collect_vec(); + let row = Row { + assigns: assign.into_iter().collect_vec(), + columns: row_items, + then: clause_then_name, + }; + + self.interner.pop_text(format!("__clause_then_{}", index)); + + row + }) + .collect_vec(); + + columns_added = columns_added + .into_iter() + .sorted_by(|a, b| { + let mut a = a.clone(); + let mut b = b.clone(); + + // It's impossible for duplicates since we check before insertion + while let Ordering::Equal = a.first().cmp(&b.first()) { + a.remove(0); + b.remove(0); + } + + a.first().cmp(&b.first()) + }) + .map(|col| { + // remove opaqueconstr paths since they are just type information + col.into_iter() + .filter(|a| !matches!(a, Path::OpaqueConstr(_))) + .collect_vec() + }) + .collect_vec(); + + rows_initial + .into_iter() + .map(|mut row| { + for (index, path) in columns_added.iter().enumerate() { + if !row + .columns + .get(index) + .map(|col| col.path == *path) + .unwrap_or(false) + { + row.columns.insert(index, self.wild_card_pattern.clone()); + } + } + + row + }) + .collect_vec() + }; let mut tree = self.do_build_tree(subject_tipo, PatternMatrix { rows }, &mut hoistables); @@ -654,6 +723,7 @@ impl<'a, 'b> TreeGen<'a, 'b> { then_map: &mut IndexMap, &'a TypedExpr)>, ) -> DecisionTree<'a> { let column_length = matrix.rows[0].columns.len(); + // First step make sure all rows have same number of columns // or something went wrong assert!(matrix @@ -734,6 +804,7 @@ impl<'a, 'b> TreeGen<'a, 'b> { .unwrap(); let specialized_tipo = get_tipo_by_path(subject_tipo.clone(), &path); + let mut relevant_columns: Vec<(CaseTest, Vec>)> = vec![]; // Time to split on the matrices based on case to test for or lack of let (default_matrix, specialized_matrices) = matrix.rows.into_iter().fold( @@ -841,37 +912,37 @@ impl<'a, 'b> TreeGen<'a, 'b> { // Add inner patterns to existing row let mut new_cols = remaining_patts.into_iter().flat_map(|x| x.1).collect_vec(); - // To align number of columns we pop off the tail since it can - // never include a pattern besides wild card - if matches!(case, CaseTest::ListWithTail(_)) { - new_cols.pop(); - } + let new_paths = new_cols.iter().map(|col| col.path.clone()).collect_vec(); - let added_columns = new_cols.len(); - - // Pop off tail so that it aligns more easily with other list patterns + if let Some(a) = relevant_columns.iter_mut().find(|a| a.0 == case) { + new_paths.iter().for_each(|col| { + if !a.1.contains(col) { + a.1.push(col.clone()); + } + }); + } else { + relevant_columns.push((case.clone(), new_paths.clone())); + }; new_cols.extend(row.columns); row.columns = new_cols; if let CaseTest::Wild = case { - let current_wild_cols = row.columns.len(); default_matrix.push(row.clone()); - case_matrices.iter_mut().for_each(|(_, matrix)| { - let mut row = row.clone(); - let total_cols = matrix[0].columns.len(); + case_matrices.iter_mut().for_each(|(case, matrix)| { + let Some(a) = relevant_columns.iter_mut().find(|a| a.0 == *case) else { + unreachable!() + }; - if total_cols != 0 { - let added_columns = total_cols - current_wild_cols; - - for _ in 0..added_columns { - row.columns.insert(0, self.wild_card_pattern.clone()); + new_paths.iter().for_each(|col| { + if !a.1.contains(col) { + a.1.push(col.clone()); } + }); - matrix.push(row); - } + matrix.push(row.clone()); }); } else if let CaseTest::ListWithTail(tail_case_length) = case { // For lists with tail it's a special case where we also add it to existing patterns @@ -886,20 +957,30 @@ impl<'a, 'b> TreeGen<'a, 'b> { for elem_count in tail_case_length..=longest_elems_no_tail { let case = CaseTest::List(elem_count); - let mut row = row.clone(); + // paths first + if let Some(a) = relevant_columns.iter_mut().find(|a| a.0 == case) { + new_paths.iter().for_each(|col| { + if !a.1.contains(col) { + a.1.push(col.clone()); + } + }); + } else { + relevant_columns.push((case.clone(), new_paths.clone())); + }; - for _ in 0..(elem_count - tail_case_length) { - row.columns - .insert(tail_case_length, self.wild_card_pattern.clone()); + let row = row.clone(); + + // now insertion into the appropriate matrix + if let Some(entry) = + case_matrices.iter_mut().find(|item| item.0 == case) + { + entry.1.push(row); + } else { + let mut rows = default_matrix.to_vec(); + + rows.push(row); + case_matrices.push((case, rows)); } - - self.insert_case( - &mut case_matrices, - case, - &default_matrix, - row, - added_columns, - ); } } @@ -907,35 +988,123 @@ impl<'a, 'b> TreeGen<'a, 'b> { for elem_count in tail_case_length..=longest_elems_with_tail { let case = CaseTest::ListWithTail(elem_count); - let mut row = row.clone(); + if let Some(a) = relevant_columns.iter_mut().find(|a| a.0 == case) { + new_paths.iter().for_each(|col| { + if !a.1.contains(col) { + a.1.push(col.clone()); + } + }); + } else { + relevant_columns.push((case.clone(), new_paths.clone())); + }; - for _ in 0..(elem_count - tail_case_length) { - row.columns - .insert(tail_case_length, self.wild_card_pattern.clone()); + let row = row.clone(); + + if let Some(entry) = case_matrices.iter_mut().find(|item| item.0 == case) { + entry.1.push(row); + } else { + let mut rows = default_matrix.clone(); + + rows.push(row); + case_matrices.push((case, rows)); } - - self.insert_case( - &mut case_matrices, - case, - &default_matrix, - row, - added_columns, - ); } + } else if let Some(entry) = case_matrices.iter_mut().find(|item| item.0 == case) { + entry.1.push(row); } else { - self.insert_case( - &mut case_matrices, - case, - &default_matrix, - row, - added_columns, - ); + let mut rows = default_matrix.clone(); + + rows.push(row); + case_matrices.push((case, rows)); } (default_matrix, case_matrices) }, ); + let (default_relevant_cols, relevant_columns): (Vec<_>, Vec<_>) = relevant_columns + .into_iter() + .map(|(case, paths)| { + ( + case, + paths + .into_iter() + .sorted_by(|a, b| { + let mut a = a.clone(); + let mut b = b.clone(); + + // It's impossible for duplicates since we check before insertion + while let Ordering::Equal = a.first().cmp(&b.first()) { + a.remove(0); + b.remove(0); + } + + a.first().cmp(&b.first()) + }) + .map(|col| { + // remove opaqueconstr paths since they are just type information + col.into_iter() + .filter(|a| !matches!(a, Path::OpaqueConstr(_))) + .collect_vec() + }) + .collect_vec(), + ) + }) + .partition_map(|(case, paths)| match case { + CaseTest::Wild => Either::Left(paths), + _ => Either::Right((case, paths)), + }); + + let default_matrix = default_matrix + .into_iter() + .map(|mut row| { + for (index, path) in default_relevant_cols[0].iter().enumerate() { + if !row + .columns + .get(index) + .map(|col| col.path == *path) + .unwrap_or(false) + { + row.columns.insert(index, self.wild_card_pattern.clone()); + } + } + + row + }) + .collect_vec(); + + let specialized_matrices = specialized_matrices + .into_iter() + .map(|(case, matrix)| { + let Some((_, relevant_cols)) = relevant_columns + .iter() + .find(|(relevant_case, _)| relevant_case == &case) + else { + unreachable!() + }; + ( + case, + matrix + .into_iter() + .map(|mut row| { + for (index, path) in relevant_cols.iter().enumerate() { + if !row + .columns + .get(index) + .map(|col| col.path == *path) + .unwrap_or(false) + { + row.columns.insert(index, self.wild_card_pattern.clone()); + } + } + + row + }) + .collect_vec(), + ) + }) + .collect_vec(); + let default_matrix = PatternMatrix { rows: default_matrix, }; @@ -1001,39 +1170,13 @@ impl<'a, 'b> TreeGen<'a, 'b> { ) -> (Vec, Vec>) { let current_tipo = get_tipo_by_path(subject_tipo.clone(), &path); - let new_columns_added = if current_tipo.is_pair() { - PAIR_NEW_COLUMNS - } else if current_tipo.is_tuple() { - let Type::Tuple { elems, .. } = current_tipo.as_ref() else { - unreachable!("{:#?}", current_tipo) - }; - elems.len() - } else if let Some(data) = lookup_data_type_by_tipo(self.data_types, ¤t_tipo) { - if data.constructors.len() == 1 { - data.constructors[0].arguments.len() - } else if data.is_never() { - 0 - } else { - MIN_NEW_COLUMNS - } - } else { - MIN_NEW_COLUMNS - }; - match pattern { Pattern::Var { name, .. } => ( vec![Assigned { path: path.clone(), assigned: name.clone(), }], - vec![RowItem { - pattern, - path: path.clone(), - }] - .into_iter() - .cycle() - .take(new_columns_added) - .collect_vec(), + vec![], ), Pattern::Assign { name, pattern, .. } => { @@ -1049,19 +1192,14 @@ impl<'a, 'b> TreeGen<'a, 'b> { ); (assigns, patts) } - Pattern::Int { .. } - | Pattern::ByteArray { .. } - | Pattern::Discard { .. } - | Pattern::List { .. } => ( + Pattern::Discard { .. } => (vec![], vec![]), + + Pattern::Int { .. } | Pattern::ByteArray { .. } | Pattern::List { .. } => ( vec![], vec![RowItem { pattern, path: path.clone(), - }] - .into_iter() - .cycle() - .take(new_columns_added) - .collect_vec(), + }], ), Pattern::Constructor { @@ -1101,11 +1239,7 @@ impl<'a, 'b> TreeGen<'a, 'b> { vec![RowItem { pattern, path: path.clone(), - }] - .into_iter() - .cycle() - .take(new_columns_added) - .collect_vec(), + }], ) } } @@ -1126,6 +1260,7 @@ impl<'a, 'b> TreeGen<'a, 'b> { (assigns, patts) } + Pattern::Tuple { elems, .. } => { elems .iter() @@ -1146,30 +1281,6 @@ impl<'a, 'b> TreeGen<'a, 'b> { } } } - - fn insert_case( - &self, - case_matrices: &mut Vec<(CaseTest, Vec>)>, - case: CaseTest, - default_matrix: &[Row<'a>], - new_row: Row<'a>, - added_columns: usize, - ) { - if let Some(entry) = case_matrices.iter_mut().find(|item| item.0 == case) { - entry.1.push(new_row); - } else { - let mut rows = default_matrix.to_vec(); - - for _ in 0..added_columns { - for row in &mut rows { - row.columns.insert(0, self.wild_card_pattern.clone()); - } - } - - rows.push(new_row); - case_matrices.push((case, rows)); - } - } } pub fn get_tipo_by_path(mut subject_tipo: Rc, mut path: &[Path]) -> Rc { diff --git a/crates/aiken-lang/src/test_framework.rs b/crates/aiken-lang/src/test_framework.rs index c4a5e8ec..20321066 100644 --- a/crates/aiken-lang/src/test_framework.rs +++ b/crates/aiken-lang/src/test_framework.rs @@ -622,7 +622,7 @@ pub struct Counterexample<'a> { pub cache: Cache<'a, PlutusData>, } -impl<'a> Counterexample<'a> { +impl Counterexample<'_> { fn consider(&mut self, choices: &[u8]) -> bool { if choices == self.choices { return true; diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 849d2571..44f36546 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -1284,7 +1284,7 @@ fn suggest_pattern( } } -fn suggest_generic(name: &String, expected: usize) -> String { +fn suggest_generic(name: &str, expected: usize) -> String { if expected == 0 { return name.to_doc().to_pretty_string(70); } diff --git a/crates/aiken-lang/src/tipo/pretty.rs b/crates/aiken-lang/src/tipo/pretty.rs index d0b437ec..1aa81ea5 100644 --- a/crates/aiken-lang/src/tipo/pretty.rs +++ b/crates/aiken-lang/src/tipo/pretty.rs @@ -206,7 +206,7 @@ impl Printer { } } -fn qualify_type_name(module: &String, typ_name: &str) -> Document<'static> { +fn qualify_type_name(module: &str, typ_name: &str) -> Document<'static> { if module.is_empty() { docvec!["aiken.", Document::String(typ_name.to_string())] } else { diff --git a/crates/aiken-project/src/docs.rs b/crates/aiken-project/src/docs.rs index fa5ebe1c..c2c683dd 100644 --- a/crates/aiken-project/src/docs.rs +++ b/crates/aiken-project/src/docs.rs @@ -52,7 +52,7 @@ struct ModuleTemplate<'a> { timestamp: String, } -impl<'a> ModuleTemplate<'a> { +impl ModuleTemplate<'_> { pub fn is_current_module(&self, module: &DocLink) -> bool { match module.path.split(".html").next() { None => false, @@ -75,7 +75,7 @@ struct PageTemplate<'a> { timestamp: &'a str, } -impl<'a> PageTemplate<'a> { +impl PageTemplate<'_> { pub fn is_current_module(&self, _module: &DocLink) -> bool { false } diff --git a/crates/aiken-project/src/error.rs b/crates/aiken-project/src/error.rs index c82b0c6a..311428e1 100644 --- a/crates/aiken-project/src/error.rs +++ b/crates/aiken-project/src/error.rs @@ -720,7 +720,7 @@ struct DisplayWarning<'a> { help: Option, } -impl<'a> Diagnostic for DisplayWarning<'a> { +impl Diagnostic for DisplayWarning<'_> { fn severity(&self) -> Option { Some(miette::Severity::Warning) } @@ -749,7 +749,7 @@ impl<'a> Diagnostic for DisplayWarning<'a> { } } -impl<'a> Debug for DisplayWarning<'a> { +impl Debug for DisplayWarning<'_> { fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { unreachable!("Display warning are never shown directly."); } diff --git a/crates/aiken-project/src/package_name.rs b/crates/aiken-project/src/package_name.rs index 9b009137..dfea801a 100644 --- a/crates/aiken-project/src/package_name.rs +++ b/crates/aiken-project/src/package_name.rs @@ -74,7 +74,7 @@ impl<'de> Deserialize<'de> for PackageName { { struct PackageNameVisitor; - impl<'de> Visitor<'de> for PackageNameVisitor { + impl Visitor<'_> for PackageNameVisitor { type Value = PackageName; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/crates/aiken/src/cmd/completion/shell.rs b/crates/aiken/src/cmd/completion/shell.rs index 821b9f8a..8b4e730f 100644 --- a/crates/aiken/src/cmd/completion/shell.rs +++ b/crates/aiken/src/cmd/completion/shell.rs @@ -191,7 +191,7 @@ enum Log<'a> { Done(&'a Shell), } -impl<'a> Display for Log<'a> { +impl Display for Log<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> { match self { Log::Detecting(what) => pretty::fmt_step(f, "Detecting", what), diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index 8c4f609c..3c56b8eb 100644 --- a/crates/uplc/src/flat.rs +++ b/crates/uplc/src/flat.rs @@ -632,7 +632,7 @@ fn encode_type(typ: &Type, bytes: &mut Vec) { } } -impl<'b> Decode<'b> for Constant { +impl Decode<'_> for Constant { fn decode(d: &mut Decoder) -> Result { match &decode_constant(d)?[..] { [0] => Ok(Constant::Integer(BigInt::decode(d)?)), @@ -806,7 +806,7 @@ impl Encode for Unique { } } -impl<'b> Decode<'b> for Unique { +impl Decode<'_> for Unique { fn decode(d: &mut Decoder) -> Result { Ok(isize::decode(d)?.into()) } @@ -821,7 +821,7 @@ impl Encode for Name { } } -impl<'b> Decode<'b> for Name { +impl Decode<'_> for Name { fn decode(d: &mut Decoder) -> Result { Ok(Name { text: String::decode(d)?, @@ -830,7 +830,7 @@ impl<'b> Decode<'b> for Name { } } -impl<'b> Binder<'b> for Name { +impl Binder<'_> for Name { fn binder_encode(&self, e: &mut Encoder) -> Result<(), en::Error> { self.encode(e)?; @@ -855,7 +855,7 @@ impl Encode for NamedDeBruijn { } } -impl<'b> Decode<'b> for NamedDeBruijn { +impl Decode<'_> for NamedDeBruijn { fn decode(d: &mut Decoder) -> Result { Ok(NamedDeBruijn { text: String::decode(d)?, @@ -864,7 +864,7 @@ impl<'b> Decode<'b> for NamedDeBruijn { } } -impl<'b> Binder<'b> for NamedDeBruijn { +impl Binder<'_> for NamedDeBruijn { fn binder_encode(&self, e: &mut Encoder) -> Result<(), en::Error> { self.text.encode(e)?; self.index.encode(e)?; @@ -892,13 +892,13 @@ impl Encode for DeBruijn { } } -impl<'b> Decode<'b> for DeBruijn { +impl Decode<'_> for DeBruijn { fn decode(d: &mut Decoder) -> Result { Ok(usize::decode(d)?.into()) } } -impl<'b> Binder<'b> for DeBruijn { +impl Binder<'_> for DeBruijn { fn binder_encode(&self, _: &mut Encoder) -> Result<(), en::Error> { Ok(()) } @@ -922,7 +922,7 @@ impl Encode for FakeNamedDeBruijn { } } -impl<'b> Decode<'b> for FakeNamedDeBruijn { +impl Decode<'_> for FakeNamedDeBruijn { fn decode(d: &mut Decoder) -> Result { let index = DeBruijn::decode(d)?; @@ -930,7 +930,7 @@ impl<'b> Decode<'b> for FakeNamedDeBruijn { } } -impl<'b> Binder<'b> for FakeNamedDeBruijn { +impl Binder<'_> for FakeNamedDeBruijn { fn binder_encode(&self, _: &mut Encoder) -> Result<(), en::Error> { Ok(()) } @@ -954,7 +954,7 @@ impl Encode for DefaultFunction { } } -impl<'b> Decode<'b> for DefaultFunction { +impl Decode<'_> for DefaultFunction { fn decode(d: &mut Decoder) -> Result { let builtin_tag = d.bits8(BUILTIN_TAG_WIDTH as usize)?; builtin_tag.try_into() diff --git a/crates/uplc/src/tx/to_plutus_data.rs b/crates/uplc/src/tx/to_plutus_data.rs index fab7cd2c..351ceb5d 100644 --- a/crates/uplc/src/tx/to_plutus_data.rs +++ b/crates/uplc/src/tx/to_plutus_data.rs @@ -132,7 +132,7 @@ impl ToPlutusData for Address { } } -impl<'a> ToPlutusData for WithWrappedTransactionId<'a, TransactionInput> { +impl ToPlutusData for WithWrappedTransactionId<'_, TransactionInput> { fn to_plutus_data(&self) -> PlutusData { wrap_multiple_with_constr( 0, @@ -197,7 +197,7 @@ where } } -impl<'a> ToPlutusData for WithWrappedTransactionId<'a, KeyValuePairs> { +impl ToPlutusData for WithWrappedTransactionId<'_, KeyValuePairs> { fn to_plutus_data(&self) -> PlutusData { let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![]; for (key, value) in self.0.iter() { @@ -210,7 +210,7 @@ impl<'a> ToPlutusData for WithWrappedTransactionId<'a, KeyValuePairs ToPlutusData for WithNeverRegistrationDeposit<'a, Vec> { +impl ToPlutusData for WithNeverRegistrationDeposit<'_, Vec> { fn to_plutus_data(&self) -> PlutusData { self.0 .iter() @@ -220,7 +220,7 @@ impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, Vec> { } } -impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, KeyValuePairs> { +impl ToPlutusData for WithNeverRegistrationDeposit<'_, KeyValuePairs> { fn to_plutus_data(&self) -> PlutusData { let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![]; for (key, value) in self.0.iter() { @@ -309,7 +309,7 @@ impl ToPlutusData for PositiveCoin { } } -impl<'a> ToPlutusData for WithZeroAdaAsset<'a, Value> { +impl ToPlutusData for WithZeroAdaAsset<'_, Value> { fn to_plutus_data(&self) -> PlutusData { match self.0 { Value::Coin(coin) => { @@ -345,7 +345,7 @@ impl ToPlutusData for Value { } } -impl<'a> ToPlutusData for WithZeroAdaAsset<'a, MintValue> { +impl ToPlutusData for WithZeroAdaAsset<'_, MintValue> { fn to_plutus_data(&self) -> PlutusData { value_to_plutus_data( self.0.mint_value.iter(), @@ -429,7 +429,7 @@ impl<'a> ToPlutusData for WithOptionDatum<'a, WithZeroAdaAsset<'a, Vec ToPlutusData for WithZeroAdaAsset<'a, Vec> { +impl ToPlutusData for WithZeroAdaAsset<'_, Vec> { fn to_plutus_data(&self) -> PlutusData { Data::list( self.0 @@ -465,7 +465,7 @@ impl<'a> ToPlutusData for WithOptionDatum<'a, WithZeroAdaAsset<'a, TransactionOu } } -impl<'a> ToPlutusData for WithZeroAdaAsset<'a, TransactionOutput> { +impl ToPlutusData for WithZeroAdaAsset<'_, TransactionOutput> { fn to_plutus_data(&self) -> PlutusData { match self.0 { TransactionOutput::Legacy(legacy_output) => { @@ -528,7 +528,7 @@ impl ToPlutusData for StakeCredential { } } -impl<'a> ToPlutusData for WithPartialCertificates<'a, Vec> { +impl ToPlutusData for WithPartialCertificates<'_, Vec> { fn to_plutus_data(&self) -> PlutusData { self.0 .iter() @@ -538,7 +538,7 @@ impl<'a> ToPlutusData for WithPartialCertificates<'a, Vec> { } } -impl<'a> ToPlutusData for WithPartialCertificates<'a, Certificate> { +impl ToPlutusData for WithPartialCertificates<'_, Certificate> { fn to_plutus_data(&self) -> PlutusData { match self.0 { Certificate::StakeRegistration(stake_credential) => { @@ -586,7 +586,7 @@ impl<'a> ToPlutusData for WithPartialCertificates<'a, Certificate> { } } -impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, Certificate> { +impl ToPlutusData for WithNeverRegistrationDeposit<'_, Certificate> { fn to_plutus_data(&self) -> PlutusData { match self.0 { Certificate::StakeRegistration(stake_credential) => wrap_multiple_with_constr( @@ -870,7 +870,7 @@ impl ToPlutusData for TxInInfo { // NOTE: This is a _small_ abuse of the 'WithWrappedTransactionId'. We know the wrapped // is needed for V1 and V2, and it also appears that for V1 and V2, the certifying // purpose mustn't include the certificate index. So, we also short-circuit it here. -impl<'a> ToPlutusData for WithWrappedTransactionId<'a, ScriptPurpose> { +impl ToPlutusData for WithWrappedTransactionId<'_, ScriptPurpose> { fn to_plutus_data(&self) -> PlutusData { match self.0 { ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()), @@ -891,7 +891,7 @@ impl<'a> ToPlutusData for WithWrappedTransactionId<'a, ScriptPurpose> { } } -impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, ScriptPurpose> { +impl ToPlutusData for WithNeverRegistrationDeposit<'_, ScriptPurpose> { fn to_plutus_data(&self) -> PlutusData { match self.0 { ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()), @@ -1210,14 +1210,14 @@ impl ToPlutusData for RationalNumber { } } -impl<'a> ToPlutusData for WithArrayRational<'a, RationalNumber> { +impl ToPlutusData for WithArrayRational<'_, RationalNumber> { fn to_plutus_data(&self) -> PlutusData { let gcd = self.0.numerator.gcd(&self.0.denominator); vec![self.0.numerator / gcd, self.0.denominator / gcd].to_plutus_data() } } -impl<'a> ToPlutusData for WithWrappedStakeCredential<'a, Vec<(Address, Coin)>> { +impl ToPlutusData for WithWrappedStakeCredential<'_, Vec<(Address, Coin)>> { fn to_plutus_data(&self) -> PlutusData { self.0 .iter() @@ -1232,7 +1232,7 @@ impl<'a> ToPlutusData for WithWrappedStakeCredential<'a, Vec<(Address, Coin)>> { } } -impl<'a> ToPlutusData for WithWrappedStakeCredential<'a, KeyValuePairs> { +impl ToPlutusData for WithWrappedStakeCredential<'_, KeyValuePairs> { fn to_plutus_data(&self) -> PlutusData { KeyValuePairs::from( self.0 @@ -1249,7 +1249,7 @@ impl<'a> ToPlutusData for WithWrappedStakeCredential<'a, KeyValuePairs ToPlutusData for WithWrappedStakeCredential<'a, StakeCredential> { +impl ToPlutusData for WithWrappedStakeCredential<'_, StakeCredential> { fn to_plutus_data(&self) -> PlutusData { wrap_with_constr(0, self.0.to_plutus_data()) } @@ -1291,7 +1291,7 @@ impl ToPlutusData for Vote { } } -impl<'a, T> ToPlutusData for WithNeverRegistrationDeposit<'a, ScriptInfo> +impl ToPlutusData for WithNeverRegistrationDeposit<'_, ScriptInfo> where T: ToPlutusData, { diff --git a/examples/acceptance_tests/115/aiken.toml b/examples/acceptance_tests/115/aiken.toml new file mode 100644 index 00000000..3b22e6d3 --- /dev/null +++ b/examples/acceptance_tests/115/aiken.toml @@ -0,0 +1,12 @@ +name = "aiken-lang/acceptance_test_006" +version = "0.0.0" +compiler = "v1.1.7" +plutus = "v3" +description = "" + +[[dependencies]] +name = "aiken-lang/stdlib" +version = "v2.1.0" +source = "github" + +[config] diff --git a/examples/acceptance_tests/115/validators/tests.ak b/examples/acceptance_tests/115/validators/tests.ak new file mode 100644 index 00000000..afdc6e0e --- /dev/null +++ b/examples/acceptance_tests/115/validators/tests.ak @@ -0,0 +1,86 @@ +use aiken/collection/list +use cardano/assets.{PolicyId} +use cardano/transaction.{InlineDatum, Output, OutputReference, Transaction} + +pub type StateMachineDatum { + state: Int, + buyer: ByteArray, + seller: ByteArray, + collateral: Int, + price: Int, + accept_range: Int, +} + +pub type StateMachineInput { + Return + Other +} + +validator statemachine(threadtoken: PolicyId) { + spend( + datum_opt: Option, + redeemer: StateMachineInput, + own_ref: OutputReference, + transaction: Transaction, + ) { + expect Some(datum) = datum_opt + when (datum, redeemer) is { + ( + StateMachineDatum { + state, + buyer, + seller, + price, + collateral, + accept_range, + }, + Return, + ) -> { + let must_be_state = state == 0 + + let must_be_signed = list.has(transaction.extra_signatories, buyer) + //One of the transaction inputs belongs to the statemachine. + expect Some(sm_input) = + list.find( + transaction.inputs, + fn(input) { input.output_reference == own_ref }, + ) + //One of the transaction outputs contains the threadtoken addressed to the statemachine itself - 1. + expect Some(sm_output) = + list.find( + transaction.outputs, + fn(output) { output.address == sm_input.output.address }, + ) + //One of the transaction outputs contains the threadtoken addressed to the statemachine itself - 2. + let must_be_policy = + list.has(assets.policies(sm_output.value), threadtoken) + + //verification of the new datum - 1. + let new_data: Data = + StateMachineDatum { + state: -1, + buyer, + seller, + collateral, + price, + accept_range, + } + //verification of the new datum - 2. + let must_be_datum = InlineDatum(new_data) == sm_output.datum + + and { + must_be_state?, + must_be_signed?, + must_be_policy?, + must_be_datum?, + } + } + + _ -> False + } + } + + else(_) { + fail + } +}