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

View File

@ -100,6 +100,7 @@ pub enum SpecificClause {
ListClause {
current_index: i64,
defined_tails: Vec<String>,
checked_index: i64,
},
TupleClause {
defined_tuple_indices: IndexSet<(usize, String)>,
@ -118,6 +119,7 @@ impl ClauseProperties {
specific_clause: SpecificClause::ListClause {
current_index: 0,
defined_tails: vec![],
checked_index: -1,
},
}
} else if t.is_tuple() {
@ -159,6 +161,7 @@ impl ClauseProperties {
specific_clause: SpecificClause::ListClause {
current_index: 0,
defined_tails: vec![],
checked_index: -1,
},
}
} 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;
// 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)| {
let clause1_len = match &clause1.pattern {
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),
_ => None,
@ -618,7 +622,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
let clause2_len = match &clause2.pattern {
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),
_ => None,
@ -635,15 +639,15 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
.map(|(_, item)| item)
.collect_vec();
let mut elems_len = 0;
let mut final_clauses = sorted_clauses.clone();
let mut holes_to_fill = vec![];
let mut last_clause_index = 0;
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
// 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() {
match &last_clause.pattern {
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() {
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
while elems_len < elements.len() {
while wild_card_clause_elems < elements.len() - usize::from(tail.is_some()) {
let mut discard_elems = vec![];
for _ in 0..elems_len {
for _ in 0..wild_card_clause_elems {
discard_elems.push(Pattern::Discard {
name: "_".to_string(),
name: "__fill".to_string(),
location: Span::empty(),
});
}
@ -719,7 +738,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
.into(),
},
guard: None,
then: plug_in_then(elems_len, last_clause),
then: plug_in_then(wild_card_clause_elems, last_clause),
}
} else {
TypedClause {
@ -730,44 +749,38 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
tail: 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));
elems_len += 1;
wild_card_clause_elems += 1;
}
}
// if we have a pattern with no clause guards and a tail then no lists will get past here to other clauses
if clause.guard.is_none() {
match &clause.pattern {
Pattern::Var { .. } => {
last_clause_index = index + 1;
last_clause_set = true;
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;
}
Pattern::Discard { .. } => {
last_clause_index = index + 1;
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 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() {
last_clause_set = true;
last_clause_index = index;
}
} else {
unreachable!("Found a clause that is not a list or var or discard");
}
// 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