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 {
|
Pattern::Constructor {
|
||||||
arguments,
|
arguments,
|
||||||
constructor: PatternConstructor::Record { name, field_map },
|
constructor: PatternConstructor::Record { name, field_map },
|
||||||
tipo: constr_tipo,
|
tipo: constr_tipo,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// TODO: Implement Pair pattern
|
// Constr execution branch
|
||||||
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
|
|
||||||
let field_map = field_map.clone();
|
let field_map = field_map.clone();
|
||||||
|
|
||||||
let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
|
let mut type_map: IndexMap<usize, Rc<Type>> = IndexMap::new();
|
||||||
|
|
||||||
for (index, arg) in constr_tipo
|
for (index, arg) in constr_tipo
|
||||||
.arg_types()
|
.arg_types()
|
||||||
.unwrap_or_else(|| {
|
.expect("Mismatched type")
|
||||||
// TODO refactor out pair from constr branch later
|
|
||||||
assert!(constr_tipo.is_pair());
|
|
||||||
|
|
||||||
constr_tipo.get_inner_types()
|
|
||||||
})
|
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
|
@ -1201,29 +1329,6 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let then = if check_replaceable_opaque_type(tipo, &self.data_types) {
|
let then = if check_replaceable_opaque_type(tipo, &self.data_types) {
|
||||||
AirTree::let_assignment(&fields[0].1, local_value, then)
|
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 {
|
} else {
|
||||||
let (is_expect, msg) = if props.full_check {
|
let (is_expect, msg) = if props.full_check {
|
||||||
(true, props.msg_func.clone())
|
(true, props.msg_func.clone())
|
||||||
|
@ -1233,17 +1338,12 @@ impl<'a> CodeGenerator<'a> {
|
||||||
AirTree::fields_expose(fields, local_value, msg, is_expect, then)
|
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)
|
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| unreachable!("Failed to find definition for {}", name));
|
||||||
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
|
let (index, _) = data_type
|
||||||
.constructors
|
.constructors
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1261,14 +1361,10 @@ impl<'a> CodeGenerator<'a> {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
then
|
then
|
||||||
}
|
|
||||||
} else {
|
|
||||||
then
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AirTree::let_assignment(constructor_name, value, then)
|
AirTree::let_assignment(constructor_name, value, then)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Pattern::Tuple {
|
Pattern::Tuple {
|
||||||
elems, location, ..
|
elems, location, ..
|
||||||
} => {
|
} => {
|
||||||
|
@ -1361,11 +1457,22 @@ impl<'a> CodeGenerator<'a> {
|
||||||
// Shouldn't be needed but still here just in case
|
// Shouldn't be needed but still here just in case
|
||||||
// this function is called from anywhere else besides assignment
|
// this function is called from anywhere else besides assignment
|
||||||
let tipo = &convert_opaque_type(tipo, &self.data_types, true);
|
let tipo = &convert_opaque_type(tipo, &self.data_types, true);
|
||||||
|
let uplc_type = tipo.get_uplc_type();
|
||||||
|
|
||||||
if tipo.is_primitive() {
|
match uplc_type {
|
||||||
// Since we would return void anyway and ignore then we can just return value here and ignore
|
UplcType::Integer
|
||||||
value
|
| UplcType::String
|
||||||
} else if tipo.is_map() {
|
| 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());
|
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];
|
||||||
|
@ -1446,115 +1553,9 @@ impl<'a> CodeGenerator<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
AirTree::let_assignment(&map_name, value, func_call)
|
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()],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
// Tuple type
|
||||||
if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) {
|
UplcType::List(_) if tipo.is_tuple() => {
|
||||||
*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() {
|
|
||||||
let tuple_inner_types = tipo.get_inner_types();
|
let tuple_inner_types = tipo.get_inner_types();
|
||||||
|
|
||||||
assert!(!tuple_inner_types.is_empty());
|
assert!(!tuple_inner_types.is_empty());
|
||||||
|
@ -1597,10 +1598,127 @@ impl<'a> CodeGenerator<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
AirTree::let_assignment(&tuple_name, value, tuple_access)
|
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 {
|
} 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)
|
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());
|
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
|
data_type
|
||||||
.typed_parameters
|
.typed_parameters
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1659,7 +1778,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let arg_name =
|
let arg_name =
|
||||||
arg.label.clone().unwrap_or(format!("__field_{index}"));
|
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()));
|
constr_args.push((index, arg_name.clone(), arg_tipo.clone()));
|
||||||
|
|
||||||
|
@ -1791,6 +1911,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
AirTree::call(func_var, void(), args)
|
AirTree::call(func_var, void(), args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_each_clause(
|
pub fn handle_each_clause(
|
||||||
&mut self,
|
&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 {
|
} else {
|
||||||
// handle final_clause
|
// handle final_clause
|
||||||
|
@ -2304,7 +2445,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
elems,
|
elems,
|
||||||
subject_tipo.clone(),
|
subject_tipo.clone(),
|
||||||
tail.is_some(),
|
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
|
// One special usage of list access here
|
||||||
// So for the msg we pass in empty string if tracing is on
|
// 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
|
// 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)
|
(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 {
|
Pattern::Constructor {
|
||||||
name,
|
name,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -2337,9 +2585,6 @@ impl<'a> CodeGenerator<'a> {
|
||||||
tipo: function_tipo,
|
tipo: function_tipo,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if subject_tipo.is_bool() {
|
|
||||||
(AirTree::bool(name == "True"), then)
|
|
||||||
} else {
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(function_tipo.as_ref().clone(), Type::Fn { .. })
|
matches!(function_tipo.as_ref().clone(), Type::Fn { .. })
|
||||||
|| matches!(function_tipo.as_ref().clone(), Type::App { .. })
|
|| matches!(function_tipo.as_ref().clone(), Type::App { .. })
|
||||||
|
@ -2434,14 +2679,11 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
fields.reverse();
|
fields.reverse();
|
||||||
|
|
||||||
let field_assign =
|
let field_assign = if check_replaceable_opaque_type(subject_tipo, &self.data_types)
|
||||||
if check_replaceable_opaque_type(subject_tipo, &self.data_types) {
|
{
|
||||||
AirTree::let_assignment(
|
AirTree::let_assignment(
|
||||||
&fields[0].1,
|
&fields[0].1,
|
||||||
AirTree::local_var(
|
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||||
props.clause_var_name.clone(),
|
|
||||||
subject_tipo.clone(),
|
|
||||||
),
|
|
||||||
next_then,
|
next_then,
|
||||||
)
|
)
|
||||||
} else if fields.iter().all(|s| s.1 == "_") {
|
} else if fields.iter().all(|s| s.1 == "_") {
|
||||||
|
@ -2449,10 +2691,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
} else {
|
} else {
|
||||||
AirTree::fields_expose(
|
AirTree::fields_expose(
|
||||||
fields,
|
fields,
|
||||||
AirTree::local_var(
|
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||||
props.clause_var_name.clone(),
|
|
||||||
subject_tipo.clone(),
|
|
||||||
),
|
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
next_then,
|
next_then,
|
||||||
|
@ -2461,7 +2700,6 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
(AirTree::int(constr_index), field_assign)
|
(AirTree::int(constr_index), field_assign)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Pattern::Tuple { elems, .. } => {
|
Pattern::Tuple { elems, .. } => {
|
||||||
let items_type = subject_tipo.get_inner_types();
|
let items_type = subject_tipo.get_inner_types();
|
||||||
|
|
||||||
|
@ -2582,7 +2820,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
AirTree::tuple_access(
|
AirTree::tuple_access(
|
||||||
names,
|
names,
|
||||||
subject_tipo.clone(),
|
subject_tipo.clone(),
|
||||||
AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
|
AirTree::local_var(&props.clause_var_name, subject_tipo.clone()),
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
tuple_name_assigns,
|
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 {
|
Pattern::Constructor {
|
||||||
name: constr_name, ..
|
name: constr_name, ..
|
||||||
} => {
|
} => {
|
||||||
|
|
Loading…
Reference in New Issue