fix: wrap data reduce had the wrong argument called in recursively, thus skipping over cases that should have been reduced

chore: Add unit tests on for uplc optimizations
This commit is contained in:
microproofs
2023-04-26 17:22:16 -04:00
parent af14d8be2e
commit c3184c544c
2 changed files with 182 additions and 11 deletions

View File

@@ -272,13 +272,10 @@ fn wrap_data_reduce(term: &mut Term<Name>) {
let Term::Builtin(second_action) = inner_func.as_ref()
else {
wrap_data_reduce(Rc::make_mut(inner_func));
wrap_data_reduce(Rc::make_mut(inner_arg));
wrap_data_reduce(Rc::make_mut(argument));
return;
};
wrap_data_reduce(Rc::make_mut(inner_arg));
match (first_action, second_action) {
(DefaultFunction::UnIData, DefaultFunction::IData)
| (DefaultFunction::IData, DefaultFunction::UnIData)
@@ -290,9 +287,12 @@ fn wrap_data_reduce(term: &mut Term<Name>) {
| (DefaultFunction::UnMapData, DefaultFunction::MapData)
| (DefaultFunction::UnConstrData, DefaultFunction::ConstrData)
| (DefaultFunction::ConstrData, DefaultFunction::UnConstrData) => {
wrap_data_reduce(Rc::make_mut(inner_arg));
*term = inner_arg.as_ref().clone();
}
_ => {}
_ => {
wrap_data_reduce(Rc::make_mut(argument));
}
}
}
Term::Force(f) => {
@@ -407,3 +407,174 @@ fn substitute_term(term: &Term<Name>, original: Rc<Name>, replace_with: &Term<Na
x => x.clone(),
}
}
#[cfg(test)]
mod test {
use pallas_primitives::babbage::{BigInt, PlutusData};
use crate::ast::{Constant, Name, NamedDeBruijn, Program, Term};
#[test]
fn lambda_reduce_var() {
let program: Program<NamedDeBruijn> = Program {
version: (1, 0, 0),
term: Term::var("bar")
.lambda("bar")
.apply(Term::var("foo"))
.lambda("foo")
.apply(
Term::constr_data()
.apply(Term::integer(3.into()))
.apply(Term::list_values(vec![])),
),
}
.try_into()
.unwrap();
let program: Program<Name> = program.try_into().unwrap();
let expected = Program {
version: (1, 0, 0),
term: Term::var("foo").lambda("foo").apply(
Term::constr_data()
.apply(Term::integer(3.into()))
.apply(Term::list_values(vec![])),
),
};
let expected: Program<NamedDeBruijn> = expected.try_into().unwrap();
let actual = program.lambda_reduce();
let actual: Program<NamedDeBruijn> = actual.try_into().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn lambda_reduce_constant() {
let program: Program<NamedDeBruijn> = Program {
version: (1, 0, 0),
term: Term::var("foo")
.lambda("foo")
.apply(Term::integer(6.into())),
}
.try_into()
.unwrap();
let program: Program<Name> = program.try_into().unwrap();
let expected: Program<Name> = Program {
version: (1, 0, 0),
term: Term::integer(6.into()),
};
let expected: Program<NamedDeBruijn> = expected.try_into().unwrap();
let actual = program.lambda_reduce();
let actual: Program<NamedDeBruijn> = actual.try_into().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn lambda_reduce_builtin() {
let program: Program<NamedDeBruijn> = Program {
version: (1, 0, 0),
term: Term::var("foo").lambda("foo").apply(Term::add_integer()),
}
.try_into()
.unwrap();
let program: Program<Name> = program.try_into().unwrap();
let expected: Program<Name> = Program {
version: (1, 0, 0),
term: Term::add_integer(),
};
let expected: Program<NamedDeBruijn> = expected.try_into().unwrap();
let actual = program.lambda_reduce();
let actual: Program<NamedDeBruijn> = actual.try_into().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn lambda_reduce_force_delay_error_lam() {
let program: Program<NamedDeBruijn> = Program {
version: (1, 0, 0),
term: Term::var("foo")
.apply(Term::var("bar"))
.apply(Term::var("baz"))
.apply(Term::var("bat"))
.lambda("foo")
.apply(Term::snd_pair())
.lambda("bar")
.apply(Term::integer(1.into()).delay())
.lambda("baz")
.apply(Term::Error)
.lambda("bat")
.apply(Term::bool(false).lambda("x")),
}
.try_into()
.unwrap();
let program: Program<Name> = program.try_into().unwrap();
let expected = Program {
version: (1, 0, 0),
term: Term::var("foo")
.apply(Term::var("bar"))
.apply(Term::var("baz"))
.apply(Term::var("bat"))
.lambda("foo")
.apply(Term::snd_pair())
.lambda("bar")
.apply(Term::integer(1.into()).delay())
.lambda("baz")
.apply(Term::Error)
.lambda("bat")
.apply(Term::bool(false).lambda("x")),
};
let expected: Program<NamedDeBruijn> = expected.try_into().unwrap();
let actual = program.lambda_reduce();
let actual: Program<NamedDeBruijn> = actual.try_into().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn wrap_data_reduce_i_data() {
let program: Program<NamedDeBruijn> = Program {
version: (1, 0, 0),
term: Term::equals_data()
.apply(Term::i_data().apply(Term::un_i_data().apply(Term::Constant(
Constant::Data(PlutusData::BigInt(BigInt::Int(5.into()))).into(),
))))
.apply(Term::i_data().apply(Term::integer(1.into())))
.lambda("x"),
}
.try_into()
.unwrap();
let program: Program<Name> = program.try_into().unwrap();
let expected = Program {
version: (1, 0, 0),
term: Term::equals_data()
.apply(Term::Constant(
Constant::Data(PlutusData::BigInt(BigInt::Int(5.into()))).into(),
))
.apply(Term::i_data().apply(Term::integer(1.into())))
.lambda("x"),
};
let expected: Program<NamedDeBruijn> = expected.try_into().unwrap();
let actual = program.wrap_data_reduce();
let actual: Program<NamedDeBruijn> = actual.try_into().unwrap();
assert_eq!(actual, expected);
}
}