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 { .. } => {
|
ValueConstructorVariant::ModuleConstant { .. } => {
|
||||||
unreachable!("{:#?}, {}", constructor, name)
|
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 {
|
ValueConstructorVariant::ModuleFn {
|
||||||
name: func_name,
|
name: func_name,
|
||||||
module,
|
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(&(
|
if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&(
|
||||||
FunctionAccessKey {
|
FunctionAccessKey {
|
||||||
module_name: module.clone(),
|
module_name: module.clone(),
|
||||||
|
@ -4514,21 +4470,19 @@ impl<'a> CodeGenerator<'a> {
|
||||||
| DefaultFunction::Trace
|
| DefaultFunction::Trace
|
||||||
| DefaultFunction::ChooseList
|
| DefaultFunction::ChooseList
|
||||||
| DefaultFunction::ChooseData
|
| DefaultFunction::ChooseData
|
||||||
|
| DefaultFunction::MkCons
|
||||||
| DefaultFunction::UnConstrData => {
|
| DefaultFunction::UnConstrData => {
|
||||||
builder::special_case_builtin(&func, count, arg_vec)
|
builder::special_case_builtin(&func, tipo, count, arg_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultFunction::FstPair | DefaultFunction::SndPair => {
|
DefaultFunction::FstPair | DefaultFunction::SndPair => {
|
||||||
builder::undata_builtin(&func, count, ret_tipo, arg_vec)
|
builder::undata_builtin(&func, count, ret_tipo, arg_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultFunction::HeadList if !tipo.is_pair() => {
|
DefaultFunction::HeadList if !tipo.is_pair() => {
|
||||||
builder::undata_builtin(&func, count, ret_tipo, arg_vec)
|
builder::undata_builtin(&func, count, ret_tipo, arg_vec)
|
||||||
}
|
}
|
||||||
|
DefaultFunction::MkPairData => {
|
||||||
DefaultFunction::MkCons | DefaultFunction::MkPairData => {
|
|
||||||
unimplemented!(
|
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(
|
pub fn special_case_builtin(
|
||||||
func: &DefaultFunction,
|
func: &DefaultFunction,
|
||||||
|
tipo: Rc<Type>,
|
||||||
count: usize,
|
count: usize,
|
||||||
mut args: Vec<Term<Name>>,
|
mut args: Vec<Term<Name>>,
|
||||||
) -> Term<Name> {
|
) -> Term<Name> {
|
||||||
|
@ -1564,6 +1565,26 @@ pub fn special_case_builtin(
|
||||||
|
|
||||||
term.lambda("_").apply(unit)
|
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::ChooseUnit
|
||||||
| DefaultFunction::IfThenElse
|
| DefaultFunction::IfThenElse
|
||||||
| DefaultFunction::ChooseList
|
| DefaultFunction::ChooseList
|
||||||
|
|
|
@ -6471,3 +6471,94 @@ fn qualified_prelude_functions() {
|
||||||
false,
|
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