From 8ea11dbab7776c98ff2c793ee21a263cf004c18e Mon Sep 17 00:00:00 2001 From: collin Date: Sat, 13 Jun 2020 17:43:59 -0700 Subject: [PATCH] add type resolution for values and fix tests --- compiler/src/constraints/expression.rs | 16 +++++++++------- compiler/src/constraints/statement.rs | 19 ++++++++++++------- compiler/src/constraints/value.rs | 15 +++++++++++++++ compiler/src/errors/constraints/statement.rs | 5 ++++- compiler/tests/integers/macros.rs | 16 ++++++++++------ compiler/tests/integers/u128/mod.rs | 1 + compiler/tests/integers/u16/mod.rs | 1 + compiler/tests/integers/u32/mod.rs | 1 + compiler/tests/integers/u64/mod.rs | 1 + compiler/tests/integers/u8/mod.rs | 1 + .../tests/statements/conditional/assert.leo | 6 +++--- .../tests/statements/conditional/chain.leo | 10 +++++----- compiler/tests/statements/conditional/mod.rs | 10 +++++----- .../tests/statements/conditional/mutate.leo | 6 +++--- 14 files changed, 71 insertions(+), 37 deletions(-) diff --git a/compiler/src/constraints/expression.rs b/compiler/src/constraints/expression.rs index ed03e1abd5..6f691df452 100644 --- a/compiler/src/constraints/expression.rs +++ b/compiler/src/constraints/expression.rs @@ -751,11 +751,13 @@ impl, CS: ConstraintSystem> Constraine left: Expression, right: Expression, ) -> Result<(ConstrainedValue, ConstrainedValue), 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, CS: ConstraintSystem> Constraine cs, file_scope.clone(), function_scope.clone(), - expected_types, + &vec![], *left, *right, )?; @@ -891,7 +893,7 @@ impl, CS: ConstraintSystem> Constraine cs, file_scope.clone(), function_scope.clone(), - expected_types, + &vec![], *left, *right, )?; @@ -903,7 +905,7 @@ impl, CS: ConstraintSystem> Constraine cs, file_scope.clone(), function_scope.clone(), - expected_types, + &vec![], *left, *right, )?; @@ -915,7 +917,7 @@ impl, CS: ConstraintSystem> Constraine cs, file_scope.clone(), function_scope.clone(), - expected_types, + &vec![], *left, *right, )?; @@ -927,7 +929,7 @@ impl, CS: ConstraintSystem> Constraine cs, file_scope.clone(), function_scope.clone(), - expected_types, + &vec![], *left, *right, )?; diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index 501be29012..c0065fa387 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -55,7 +55,7 @@ impl, CS: ConstraintSystem> Constraine indicator: Option, name: String, range_or_expression: RangeOrExpression, - new_value: ConstrainedValue, + mut new_value: ConstrainedValue, ) -> Result<(), StatementError> { let condition = indicator.unwrap_or(Boolean::Constant(true)); @@ -67,10 +67,13 @@ impl, CS: ConstraintSystem> 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, CS: ConstraintSystem> Constraine indicator: Option, circuit_name: String, object_name: Identifier, - new_value: ConstrainedValue, + mut new_value: ConstrainedValue, ) -> Result<(), StatementError> { let condition = indicator.unwrap_or(Boolean::Constant(true)); @@ -132,6 +135,8 @@ impl, CS: ConstraintSystem> 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, CS: ConstraintSystem> 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, CS: ConstraintSystem> 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)?; } diff --git a/compiler/src/constraints/value.rs b/compiler/src/constraints/value.rs index fe1e606fd1..bf658c4691 100644 --- a/compiler/src/constraints/value.rs +++ b/compiler/src/constraints/value.rs @@ -85,6 +85,21 @@ impl> ConstrainedValue { Ok(()) } + /// Expect both `self` and `other` to resolve to the same type + pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec) -> 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() diff --git a/compiler/src/errors/constraints/statement.rs b/compiler/src/errors/constraints/statement.rs index ac9615df43..180d5acbb6 100644 --- a/compiler/src/errors/constraints/statement.rs +++ b/compiler/src/errors/constraints/statement.rs @@ -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), } diff --git a/compiler/tests/integers/macros.rs b/compiler/tests/integers/macros.rs index f322113f39..4973535f7c 100644 --- a/compiler/tests/integers/macros.rs +++ b/compiler/tests/integers/macros.rs @@ -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::::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::::new(); + let quotient = r1.wrapping_div(r2); + let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap(); + + output_expected_allocated(program, quotient_allocated); + } } } diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index ad5cc58bd9..2989214a8b 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -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, diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index e6aa8b1060..9978bfdda8 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -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, diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index 30005670c9..bcc17744c1 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -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, diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index 87d73ddcfe..d1e19725ae 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -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, diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index 40796075f8..4e973c9c71 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -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, diff --git a/compiler/tests/statements/conditional/assert.leo b/compiler/tests/statements/conditional/assert.leo index ecf6c0268c..0f5fde2224 100644 --- a/compiler/tests/statements/conditional/assert.leo +++ b/compiler/tests/statements/conditional/assert.leo @@ -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); } } diff --git a/compiler/tests/statements/conditional/chain.leo b/compiler/tests/statements/conditional/chain.leo index f916a8d628..159c94be8b 100644 --- a/compiler/tests/statements/conditional/chain.leo +++ b/compiler/tests/statements/conditional/chain.leo @@ -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 diff --git a/compiler/tests/statements/conditional/mod.rs b/compiler/tests/statements/conditional/mod.rs index 705833f4d6..15133bedd1 100644 --- a/compiler/tests/statements/conditional/mod.rs +++ b/compiler/tests/statements/conditional/mod.rs @@ -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(); diff --git a/compiler/tests/statements/conditional/mutate.leo b/compiler/tests/statements/conditional/mutate.leo index 2a4a9e66d2..168fa3866c 100644 --- a/compiler/tests/statements/conditional/mutate.leo +++ b/compiler/tests/statements/conditional/mutate.leo @@ -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