Support mk_cons builtin
While this builtin is readily available through the Aiken syntax `[head, ..tail]`, there's no reason to not support its builtin form even though we may not encourage its usage. For completeness and to avoid bad surprises, it is now supported. Fixes #964.
This commit is contained in:
parent
bf5a406ffb
commit
1c58da4d86
|
@ -4060,61 +4060,17 @@ impl<'a> CodeGenerator<'a> {
|
|||
ValueConstructorVariant::ModuleConstant { .. } => {
|
||||
unreachable!("{:#?}, {}", constructor, name)
|
||||
}
|
||||
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
builtin: Some(builtin),
|
||||
..
|
||||
} => {
|
||||
let term = match builtin {
|
||||
DefaultFunction::IfThenElse
|
||||
| DefaultFunction::ChooseUnit
|
||||
| DefaultFunction::Trace
|
||||
| DefaultFunction::ChooseList
|
||||
| DefaultFunction::ChooseData
|
||||
| DefaultFunction::UnConstrData => {
|
||||
builder::special_case_builtin(builtin, 0, vec![])
|
||||
}
|
||||
|
||||
DefaultFunction::FstPair | DefaultFunction::SndPair => {
|
||||
builder::undata_builtin(
|
||||
builtin,
|
||||
0,
|
||||
&constructor.tipo.return_type().unwrap(),
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
DefaultFunction::HeadList
|
||||
if !constructor.tipo.return_type().unwrap().is_pair() =>
|
||||
{
|
||||
builder::undata_builtin(
|
||||
builtin,
|
||||
0,
|
||||
&constructor.tipo.return_type().unwrap(),
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
DefaultFunction::MkCons | DefaultFunction::MkPairData => {
|
||||
unimplemented!(
|
||||
"MkCons and MkPairData should be handled by an anon function or using [] or ( a, b, .., z) or Pair {{fst:a, snd: b}}.\n"
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let mut term: Term<Name> = (*builtin).into();
|
||||
|
||||
term = builder::apply_builtin_forces(term, builtin.force_count());
|
||||
|
||||
term
|
||||
}
|
||||
};
|
||||
Some(term)
|
||||
}
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
name: func_name,
|
||||
module,
|
||||
builtin,
|
||||
..
|
||||
} => {
|
||||
assert!(
|
||||
builtin.is_none(),
|
||||
"found remaining builtin function {func_name:?} ({builtin:?} declared as a module function in {module:?}"
|
||||
);
|
||||
|
||||
if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&(
|
||||
FunctionAccessKey {
|
||||
module_name: module.clone(),
|
||||
|
@ -4514,21 +4470,19 @@ impl<'a> CodeGenerator<'a> {
|
|||
| DefaultFunction::Trace
|
||||
| DefaultFunction::ChooseList
|
||||
| DefaultFunction::ChooseData
|
||||
| DefaultFunction::MkCons
|
||||
| DefaultFunction::UnConstrData => {
|
||||
builder::special_case_builtin(&func, count, arg_vec)
|
||||
builder::special_case_builtin(&func, tipo, count, arg_vec)
|
||||
}
|
||||
|
||||
DefaultFunction::FstPair | DefaultFunction::SndPair => {
|
||||
builder::undata_builtin(&func, count, ret_tipo, arg_vec)
|
||||
}
|
||||
|
||||
DefaultFunction::HeadList if !tipo.is_pair() => {
|
||||
builder::undata_builtin(&func, count, ret_tipo, arg_vec)
|
||||
}
|
||||
|
||||
DefaultFunction::MkCons | DefaultFunction::MkPairData => {
|
||||
DefaultFunction::MkPairData => {
|
||||
unimplemented!(
|
||||
"MkCons and MkPairData should be handled by an anon function or using [] or ( a, b, .., z).\n"
|
||||
"MkPairData should be handled by an anon function ( a, b, .., z).\n"
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -1554,6 +1554,7 @@ pub fn to_data_builtin(
|
|||
|
||||
pub fn special_case_builtin(
|
||||
func: &DefaultFunction,
|
||||
tipo: Rc<Type>,
|
||||
count: usize,
|
||||
mut args: Vec<Term<Name>>,
|
||||
) -> Term<Name> {
|
||||
|
@ -1564,6 +1565,26 @@ pub fn special_case_builtin(
|
|||
|
||||
term.lambda("_").apply(unit)
|
||||
}
|
||||
|
||||
DefaultFunction::MkCons => {
|
||||
let arg_type = tipo
|
||||
.arg_types()
|
||||
.and_then(|generics| generics.first().cloned())
|
||||
.expect("mk_cons should have (exactly) one type parameter");
|
||||
|
||||
if let [head, tail] = &args[..] {
|
||||
Term::mk_cons()
|
||||
.apply(if arg_type.is_pair() {
|
||||
head.clone()
|
||||
} else {
|
||||
convert_type_to_data(head.clone(), &arg_type)
|
||||
})
|
||||
.apply(tail.clone())
|
||||
} else {
|
||||
unreachable!("mk_cons has two arguments.");
|
||||
}
|
||||
}
|
||||
|
||||
DefaultFunction::ChooseUnit
|
||||
| DefaultFunction::IfThenElse
|
||||
| DefaultFunction::ChooseList
|
||||
|
|
|
@ -6471,3 +6471,94 @@ fn qualified_prelude_functions() {
|
|||
false,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mk_cons_direct_invoke_1() {
|
||||
let src = r#"
|
||||
use aiken/builtin
|
||||
|
||||
test mk_cons_1() {
|
||||
builtin.cons_list(1, []) == [1]
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
.apply(
|
||||
Term::list_data().apply(
|
||||
Term::mk_cons()
|
||||
.apply(Term::data(Data::integer(1.into())))
|
||||
.apply(Term::empty_list()),
|
||||
),
|
||||
)
|
||||
.apply(Term::data(Data::list(vec![Data::integer(1.into())]))),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mk_cons_direct_invoke_2() {
|
||||
let src = r#"
|
||||
use aiken/builtin.{cons_list}
|
||||
|
||||
test mk_cons_2() {
|
||||
cons_list(Some(42), [None]) == [Some(42), None]
|
||||
}
|
||||
"#;
|
||||
|
||||
let none = Data::constr(1, Vec::new());
|
||||
let some = Data::constr(0, vec![Data::integer(42.into())]);
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
.apply(
|
||||
Term::list_data().apply(Term::mk_cons().apply(Term::data(some.clone())).apply(
|
||||
Term::Constant(
|
||||
Constant::ProtoList(Type::Data, vec![Constant::Data(none.clone())]).into(),
|
||||
),
|
||||
)),
|
||||
)
|
||||
.apply(Term::data(Data::list(vec![some, none]))),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mk_cons_direct_invoke_3() {
|
||||
let src = r#"
|
||||
use aiken/builtin.{cons_list, i_data, mk_nil_pair_data}
|
||||
|
||||
test mk_cons_3() {
|
||||
cons_list(Pair(i_data(1), i_data(1)), mk_nil_pair_data()) == [
|
||||
Pair(i_data(1), i_data(1)),
|
||||
]
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_uplc(
|
||||
src,
|
||||
Term::equals_data()
|
||||
.apply(
|
||||
Term::map_data().apply(
|
||||
Term::mk_cons()
|
||||
.apply(Term::Constant(
|
||||
Constant::ProtoPair(
|
||||
Type::Data,
|
||||
Type::Data,
|
||||
Constant::Data(Data::integer(1.into())).into(),
|
||||
Constant::Data(Data::integer(1.into())).into(),
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
.apply(Term::mk_nil_pair_data().apply(Term::unit())),
|
||||
),
|
||||
)
|
||||
.apply(Term::data(Data::map(vec![(
|
||||
Data::integer(1.into()),
|
||||
Data::integer(1.into()),
|
||||
)]))),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue