mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-01 18:56:38 +03:00
add type resolution for values and fix tests
This commit is contained in:
parent
499805efdf
commit
8ea11dbab7
@ -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,
|
||||
)?;
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user