fix: found various unify and type issues while running tests
This commit is contained in:
parent
fd226be51f
commit
26f68c2fb4
|
@ -372,6 +372,15 @@ impl<'a> CodeGenerator<'a> {
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
if tipo.is_pair() {
|
||||||
|
assert!(args.len() == 2);
|
||||||
|
|
||||||
|
let arg1 = self.build(&args[0].value, module_build_name, &[]);
|
||||||
|
|
||||||
|
let arg2 = self.build(&args[1].value, module_build_name, &[]);
|
||||||
|
|
||||||
|
AirTree::pair(arg1, arg2, tipo.clone())
|
||||||
|
} 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)
|
||||||
.expect("Creating a record with no record definition.");
|
.expect("Creating a record with no record definition.");
|
||||||
|
|
||||||
|
@ -399,6 +408,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
AirTree::create_constr(constr_index, constr_tipo.clone(), constr_args)
|
AirTree::create_constr(constr_index, constr_tipo.clone(), constr_args)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypedExpr::Var {
|
TypedExpr::Var {
|
||||||
constructor:
|
constructor:
|
||||||
|
@ -5420,12 +5430,13 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
match (extract_constant(&fst), extract_constant(&snd)) {
|
match (extract_constant(&fst), extract_constant(&snd)) {
|
||||||
(Some(fst), Some(snd)) => {
|
(Some(fst), Some(snd)) => {
|
||||||
|
let mut pair_fields = builder::convert_constants_to_data(vec![fst, snd]);
|
||||||
let term = Term::Constant(
|
let term = Term::Constant(
|
||||||
UplcConstant::ProtoPair(
|
UplcConstant::ProtoPair(
|
||||||
UplcType::Data,
|
UplcType::Data,
|
||||||
UplcType::Data,
|
UplcType::Data,
|
||||||
fst.clone(),
|
pair_fields.remove(0).into(),
|
||||||
snd.clone(),
|
pair_fields.remove(0).into(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -695,14 +695,22 @@ pub fn pattern_has_conditions(
|
||||||
Pattern::Constructor {
|
Pattern::Constructor {
|
||||||
arguments, tipo, ..
|
arguments, tipo, ..
|
||||||
} => {
|
} => {
|
||||||
let data_type =
|
if tipo.is_pair()
|
||||||
lookup_data_type_by_tipo(data_types, tipo).expect("Data type not found");
|
|| (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
|
data_type.constructors.len() > 1
|
||||||
|| arguments
|
|| arguments
|
||||||
.iter()
|
.iter()
|
||||||
.any(|arg| pattern_has_conditions(&arg.value, data_types))
|
.any(|arg| pattern_has_conditions(&arg.value, data_types))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Pattern::Assign { pattern, .. } => pattern_has_conditions(pattern, data_types),
|
Pattern::Assign { pattern, .. } => pattern_has_conditions(pattern, data_types),
|
||||||
Pattern::Var { .. } | Pattern::Discard { .. } => false,
|
Pattern::Var { .. } | Pattern::Discard { .. } => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1495,8 +1495,7 @@ impl<'a> Environment<'a> {
|
||||||
.map_err(|e| e.flip_unify());
|
.map_err(|e| e.flip_unify());
|
||||||
}
|
}
|
||||||
|
|
||||||
match (lhs.deref(), rhs.deref()) {
|
match lhs.deref() {
|
||||||
(
|
|
||||||
Type::App {
|
Type::App {
|
||||||
module: m1,
|
module: m1,
|
||||||
name: n1,
|
name: n1,
|
||||||
|
@ -1504,16 +1503,17 @@ impl<'a> Environment<'a> {
|
||||||
public: _,
|
public: _,
|
||||||
contains_opaque: _,
|
contains_opaque: _,
|
||||||
alias: _,
|
alias: _,
|
||||||
},
|
} => {
|
||||||
Type::App {
|
if let Type::App {
|
||||||
module: m2,
|
module: m2,
|
||||||
name: n2,
|
name: n2,
|
||||||
args: args2,
|
args: args2,
|
||||||
public: _,
|
public: _,
|
||||||
contains_opaque: _,
|
contains_opaque: _,
|
||||||
alias: _,
|
alias: _,
|
||||||
},
|
} = rhs.deref()
|
||||||
) if m1 == m2 && n1 == n2 && args1.len() == args2.len() => {
|
{
|
||||||
|
if m1 == m2 && n1 == n2 && args1.len() == args2.len() {
|
||||||
for (a, b) in args1.iter().zip(args2) {
|
for (a, b) in args1.iter().zip(args2) {
|
||||||
unify_enclosed_type(
|
unify_enclosed_type(
|
||||||
lhs.clone(),
|
lhs.clone(),
|
||||||
|
@ -1522,18 +1522,36 @@ impl<'a> Environment<'a> {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
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::Tuple {
|
Type::Tuple {
|
||||||
elems: elems1,
|
elems: elems1,
|
||||||
alias: _,
|
alias: _,
|
||||||
},
|
} => {
|
||||||
Type::Tuple {
|
if let Type::Tuple {
|
||||||
elems: elems2,
|
elems: elems2,
|
||||||
alias: _,
|
alias: _,
|
||||||
},
|
} = rhs.deref()
|
||||||
) if elems1.len() == elems2.len() => {
|
{
|
||||||
|
if elems1.len() == elems2.len() {
|
||||||
for (a, b) in elems1.iter().zip(elems2) {
|
for (a, b) in elems1.iter().zip(elems2) {
|
||||||
unify_enclosed_type(
|
unify_enclosed_type(
|
||||||
lhs.clone(),
|
lhs.clone(),
|
||||||
|
@ -1542,20 +1560,38 @@ impl<'a> Environment<'a> {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
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 {
|
Type::Fn {
|
||||||
args: args1,
|
args: args1,
|
||||||
ret: retrn1,
|
ret: retrn1,
|
||||||
alias: _,
|
alias: _,
|
||||||
},
|
} => {
|
||||||
Type::Fn {
|
if let Type::Fn {
|
||||||
args: args2,
|
args: args2,
|
||||||
ret: retrn2,
|
ret: retrn2,
|
||||||
alias: _,
|
alias: _,
|
||||||
},
|
} = rhs.deref()
|
||||||
) if args1.len() == args2.len() => {
|
{
|
||||||
|
if args1.len() == args2.len() {
|
||||||
for (a, b) in args1.iter().zip(args2) {
|
for (a, b) in args1.iter().zip(args2) {
|
||||||
self.unify(a.clone(), b.clone(), location, allow_cast)
|
self.unify(a.clone(), b.clone(), location, allow_cast)
|
||||||
.map_err(|_| Error::CouldNotUnify {
|
.map_err(|_| Error::CouldNotUnify {
|
||||||
|
@ -1574,15 +1610,57 @@ impl<'a> Environment<'a> {
|
||||||
situation: None,
|
situation: None,
|
||||||
rigid_type_names: HashMap::new(),
|
rigid_type_names: HashMap::new(),
|
||||||
})
|
})
|
||||||
}
|
} else {
|
||||||
|
Err(Error::CouldNotUnify {
|
||||||
_ => Err(Error::CouldNotUnify {
|
|
||||||
location,
|
location,
|
||||||
expected: lhs.clone(),
|
expected: lhs.clone(),
|
||||||
given: rhs.clone(),
|
given: rhs.clone(),
|
||||||
situation: None,
|
situation: None,
|
||||||
rigid_type_names: HashMap::new(),
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Type::Pair { fst, snd, .. } => {
|
Type::Pair { fst, snd, alias: _ } => {
|
||||||
unify_unbound_type(fst.clone(), own_id, location)?;
|
unify_unbound_type(fst.clone(), own_id, location)?;
|
||||||
unify_unbound_type(snd.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 itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast, builtins,
|
ast,
|
||||||
|
builtins::{self, PAIR},
|
||||||
tipo::{self, environment::Environment, error::Error},
|
tipo::{self, environment::Environment, error::Error},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -563,6 +564,8 @@ pub(super) fn simplify(
|
||||||
constructor: super::PatternConstructor::Record { name, .. },
|
constructor: super::PatternConstructor::Record { name, .. },
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
let (empty, pair) = (&"".to_string(), &PAIR.to_string());
|
||||||
|
|
||||||
let (module, type_name, arity) = match tipo.deref() {
|
let (module, type_name, arity) = match tipo.deref() {
|
||||||
tipo::Type::App {
|
tipo::Type::App {
|
||||||
name: type_name,
|
name: type_name,
|
||||||
|
@ -575,11 +578,13 @@ pub(super) fn simplify(
|
||||||
module,
|
module,
|
||||||
..
|
..
|
||||||
} => (module, type_name, args.len()),
|
} => (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)?;
|
let alts = environment.get_constructors_for_type(module, type_name, *location)?;
|
||||||
|
|
|
@ -680,10 +680,10 @@ fn acceptance_test_6_if_else() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn acceptance_test_6_equals() {
|
fn acceptance_test_6_equals_pair() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
test foo() {
|
test foo() {
|
||||||
(1, []) == (1, [])
|
Pair(1, []) == Pair(1, [])
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
@ -725,7 +725,46 @@ fn acceptance_test_6_equals() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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#"
|
let src = r#"
|
||||||
pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
|
pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
|
||||||
when xs is {
|
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(
|
assert_uplc(
|
||||||
src,
|
src,
|
||||||
Term::equals_data()
|
Term::equals_data()
|
||||||
|
@ -1414,7 +1574,7 @@ fn acceptance_test_14_list_creation() {
|
||||||
fn acceptance_test_15_zero_arg() {
|
fn acceptance_test_15_zero_arg() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
pub opaque type Map<key, value> {
|
pub opaque type Map<key, value> {
|
||||||
inner: List<(key, value)>,
|
inner: List<Pair<key, value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() {
|
pub fn new() {
|
||||||
|
@ -1956,15 +2116,18 @@ fn acceptance_test_22_filter_map() {
|
||||||
#[test]
|
#[test]
|
||||||
fn acceptance_test_23_to_list() {
|
fn acceptance_test_23_to_list() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
|
pub type Map<key, value> =
|
||||||
|
List<Pair<key, value>>
|
||||||
|
|
||||||
pub opaque type AssocList<key, value> {
|
pub opaque type AssocList<key, value> {
|
||||||
inner: List<(key, value)>,
|
inner: Map<key, value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> AssocList<key, value> {
|
pub fn new() -> AssocList<key, value> {
|
||||||
AssocList { inner: [] }
|
AssocList { inner: [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_list(m: AssocList<key, value>) -> List<(key, value)> {
|
pub fn to_list(m: AssocList<key, value>) -> Map<key, value> {
|
||||||
m.inner
|
m.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1976,15 +2139,15 @@ fn acceptance_test_23_to_list() {
|
||||||
AssocList { inner: do_insert(m.inner, k, v) }
|
AssocList { inner: do_insert(m.inner, k, v) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_insert(elems: List<(key, value)>, k: key, v: value) -> List<(key, value)> {
|
fn do_insert(elems: Map<key, value>, k: key, v: value) -> Map<key, value> {
|
||||||
when elems is {
|
when elems is {
|
||||||
[] ->
|
[] ->
|
||||||
[(k, v)]
|
[Pair(k, v)]
|
||||||
[(k2, v2), ..rest] ->
|
[Pair { fst: k2, snd: v2 }, ..rest] ->
|
||||||
if k == k2 {
|
if k == k2 {
|
||||||
[(k, v), ..rest]
|
[Pair(k, v), ..rest]
|
||||||
} else {
|
} else {
|
||||||
[(k2, v2), ..do_insert(rest, k, v)]
|
[Pair(k2, v2), ..do_insert(rest, k, v)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1996,7 +2159,7 @@ fn acceptance_test_23_to_list() {
|
||||||
}
|
}
|
||||||
|
|
||||||
test to_list_2() {
|
test to_list_2() {
|
||||||
to_list(fixture_1()) == [("foo", 42), ("bar", 14)]
|
to_list(fixture_1()) == [Pair("foo", 42), Pair("bar", 14)]
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
@ -2036,7 +2199,7 @@ fn acceptance_test_23_to_list() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn acceptance_test_24_map2() {
|
fn acceptance_test_24_map_pair() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
pub fn map2(
|
pub fn map2(
|
||||||
opt_a: Option<a>,
|
opt_a: Option<a>,
|
||||||
|
@ -2057,7 +2220,7 @@ fn acceptance_test_24_map2() {
|
||||||
}
|
}
|
||||||
|
|
||||||
test map2_3() {
|
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]
|
#[test]
|
||||||
fn acceptance_test_25_void_equal() {
|
fn acceptance_test_25_void_equal() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
|
|
Loading…
Reference in New Issue