add type resolution for values and fix tests

This commit is contained in:
collin 2020-06-13 17:43:59 -07:00
parent 499805efdf
commit 8ea11dbab7
14 changed files with 71 additions and 37 deletions

View File

@ -751,11 +751,13 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
left: Expression,
right: Expression,
) -> Result<(ConstrainedValue<F, G>, ConstrainedValue<F, G>), ExpressionError> {
let resolved_left =
let mut resolved_left =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, left)?;
let resolved_right =
let mut resolved_right =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, right)?;
resolved_left.resolve_types(&mut resolved_right, expected_types)?;
Ok((resolved_left, resolved_right))
}
@ -879,7 +881,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&vec![],
*left,
*right,
)?;
@ -891,7 +893,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&vec![],
*left,
*right,
)?;
@ -903,7 +905,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&vec![],
*left,
*right,
)?;
@ -915,7 +917,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&vec![],
*left,
*right,
)?;
@ -927,7 +929,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&vec![],
*left,
*right,
)?;

View File

@ -55,7 +55,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
indicator: Option<Boolean>,
name: String,
range_or_expression: RangeOrExpression,
new_value: ConstrainedValue<F, G>,
mut new_value: ConstrainedValue<F, G>,
) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
@ -67,10 +67,13 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
// Modify the single value of the array in place
match self.get_mutable_assignee(name)? {
ConstrainedValue::Array(old) => {
new_value.resolve_type(&vec![old[index].to_type()])?;
let selected_value =
ConstrainedValue::conditionally_select(cs, &condition, &new_value, &old[index]).map_err(
|_| StatementError::SelectFail(new_value.to_string(), old[index].to_string()),
)?;
old[index] = selected_value;
}
_ => return Err(StatementError::ArrayAssignIndex),
@ -112,7 +115,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
indicator: Option<Boolean>,
circuit_name: String,
object_name: Identifier,
new_value: ConstrainedValue<F, G>,
mut new_value: ConstrainedValue<F, G>,
) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
@ -132,6 +135,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
return Err(StatementError::ImmutableCircuitFunction("static".into()));
}
_ => {
new_value.resolve_type(&vec![object.1.to_type()])?;
let selected_value = ConstrainedValue::conditionally_select(
cs, &condition, &new_value, &object.1,
)
@ -162,13 +167,15 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
let variable_name = self.resolve_assignee(function_scope.clone(), assignee.clone());
// Evaluate new value
let new_value = self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), &vec![], expression)?;
let mut new_value =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), &vec![], expression)?;
// Mutate the old value into the new value
match assignee {
Assignee::Identifier(_identifier) => {
let condition = indicator.unwrap_or(Boolean::Constant(true));
let old_value = self.get_mutable_assignee(variable_name.clone())?;
new_value.resolve_type(&vec![old_value.to_type()])?;
let selected_value = ConstrainedValue::conditionally_select(cs, &condition, &new_value, old_value)
.map_err(|_| StatementError::SelectFail(new_value.to_string(), old_value.to_string()))?;
@ -514,10 +521,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
}
}
Statement::AssertEq(left, right) => {
let resolved_left =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), &vec![], left)?;
let resolved_right =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), &vec![], right)?;
let (resolved_left, resolved_right) =
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right)?;
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right)?;
}

View File

@ -85,6 +85,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
Ok(())
}
/// Expect both `self` and `other` to resolve to the same type
pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec<Type>) -> Result<(), ValueError> {
if !types.is_empty() {
self.resolve_type(types)?;
return other.resolve_type(types);
}
match (&self, &other) {
(ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()),
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type()]),
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type()]),
_ => Ok(()),
}
}
pub(crate) fn get_inner_mut(&mut self) {
if let ConstrainedValue::Mutable(inner) = self {
*self = *inner.clone()

View File

@ -1,4 +1,4 @@
use crate::errors::{BooleanError, ExpressionError};
use crate::errors::{BooleanError, ExpressionError, ValueError};
use snarkos_errors::gadgets::SynthesisError;
@ -57,4 +57,7 @@ pub enum StatementError {
#[error("Expected assignment of return values for expression {}", _0)]
Unassigned(String),
#[error("{}", _0)]
ValueError(#[from] ValueError),
}

View File

@ -118,11 +118,6 @@ macro_rules! test_uint {
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let quotient = r1.wrapping_div(r2);
let cs = TestConstraintSystem::<Fq>::new();
let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap();
let bytes = include_bytes!("div.leo");
let mut program = parse_program(bytes).unwrap();
@ -131,7 +126,16 @@ macro_rules! test_uint {
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program, quotient_allocated);
// expect an error when dividing by zero
if r2 == 0 {
let _err = get_error(program);
} else {
let cs = TestConstraintSystem::<Fq>::new();
let quotient = r1.wrapping_div(r2);
let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap();
output_expected_allocated(program, quotient_allocated);
}
}
}

View File

@ -1,5 +1,6 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
parse_program,

View File

@ -1,5 +1,6 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
parse_program,

View File

@ -1,5 +1,6 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
parse_program,

View File

@ -1,5 +1,6 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
parse_program,

View File

@ -1,5 +1,6 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
parse_program,

View File

@ -1,7 +1,7 @@
function main(bit: private u32) {
if bit == 1u32 {
assert_eq!(bit, 1u32);
if bit == 1 {
assert_eq!(bit, 1);
} else {
assert_eq!(bit, 0u32);
assert_eq!(bit, 0);
}
}

View File

@ -1,12 +1,12 @@
function main(bit: u32) -> u32 {
let mut result = 0u32;
if bit == 1u32 {
result = 1u32;
} else if bit == 2u32 {
result = 2u32;
if bit == 1 {
result = 1;
} else if bit == 2 {
result = 2;
} else {
result = 3u32;
result = 3;
}
return result

View File

@ -28,7 +28,7 @@ fn empty_output_satisfied(program: EdwardsTestCompiler) {
// }
// }
#[test]
fn conditional_basic() {
fn test_assert() {
let bytes = include_bytes!("assert.leo");
let mut program_1_pass = parse_program(bytes).unwrap();
let mut program_0_pass = program_1_pass.clone();
@ -53,7 +53,7 @@ fn conditional_basic() {
}
#[test]
fn conditional_mutate() {
fn test_mutate() {
let bytes = include_bytes!("mutate.leo");
let mut program_1_true = parse_program(bytes).unwrap();
let mut program_0_pass = program_1_true.clone();
@ -70,7 +70,7 @@ fn conditional_mutate() {
}
#[test]
fn conditional_for_loop() {
fn test_for_loop() {
let bytes = include_bytes!("for_loop.leo");
let mut program_true_6 = parse_program(bytes).unwrap();
let mut program_false_0 = program_true_6.clone();
@ -87,7 +87,7 @@ fn conditional_for_loop() {
}
#[test]
fn conditional_chain() {
fn test_chain() {
let bytes = include_bytes!("chain.leo");
let mut program_1_1 = parse_program(bytes).unwrap();
let mut program_2_2 = program_1_1.clone();
@ -107,7 +107,7 @@ fn conditional_chain() {
}
#[test]
fn conditional_nested() {
fn test_nested() {
let bytes = include_bytes!("nested.leo");
let mut program_true_true_3 = parse_program(bytes).unwrap();
let mut program_true_false_1 = program_true_true_3.clone();

View File

@ -1,10 +1,10 @@
function main(bit: private u32) -> u32 {
let mut a = 5u32;
if bit == 1u32 {
a = 1u32;
if bit == 1 {
a = 1;
} else {
a = 0u32;
a = 0;
}
return a