fixing list condition edge cases and clean up rearrange list clauses

This commit is contained in:
microproofs 2023-07-28 11:47:27 -04:00 committed by Kasey
parent e8fa8f5423
commit 03dd13dc7d
3 changed files with 91 additions and 84 deletions

View File

@ -25,7 +25,8 @@ use crate::{
gen_uplc::builder::{
convert_opaque_type, erase_opaque_type_operations, find_and_replace_generics,
get_arg_type_name, get_generic_id_and_type, get_variant_name, monomorphize,
wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction, SpecificClause,
pattern_has_conditions, wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction,
SpecificClause,
},
tipo::{
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
@ -1680,7 +1681,7 @@ impl<'a> CodeGenerator<'a> {
let next_elements_len = match next_clause_pattern {
Pattern::List { elements, tail, .. } => {
elements.len() - usize::from(tail.is_some())
elements.len() + usize::from(tail.is_none())
}
_ => 0,
};
@ -1708,16 +1709,11 @@ impl<'a> CodeGenerator<'a> {
};
let mut is_wild_card_elems_clause = clause.guard.is_none();
for elements in elements.iter() {
if let Pattern::Constructor { .. }
| Pattern::Tuple { .. }
| Pattern::List { .. }
| Pattern::Assign { .. } = elements
{
is_wild_card_elems_clause = false;
}
for element in elements.iter() {
is_wild_card_elems_clause =
is_wild_card_elems_clause && !pattern_has_conditions(element);
}
let elements_len = elements.len() - usize::from(tail.is_some());
let elements_len = elements.len() + usize::from(tail.is_none());
let current_checked_index = *checked_index;
if *checked_index < elements_len.try_into().unwrap()
@ -2360,8 +2356,8 @@ impl<'a> CodeGenerator<'a> {
is_record,
..
} => {
props.complex_clause = true;
if subject_tipo.is_bool() {
props.complex_clause = true;
AirTree::clause_guard(
&props.original_subject_name,
AirTree::bool(constr_name == "True"),
@ -2373,6 +2369,7 @@ impl<'a> CodeGenerator<'a> {
if *is_record {
assign
} else {
props.complex_clause = true;
AirTree::UnhoistedSequence(vec![
AirTree::clause_guard(
&props.original_subject_name,
@ -2385,7 +2382,6 @@ impl<'a> CodeGenerator<'a> {
}
}
Pattern::Tuple { .. } => {
props.complex_clause = true;
let (_, assign) = self.clause_pattern(pattern, subject_tipo, props);
let defined_indices = match &props.specific_clause {

View File

@ -14,7 +14,9 @@ use uplc::{
};
use crate::{
ast::{AssignmentKind, DataType, Pattern, Span, TypedArg, TypedClause, TypedDataType},
ast::{
AssignmentKind, DataType, Pattern, Span, TypedArg, TypedClause, TypedDataType, TypedPattern,
},
builtins::{bool, void},
expr::TypedExpr,
tipo::{PatternConstructor, TypeVar, ValueConstructor, ValueConstructorVariant},
@ -521,7 +523,6 @@ pub fn get_variant_name(t: &Arc<Type>) -> String {
let full_type = "_data".to_string();
if t.is_generic() {
println!("FULL TYPE: {:#?}", t);
panic!("FOUND A POLYMORPHIC TYPE. EXPECTED MONOMORPHIC TYPE");
}
@ -601,6 +602,25 @@ pub fn modify_self_calls(air_tree: &mut AirTree, func_key: &FunctionAccessKey, v
}
}
pub fn pattern_has_conditions(pattern: &TypedPattern) -> bool {
match pattern {
Pattern::Constructor {
is_record: false, ..
}
| Pattern::List { .. }
| Pattern::Int { .. } => true,
Pattern::Tuple { elems, .. } => elems.iter().any(pattern_has_conditions),
Pattern::Constructor {
is_record: true,
arguments,
..
} => arguments
.iter()
.any(|arg| pattern_has_conditions(&arg.value)),
Pattern::Var { .. } | Pattern::Discard { .. } | Pattern::Assign { .. } => false,
}
}
// TODO: write some tests
pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
let mut sorted_clauses = clauses;
@ -695,8 +715,6 @@ pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
None
};
println!("sorted clauses: {:#?}", sorted_clauses);
for (index, clause) in sorted_clauses.iter().enumerate() {
if last_clause_set {
continue;
@ -710,15 +728,12 @@ pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
assert!(matches!(
clause_pattern,
Pattern::List { .. }
| Pattern::Var { .. }
| Pattern::Discard { .. }
| Pattern::Assign { .. }
Pattern::List { .. } | Pattern::Var { .. } | Pattern::Discard { .. }
));
if let Pattern::List { elements, tail, .. } = &clause.pattern {
if let Pattern::List { elements, tail, .. } = clause_pattern {
// found a hole and now we plug it
while wild_card_clause_elems < elements.len() - usize::from(tail.is_some()) {
while wild_card_clause_elems < elements.len() {
let mut discard_elems = vec![];
for _ in 0..wild_card_clause_elems {
@ -764,17 +779,14 @@ pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
let mut is_wild_card_elems_clause = clause.guard.is_none();
for elements in elements.iter() {
if let Pattern::Constructor { .. }
| Pattern::Tuple { .. }
| Pattern::List { .. }
| Pattern::Assign { .. } = elements
{
is_wild_card_elems_clause = false;
}
for element in elements.iter() {
is_wild_card_elems_clause =
is_wild_card_elems_clause && !pattern_has_conditions(element);
}
if is_wild_card_elems_clause {
if is_wild_card_elems_clause
&& wild_card_clause_elems < elements.len() + usize::from(tail.is_none())
{
wild_card_clause_elems += 1;
if clause.guard.is_none() && tail.is_some() && !elements.is_empty() {
last_clause_index = index;
@ -808,7 +820,7 @@ pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
// Encountered a tail so stop there with that as last clause
if last_clause_set {
final_clauses = final_clauses[0..last_clause_index + 1].to_vec();
final_clauses = final_clauses[0..last_clause_index].to_vec();
}
// insert hole fillers into clauses

View File

@ -103,6 +103,8 @@ fn assert_uplc(source_code: &str, expected: Term<Name>, should_fail: bool) {
term: expected,
};
println!("expected: {}", expected.to_pretty());
let expected = optimize::aiken_optimize_and_intern(expected);
let expected: Program<DeBruijn> = expected.try_into().unwrap();
@ -2898,6 +2900,52 @@ fn when_tuple_deconstruction() {
.apply(Term::var("red")),
)
.delayed_if_else(Term::unit(), Term::Error)
.lambda("red")
.apply(
Term::var("red").lambda("_").apply(
Term::var("expect_RedSpend")
.lambda("expect_RedSpend")
.apply(
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(Term::var("subject"))
.delayed_if_else(
Term::tail_list()
.apply(Term::var("red_constr_fields"))
.delayed_choose_list(
Term::unit(),
Term::Error.trace(Term::string("List/Tuple/Constr contains more items than expected")),
)
.lambda("field_1")
.apply(Term::un_i_data().apply(
Term::head_list().apply(Term::var("red_constr_fields")),
))
.lambda("red_constr_fields")
.apply(
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)
.apply(Term::var("red"))
.delayed_choose_list(
Term::unit(),
Term::Error
.trace(Term::string("Expected no fields for Constr"))
),
Term::Error.trace(Term::string("Constr index did not match any type variant")),
),
)
.lambda("subject")
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("red")))
.lambda("red"),
)
.apply(Term::var("red")),
),
)
.lambda("dat")
.apply(
Term::var("dat").lambda("_").apply(
@ -2980,53 +3028,7 @@ fn when_tuple_deconstruction() {
)
.apply(Term::var("dat")),
),
)
.lambda("red")
.apply(
Term::var("red").lambda("_").apply(
Term::var("expect_RedSpend")
.lambda("expect_RedSpend")
.apply(
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(Term::var("subject"))
.delayed_if_else(
Term::tail_list()
.apply(Term::var("red_constr_fields"))
.delayed_choose_list(
Term::unit(),
Term::Error.trace(Term::string("List/Tuple/Constr contains more items than expected")),
)
.lambda("field_1")
.apply(Term::un_i_data().apply(
Term::head_list().apply(Term::var("red_constr_fields")),
))
.lambda("red_constr_fields")
.apply(
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)
.apply(Term::var("red"))
.delayed_choose_list(
Term::unit(),
Term::Error
.trace(Term::string("Expected no fields for Constr"))
),
Term::Error.trace(Term::string("Constr index did not match any type variant")),
),
)
.lambda("subject")
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("red")))
.lambda("red"),
)
.apply(Term::var("red")),
),
)
)
.lambda("ctx")
.lambda("red")
.lambda("dat")
@ -3771,10 +3773,7 @@ fn list_fields_unwrap() {
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("item_1")))
.lambda("item_1")
.apply(Term::head_list().apply(Term::var("field_list")))
.lambda("clauses_delayed")
.apply(Term::bool(false).delay())
.lambda("tail_1")
.apply(Term::tail_list().apply(Term::var("field_list"))),
)
.lambda("field_list")
.apply(Term::list_values(vec![