Few more places in codegen where we need to be able to deal with Pair records

This commit is contained in:
microproofs 2024-03-29 16:05:16 -04:00 committed by Kasey
parent 26f68c2fb4
commit 3c332ca42a
3 changed files with 347 additions and 69 deletions

View File

@ -659,6 +659,12 @@ impl<'a> CodeGenerator<'a> {
} => { } => {
if check_replaceable_opaque_type(&record.tipo(), &self.data_types) { if check_replaceable_opaque_type(&record.tipo(), &self.data_types) {
self.build(record, module_build_name, &[]) self.build(record, module_build_name, &[])
} else if record.tipo().is_pair() {
AirTree::pair_index(
*index,
tipo.clone(),
self.build(record, module_build_name, &[]),
)
} else { } else {
let function_name = format!("__access_index_{}", *index); let function_name = format!("__access_index_{}", *index);
@ -708,9 +714,22 @@ impl<'a> CodeGenerator<'a> {
field_map, field_map,
.. ..
} => { } => {
let val_constructor = if tipo.is_pair() {
ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::Record {
module: "".into(),
name: name.clone(),
field_map: field_map.clone(),
arity: 2,
location: Span::empty(),
constructors_count: 1,
},
)
} else {
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo); let data_type = lookup_data_type_by_tipo(&self.data_types, tipo);
let val_constructor = ValueConstructor::public( ValueConstructor::public(
tipo.clone(), tipo.clone(),
ValueConstructorVariant::Record { ValueConstructorVariant::Record {
name: name.clone(), name: name.clone(),
@ -724,7 +743,8 @@ impl<'a> CodeGenerator<'a> {
.len() .len()
as u16, as u16,
}, },
); )
};
AirTree::var(val_constructor, name, "") AirTree::var(val_constructor, name, "")
} }
@ -772,13 +792,6 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::TupleIndex { TypedExpr::TupleIndex {
index, tuple, tipo, .. index, tuple, tipo, ..
} => { } => {
if tuple.tipo().is_pair() {
AirTree::pair_index(
*index,
tipo.clone(),
self.build(tuple, module_build_name, &[]),
)
} else {
let function_name = format!("__access_index_{}", *index); let function_name = format!("__access_index_{}", *index);
if self.code_gen_functions.get(&function_name).is_none() { if self.code_gen_functions.get(&function_name).is_none() {
@ -809,13 +822,45 @@ impl<'a> CodeGenerator<'a> {
self.build(tuple, module_build_name, &[]), self.build(tuple, module_build_name, &[]),
) )
} }
}
TypedExpr::ErrorTerm { tipo, .. } => AirTree::error(tipo.clone(), false), TypedExpr::ErrorTerm { tipo, .. } => AirTree::error(tipo.clone(), false),
TypedExpr::RecordUpdate { TypedExpr::RecordUpdate {
tipo, spread, args, .. tipo, spread, args, ..
} => { } => {
if tipo.is_pair() {
assert!(args.len() == 1);
let Some(arg) = args.first() else {
unreachable!("Pair update with no arguments")
};
let arg_val = self.build(&arg.value, module_build_name, &[]);
let other_pair = self.build(spread, module_build_name, &[]);
if arg.index == 0 {
AirTree::pair(
arg_val,
AirTree::pair_index(
1,
tipo.get_inner_types()[1].clone(),
other_pair,
),
tipo.clone(),
)
} else {
AirTree::pair(
AirTree::pair_index(
0,
tipo.get_inner_types()[0].clone(),
other_pair,
),
arg_val,
tipo.clone(),
)
}
} else {
let mut index_types = vec![]; let mut index_types = vec![];
let mut update_args = vec![]; let mut update_args = vec![];
@ -843,6 +888,7 @@ impl<'a> CodeGenerator<'a> {
update_args, update_args,
) )
} }
}
TypedExpr::UnOp { value, op, .. } => { TypedExpr::UnOp { value, op, .. } => {
AirTree::unop(*op, self.build(value, module_build_name, &[])) AirTree::unop(*op, self.build(value, module_build_name, &[]))
} }
@ -4195,6 +4241,7 @@ impl<'a> CodeGenerator<'a> {
ValueConstructorVariant::Record { ValueConstructorVariant::Record {
name: constr_name, .. name: constr_name, ..
} => { } => {
// TODO handle pair
if constructor.tipo.is_bool() { if constructor.tipo.is_bool() {
Some(Term::bool(constr_name == "True")) Some(Term::bool(constr_name == "True"))
} else if constructor.tipo.is_void() { } else if constructor.tipo.is_void() {

View File

@ -937,7 +937,7 @@ impl AirTree {
} }
} }
pub fn pair_index(index: usize, tipo: Rc<Type>, tuple: AirTree) -> AirTree { pub fn pair_index(index: u64, tipo: Rc<Type>, tuple: AirTree) -> AirTree {
AirTree::cast_from_data( AirTree::cast_from_data(
AirTree::builtin( AirTree::builtin(
if index == 0 { if index == 0 {

View File

@ -2994,7 +2994,238 @@ fn acceptance_test_28_unique_list() {
} }
#[test] #[test]
fn acceptance_test_29_union() { fn acceptance_test_29_union_pair() {
let src = r#"
type Map<a,b> = List<Pair<a,b>>
pub opaque type AssocList<key, value> {
inner: Map<key, value>,
}
pub fn new() -> AssocList<key, value> {
AssocList { inner: [] }
}
pub fn from_list(xs: Map<key, value>) -> AssocList<key, value> {
AssocList { inner: do_from_list(xs) }
}
fn do_from_list(xs: Map<key, value>) -> Map<key, value> {
when xs is {
[] ->
[]
[Pair(k, v), ..rest] ->
do_insert(do_from_list(rest), k, v)
}
}
pub fn insert(
in m: AssocList<key, value>,
key k: key,
value v: value,
) -> AssocList<key, value> {
AssocList { inner: do_insert(m.inner, k, v) }
}
fn do_insert(elems: Map<key, value>, k: key, v: value) -> Map<key, value> {
when elems is {
[] ->
[Pair(k, v)]
[Pair(k2, v2), ..rest] ->
if k == k2 {
[Pair(k, v), ..rest]
} else {
[Pair(k2, v2), ..do_insert(rest, k, v)]
}
}
}
pub fn union(
left: AssocList<key, value>,
right: AssocList<key, value>,
) -> AssocList<key, value> {
AssocList { inner: do_union(left.inner, right.inner) }
}
fn do_union(
left: Map<key, value>,
right: Map<key, value>,
) -> Map<key, value> {
when left is {
[] ->
right
[Pair{fst: k, snd: v}, ..rest] ->
do_union(rest, do_insert(right, k, v))
}
}
fn fixture_1() {
new()
|> insert("foo", 42)
|> insert("bar", 14)
}
test union_1() {
union(fixture_1(), new()) == fixture_1()
}
"#;
assert_uplc(
src,
Term::equals_data()
.apply(
Term::map_data().apply(
Term::var("union")
.lambda("union")
.apply(
Term::var("do_union")
.apply(Term::var("left"))
.apply(Term::var("right"))
.lambda("right")
.lambda("left"),
)
.lambda("do_union")
.apply(Term::var("do_union").apply(Term::var("do_union")))
.lambda("do_union")
.apply(
Term::var("left")
.delayed_choose_list(
Term::var("right"),
Term::var("do_union")
.apply(Term::var("do_union"))
.apply(Term::var("rest"))
.apply(
Term::var("do_insert")
.apply(Term::var("right"))
.apply(Term::var("k"))
.apply(Term::var("v")),
)
.lambda("v")
.apply(
Term::un_i_data()
.apply(Term::snd_pair().apply(Term::var("pair"))),
)
.lambda("k")
.apply(
Term::un_b_data()
.apply(Term::fst_pair().apply(Term::var("pair"))),
)
.lambda("rest")
.apply(Term::tail_list().apply(Term::var("left")))
.lambda("pair")
.apply(Term::head_list().apply(Term::var("left"))),
)
.lambda("right")
.lambda("left")
.lambda("do_union"),
)
.lambda("do_insert")
.apply(
Term::var("do_insert")
.apply(Term::var("do_insert"))
.apply(Term::var("elems"))
.lambda("do_insert")
.apply(
Term::var("elems")
.delayed_choose_list(
Term::mk_cons()
.apply(
Term::mk_pair_data()
.apply(Term::b_data().apply(Term::var("k")))
.apply(
Term::i_data().apply(Term::var("v")),
),
)
.apply(Term::empty_map()),
Term::equals_bytestring()
.apply(Term::var("k"))
.apply(Term::var("k2"))
.delayed_if_then_else(
Term::mk_cons()
.apply(
Term::mk_pair_data()
.apply(
Term::b_data()
.apply(Term::var("k")),
)
.apply(
Term::i_data()
.apply(Term::var("v")),
),
)
.apply(Term::var("rest")),
Term::mk_cons()
.apply(
Term::mk_pair_data()
.apply(
Term::b_data()
.apply(Term::var("k2")),
)
.apply(
Term::i_data()
.apply(Term::var("v2")),
),
)
.apply(
Term::var("do_insert")
.apply(Term::var("do_insert"))
.apply(Term::var("rest")),
),
)
.lambda("v2")
.apply(Term::un_i_data().apply(
Term::snd_pair().apply(Term::var("pair")),
))
.lambda("k2")
.apply(Term::un_b_data().apply(
Term::fst_pair().apply(Term::var("pair")),
))
.lambda("rest")
.apply(Term::tail_list().apply(Term::var("elems")))
.lambda("pair")
.apply(Term::head_list().apply(Term::var("elems"))),
)
.lambda("elems")
.lambda("do_insert"),
)
.lambda("v")
.lambda("k")
.lambda("elems"),
)
.apply(Term::map_values(vec![
Constant::ProtoPair(
Type::Data,
Type::Data,
Constant::Data(Data::bytestring("foo".as_bytes().to_vec())).into(),
Constant::Data(Data::integer(42.into())).into(),
),
Constant::ProtoPair(
Type::Data,
Type::Data,
Constant::Data(Data::bytestring("bar".as_bytes().to_vec())).into(),
Constant::Data(Data::integer(14.into())).into(),
),
]))
.apply(Term::empty_map()),
),
)
.apply(Term::data(Data::map(vec![
(
Data::bytestring("foo".as_bytes().to_vec()),
Data::integer(42.into()),
),
(
Data::bytestring("bar".as_bytes().to_vec()),
Data::integer(14.into()),
),
]))),
false,
);
}
#[test]
fn acceptance_test_29_union_tuple() {
let src = r#" let src = r#"
pub opaque type AssocList<key, value> { pub opaque type AssocList<key, value> {
inner: List<(key, value)>, inner: List<(key, value)>,