fix: found various unify and type issues while running tests
This commit is contained in:
parent
fd226be51f
commit
26f68c2fb4
|
@ -372,32 +372,42 @@ impl<'a> CodeGenerator<'a> {
|
|||
},
|
||||
..
|
||||
} => {
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
.expect("Creating a record with no record definition.");
|
||||
if tipo.is_pair() {
|
||||
assert!(args.len() == 2);
|
||||
|
||||
let (constr_index, _) = data_type
|
||||
.constructors
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, dt)| &dt.name == constr_name)
|
||||
.unwrap();
|
||||
let arg1 = self.build(&args[0].value, module_build_name, &[]);
|
||||
|
||||
let constr_args = args
|
||||
.iter()
|
||||
.zip(constr_tipo.arg_types().unwrap())
|
||||
.map(|(arg, tipo)| {
|
||||
if tipo.is_data() {
|
||||
AirTree::cast_to_data(
|
||||
self.build(&arg.value, module_build_name, &[]),
|
||||
arg.value.tipo(),
|
||||
)
|
||||
} else {
|
||||
self.build(&arg.value, module_build_name, &[])
|
||||
}
|
||||
})
|
||||
.collect_vec();
|
||||
let arg2 = self.build(&args[1].value, module_build_name, &[]);
|
||||
|
||||
AirTree::create_constr(constr_index, constr_tipo.clone(), constr_args)
|
||||
AirTree::pair(arg1, arg2, tipo.clone())
|
||||
} else {
|
||||
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
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, dt)| &dt.name == constr_name)
|
||||
.unwrap();
|
||||
|
||||
let constr_args = args
|
||||
.iter()
|
||||
.zip(constr_tipo.arg_types().unwrap())
|
||||
.map(|(arg, tipo)| {
|
||||
if tipo.is_data() {
|
||||
AirTree::cast_to_data(
|
||||
self.build(&arg.value, module_build_name, &[]),
|
||||
arg.value.tipo(),
|
||||
)
|
||||
} else {
|
||||
self.build(&arg.value, module_build_name, &[])
|
||||
}
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
AirTree::create_constr(constr_index, constr_tipo.clone(), constr_args)
|
||||
}
|
||||
}
|
||||
|
||||
TypedExpr::Var {
|
||||
|
@ -5420,12 +5430,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
match (extract_constant(&fst), extract_constant(&snd)) {
|
||||
(Some(fst), Some(snd)) => {
|
||||
let mut pair_fields = builder::convert_constants_to_data(vec![fst, snd]);
|
||||
let term = Term::Constant(
|
||||
UplcConstant::ProtoPair(
|
||||
UplcType::Data,
|
||||
UplcType::Data,
|
||||
fst.clone(),
|
||||
snd.clone(),
|
||||
pair_fields.remove(0).into(),
|
||||
pair_fields.remove(0).into(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
|
|
|
@ -695,13 +695,21 @@ pub fn pattern_has_conditions(
|
|||
Pattern::Constructor {
|
||||
arguments, tipo, ..
|
||||
} => {
|
||||
let data_type =
|
||||
lookup_data_type_by_tipo(data_types, tipo).expect("Data type not found");
|
||||
|
||||
data_type.constructors.len() > 1
|
||||
|| arguments
|
||||
if tipo.is_pair()
|
||||
|| (tipo.is_function() && tipo.return_type().map(|t| t.is_pair()).unwrap_or(false))
|
||||
{
|
||||
arguments
|
||||
.iter()
|
||||
.any(|arg| pattern_has_conditions(&arg.value, data_types))
|
||||
} else {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, tipo)
|
||||
.unwrap_or_else(|| panic!("Data type not found: {:#?}", tipo));
|
||||
|
||||
data_type.constructors.len() > 1
|
||||
|| arguments
|
||||
.iter()
|
||||
.any(|arg| pattern_has_conditions(&arg.value, data_types))
|
||||
}
|
||||
}
|
||||
Pattern::Assign { pattern, .. } => pattern_has_conditions(pattern, data_types),
|
||||
Pattern::Var { .. } | Pattern::Discard { .. } => false,
|
||||
|
|
|
@ -1495,94 +1495,172 @@ impl<'a> Environment<'a> {
|
|||
.map_err(|e| e.flip_unify());
|
||||
}
|
||||
|
||||
match (lhs.deref(), rhs.deref()) {
|
||||
(
|
||||
Type::App {
|
||||
module: m1,
|
||||
name: n1,
|
||||
args: args1,
|
||||
public: _,
|
||||
contains_opaque: _,
|
||||
alias: _,
|
||||
},
|
||||
Type::App {
|
||||
match lhs.deref() {
|
||||
Type::App {
|
||||
module: m1,
|
||||
name: n1,
|
||||
args: args1,
|
||||
public: _,
|
||||
contains_opaque: _,
|
||||
alias: _,
|
||||
} => {
|
||||
if let Type::App {
|
||||
module: m2,
|
||||
name: n2,
|
||||
args: args2,
|
||||
public: _,
|
||||
contains_opaque: _,
|
||||
alias: _,
|
||||
},
|
||||
) if m1 == m2 && n1 == n2 && args1.len() == args2.len() => {
|
||||
for (a, b) in args1.iter().zip(args2) {
|
||||
unify_enclosed_type(
|
||||
lhs.clone(),
|
||||
rhs.clone(),
|
||||
self.unify(a.clone(), b.clone(), location, false),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
(
|
||||
Type::Tuple {
|
||||
elems: elems1,
|
||||
alias: _,
|
||||
},
|
||||
Type::Tuple {
|
||||
elems: elems2,
|
||||
alias: _,
|
||||
},
|
||||
) if elems1.len() == elems2.len() => {
|
||||
for (a, b) in elems1.iter().zip(elems2) {
|
||||
unify_enclosed_type(
|
||||
lhs.clone(),
|
||||
rhs.clone(),
|
||||
self.unify(a.clone(), b.clone(), location, false),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
(
|
||||
Type::Fn {
|
||||
args: args1,
|
||||
ret: retrn1,
|
||||
alias: _,
|
||||
},
|
||||
Type::Fn {
|
||||
args: args2,
|
||||
ret: retrn2,
|
||||
alias: _,
|
||||
},
|
||||
) if args1.len() == args2.len() => {
|
||||
for (a, b) in args1.iter().zip(args2) {
|
||||
self.unify(a.clone(), b.clone(), location, allow_cast)
|
||||
.map_err(|_| Error::CouldNotUnify {
|
||||
} = rhs.deref()
|
||||
{
|
||||
if m1 == m2 && n1 == n2 && args1.len() == args2.len() {
|
||||
for (a, b) in args1.iter().zip(args2) {
|
||||
unify_enclosed_type(
|
||||
lhs.clone(),
|
||||
rhs.clone(),
|
||||
self.unify(a.clone(), b.clone(), location, false),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})?;
|
||||
}
|
||||
self.unify(retrn1.clone(), retrn2.clone(), location, false)
|
||||
.map_err(|_| Error::CouldNotUnify {
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
}),
|
||||
Type::Tuple {
|
||||
elems: elems1,
|
||||
alias: _,
|
||||
} => {
|
||||
if let Type::Tuple {
|
||||
elems: elems2,
|
||||
alias: _,
|
||||
} = rhs.deref()
|
||||
{
|
||||
if elems1.len() == elems2.len() {
|
||||
for (a, b) in elems1.iter().zip(elems2) {
|
||||
unify_enclosed_type(
|
||||
lhs.clone(),
|
||||
rhs.clone(),
|
||||
self.unify(a.clone(), b.clone(), location, false),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Type::Fn {
|
||||
args: args1,
|
||||
ret: retrn1,
|
||||
alias: _,
|
||||
} => {
|
||||
if let Type::Fn {
|
||||
args: args2,
|
||||
ret: retrn2,
|
||||
alias: _,
|
||||
} = rhs.deref()
|
||||
{
|
||||
if args1.len() == args2.len() {
|
||||
for (a, b) in args1.iter().zip(args2) {
|
||||
self.unify(a.clone(), b.clone(), location, allow_cast)
|
||||
.map_err(|_| Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})?;
|
||||
}
|
||||
self.unify(retrn1.clone(), retrn2.clone(), location, false)
|
||||
.map_err(|_| Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Type::Pair { fst, snd, alias: _ } => {
|
||||
if let Type::Pair {
|
||||
fst: fst2,
|
||||
snd: snd2,
|
||||
alias: _,
|
||||
} = rhs.deref()
|
||||
{
|
||||
unify_enclosed_type(
|
||||
lhs.clone(),
|
||||
rhs.clone(),
|
||||
self.unify(fst.clone(), fst2.clone(), location, false),
|
||||
)?;
|
||||
|
||||
unify_enclosed_type(
|
||||
lhs.clone(),
|
||||
rhs.clone(),
|
||||
self.unify(snd.clone(), snd2.clone(), location, false),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::CouldNotUnify {
|
||||
location,
|
||||
expected: lhs.clone(),
|
||||
given: rhs.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: HashMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Type::Var { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1801,7 +1879,7 @@ fn unify_unbound_type(tipo: Rc<Type>, own_id: u64, location: Span) -> Result<(),
|
|||
|
||||
Ok(())
|
||||
}
|
||||
Type::Pair { fst, snd, .. } => {
|
||||
Type::Pair { fst, snd, alias: _ } => {
|
||||
unify_unbound_type(fst.clone(), own_id, location)?;
|
||||
unify_unbound_type(snd.clone(), own_id, location)?;
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@ use std::{collections::BTreeMap, iter, ops::Deref};
|
|||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
ast, builtins,
|
||||
ast,
|
||||
builtins::{self, PAIR},
|
||||
tipo::{self, environment::Environment, error::Error},
|
||||
};
|
||||
|
||||
|
@ -563,6 +564,8 @@ pub(super) fn simplify(
|
|||
constructor: super::PatternConstructor::Record { name, .. },
|
||||
..
|
||||
} => {
|
||||
let (empty, pair) = (&"".to_string(), &PAIR.to_string());
|
||||
|
||||
let (module, type_name, arity) = match tipo.deref() {
|
||||
tipo::Type::App {
|
||||
name: type_name,
|
||||
|
@ -575,11 +578,13 @@ pub(super) fn simplify(
|
|||
module,
|
||||
..
|
||||
} => (module, type_name, args.len()),
|
||||
tipo::Type::Pair { .. } => (empty, pair, 2),
|
||||
_ => {
|
||||
unreachable!("ret should be a Type::App")
|
||||
unreachable!("ret should be a Type::App or Type::Pair")
|
||||
}
|
||||
},
|
||||
_ => unreachable!("tipo should be a Type::App"),
|
||||
tipo::Type::Pair { .. } => (empty, pair, 2),
|
||||
_ => unreachable!("tipo should be a Type::App or Type::Pair"),
|
||||
};
|
||||
|
||||
let alts = environment.get_constructors_for_type(module, type_name, *location)?;
|
||||
|
|
|
@ -680,10 +680,10 @@ fn acceptance_test_6_if_else() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_6_equals() {
|
||||
fn acceptance_test_6_equals_pair() {
|
||||
let src = r#"
|
||||
test foo() {
|
||||
(1, []) == (1, [])
|
||||
Pair(1, []) == Pair(1, [])
|
||||
}
|
||||
"#;
|
||||
|
||||
|
@ -725,7 +725,46 @@ fn acceptance_test_6_equals() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_7_unzip() {
|
||||
fn acceptance_test_6_equals_tuple() {
|
||||
let src = r#"
|
||||
test foo() {
|
||||
(1, []) == (1, [])
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
.apply(
|
||||
Term::list_data().apply(Term::Constant(
|
||||
Constant::ProtoList(
|
||||
Type::Data,
|
||||
vec![
|
||||
Constant::Data(Data::integer(1.into())),
|
||||
Constant::Data(Data::list(vec![])),
|
||||
],
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
)
|
||||
.apply(
|
||||
Term::list_data().apply(Term::Constant(
|
||||
Constant::ProtoList(
|
||||
Type::Data,
|
||||
vec![
|
||||
Constant::Data(Data::integer(1.into())),
|
||||
Constant::Data(Data::list(vec![])),
|
||||
],
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_7_unzip_tuple() {
|
||||
let src = r#"
|
||||
pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
|
||||
when xs is {
|
||||
|
@ -744,6 +783,127 @@ fn acceptance_test_7_unzip() {
|
|||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
.apply(
|
||||
Term::list_data().apply(
|
||||
Term::var("unzip")
|
||||
.lambda("unzip")
|
||||
.apply(Term::var("unzip").apply(Term::var("unzip")))
|
||||
.lambda("unzip")
|
||||
.apply(
|
||||
Term::var("xs")
|
||||
.delayed_choose_list(
|
||||
Term::list_values(vec![
|
||||
Constant::Data(Data::list(vec![])),
|
||||
Constant::Data(Data::list(vec![])),
|
||||
]),
|
||||
Term::mk_cons()
|
||||
.apply(
|
||||
Term::list_data().apply(
|
||||
Term::mk_cons()
|
||||
.apply(Term::i_data().apply(Term::var("a")))
|
||||
.apply(Term::var("a_tail")),
|
||||
),
|
||||
)
|
||||
.apply(
|
||||
Term::mk_cons()
|
||||
.apply(
|
||||
Term::list_data().apply(
|
||||
Term::mk_cons()
|
||||
.apply(
|
||||
Term::b_data()
|
||||
.apply(Term::var("b")),
|
||||
)
|
||||
.apply(Term::var("b_tail")),
|
||||
),
|
||||
)
|
||||
.apply(Term::empty_list()),
|
||||
)
|
||||
.lambda("b_tail")
|
||||
.apply(Term::unlist_data().apply(Term::head_list().apply(
|
||||
Term::tail_list().apply(Term::var("tail_tuple")),
|
||||
)))
|
||||
.lambda("a_tail")
|
||||
.apply(Term::unlist_data().apply(
|
||||
Term::head_list().apply(Term::var("tail_tuple")),
|
||||
))
|
||||
.lambda("tail_tuple")
|
||||
.apply(
|
||||
Term::var("unzip")
|
||||
.apply(Term::var("unzip"))
|
||||
.apply(Term::var("rest")),
|
||||
)
|
||||
.lambda("b")
|
||||
.apply(Term::un_b_data().apply(Term::head_list().apply(
|
||||
Term::tail_list().apply(Term::var("head_tuple")),
|
||||
)))
|
||||
.lambda("a")
|
||||
.apply(Term::un_i_data().apply(
|
||||
Term::head_list().apply(Term::var("head_tuple")),
|
||||
))
|
||||
.lambda("rest")
|
||||
.apply(Term::tail_list().apply(Term::var("xs")))
|
||||
.lambda("head_tuple")
|
||||
.apply(
|
||||
Term::unlist_data()
|
||||
.apply(Term::head_list().apply(Term::var("xs"))),
|
||||
),
|
||||
)
|
||||
.lambda("xs")
|
||||
.lambda("unzip"),
|
||||
)
|
||||
.apply(Term::var("x")),
|
||||
),
|
||||
)
|
||||
.apply(Term::list_data().apply(Term::list_values(vec![
|
||||
Constant::Data(Data::list(vec![
|
||||
Data::integer(3.into()),
|
||||
Data::integer(4.into()),
|
||||
])),
|
||||
Constant::Data(Data::list(vec![
|
||||
Data::bytestring(vec![85]),
|
||||
Data::bytestring(vec![119, 153]),
|
||||
])),
|
||||
])))
|
||||
.lambda("x")
|
||||
.apply(Term::list_values(vec![
|
||||
Constant::Data(Data::list(vec![
|
||||
Data::integer(3.into()),
|
||||
Data::bytestring(vec![85]),
|
||||
])),
|
||||
Constant::Data(Data::list(vec![
|
||||
Data::integer(4.into()),
|
||||
Data::bytestring(vec![119, 153]),
|
||||
])),
|
||||
])),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_7_unzip_pair() {
|
||||
let src = r#"
|
||||
type Map<a,b> = List<Pair<a,b>>
|
||||
|
||||
pub fn unzip(xs: Map<a, b>) -> Pair<List<a>, List<b>> {
|
||||
when xs is {
|
||||
[] -> Pair([], [])
|
||||
[Pair(a, b), ..rest] -> {
|
||||
let Pair(a_tail, b_tail) = unzip(rest)
|
||||
Pair([a, ..a_tail], [b, ..b_tail])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test unzip1() {
|
||||
let x = [Pair(3, #"55"), Pair(4, #"7799")]
|
||||
|
||||
unzip(x) == Pair([3, 4], [#"55", #"7799"])
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
|
@ -1414,7 +1574,7 @@ fn acceptance_test_14_list_creation() {
|
|||
fn acceptance_test_15_zero_arg() {
|
||||
let src = r#"
|
||||
pub opaque type Map<key, value> {
|
||||
inner: List<(key, value)>,
|
||||
inner: List<Pair<key, value>>,
|
||||
}
|
||||
|
||||
pub fn new() {
|
||||
|
@ -1956,48 +2116,51 @@ fn acceptance_test_22_filter_map() {
|
|||
#[test]
|
||||
fn acceptance_test_23_to_list() {
|
||||
let src = r#"
|
||||
pub opaque type AssocList<key, value> {
|
||||
inner: List<(key, value)>,
|
||||
}
|
||||
|
||||
pub fn new() -> AssocList<key, value> {
|
||||
AssocList { inner: [] }
|
||||
}
|
||||
|
||||
pub fn to_list(m: AssocList<key, value>) -> List<(key, value)> {
|
||||
m.inner
|
||||
}
|
||||
|
||||
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: List<(key, value)>, k: key, v: value) -> List<(key, value)> {
|
||||
when elems is {
|
||||
[] ->
|
||||
[(k, v)]
|
||||
[(k2, v2), ..rest] ->
|
||||
if k == k2 {
|
||||
[(k, v), ..rest]
|
||||
} else {
|
||||
[(k2, v2), ..do_insert(rest, k, v)]
|
||||
pub type Map<key, value> =
|
||||
List<Pair<key, value>>
|
||||
|
||||
pub opaque type AssocList<key, value> {
|
||||
inner: Map<key, value>,
|
||||
}
|
||||
|
||||
pub fn new() -> AssocList<key, value> {
|
||||
AssocList { inner: [] }
|
||||
}
|
||||
|
||||
pub fn to_list(m: AssocList<key, value>) -> Map<key, value> {
|
||||
m.inner
|
||||
}
|
||||
|
||||
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 { fst: k2, snd: v2 }, ..rest] ->
|
||||
if k == k2 {
|
||||
[Pair(k, v), ..rest]
|
||||
} else {
|
||||
[Pair(k2, v2), ..do_insert(rest, k, v)]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fixture_1() {
|
||||
new()
|
||||
|> insert("foo", 42)
|
||||
|> insert("bar", 14)
|
||||
}
|
||||
|
||||
test to_list_2() {
|
||||
to_list(fixture_1()) == [("foo", 42), ("bar", 14)]
|
||||
}
|
||||
|
||||
fn fixture_1() {
|
||||
new()
|
||||
|> insert("foo", 42)
|
||||
|> insert("bar", 14)
|
||||
}
|
||||
|
||||
test to_list_2() {
|
||||
to_list(fixture_1()) == [Pair("foo", 42), Pair("bar", 14)]
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
|
@ -2036,7 +2199,7 @@ fn acceptance_test_23_to_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_24_map2() {
|
||||
fn acceptance_test_24_map_pair() {
|
||||
let src = r#"
|
||||
pub fn map2(
|
||||
opt_a: Option<a>,
|
||||
|
@ -2057,7 +2220,7 @@ fn acceptance_test_24_map2() {
|
|||
}
|
||||
|
||||
test map2_3() {
|
||||
map2(Some(14), Some(42), fn(a, b) { (a, b) }) == Some((14, 42))
|
||||
map2(Some(14), Some(42), fn(a, b) { Pair(a, b) }) == Some(Pair(14, 42))
|
||||
}
|
||||
"#;
|
||||
|
||||
|
@ -2178,6 +2341,129 @@ fn acceptance_test_24_map2() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_24_map2() {
|
||||
let src = r#"
|
||||
pub fn map2(
|
||||
opt_a: Option<a>,
|
||||
opt_b: Option<b>,
|
||||
f: fn(a, b) -> result,
|
||||
) -> Option<result> {
|
||||
when opt_a is {
|
||||
None ->
|
||||
None
|
||||
Some(a) ->
|
||||
when opt_b is {
|
||||
None ->
|
||||
None
|
||||
Some(b) ->
|
||||
Some(f(a, b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test map2_3() {
|
||||
map2(Some(14), Some(42), fn(a, b) { (a, b) }) == Some((14, 42))
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
.apply(
|
||||
Term::var("map2")
|
||||
.lambda("map2")
|
||||
.apply(
|
||||
Term::equals_integer()
|
||||
.apply(Term::integer(1.into()))
|
||||
.apply(Term::var("opt_a_index"))
|
||||
.delayed_if_then_else(
|
||||
Term::Constant(Constant::Data(Data::constr(1, vec![])).into()),
|
||||
Term::equals_integer()
|
||||
.apply(Term::integer(1.into()))
|
||||
.apply(Term::var("opt_b_index"))
|
||||
.delayed_if_then_else(
|
||||
Term::Constant(
|
||||
Constant::Data(Data::constr(1, vec![])).into(),
|
||||
),
|
||||
Term::constr_data()
|
||||
.apply(Term::integer(0.into()))
|
||||
.apply(
|
||||
Term::mk_cons()
|
||||
.apply(
|
||||
Term::list_data().apply(
|
||||
Term::var("f")
|
||||
.apply(Term::var("a"))
|
||||
.apply(Term::var("b")),
|
||||
),
|
||||
)
|
||||
.apply(Term::empty_list()),
|
||||
)
|
||||
.lambda("b")
|
||||
.apply(Term::un_i_data().apply(
|
||||
Term::head_list().apply(Term::var("opt_b_fields")),
|
||||
))
|
||||
.lambda("opt_b_fields")
|
||||
.apply(
|
||||
Term::var(CONSTR_FIELDS_EXPOSER)
|
||||
.apply(Term::var("opt_b")),
|
||||
),
|
||||
)
|
||||
.lambda("opt_b_index")
|
||||
.apply(
|
||||
Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("opt_b")),
|
||||
)
|
||||
.lambda("a")
|
||||
.apply(
|
||||
Term::un_i_data().apply(
|
||||
Term::head_list().apply(Term::var("opt_a_fields")),
|
||||
),
|
||||
)
|
||||
.lambda("opt_a_fields")
|
||||
.apply(
|
||||
Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("opt_a")),
|
||||
),
|
||||
)
|
||||
.lambda("opt_a_index")
|
||||
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("opt_a")))
|
||||
.lambda("f")
|
||||
.lambda("opt_b")
|
||||
.lambda("opt_a"),
|
||||
)
|
||||
.apply(Term::Constant(
|
||||
Constant::Data(Data::constr(0, vec![Data::integer(14.into())])).into(),
|
||||
))
|
||||
.apply(Term::Constant(
|
||||
Constant::Data(Data::constr(0, vec![Data::integer(42.into())])).into(),
|
||||
))
|
||||
.apply(
|
||||
Term::mk_cons()
|
||||
.apply(Term::i_data().apply(Term::var("a")))
|
||||
.apply(
|
||||
Term::mk_cons()
|
||||
.apply(Term::i_data().apply(Term::var("b")))
|
||||
.apply(Term::empty_list()),
|
||||
)
|
||||
.lambda("b")
|
||||
.lambda("a"),
|
||||
),
|
||||
)
|
||||
.apply(Term::Constant(
|
||||
Constant::Data(Data::constr(
|
||||
0,
|
||||
vec![Data::list(vec![
|
||||
Data::integer(14.into()),
|
||||
Data::integer(42.into()),
|
||||
])],
|
||||
))
|
||||
.into(),
|
||||
))
|
||||
.constr_fields_exposer()
|
||||
.constr_index_exposer(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acceptance_test_25_void_equal() {
|
||||
let src = r#"
|
||||
|
|
Loading…
Reference in New Issue