Finishing up codegen changes for pair
This commit is contained in:
parent
963d275bb8
commit
a8c8cf41cf
|
@ -1085,33 +1085,161 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
}
|
||||
}
|
||||
// Pairs overlap by using the Constructor pattern type
|
||||
// The logic is slightly different for pairs
|
||||
Pattern::Constructor {
|
||||
arguments,
|
||||
constructor: PatternConstructor::Record { name, field_map },
|
||||
tipo: constr_tipo,
|
||||
..
|
||||
} if tipo.is_pair() => {
|
||||
// Constr and Pair execution branch
|
||||
let field_map = field_map.clone();
|
||||
|
||||
let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
|
||||
|
||||
for (index, arg) in constr_tipo.get_inner_types().iter().enumerate() {
|
||||
let field_type = arg.clone();
|
||||
|
||||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
assert!(type_map.len() >= arguments.len());
|
||||
|
||||
let mut fields = vec![];
|
||||
|
||||
let then = arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rfold(then, |then, (index, arg)| {
|
||||
let label = arg.label.clone().unwrap_or_default();
|
||||
|
||||
let field_index = if let Some(field_map) = &field_map {
|
||||
*field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index)
|
||||
} else {
|
||||
index
|
||||
};
|
||||
|
||||
let field_name = match &arg.value {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.full_check {
|
||||
format!("__discard_{}_{}", name, index)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"field_{}_span_{}_{}",
|
||||
field_index,
|
||||
arg.value.location().start,
|
||||
arg.value.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
|
||||
unreachable!(
|
||||
"Missing type for field {} of constr {}",
|
||||
field_index, name
|
||||
)
|
||||
});
|
||||
|
||||
let val = AirTree::local_var(&field_name, arg_type.clone());
|
||||
|
||||
let then = if field_name != "_" {
|
||||
self.assignment(
|
||||
&arg.value,
|
||||
val,
|
||||
then,
|
||||
arg_type,
|
||||
AssignmentProperties {
|
||||
value_type: arg_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
msg_func: props.msg_func.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
then
|
||||
};
|
||||
|
||||
fields.push((field_index, field_name, arg_type.clone()));
|
||||
|
||||
then
|
||||
});
|
||||
|
||||
fields.reverse();
|
||||
|
||||
// This `value` is either value param that was passed in or
|
||||
// local var
|
||||
let constructor_name = format!(
|
||||
"__constructor_{}_span_{}_{}",
|
||||
name,
|
||||
pattern.location().start,
|
||||
pattern.location().end
|
||||
);
|
||||
|
||||
let local_value = AirTree::local_var(&constructor_name, tipo.clone());
|
||||
|
||||
let then = {
|
||||
let (is_expect, msg) = if props.full_check {
|
||||
(true, props.msg_func.clone())
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
assert!(fields.len() == 2);
|
||||
|
||||
AirTree::pair_access(
|
||||
fields
|
||||
.first()
|
||||
.map(|x| if x.1 == "_" { None } else { Some(x.1.clone()) })
|
||||
.unwrap(),
|
||||
fields
|
||||
.last()
|
||||
.map(|x| if x.1 == "_" { None } else { Some(x.1.clone()) })
|
||||
.unwrap(),
|
||||
tipo.clone(),
|
||||
local_value,
|
||||
msg,
|
||||
is_expect,
|
||||
then,
|
||||
)
|
||||
};
|
||||
|
||||
AirTree::let_assignment(constructor_name, value, then)
|
||||
}
|
||||
|
||||
Pattern::Constructor {
|
||||
constructor: PatternConstructor::Record { name, .. },
|
||||
..
|
||||
} if tipo.is_bool() => {
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
AirTree::assert_bool(name == "True", value, props.msg_func, then)
|
||||
}
|
||||
|
||||
Pattern::Constructor { .. } if tipo.is_void() => {
|
||||
// Void type is checked when casting from data
|
||||
// So we just assign the value and move on
|
||||
AirTree::let_assignment("_", value, then)
|
||||
}
|
||||
|
||||
Pattern::Constructor {
|
||||
arguments,
|
||||
constructor: PatternConstructor::Record { name, field_map },
|
||||
tipo: constr_tipo,
|
||||
..
|
||||
} => {
|
||||
// TODO: Implement Pair pattern
|
||||
if tipo.is_bool() {
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
AirTree::assert_bool(name == "True", value, props.msg_func, then)
|
||||
} else if tipo.is_void() {
|
||||
AirTree::let_assignment("_", value, then)
|
||||
} else {
|
||||
// Constr and Pair execution branch
|
||||
// Constr execution branch
|
||||
let field_map = field_map.clone();
|
||||
|
||||
let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
|
||||
|
||||
for (index, arg) in constr_tipo
|
||||
.arg_types()
|
||||
.unwrap_or_else(|| {
|
||||
// TODO refactor out pair from constr branch later
|
||||
assert!(constr_tipo.is_pair());
|
||||
|
||||
constr_tipo.get_inner_types()
|
||||
})
|
||||
.expect("Mismatched type")
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
|
@ -1201,29 +1329,6 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let then = if check_replaceable_opaque_type(tipo, &self.data_types) {
|
||||
AirTree::let_assignment(&fields[0].1, local_value, then)
|
||||
} else if tipo.is_pair() {
|
||||
let (is_expect, msg) = if props.full_check {
|
||||
(true, props.msg_func.clone())
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
assert!(fields.len() == 2);
|
||||
|
||||
AirTree::pair_access(
|
||||
fields
|
||||
.first()
|
||||
.map(|x| if x.1 == "_" { None } else { Some(x.1.clone()) })
|
||||
.unwrap(),
|
||||
fields
|
||||
.last()
|
||||
.map(|x| if x.1 == "_" { None } else { Some(x.1.clone()) })
|
||||
.unwrap(),
|
||||
tipo.clone(),
|
||||
local_value,
|
||||
msg,
|
||||
is_expect,
|
||||
then,
|
||||
)
|
||||
} else {
|
||||
let (is_expect, msg) = if props.full_check {
|
||||
(true, props.msg_func.clone())
|
||||
|
@ -1233,17 +1338,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::fields_expose(fields, local_value, msg, is_expect, then)
|
||||
};
|
||||
|
||||
// TODO: See if we can combine these two if-conditions;
|
||||
//
|
||||
// i.e. can we lift data_type assignment out of the first if?
|
||||
|
||||
let then = if props.kind.is_expect() {
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
.unwrap_or_else(|| {
|
||||
unreachable!("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 then = if props.kind.is_expect()
|
||||
&& (data_type.constructors.len() > 1 || props.full_check)
|
||||
{
|
||||
let (index, _) = data_type
|
||||
.constructors
|
||||
.iter()
|
||||
|
@ -1261,14 +1361,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
} else {
|
||||
then
|
||||
}
|
||||
} else {
|
||||
then
|
||||
};
|
||||
|
||||
AirTree::let_assignment(constructor_name, value, then)
|
||||
}
|
||||
}
|
||||
Pattern::Tuple {
|
||||
elems, location, ..
|
||||
} => {
|
||||
|
@ -1361,11 +1457,22 @@ impl<'a> CodeGenerator<'a> {
|
|||
// Shouldn't be needed but still here just in case
|
||||
// this function is called from anywhere else besides assignment
|
||||
let tipo = &convert_opaque_type(tipo, &self.data_types, true);
|
||||
let uplc_type = tipo.get_uplc_type();
|
||||
|
||||
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() {
|
||||
match uplc_type {
|
||||
UplcType::Integer
|
||||
| UplcType::String
|
||||
| UplcType::Bool
|
||||
| UplcType::ByteString
|
||||
| UplcType::Unit
|
||||
| UplcType::Bls12_381G1Element
|
||||
| UplcType::Bls12_381G2Element
|
||||
| UplcType::Bls12_381MlResult => value,
|
||||
// Untyped Data
|
||||
UplcType::Data if tipo.is_data() => value,
|
||||
|
||||
// Map type
|
||||
UplcType::List(_) if tipo.is_map() => {
|
||||
assert!(!tipo.get_inner_types().is_empty());
|
||||
|
||||
let inner_list_type = &tipo.get_inner_types()[0];
|
||||
|
@ -1446,115 +1553,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
);
|
||||
|
||||
AirTree::let_assignment(&map_name, value, func_call)
|
||||
} else if tipo.is_list() {
|
||||
assert!(!tipo.get_inner_types().is_empty());
|
||||
|
||||
let inner_list_type = &tipo.get_inner_types()[0];
|
||||
|
||||
if inner_list_type.is_data() {
|
||||
value
|
||||
} else {
|
||||
let list_name = format!("__list_span_{}_{}", location.start, location.end);
|
||||
let item_name = format!("__item_span_{}_{}", location.start, location.end);
|
||||
|
||||
let expect_item = self.expect_type_assign(
|
||||
inner_list_type,
|
||||
AirTree::cast_from_data(
|
||||
AirTree::local_var(&item_name, data()),
|
||||
inner_list_type.clone(),
|
||||
msg_func.clone(),
|
||||
),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func,
|
||||
);
|
||||
|
||||
let anon_func_body = expect_item;
|
||||
|
||||
let unwrap_function = AirTree::anon_func(vec![item_name], anon_func_body);
|
||||
|
||||
let function = self.code_gen_functions.get(EXPECT_ON_LIST);
|
||||
|
||||
if function.is_none() {
|
||||
let expect_list_func = AirTree::expect_on_list();
|
||||
self.code_gen_functions.insert(
|
||||
EXPECT_ON_LIST.to_string(),
|
||||
CodeGenFunction::Function {
|
||||
body: expect_list_func,
|
||||
params: vec!["__list_to_check".to_string(), "__check_with".to_string()],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) {
|
||||
*counter += 1
|
||||
} else {
|
||||
defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1);
|
||||
}
|
||||
|
||||
let func_call = AirTree::call(
|
||||
AirTree::var(
|
||||
ValueConstructor::public(
|
||||
void(),
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
name: EXPECT_ON_LIST.to_string(),
|
||||
field_map: None,
|
||||
module: "".to_string(),
|
||||
arity: 1,
|
||||
location,
|
||||
builtin: None,
|
||||
},
|
||||
),
|
||||
EXPECT_ON_LIST,
|
||||
"",
|
||||
),
|
||||
void(),
|
||||
vec![
|
||||
AirTree::local_var(&list_name, tipo.clone()),
|
||||
unwrap_function,
|
||||
],
|
||||
);
|
||||
|
||||
AirTree::let_assignment(&list_name, value, func_call)
|
||||
}
|
||||
} else if tipo.is_pair() {
|
||||
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);
|
||||
let snd_name = format!("__pair_snd_span_{}_{}", location.start, location.end);
|
||||
|
||||
let expect_fst = self.expect_type_assign(
|
||||
&tuple_inner_types[0],
|
||||
AirTree::local_var(fst_name.clone(), tuple_inner_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type_assign(
|
||||
&tuple_inner_types[1],
|
||||
AirTree::local_var(snd_name.clone(), tuple_inner_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let pair_access = AirTree::pair_access(
|
||||
Some(fst_name.clone()),
|
||||
Some(snd_name.clone()),
|
||||
tipo.clone(),
|
||||
AirTree::local_var(&pair_name, tipo.clone()),
|
||||
msg_func.clone(),
|
||||
true,
|
||||
AirTree::let_assignment("_", expect_fst, expect_snd),
|
||||
);
|
||||
|
||||
AirTree::let_assignment(&pair_name, value, pair_access)
|
||||
} else if tipo.is_tuple() {
|
||||
// Tuple type
|
||||
UplcType::List(_) if tipo.is_tuple() => {
|
||||
let tuple_inner_types = tipo.get_inner_types();
|
||||
|
||||
assert!(!tuple_inner_types.is_empty());
|
||||
|
@ -1597,10 +1598,127 @@ impl<'a> CodeGenerator<'a> {
|
|||
);
|
||||
|
||||
AirTree::let_assignment(&tuple_name, value, tuple_access)
|
||||
}
|
||||
// Regular List type
|
||||
UplcType::List(_) => {
|
||||
assert!(!tipo.get_inner_types().is_empty());
|
||||
|
||||
// Constructor
|
||||
let inner_list_type = &tipo.get_inner_types()[0];
|
||||
|
||||
if inner_list_type.is_data() {
|
||||
value
|
||||
} else {
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| {
|
||||
let list_name = format!("__list_span_{}_{}", location.start, location.end);
|
||||
let item_name = format!("__item_span_{}_{}", location.start, location.end);
|
||||
|
||||
let expect_item = self.expect_type_assign(
|
||||
inner_list_type,
|
||||
AirTree::cast_from_data(
|
||||
AirTree::local_var(&item_name, data()),
|
||||
inner_list_type.clone(),
|
||||
msg_func.clone(),
|
||||
),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func,
|
||||
);
|
||||
|
||||
let anon_func_body = expect_item;
|
||||
|
||||
let unwrap_function = AirTree::anon_func(vec![item_name], anon_func_body);
|
||||
|
||||
let function = self.code_gen_functions.get(EXPECT_ON_LIST);
|
||||
|
||||
if function.is_none() {
|
||||
let expect_list_func = AirTree::expect_on_list();
|
||||
self.code_gen_functions.insert(
|
||||
EXPECT_ON_LIST.to_string(),
|
||||
CodeGenFunction::Function {
|
||||
body: expect_list_func,
|
||||
params: vec![
|
||||
"__list_to_check".to_string(),
|
||||
"__check_with".to_string(),
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) {
|
||||
*counter += 1
|
||||
} else {
|
||||
defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1);
|
||||
}
|
||||
|
||||
let func_call = AirTree::call(
|
||||
AirTree::var(
|
||||
ValueConstructor::public(
|
||||
void(),
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
name: EXPECT_ON_LIST.to_string(),
|
||||
field_map: None,
|
||||
module: "".to_string(),
|
||||
arity: 1,
|
||||
location,
|
||||
builtin: None,
|
||||
},
|
||||
),
|
||||
EXPECT_ON_LIST,
|
||||
"",
|
||||
),
|
||||
void(),
|
||||
vec![
|
||||
AirTree::local_var(&list_name, tipo.clone()),
|
||||
unwrap_function,
|
||||
],
|
||||
);
|
||||
|
||||
AirTree::let_assignment(&list_name, value, func_call)
|
||||
}
|
||||
}
|
||||
// Pair type
|
||||
UplcType::Pair(_, _) => {
|
||||
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);
|
||||
let snd_name = format!("__pair_snd_span_{}_{}", location.start, location.end);
|
||||
|
||||
let expect_fst = self.expect_type_assign(
|
||||
&tuple_inner_types[0],
|
||||
AirTree::local_var(fst_name.clone(), tuple_inner_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type_assign(
|
||||
&tuple_inner_types[1],
|
||||
AirTree::local_var(snd_name.clone(), tuple_inner_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let pair_access = AirTree::pair_access(
|
||||
Some(fst_name.clone()),
|
||||
Some(snd_name.clone()),
|
||||
tipo.clone(),
|
||||
AirTree::local_var(&pair_name, tipo.clone()),
|
||||
msg_func.clone(),
|
||||
true,
|
||||
AirTree::let_assignment("_", expect_fst, expect_snd),
|
||||
);
|
||||
|
||||
AirTree::let_assignment(&pair_name, value, pair_access)
|
||||
}
|
||||
|
||||
// Constr type
|
||||
UplcType::Data => {
|
||||
let data_type =
|
||||
lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| {
|
||||
unreachable!("We need a data type definition for type {:#?}", tipo)
|
||||
});
|
||||
|
||||
|
@ -1612,7 +1730,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
assert!(data_type.typed_parameters.len() == tipo.arg_types().unwrap().len());
|
||||
|
||||
let mono_types: IndexMap<u64, Rc<Type>> = if !data_type.typed_parameters.is_empty() {
|
||||
let mono_types: IndexMap<u64, Rc<Type>> = if !data_type.typed_parameters.is_empty()
|
||||
{
|
||||
data_type
|
||||
.typed_parameters
|
||||
.iter()
|
||||
|
@ -1659,7 +1778,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
let arg_name =
|
||||
arg.label.clone().unwrap_or(format!("__field_{index}"));
|
||||
|
||||
let arg_tipo = find_and_replace_generics(&arg.tipo, &mono_types);
|
||||
let arg_tipo =
|
||||
find_and_replace_generics(&arg.tipo, &mono_types);
|
||||
|
||||
constr_args.push((index, arg_name.clone(), arg_tipo.clone()));
|
||||
|
||||
|
@ -1791,6 +1911,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::call(func_var, void(), args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_each_clause(
|
||||
&mut self,
|
||||
|
@ -2131,7 +2252,27 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
}
|
||||
}
|
||||
SpecificClause::PairClause => todo!(),
|
||||
SpecificClause::PairClause => {
|
||||
let (_, pattern_assigns) =
|
||||
self.clause_pattern(&clause.pattern, subject_tipo, props, clause_then);
|
||||
|
||||
let mut next_clause_props = ClauseProperties::init(
|
||||
subject_tipo,
|
||||
props.clause_var_name.clone(),
|
||||
props.original_subject_name.clone(),
|
||||
);
|
||||
|
||||
AirTree::wrap_clause(
|
||||
pattern_assigns,
|
||||
self.handle_each_clause(
|
||||
rest_clauses,
|
||||
final_clause,
|
||||
subject_tipo,
|
||||
&mut next_clause_props,
|
||||
module_name,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// handle final_clause
|
||||
|
@ -2304,7 +2445,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
elems,
|
||||
subject_tipo.clone(),
|
||||
tail.is_some(),
|
||||
AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
|
||||
AirTree::local_var(&props.clause_var_name, subject_tipo.clone()),
|
||||
// One special usage of list access here
|
||||
// So for the msg we pass in empty string if tracing is on
|
||||
// Since check_last_item is false this will never get added to the final uplc anyway
|
||||
|
@ -2330,6 +2471,113 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
(AirTree::void(), list_assign)
|
||||
}
|
||||
|
||||
Pattern::Constructor {
|
||||
name,
|
||||
arguments,
|
||||
constructor,
|
||||
tipo: function_tipo,
|
||||
..
|
||||
} if subject_tipo.is_pair() => {
|
||||
assert!(
|
||||
matches!(function_tipo.as_ref().clone(), Type::Fn { .. })
|
||||
|| matches!(function_tipo.as_ref().clone(), Type::App { .. })
|
||||
);
|
||||
|
||||
let field_map = match constructor {
|
||||
PatternConstructor::Record { field_map, .. } => field_map.clone(),
|
||||
};
|
||||
|
||||
let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
|
||||
|
||||
for (index, arg) in function_tipo.arg_types().unwrap().iter().enumerate() {
|
||||
let field_type = arg.clone();
|
||||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
let mut fields = vec![];
|
||||
|
||||
let next_then =
|
||||
arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rfold(then, |inner_then, (index, arg)| {
|
||||
let label = arg.label.clone().unwrap_or_default();
|
||||
|
||||
let field_index = if let Some(field_map) = &field_map {
|
||||
*field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index)
|
||||
} else {
|
||||
index
|
||||
};
|
||||
|
||||
let field_name = match &arg.value {
|
||||
Pattern::Var { name, .. } => Some(name.to_string()),
|
||||
Pattern::Assign { name, .. } => Some(name.to_string()),
|
||||
Pattern::Discard { .. } => None,
|
||||
_ => Some(format!(
|
||||
"field_{}_span_{}_{}",
|
||||
field_index,
|
||||
arg.value.location().start,
|
||||
arg.value.location().end
|
||||
)),
|
||||
};
|
||||
|
||||
let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
|
||||
unreachable!(
|
||||
"Missing type for field {} of constr {}",
|
||||
field_index, name
|
||||
)
|
||||
});
|
||||
|
||||
let mut field_props = ClauseProperties::init_inner(
|
||||
arg_type,
|
||||
field_name.clone().unwrap_or_else(|| "_".to_string()),
|
||||
field_name.clone().unwrap_or_else(|| "_".to_string()),
|
||||
props.final_clause,
|
||||
);
|
||||
|
||||
let statement = if field_name.is_some() {
|
||||
self.nested_clause_condition(
|
||||
&arg.value,
|
||||
arg_type,
|
||||
&mut field_props,
|
||||
inner_then,
|
||||
)
|
||||
} else {
|
||||
inner_then
|
||||
};
|
||||
|
||||
props.complex_clause =
|
||||
props.complex_clause || field_props.complex_clause;
|
||||
|
||||
fields.push((field_name, arg_type.clone()));
|
||||
|
||||
statement
|
||||
});
|
||||
|
||||
fields.reverse();
|
||||
|
||||
let field_assign = if fields.iter().all(|s| s.0.is_none()) {
|
||||
next_then
|
||||
} else {
|
||||
AirTree::pair_access(
|
||||
fields[0].0.clone(),
|
||||
fields[1].0.clone(),
|
||||
subject_tipo.clone(),
|
||||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
None,
|
||||
false,
|
||||
next_then,
|
||||
)
|
||||
};
|
||||
|
||||
(AirTree::void(), field_assign)
|
||||
}
|
||||
|
||||
Pattern::Constructor { name, .. } if subject_tipo.is_bool() => {
|
||||
(AirTree::bool(name == "True"), then)
|
||||
}
|
||||
|
||||
Pattern::Constructor {
|
||||
name,
|
||||
arguments,
|
||||
|
@ -2337,9 +2585,6 @@ impl<'a> CodeGenerator<'a> {
|
|||
tipo: function_tipo,
|
||||
..
|
||||
} => {
|
||||
if subject_tipo.is_bool() {
|
||||
(AirTree::bool(name == "True"), then)
|
||||
} else {
|
||||
assert!(
|
||||
matches!(function_tipo.as_ref().clone(), Type::Fn { .. })
|
||||
|| matches!(function_tipo.as_ref().clone(), Type::App { .. })
|
||||
|
@ -2434,14 +2679,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
fields.reverse();
|
||||
|
||||
let field_assign =
|
||||
if check_replaceable_opaque_type(subject_tipo, &self.data_types) {
|
||||
let field_assign = if check_replaceable_opaque_type(subject_tipo, &self.data_types)
|
||||
{
|
||||
AirTree::let_assignment(
|
||||
&fields[0].1,
|
||||
AirTree::local_var(
|
||||
props.clause_var_name.clone(),
|
||||
subject_tipo.clone(),
|
||||
),
|
||||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
next_then,
|
||||
)
|
||||
} else if fields.iter().all(|s| s.1 == "_") {
|
||||
|
@ -2449,10 +2691,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else {
|
||||
AirTree::fields_expose(
|
||||
fields,
|
||||
AirTree::local_var(
|
||||
props.clause_var_name.clone(),
|
||||
subject_tipo.clone(),
|
||||
),
|
||||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
None,
|
||||
false,
|
||||
next_then,
|
||||
|
@ -2461,7 +2700,6 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
(AirTree::int(constr_index), field_assign)
|
||||
}
|
||||
}
|
||||
Pattern::Tuple { elems, .. } => {
|
||||
let items_type = subject_tipo.get_inner_types();
|
||||
|
||||
|
@ -2582,7 +2820,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::tuple_access(
|
||||
names,
|
||||
subject_tipo.clone(),
|
||||
AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
|
||||
AirTree::local_var(&props.clause_var_name, subject_tipo.clone()),
|
||||
None,
|
||||
false,
|
||||
tuple_name_assigns,
|
||||
|
@ -2724,6 +2962,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
Pattern::Constructor { .. } if subject_tipo.is_pair() => {
|
||||
let (_, assign) = self.clause_pattern(pattern, subject_tipo, props, then);
|
||||
|
||||
assign
|
||||
}
|
||||
|
||||
Pattern::Constructor {
|
||||
name: constr_name, ..
|
||||
} => {
|
||||
|
|
Loading…
Reference in New Issue