checkpoint

This commit is contained in:
microproofs 2023-07-27 14:42:21 -04:00 committed by Kasey
parent 389699f485
commit c6f90a999b
2 changed files with 175 additions and 81 deletions

View File

@ -38,8 +38,8 @@ use self::{
air::Air, air::Air,
builder::{ builder::{
cast_validator_args, convert_type_to_data, lookup_data_type_by_tipo, modify_self_calls, cast_validator_args, convert_type_to_data, lookup_data_type_by_tipo, modify_self_calls,
rearrange_clauses, AssignmentProperties, ClauseProperties, DataTypeKey, FunctionAccessKey, rearrange_list_clauses, AssignmentProperties, ClauseProperties, DataTypeKey,
UserFunction, FunctionAccessKey, UserFunction,
}, },
tree::{AirExpression, AirTree, TreePath}, tree::{AirExpression, AirTree, TreePath},
}; };
@ -218,9 +218,12 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => {
let mut expressions = expressions.clone(); let mut expressions = expressions.clone();
let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| { assert!(
unreachable!("Sequence or Pipeline should have at least one expression") !expressions.is_empty(),
})); "Sequence or Pipeline should have at least one expression"
);
let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| unreachable!()));
while let Some(expression) = expressions.pop() { while let Some(expression) = expressions.pop() {
let exp_tree = self.build(&expression); let exp_tree = self.build(&expression);
@ -276,8 +279,8 @@ impl<'a> CodeGenerator<'a> {
}, },
.. ..
} => { } => {
let Some(data_type) = lookup_data_type_by_tipo(&self.data_types, tipo) let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
else {unreachable!("Creating a record with no record definition.")}; .expect("Creating a record with no record definition.");
let (constr_index, _) = data_type let (constr_index, _) = data_type
.constructors .constructors
@ -299,7 +302,12 @@ impl<'a> CodeGenerator<'a> {
}, },
.. ..
} => { } => {
let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; let fun_arg_types = fun
.tipo()
.arg_types()
.expect("Expected a function type with arguments");
assert!(args.len() == fun_arg_types.len());
let func_args = args let func_args = args
.iter() .iter()
@ -331,7 +339,12 @@ impl<'a> CodeGenerator<'a> {
let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant else {unreachable!("Missing module function definition")}; let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant else {unreachable!("Missing module function definition")};
let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; let fun_arg_types = fun
.tipo()
.arg_types()
.expect("Expected a function type with arguments");
assert!(args.len() == fun_arg_types.len());
let func_args = args let func_args = args
.iter() .iter()
@ -353,7 +366,12 @@ impl<'a> CodeGenerator<'a> {
} }
} }
_ => { _ => {
let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; let fun_arg_types = fun
.tipo()
.arg_types()
.expect("Expected a function type with arguments");
assert!(args.len() == fun_arg_types.len());
let func_args = args let func_args = args
.iter() .iter()
@ -447,7 +465,7 @@ impl<'a> CodeGenerator<'a> {
assignment.hoist_over(clause_then) assignment.hoist_over(clause_then)
} else { } else {
clauses = if subject.tipo().is_list() { clauses = if subject.tipo().is_list() {
rearrange_clauses(clauses) rearrange_list_clauses(clauses)
} else { } else {
clauses clauses
}; };
@ -478,6 +496,7 @@ impl<'a> CodeGenerator<'a> {
); );
let constr_assign = AirTree::let_assignment(&constr_var, self.build(subject)); let constr_assign = AirTree::let_assignment(&constr_var, self.build(subject));
let when_assign = AirTree::when( let when_assign = AirTree::when(
subject_name, subject_name,
tipo.clone(), tipo.clone(),
@ -535,9 +554,7 @@ impl<'a> CodeGenerator<'a> {
location: Span::empty(), location: Span::empty(),
module: module_name.clone(), module: module_name.clone(),
constructors_count: data_type constructors_count: data_type
.unwrap_or_else(|| { .expect("Created a module type without a definition?")
unreachable!("Created a module type without a definition?")
})
.constructors .constructors
.len() as u16, .len() as u16,
}, },
@ -552,6 +569,7 @@ impl<'a> CodeGenerator<'a> {
}); });
let type_info = self.module_types.get(module_name).unwrap(); let type_info = self.module_types.get(module_name).unwrap();
let value = type_info.values.get(name).unwrap(); let value = type_info.values.get(name).unwrap();
if let Some(_func) = func { if let Some(_func) = func {
@ -643,6 +661,7 @@ impl<'a> CodeGenerator<'a> {
"__expected_by_{}_span_{}_{}", "__expected_by_{}_span_{}_{}",
expected_int, location.start, location.end expected_int, location.start, location.end
); );
let assignment = AirTree::let_assignment(&name, value); let assignment = AirTree::let_assignment(&name, value);
let expect = AirTree::binop( let expect = AirTree::binop(
@ -660,9 +679,11 @@ impl<'a> CodeGenerator<'a> {
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
if props.full_check { if props.full_check {
let mut index_map = IndexMap::new(); let mut index_map = IndexMap::new();
let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types); let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types);
let assignment = AirTree::let_assignment(name, value); let assignment = AirTree::let_assignment(name, value);
let val = AirTree::local_var(name, tipo.clone()); let val = AirTree::local_var(name, tipo.clone());
if tipo.is_primitive() { if tipo.is_primitive() {
@ -676,6 +697,7 @@ impl<'a> CodeGenerator<'a> {
); );
let assign_expect = AirTree::let_assignment("_", expect); let assign_expect = AirTree::let_assignment("_", expect);
AirTree::let_assignment( AirTree::let_assignment(
name, name,
assignment.hoist_over(assign_expect.hoist_over(val)), assignment.hoist_over(assign_expect.hoist_over(val)),
@ -688,6 +710,7 @@ impl<'a> CodeGenerator<'a> {
Pattern::Assign { name, pattern, .. } => { Pattern::Assign { name, pattern, .. } => {
let inner_pattern = let inner_pattern =
self.assignment(pattern, AirTree::local_var(name, tipo.clone()), tipo, props); self.assignment(pattern, AirTree::local_var(name, tipo.clone()), tipo, props);
let assign = AirTree::let_assignment(name, value); let assign = AirTree::let_assignment(name, value);
AirTree::UnhoistedSequence(vec![assign, inner_pattern]) AirTree::UnhoistedSequence(vec![assign, inner_pattern])
@ -696,9 +719,13 @@ impl<'a> CodeGenerator<'a> {
if props.full_check { if props.full_check {
let name = &format!("__discard_expect_{}", name); let name = &format!("__discard_expect_{}", name);
let mut index_map = IndexMap::new(); let mut index_map = IndexMap::new();
let tipo = convert_opaque_type(tipo, &self.data_types); let tipo = convert_opaque_type(tipo, &self.data_types);
let assignment = AirTree::let_assignment(name, value); let assignment = AirTree::let_assignment(name, value);
let val = AirTree::local_var(name, tipo.clone()); let val = AirTree::local_var(name, tipo.clone());
if tipo.is_primitive() { if tipo.is_primitive() {
AirTree::let_assignment(name, assignment.hoist_over(val)) AirTree::let_assignment(name, assignment.hoist_over(val))
} else { } else {
@ -710,6 +737,7 @@ impl<'a> CodeGenerator<'a> {
); );
let assign_expect = AirTree::let_assignment("_", expect); let assign_expect = AirTree::let_assignment("_", expect);
AirTree::let_assignment( AirTree::let_assignment(
name, name,
assignment.hoist_over(assign_expect.hoist_over(val)), assignment.hoist_over(assign_expect.hoist_over(val)),
@ -724,6 +752,7 @@ impl<'a> CodeGenerator<'a> {
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
assert!(tipo.is_list()); assert!(tipo.is_list());
assert!(props.kind.is_expect()); assert!(props.kind.is_expect());
let list_elem_types = tipo.get_inner_types(); let list_elem_types = tipo.get_inner_types();
let list_elem_type = list_elem_types let list_elem_type = list_elem_types
@ -843,7 +872,9 @@ impl<'a> CodeGenerator<'a> {
} else { } else {
if props.kind.is_expect() { if props.kind.is_expect() {
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo) let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
.unwrap_or_else(|| panic!("Failed to find definition for {}", name)); .unwrap_or_else(|| {
unreachable!("Failed to find definition for {}", name)
});
if data_type.constructors.len() > 1 || props.full_check { if data_type.constructors.len() > 1 || props.full_check {
let (index, _) = data_type let (index, _) = data_type
@ -885,11 +916,19 @@ impl<'a> CodeGenerator<'a> {
let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new(); let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new();
for (index, arg) in constr_tipo.arg_types().unwrap().iter().enumerate() { for (index, arg) in constr_tipo
.arg_types()
.expect("Mismatched type")
.iter()
.enumerate()
{
let field_type = arg.clone(); let field_type = arg.clone();
type_map.insert(index, field_type); type_map.insert(index, field_type);
} }
assert!(type_map.len() == arguments.len());
let fields = arguments let fields = arguments
.iter() .iter()
.enumerate() .enumerate()
@ -979,7 +1018,7 @@ impl<'a> CodeGenerator<'a> {
type_map.insert(index, field_type); type_map.insert(index, field_type);
} }
println!("TIPO {:#?}", tipo); assert!(type_map.len() == elems.len());
let elems = elems let elems = elems
.iter() .iter()
@ -1055,13 +1094,16 @@ impl<'a> CodeGenerator<'a> {
location: Span, location: Span,
) -> AirTree { ) -> AirTree {
assert!(tipo.get_generic().is_none()); assert!(tipo.get_generic().is_none());
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
value value
} else if tipo.is_map() { } else if tipo.is_map() {
assert!(!tipo.get_inner_types().is_empty()); assert!(!tipo.get_inner_types().is_empty());
let inner_list_type = &tipo.get_inner_types()[0]; let inner_list_type = &tipo.get_inner_types()[0];
let inner_pair_types = inner_list_type.get_inner_types(); let inner_pair_types = inner_list_type.get_inner_types();
assert!(inner_pair_types.len() == 2); assert!(inner_pair_types.len() == 2);
let map_name = format!("__map_span_{}_{}", location.start, location.end); let map_name = format!("__map_span_{}_{}", location.start, location.end);
@ -1142,6 +1184,7 @@ impl<'a> CodeGenerator<'a> {
assign.hoist_over(func_call) assign.hoist_over(func_call)
} else if tipo.is_list() { } else if tipo.is_list() {
assert!(!tipo.get_inner_types().is_empty()); assert!(!tipo.get_inner_types().is_empty());
let inner_list_type = &tipo.get_inner_types()[0]; let inner_list_type = &tipo.get_inner_types()[0];
let list_name = format!("__list_span_{}_{}", location.start, location.end); let list_name = format!("__list_span_{}_{}", location.start, location.end);
@ -1206,6 +1249,8 @@ impl<'a> CodeGenerator<'a> {
} else if tipo.is_2_tuple() { } else if tipo.is_2_tuple() {
let tuple_inner_types = tipo.get_inner_types(); let tuple_inner_types = tipo.get_inner_types();
assert!(tuple_inner_types.len() == 2);
let pair_name = format!("__pair_span_{}_{}", location.start, location.end); let pair_name = format!("__pair_span_{}_{}", location.start, location.end);
let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end); let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end);
@ -1243,6 +1288,8 @@ impl<'a> CodeGenerator<'a> {
} else if tipo.is_tuple() { } else if tipo.is_tuple() {
let tuple_inner_types = tipo.get_inner_types(); let tuple_inner_types = tipo.get_inner_types();
assert!(!tuple_inner_types.is_empty());
let tuple_name = format!("__tuple_span_{}_{}", location.start, location.end); let tuple_name = format!("__tuple_span_{}_{}", location.start, location.end);
let tuple_assign = AirTree::let_assignment(&tuple_name, value); let tuple_assign = AirTree::let_assignment(&tuple_name, value);
@ -1293,7 +1340,7 @@ impl<'a> CodeGenerator<'a> {
AirTree::UnhoistedSequence(sequence).hoist_over(AirTree::void()) AirTree::UnhoistedSequence(sequence).hoist_over(AirTree::void())
} else { } else {
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| { let data_type = lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| {
unreachable!("We need a data type definition fot type {:#?}", tipo) unreachable!("We need a data type definition for type {:#?}", tipo)
}); });
let data_type_variant = tipo let data_type_variant = tipo
@ -1302,6 +1349,8 @@ impl<'a> CodeGenerator<'a> {
.map(|arg| get_arg_type_name(arg)) .map(|arg| get_arg_type_name(arg))
.join("_"); .join("_");
assert!(data_type.typed_parameters.len() == tipo.arg_types().unwrap().len());
let mono_types: IndexMap<u64, Arc<Type>> = if !data_type.typed_parameters.is_empty() { let mono_types: IndexMap<u64, Arc<Type>> = if !data_type.typed_parameters.is_empty() {
data_type data_type
.typed_parameters .typed_parameters
@ -1484,8 +1533,10 @@ impl<'a> CodeGenerator<'a> {
if let Some((clause, rest_clauses)) = clauses.split_first() { if let Some((clause, rest_clauses)) = clauses.split_first() {
let mut clause_then = self.build(&clause.then); let mut clause_then = self.build(&clause.then);
// handles clause guard if it exists
if let Some(guard) = &clause.guard { if let Some(guard) = &clause.guard {
props.complex_clause = true; props.complex_clause = true;
let clause_guard_name = format!( let clause_guard_name = format!(
"__clause_guard_span_{}_{}", "__clause_guard_span_{}_{}",
clause.location.start, clause.location.end clause.location.start, clause.location.end
@ -1546,6 +1597,9 @@ impl<'a> CodeGenerator<'a> {
) )
} }
} else { } else {
// Case of ByteArray or Int or Bool matches
assert!(subject_tipo.is_primitive());
AirTree::clause( AirTree::clause(
&props.original_subject_name, &props.original_subject_name,
clause_cond, clause_cond,
@ -1564,7 +1618,19 @@ impl<'a> CodeGenerator<'a> {
SpecificClause::ListClause { SpecificClause::ListClause {
current_index, current_index,
defined_tails, defined_tails,
checked_index,
} => { } => {
let mut clause_pattern = &clause.pattern;
if let Pattern::Assign { pattern, .. } = clause_pattern {
clause_pattern = pattern;
}
assert!(matches!(
clause_pattern,
Pattern::List { .. } | Pattern::Var { .. } | Pattern::Discard { .. }
));
let Pattern::List { elements, tail, .. } = &clause.pattern let Pattern::List { elements, tail, .. } = &clause.pattern
else { else {
let mut next_clause_props = ClauseProperties { let mut next_clause_props = ClauseProperties {
@ -1576,6 +1642,7 @@ impl<'a> CodeGenerator<'a> {
specific_clause: SpecificClause::ListClause { specific_clause: SpecificClause::ListClause {
current_index: *current_index, current_index: *current_index,
defined_tails: defined_tails.clone(), defined_tails: defined_tails.clone(),
checked_index: *checked_index,
}, },
}; };
@ -1595,31 +1662,37 @@ impl<'a> CodeGenerator<'a> {
); );
}; };
let mut tail_name = if *current_index == 0 { let tail_name = defined_tails
props.original_subject_name.clone() .last()
} else { .cloned()
format!( .unwrap_or(props.original_subject_name.clone());
"tail_index_{}_span_{}_{}",
*current_index,
clause.pattern.location().start,
clause.pattern.location().end
)
};
let next_tail_name = { let next_tail_name = {
if rest_clauses.is_empty() { if rest_clauses.is_empty() {
None None
} else { } else {
let next_clause = &rest_clauses[0]; let next_clause = &rest_clauses[0];
let next_elements_len = match &next_clause.pattern { let next_elements_len = match &next_clause.pattern {
Pattern::List { elements, .. } => elements.len(), Pattern::List { elements, tail, .. } => {
elements.len() - usize::from(tail.is_some())
}
_ => 0, _ => 0,
}; };
if (*current_index as usize) < next_elements_len { if (*current_index as usize) < next_elements_len {
*current_index += 1;
defined_tails.push(format!(
"tail_index_{}_span_{}_{}",
*current_index,
clause.pattern.location().start,
clause.pattern.location().end
));
Some(format!( Some(format!(
"tail_index_{}_span_{}_{}", "tail_index_{}_span_{}_{}",
*current_index + 1, *current_index,
next_clause.pattern.location().start, next_clause.pattern.location().start,
next_clause.pattern.location().end next_clause.pattern.location().end
)) ))
@ -1629,16 +1702,21 @@ impl<'a> CodeGenerator<'a> {
} }
}; };
if elements.len() - usize::from(tail.is_some() && !elements.is_empty()) let mut is_wild_card_elems_clause = clause.guard.is_none();
>= *current_index as usize for elements in elements.iter() {
if let Pattern::Constructor { .. }
| Pattern::Tuple { .. }
| Pattern::List { .. } = elements
{ {
*current_index += 1; is_wild_card_elems_clause = false;
defined_tails.push(tail_name.clone()); }
} else if next_tail_name.is_none() { }
tail_name = defined_tails let elements_len = elements.len() - usize::from(tail.is_some());
.last()
.cloned() if *checked_index < elements_len.try_into().unwrap()
.unwrap_or(props.original_subject_name.clone()); && is_wild_card_elems_clause
{
*checked_index += 1;
} }
let mut next_clause_props = ClauseProperties { let mut next_clause_props = ClauseProperties {
@ -1650,6 +1728,7 @@ impl<'a> CodeGenerator<'a> {
specific_clause: SpecificClause::ListClause { specific_clause: SpecificClause::ListClause {
current_index: *current_index, current_index: *current_index,
defined_tails: defined_tails.clone(), defined_tails: defined_tails.clone(),
checked_index: *checked_index,
}, },
}; };
@ -1660,6 +1739,7 @@ impl<'a> CodeGenerator<'a> {
let complex_clause = props.complex_clause; let complex_clause = props.complex_clause;
// TODO: stuff
AirTree::list_clause( AirTree::list_clause(
tail_name, tail_name,
subject_tipo.clone(), subject_tipo.clone(),
@ -1734,7 +1814,9 @@ impl<'a> CodeGenerator<'a> {
} else { } else {
// handle final_clause // handle final_clause
props.final_clause = true; props.final_clause = true;
assert!(final_clause.guard.is_none()); assert!(final_clause.guard.is_none());
let clause_then = self.build(&final_clause.then); let clause_then = self.build(&final_clause.then);
let (condition, assignments) = let (condition, assignments) =
self.clause_pattern(&final_clause.pattern, subject_tipo, props); self.clause_pattern(&final_clause.pattern, subject_tipo, props);
@ -2190,6 +2272,7 @@ impl<'a> CodeGenerator<'a> {
SpecificClause::ListClause { SpecificClause::ListClause {
current_index, current_index,
defined_tails, defined_tails,
..
}, },
.. ..
} = props } = props

View File

@ -100,6 +100,7 @@ pub enum SpecificClause {
ListClause { ListClause {
current_index: i64, current_index: i64,
defined_tails: Vec<String>, defined_tails: Vec<String>,
checked_index: i64,
}, },
TupleClause { TupleClause {
defined_tuple_indices: IndexSet<(usize, String)>, defined_tuple_indices: IndexSet<(usize, String)>,
@ -118,6 +119,7 @@ impl ClauseProperties {
specific_clause: SpecificClause::ListClause { specific_clause: SpecificClause::ListClause {
current_index: 0, current_index: 0,
defined_tails: vec![], defined_tails: vec![],
checked_index: -1,
}, },
} }
} else if t.is_tuple() { } else if t.is_tuple() {
@ -159,6 +161,7 @@ impl ClauseProperties {
specific_clause: SpecificClause::ListClause { specific_clause: SpecificClause::ListClause {
current_index: 0, current_index: 0,
defined_tails: vec![], defined_tails: vec![],
checked_index: -1,
}, },
} }
} else if t.is_tuple() { } else if t.is_tuple() {
@ -598,7 +601,8 @@ pub fn modify_self_calls(air_tree: &mut AirTree, func_key: &FunctionAccessKey, v
} }
} }
pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> { // TODO: write some tests
pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
let mut sorted_clauses = clauses; let mut sorted_clauses = clauses;
// if we have a list sort clauses so we can plug holes for cases not covered by clauses // if we have a list sort clauses so we can plug holes for cases not covered by clauses
@ -610,7 +614,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
.sorted_by(|(index1, clause1), (index2, clause2)| { .sorted_by(|(index1, clause1), (index2, clause2)| {
let clause1_len = match &clause1.pattern { let clause1_len = match &clause1.pattern {
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
Some(elements.len() + usize::from(tail.is_some())) Some(elements.len() + usize::from(tail.is_some() && clause1.guard.is_none()))
} }
_ if clause1.guard.is_none() => Some(100000), _ if clause1.guard.is_none() => Some(100000),
_ => None, _ => None,
@ -618,7 +622,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
let clause2_len = match &clause2.pattern { let clause2_len = match &clause2.pattern {
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
Some(elements.len() + usize::from(tail.is_some())) Some(elements.len() + usize::from(tail.is_some() && clause2.guard.is_none()))
} }
_ if clause2.guard.is_none() => Some(100001), _ if clause2.guard.is_none() => Some(100001),
_ => None, _ => None,
@ -635,15 +639,15 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
.map(|(_, item)| item) .map(|(_, item)| item)
.collect_vec(); .collect_vec();
let mut elems_len = 0;
let mut final_clauses = sorted_clauses.clone(); let mut final_clauses = sorted_clauses.clone();
let mut holes_to_fill = vec![]; let mut holes_to_fill = vec![];
let mut last_clause_index = 0; let mut last_clause_index = 0;
let mut last_clause_set = false; let mut last_clause_set = false;
let mut wild_card_clause_elems = 0;
// If we have a catch all, use that. Otherwise use todo which will result in error // If we have a catch all, use that. Otherwise use todo which will result in error
// TODO: fill in todo label with description // TODO: fill in todo label with description
let plug_in_then = |index: usize, last_clause: &TypedClause| { let plug_in_then = &|index: usize, last_clause: &TypedClause| {
if last_clause.guard.is_none() { if last_clause.guard.is_none() {
match &last_clause.pattern { match &last_clause.pattern {
Pattern::Var { .. } | Pattern::Discard { .. } => last_clause.clone().then, Pattern::Var { .. } | Pattern::Discard { .. } => last_clause.clone().then,
@ -692,14 +696,29 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
}; };
for (index, clause) in sorted_clauses.iter().enumerate() { for (index, clause) in sorted_clauses.iter().enumerate() {
if let Pattern::List { elements, .. } = &clause.pattern { if last_clause_set {
continue;
}
let mut clause_pattern = &clause.pattern;
if let Pattern::Assign { pattern, .. } = clause_pattern {
clause_pattern = pattern;
}
assert!(matches!(
clause_pattern,
Pattern::List { .. } | Pattern::Var { .. } | Pattern::Discard { .. }
));
if let Pattern::List { elements, tail, .. } = &clause.pattern {
// found a hole and now we plug it // found a hole and now we plug it
while elems_len < elements.len() { while wild_card_clause_elems < elements.len() - usize::from(tail.is_some()) {
let mut discard_elems = vec![]; let mut discard_elems = vec![];
for _ in 0..elems_len { for _ in 0..wild_card_clause_elems {
discard_elems.push(Pattern::Discard { discard_elems.push(Pattern::Discard {
name: "_".to_string(), name: "__fill".to_string(),
location: Span::empty(), location: Span::empty(),
}); });
} }
@ -719,7 +738,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
.into(), .into(),
}, },
guard: None, guard: None,
then: plug_in_then(elems_len, last_clause), then: plug_in_then(wild_card_clause_elems, last_clause),
} }
} else { } else {
TypedClause { TypedClause {
@ -730,44 +749,38 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
tail: None, tail: None,
}, },
guard: None, guard: None,
then: plug_in_then(elems_len, last_clause), then: plug_in_then(wild_card_clause_elems, last_clause),
} }
}; };
holes_to_fill.push((index, clause_to_fill)); holes_to_fill.push((index, clause_to_fill));
elems_len += 1; wild_card_clause_elems += 1;
}
let mut is_wild_card_elems_clause = clause.guard.is_none();
for elements in elements.iter() {
if let Pattern::Constructor { .. } | Pattern::Tuple { .. } | Pattern::List { .. } =
elements
{
is_wild_card_elems_clause = false;
} }
} }
// if we have a pattern with no clause guards and a tail then no lists will get past here to other clauses if is_wild_card_elems_clause {
wild_card_clause_elems += 1;
if clause.guard.is_none() && tail.is_some() {
last_clause_index = index;
last_clause_set = true;
}
}
} else if let Pattern::Var { .. } | Pattern::Discard { .. } = &clause.pattern {
if clause.guard.is_none() { if clause.guard.is_none() {
match &clause.pattern {
Pattern::Var { .. } => {
last_clause_index = index + 1;
last_clause_set = true; last_clause_set = true;
last_clause_index = index;
} }
Pattern::Discard { .. } => { } else {
last_clause_index = index + 1; unreachable!("Found a clause that is not a list or var or discard");
last_clause_set = true;
}
Pattern::List {
elements,
tail: Some(tail),
..
} => {
let mut elements = elements.clone();
elements.push(*tail.clone());
if elements.iter().all(|element| {
matches!(element, Pattern::Var { .. } | Pattern::Discard { .. })
}) && !last_clause_set
&& !elements.is_empty()
{
last_clause_index = index + 1;
last_clause_set = true;
}
}
_ => {}
}
} }
// If the last condition doesn't have a catch all or tail then add a catch all with a todo // If the last condition doesn't have a catch all or tail then add a catch all with a todo
@ -784,8 +797,6 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
}); });
} }
} }
elems_len += 1;
} }
// Encountered a tail so stop there with that as last clause // Encountered a tail so stop there with that as last clause