mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-25 18:42:26 +03:00
Merge pull request #601 from AleoHQ/remove-mutable-value
Remove mutable ConstrainedValue
This commit is contained in:
commit
0e74f9e10f
@ -22,12 +22,8 @@ use leo_asg::Variable;
|
||||
use snarkvm_models::curves::{Field, PrimeField};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn store_definition(&mut self, variable: &Variable, mut value: ConstrainedValue<F, G>) {
|
||||
pub fn store_definition(&mut self, variable: &Variable, value: ConstrainedValue<F, G>) {
|
||||
let variable = variable.borrow();
|
||||
// Store with given mutability
|
||||
if variable.mutable {
|
||||
value = ConstrainedValue::Mutable(Box::new(value));
|
||||
}
|
||||
|
||||
self.store(variable.id, value);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
index: &Arc<Expression>,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let array = match self.enforce_operand(cs, array)? {
|
||||
let array = match self.enforce_expression(cs, array)? {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||
};
|
||||
@ -52,7 +52,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
right: Option<&Arc<Expression>>,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let array = match self.enforce_operand(cs, array)? {
|
||||
let array = match self.enforce_expression(cs, array)? {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
index: &Arc<Expression>,
|
||||
span: &Span,
|
||||
) -> Result<usize, ExpressionError> {
|
||||
match self.enforce_operand(cs, index)? {
|
||||
match self.enforce_expression(cs, index)? {
|
||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
|
||||
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
left: &Arc<Expression>,
|
||||
right: &Arc<Expression>,
|
||||
) -> Result<ConstrainedValuePair<F, G>, ExpressionError> {
|
||||
let resolved_left = self.enforce_operand(cs, left)?;
|
||||
let resolved_right = self.enforce_operand(cs, right)?;
|
||||
let resolved_left = self.enforce_expression(cs, left)?;
|
||||
let resolved_right = self.enforce_expression(cs, right)?;
|
||||
|
||||
Ok((resolved_left, resolved_right))
|
||||
}
|
||||
|
@ -18,6 +18,3 @@
|
||||
|
||||
pub mod binary;
|
||||
pub use self::binary::*;
|
||||
|
||||
pub mod operand;
|
||||
pub use self::operand::*;
|
||||
|
@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Enforces one operand in a binary expression in a compiled Leo program.
|
||||
|
||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_asg::Expression;
|
||||
use std::sync::Arc;
|
||||
|
||||
use snarkvm_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Enforce an operand of a binary expression.
|
||||
/// We don't care about mutability because we are not changing any variables.
|
||||
/// We try to resolve unresolved types here if the type is given explicitly.
|
||||
pub fn enforce_operand<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
expression: &Arc<Expression>,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let mut branch = self.enforce_expression(cs, expression)?;
|
||||
|
||||
branch.get_inner_mut();
|
||||
|
||||
Ok(branch)
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
if let Some(target) = &expr.target {
|
||||
//todo: we can prob pass values by ref here to avoid copying the entire circuit on access
|
||||
let target_value = self.enforce_operand(cs, target)?;
|
||||
let target_value = self.enforce_expression(cs, target)?;
|
||||
match target_value {
|
||||
ConstrainedValue::CircuitExpression(def, members) => {
|
||||
assert!(def.circuit == expr.circuit);
|
||||
|
@ -41,9 +41,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
||||
let first_value = self.enforce_operand(cs, first)?;
|
||||
let first_value = self.enforce_expression(cs, first)?;
|
||||
|
||||
let second_value = self.enforce_operand(cs, second)?;
|
||||
let second_value = self.enforce_expression(cs, second)?;
|
||||
|
||||
let unique_namespace = cs.ns(|| {
|
||||
format!(
|
||||
|
@ -92,7 +92,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let resolved_inner = self.enforce_expression(cs, inner)?;
|
||||
enforce_negate(cs, resolved_inner, &span)
|
||||
}
|
||||
UnaryOperation::Not => Ok(evaluate_not(self.enforce_operand(cs, inner)?, &span)?),
|
||||
UnaryOperation::Not => Ok(evaluate_not(self.enforce_expression(cs, inner)?, &span)?),
|
||||
},
|
||||
|
||||
Expression::Ternary(TernaryExpression {
|
||||
|
@ -35,7 +35,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Get the tuple values.
|
||||
let tuple = match self.enforce_operand(cs, tuple)? {
|
||||
let tuple = match self.enforce_expression(cs, tuple)? {
|
||||
ConstrainedValue::Tuple(tuple) => tuple,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
@ -61,13 +61,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
// Store input values as new variables in resolved program
|
||||
for (variable, input_expression) in function.arguments.iter().zip(arguments.iter()) {
|
||||
let mut input_value = self.enforce_expression(cs, input_expression)?;
|
||||
let input_value = self.enforce_expression(cs, input_expression)?;
|
||||
let variable = variable.borrow();
|
||||
|
||||
if variable.mutable {
|
||||
input_value = ConstrainedValue::Mutable(Box::new(input_value))
|
||||
}
|
||||
|
||||
self.store(variable.id, input_value);
|
||||
}
|
||||
|
||||
|
@ -109,10 +109,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let variable = variable.borrow();
|
||||
|
||||
let mut result = vec![match self.get_mut(&variable.id) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Mutable(mutable) => &mut **mutable,
|
||||
_ => return Err(StatementError::immutable_assign(variable.name.to_string(), span)),
|
||||
},
|
||||
Some(value) => value,
|
||||
None => return Err(StatementError::undefined_variable(variable.name.to_string(), span)),
|
||||
}];
|
||||
|
||||
|
@ -31,8 +31,7 @@ use snarkvm_models::{
|
||||
|
||||
pub struct Blake2s;
|
||||
|
||||
fn unwrap_argument<F: Field + PrimeField, G: GroupType<F>>(mut arg: ConstrainedValue<F, G>) -> Vec<UInt8> {
|
||||
arg.get_inner_mut();
|
||||
fn unwrap_argument<F: Field + PrimeField, G: GroupType<F>>(arg: ConstrainedValue<F, G>) -> Vec<UInt8> {
|
||||
if let ConstrainedValue::Array(args) = arg {
|
||||
assert_eq!(args.len(), 32); // asg enforced
|
||||
args.into_iter()
|
||||
|
@ -67,10 +67,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let variable = assignee.target_variable.borrow();
|
||||
|
||||
let mut result = vec![match self.get_mut(&variable.id) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Mutable(mutable) => &mut **mutable,
|
||||
_ => return Err(StatementError::immutable_assign(variable.name.to_string(), span)),
|
||||
},
|
||||
Some(value) => value,
|
||||
None => return Err(StatementError::undefined_variable(variable.name.to_string(), span)),
|
||||
}];
|
||||
|
||||
@ -101,14 +98,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
// discards unnecessary mutable wrappers
|
||||
fn unwrap_mutable(input: &mut ConstrainedValue<F, G>) -> &mut ConstrainedValue<F, G> {
|
||||
match input {
|
||||
ConstrainedValue::Mutable(x) => Self::unwrap_mutable(&mut **x),
|
||||
x => x,
|
||||
}
|
||||
}
|
||||
|
||||
// todo: this can prob have most of its error checking removed
|
||||
pub(crate) fn resolve_assignee_access<'a>(
|
||||
access: ResolvedAssigneeAccess,
|
||||
@ -120,7 +109,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
if value.len() != 1 {
|
||||
return Err(StatementError::array_assign_interior_index(span.clone()));
|
||||
}
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
match value.remove(0) {
|
||||
ConstrainedValue::Array(old) => {
|
||||
if index > old.len() {
|
||||
Err(StatementError::array_assign_index_bounds(
|
||||
@ -140,7 +129,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
if value.len() == 1 {
|
||||
// not a range of a range
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
match value.remove(0) {
|
||||
ConstrainedValue::Array(old) => {
|
||||
let stop_index = stop_index.unwrap_or(old.len());
|
||||
Self::check_range_index(start_index, stop_index, old.len(), &span)?;
|
||||
@ -154,14 +143,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let stop_index = stop_index.unwrap_or(value.len());
|
||||
Self::check_range_index(start_index, stop_index, value.len(), &span)?;
|
||||
|
||||
Ok(value.drain(start_index..stop_index).map(Self::unwrap_mutable).collect())
|
||||
Ok(value.drain(start_index..stop_index).collect())
|
||||
}
|
||||
}
|
||||
ResolvedAssigneeAccess::Tuple(index, span) => {
|
||||
if value.len() != 1 {
|
||||
return Err(StatementError::array_assign_interior_index(span));
|
||||
}
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
match value.remove(0) {
|
||||
ConstrainedValue::Tuple(old) => {
|
||||
if index > old.len() {
|
||||
Err(StatementError::tuple_assign_index_bounds(index, old.len(), span))
|
||||
@ -176,7 +165,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
if value.len() != 1 {
|
||||
return Err(StatementError::array_assign_interior_index(span.clone()));
|
||||
}
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
match value.remove(0) {
|
||||
ConstrainedValue::CircuitExpression(_variable, members) => {
|
||||
// Modify the circuit variable in place
|
||||
let matched_variable = members.iter_mut().find(|member| member.0 == name);
|
||||
|
@ -30,7 +30,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
statement: &ReturnStatement,
|
||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||
let result = self.enforce_operand(cs, &statement.expression)?;
|
||||
let result = self.enforce_expression(cs, &statement.expression)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,6 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
|
||||
|
||||
// Circuits
|
||||
CircuitExpression(Arc<CircuitBody>, Vec<ConstrainedCircuitMember<F, G>>),
|
||||
|
||||
// Modifiers
|
||||
Mutable(Box<ConstrainedValue<F, G>>),
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
||||
@ -81,22 +78,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
||||
Type::Tuple(types)
|
||||
}
|
||||
ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.circuit.clone()),
|
||||
ConstrainedValue::Mutable(value) => return value.to_type(span),
|
||||
})
|
||||
}
|
||||
|
||||
///
|
||||
/// Modifies the `self` [ConstrainedValue] so there are no `mut` keywords wrapping the `self` value.
|
||||
///
|
||||
pub(crate) fn get_inner_mut(&mut self) {
|
||||
if let ConstrainedValue::Mutable(inner) = self {
|
||||
// Recursively remove `mut` keywords.
|
||||
inner.get_inner_mut();
|
||||
|
||||
// Modify the value.
|
||||
*self = *inner.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F, G> {
|
||||
@ -142,7 +125,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
ConstrainedValue::Mutable(ref value) => write!(f, "{}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,8 +247,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
|
||||
|
||||
ConstrainedValue::CircuitExpression(identifier.clone(), members)
|
||||
}
|
||||
(ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?,
|
||||
(_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?,
|
||||
(_, _) => return Err(SynthesisError::Unsatisfiable),
|
||||
})
|
||||
}
|
||||
|
6
compiler/tests/boolean/conditional_mut.leo
Normal file
6
compiler/tests/boolean/conditional_mut.leo
Normal file
@ -0,0 +1,6 @@
|
||||
function main () {
|
||||
let mut x = true;
|
||||
if x {
|
||||
let y = 0u8;
|
||||
}
|
||||
}
|
@ -101,6 +101,14 @@ fn test_not_mutable() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conditional_mut() {
|
||||
let program_string = include_str!("conditional_mut.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_u32() {
|
||||
let program_string = include_str!("not_u32.leo");
|
||||
|
Loading…
Reference in New Issue
Block a user