mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-24 18:52:58 +03:00
add support for refactored array type in compiler
This commit is contained in:
parent
1daf6c9831
commit
d7ff808660
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::PositiveNumber;
|
use crate::{PositiveNumber, Span};
|
||||||
use leo_grammar::types::ArrayDimensions as GrammarArrayDimensions;
|
use leo_grammar::types::ArrayDimensions as GrammarArrayDimensions;
|
||||||
use leo_input::types::ArrayDimensions as InputArrayDimensions;
|
use leo_input::types::ArrayDimensions as InputArrayDimensions;
|
||||||
|
|
||||||
@ -23,16 +23,71 @@ use std::fmt;
|
|||||||
|
|
||||||
/// A vector of positive numbers that represent array dimensions.
|
/// A vector of positive numbers that represent array dimensions.
|
||||||
/// Can be used in an array [`Type`] or an array initializer [`Expression`].
|
/// Can be used in an array [`Type`] or an array initializer [`Expression`].
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct ArrayDimensions(pub Vec<PositiveNumber>);
|
pub struct ArrayDimensions(pub Vec<PositiveNumber>);
|
||||||
|
|
||||||
impl ArrayDimensions {
|
impl ArrayDimensions {
|
||||||
|
///
|
||||||
|
/// Creates a new `PositiveNumber` from the given `usize` and `Span`.
|
||||||
|
/// Appends the new `PositiveNumber` to the array dimensions.
|
||||||
|
///
|
||||||
|
pub fn push_usize(&mut self, number: usize, span: Span) {
|
||||||
|
let positive_number = PositiveNumber {
|
||||||
|
value: number.to_string(),
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.0.push(positive_number)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Appends a vector of array dimensions to the self array dimensions.
|
||||||
|
///
|
||||||
|
pub fn append(&mut self, other: &mut ArrayDimensions) {
|
||||||
|
self.0.append(&mut other.0)
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the array dimensions as strings.
|
/// Returns the array dimensions as strings.
|
||||||
///
|
///
|
||||||
pub fn to_strings(&self) -> Vec<String> {
|
pub fn to_strings(&self) -> Vec<String> {
|
||||||
self.0.iter().map(|number| number.to_string()).collect()
|
self.0.iter().map(|number| number.to_string()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns `true` if the all array dimensions have been removed.
|
||||||
|
///
|
||||||
|
/// This method is called after repeated calls to `remove_first`.
|
||||||
|
///
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the first dimension of the array.
|
||||||
|
///
|
||||||
|
pub fn first(&self) -> Option<&PositiveNumber> {
|
||||||
|
self.0.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to remove the first dimension from the array.
|
||||||
|
///
|
||||||
|
/// If the first dimension exists, then remove and return `Some(PositiveNumber)`.
|
||||||
|
/// If the first dimension does not exist, then return `None`.
|
||||||
|
///
|
||||||
|
pub fn remove_first(&mut self) -> Option<PositiveNumber> {
|
||||||
|
// If there are no dimensions in the array, then return None.
|
||||||
|
if self.0.get(0).is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the first dimension.
|
||||||
|
let removed = self.0.remove(0);
|
||||||
|
|
||||||
|
// Return the first dimension.
|
||||||
|
Some(removed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`ArrayDimensions`] from a [`GrammarArrayDimensions`] in a Leo program file.
|
/// Create a new [`ArrayDimensions`] from a [`GrammarArrayDimensions`] in a Leo program file.
|
||||||
|
@ -109,10 +109,10 @@ impl ExpressionError {
|
|||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invalid_index(actual: String, span: Span) -> Self {
|
pub fn invalid_index(actual: String, span: &Span) -> Self {
|
||||||
let message = format!("index must resolve to an integer, found `{}`", actual);
|
let message = format!("index must resolve to an integer, found `{}`", actual);
|
||||||
|
|
||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span.to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invalid_length(expected: usize, actual: usize, span: Span) -> Self {
|
pub fn invalid_length(expected: usize, actual: usize, span: Span) -> Self {
|
||||||
@ -157,6 +157,12 @@ impl ExpressionError {
|
|||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn undefined_tuple(actual: String, span: Span) -> Self {
|
||||||
|
let message = format!("tuple `{}` must be declared before it is used in an expression", actual);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn undefined_circuit(actual: String, span: Span) -> Self {
|
pub fn undefined_circuit(actual: String, span: Span) -> Self {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"circuit `{}` must be declared before it is used in an expression",
|
"circuit `{}` must be declared before it is used in an expression",
|
||||||
|
@ -22,7 +22,7 @@ use crate::{
|
|||||||
value::ConstrainedValue,
|
value::ConstrainedValue,
|
||||||
GroupType,
|
GroupType,
|
||||||
};
|
};
|
||||||
use leo_ast::{Expression, Span, SpreadOrExpression, Type};
|
use leo_ast::{ArrayDimensions, Expression, PositiveNumber, Span, SpreadOrExpression, Type};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -41,20 +41,28 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Check explicit array type dimension if given
|
// Check explicit array type dimension if given
|
||||||
let mut expected_dimensions = vec![];
|
let mut expected_dimension = None;
|
||||||
|
|
||||||
if let Some(type_) = expected_type {
|
if let Some(type_) = expected_type {
|
||||||
match type_ {
|
match type_ {
|
||||||
Type::Array(ref type_, ref dimensions) => {
|
Type::Array(type_, mut dimensions) => {
|
||||||
let number = match dimensions.first() {
|
// Remove the first dimension of the array.
|
||||||
Some(number) => *number,
|
let first = match dimensions.remove_first() {
|
||||||
|
Some(number) => {
|
||||||
|
// Parse the array dimension into a `usize`.
|
||||||
|
parse_index(&number, &span)?
|
||||||
|
}
|
||||||
None => return Err(ExpressionError::unexpected_array(type_.to_string(), span)),
|
None => return Err(ExpressionError::unexpected_array(type_.to_string(), span)),
|
||||||
};
|
};
|
||||||
|
|
||||||
expected_dimensions.push(number);
|
// Update the expected dimension to the first dimension.
|
||||||
expected_type = Some(type_.outer_dimension(dimensions));
|
expected_dimension = Some(first);
|
||||||
|
|
||||||
|
// Update the expected type to a new array type with the first dimension removed.
|
||||||
|
expected_type = Some(inner_array_type(*type_, dimensions));
|
||||||
}
|
}
|
||||||
ref type_ => {
|
ref type_ => {
|
||||||
|
// Return an error if the expected type is not an array.
|
||||||
return Err(ExpressionError::unexpected_array(type_.to_string(), span));
|
return Err(ExpressionError::unexpected_array(type_.to_string(), span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,15 +96,44 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check expected_dimensions if given
|
// Check expected_dimension if given.
|
||||||
if !expected_dimensions.is_empty() && expected_dimensions[expected_dimensions.len() - 1] != result.len() {
|
if let Some(dimension) = expected_dimension {
|
||||||
return Err(ExpressionError::invalid_length(
|
// Return an error if the expected dimension != the actual dimension.
|
||||||
expected_dimensions[expected_dimensions.len() - 1],
|
if dimension != result.len() {
|
||||||
result.len(),
|
return Err(ExpressionError::invalid_length(dimension, result.len(), span));
|
||||||
span,
|
}
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ConstrainedValue::Array(result))
|
Ok(ConstrainedValue::Array(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the index as a usize.
|
||||||
|
///
|
||||||
|
pub fn parse_index(number: &PositiveNumber, span: &Span) -> Result<usize, ExpressionError> {
|
||||||
|
number
|
||||||
|
.value
|
||||||
|
.parse::<usize>()
|
||||||
|
.map_err(|_| ExpressionError::invalid_index(number.value.to_owned(), span))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the type of the inner array given an array element and array dimensions.
|
||||||
|
///
|
||||||
|
/// If the array has no dimensions, then an inner array does not exist. Simply return the given
|
||||||
|
/// element type.
|
||||||
|
///
|
||||||
|
/// If the array has dimensions, then an inner array exists. Create a new type for the
|
||||||
|
/// inner array. The element type of the new array should be the same as the old array. The
|
||||||
|
/// dimensions of the new array should be the old array dimensions with the first dimension removed.
|
||||||
|
///
|
||||||
|
pub fn inner_array_type(element_type: Type, dimensions: ArrayDimensions) -> Type {
|
||||||
|
if dimensions.is_empty() {
|
||||||
|
// The array has one dimension.
|
||||||
|
element_type
|
||||||
|
} else {
|
||||||
|
// The array has multiple dimensions.
|
||||||
|
Type::Array(Box::new(element_type), dimensions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,7 +36,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
let expected_type = Some(Type::IntegerType(IntegerType::U32));
|
let expected_type = Some(Type::IntegerType(IntegerType::U32));
|
||||||
match self.enforce_operand(cs, file_scope, function_scope, expected_type, index, &span)? {
|
match self.enforce_operand(cs, file_scope, function_scope, expected_type, index, &span)? {
|
||||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
|
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
|
||||||
value => Err(ExpressionError::invalid_index(value.to_string(), span.to_owned())),
|
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,9 +260,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
Expression::Tuple(tuple, span) => {
|
Expression::Tuple(tuple, span) => {
|
||||||
self.enforce_tuple(cs, file_scope, function_scope, expected_type, tuple, span)
|
self.enforce_tuple(cs, file_scope, function_scope, expected_type, tuple, span)
|
||||||
}
|
}
|
||||||
Expression::TupleAccess(tuple, index, span) => {
|
Expression::TupleAccess(tuple_w_index, span) => self.enforce_tuple_access(
|
||||||
self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, *tuple, index, &span)
|
cs,
|
||||||
}
|
file_scope,
|
||||||
|
function_scope,
|
||||||
|
expected_type,
|
||||||
|
tuple_w_index.0,
|
||||||
|
tuple_w_index.1,
|
||||||
|
&span,
|
||||||
|
),
|
||||||
|
|
||||||
// Circuits
|
// Circuits
|
||||||
Expression::Circuit(circuit_name, members, span) => {
|
Expression::Circuit(circuit_name, members, span) => {
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
//! Enforces array access in a compiled Leo program.
|
//! Enforces array access in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, parse_index, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::{Expression, Span, Type};
|
use leo_ast::{Expression, PositiveNumber, Span, Type};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -33,18 +33,23 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
function_scope: &str,
|
function_scope: &str,
|
||||||
expected_type: Option<Type>,
|
expected_type: Option<Type>,
|
||||||
tuple: Expression,
|
tuple: Expression,
|
||||||
index: usize,
|
index: PositiveNumber,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
|
// Get the tuple values.
|
||||||
let tuple = match self.enforce_operand(cs, file_scope, function_scope, expected_type, tuple, &span)? {
|
let tuple = match self.enforce_operand(cs, file_scope, function_scope, expected_type, tuple, &span)? {
|
||||||
ConstrainedValue::Tuple(tuple) => tuple,
|
ConstrainedValue::Tuple(tuple) => tuple,
|
||||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||||
};
|
};
|
||||||
|
|
||||||
if index > tuple.len() - 1 {
|
// Parse the tuple index.
|
||||||
return Err(ExpressionError::index_out_of_bounds(index, span.to_owned()));
|
let index_usize = parse_index(&index, &span)?;
|
||||||
|
|
||||||
|
// Check for out of bounds access.
|
||||||
|
if index_usize > tuple.len() - 1 {
|
||||||
|
return Err(ExpressionError::index_out_of_bounds(index_usize, span.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(tuple[index].to_owned())
|
Ok(tuple[index_usize].to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,16 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::FunctionError,
|
errors::FunctionError,
|
||||||
|
inner_array_type,
|
||||||
|
parse_index,
|
||||||
program::{new_scope, ConstrainedProgram},
|
program::{new_scope, ConstrainedProgram},
|
||||||
value::ConstrainedValue,
|
value::ConstrainedValue,
|
||||||
GroupType,
|
GroupType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use leo_ast::{InputValue, Span, Type};
|
use leo_ast::{ArrayDimensions, InputValue, Span, Type};
|
||||||
|
|
||||||
|
use crate::errors::ExpressionError;
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
@ -36,11 +39,27 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: &str,
|
name: &str,
|
||||||
array_type: Type,
|
array_type: Type,
|
||||||
array_dimensions: Vec<usize>,
|
mut array_dimensions: ArrayDimensions,
|
||||||
input_value: Option<InputValue>,
|
input_value: Option<InputValue>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let expected_length = array_dimensions[0];
|
let expected_length = match array_dimensions.remove_first() {
|
||||||
|
Some(number) => {
|
||||||
|
// Parse the array dimension into a `usize`.
|
||||||
|
parse_index(&number, &span)?
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(FunctionError::ExpressionError(ExpressionError::unexpected_array(
|
||||||
|
array_type.to_string(),
|
||||||
|
span.to_owned(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the expected type for each array element.
|
||||||
|
let inner_array_type = inner_array_type(array_type, array_dimensions);
|
||||||
|
|
||||||
|
// Build the array value using the expected types.
|
||||||
let mut array_value = vec![];
|
let mut array_value = vec![];
|
||||||
|
|
||||||
match input_value {
|
match input_value {
|
||||||
@ -48,11 +67,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
// Allocate each value in the current row
|
// Allocate each value in the current row
|
||||||
for (i, value) in arr.into_iter().enumerate() {
|
for (i, value) in arr.into_iter().enumerate() {
|
||||||
let value_name = new_scope(&name, &i.to_string());
|
let value_name = new_scope(&name, &i.to_string());
|
||||||
let value_type = array_type.outer_dimension(&array_dimensions);
|
|
||||||
|
|
||||||
array_value.push(self.allocate_main_function_input(
|
array_value.push(self.allocate_main_function_input(
|
||||||
cs,
|
cs,
|
||||||
value_type,
|
inner_array_type.clone(),
|
||||||
&value_name,
|
&value_name,
|
||||||
Some(value),
|
Some(value),
|
||||||
span,
|
span,
|
||||||
@ -63,9 +81,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
// Allocate all row values as none
|
// Allocate all row values as none
|
||||||
for i in 0..expected_length {
|
for i in 0..expected_length {
|
||||||
let value_name = new_scope(&name, &i.to_string());
|
let value_name = new_scope(&name, &i.to_string());
|
||||||
let value_type = array_type.outer_dimension(&array_dimensions);
|
|
||||||
|
|
||||||
array_value.push(self.allocate_main_function_input(cs, value_type, &value_name, None, span)?);
|
array_value.push(self.allocate_main_function_input(
|
||||||
|
cs,
|
||||||
|
inner_array_type.clone(),
|
||||||
|
&value_name,
|
||||||
|
None,
|
||||||
|
span,
|
||||||
|
)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -83,8 +83,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
new_value,
|
new_value,
|
||||||
span,
|
span,
|
||||||
),
|
),
|
||||||
AssigneeAccess::Tuple(index) => {
|
AssigneeAccess::Tuple(index, span) => {
|
||||||
self.assign_tuple(cs, indicator, &variable_name, index, new_value, span)
|
self.assign_tuple(cs, indicator, &variable_name, index, new_value, &span)
|
||||||
}
|
}
|
||||||
AssigneeAccess::Member(identifier) => {
|
AssigneeAccess::Member(identifier) => {
|
||||||
// Mutate a circuit variable using the self keyword.
|
// Mutate a circuit variable using the self keyword.
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
//! Enforces a tuple assignment statement in a compiled Leo program.
|
//! Enforces a tuple assignment statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
use crate::{errors::StatementError, parse_index, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_ast::{PositiveNumber, Span};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -33,28 +33,32 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
indicator: Option<Boolean>,
|
indicator: Option<Boolean>,
|
||||||
name: &str,
|
name: &str,
|
||||||
index: usize,
|
index: PositiveNumber,
|
||||||
mut new_value: ConstrainedValue<F, G>,
|
mut new_value: ConstrainedValue<F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
|
// Get the indicator value.
|
||||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||||
|
|
||||||
|
// Parse the index.
|
||||||
|
let index_usize = parse_index(&index, &span)?;
|
||||||
|
|
||||||
// Modify the single value of the tuple in place
|
// Modify the single value of the tuple in place
|
||||||
match self.get_mutable_assignee(name, &span)? {
|
match self.get_mutable_assignee(name, &span)? {
|
||||||
ConstrainedValue::Tuple(old) => {
|
ConstrainedValue::Tuple(old) => {
|
||||||
new_value.resolve_type(Some(old[index].to_type(&span)?), &span)?;
|
new_value.resolve_type(Some(old[index_usize].to_type(&span)?), &span)?;
|
||||||
|
|
||||||
let selected_value = ConstrainedValue::conditionally_select(
|
let selected_value = ConstrainedValue::conditionally_select(
|
||||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||||
&condition,
|
&condition,
|
||||||
&new_value,
|
&new_value,
|
||||||
&old[index],
|
&old[index_usize],
|
||||||
)
|
)
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span.to_owned())
|
StatementError::select_fail(new_value.to_string(), old[index_usize].to_string(), span.to_owned())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
old[index] = selected_value;
|
old[index_usize] = selected_value;
|
||||||
}
|
}
|
||||||
_ => return Err(StatementError::tuple_assign_index(span.to_owned())),
|
_ => return Err(StatementError::tuple_assign_index(span.to_owned())),
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ use crate::{
|
|||||||
GroupType,
|
GroupType,
|
||||||
Integer,
|
Integer,
|
||||||
};
|
};
|
||||||
use leo_ast::{Circuit, Function, GroupValue, Identifier, Span, Type};
|
use leo_ast::{ArrayDimensions, Circuit, Function, GroupValue, Identifier, Span, Type};
|
||||||
use leo_core::Value;
|
use leo_core::Value;
|
||||||
|
|
||||||
use snarkos_errors::gadgets::SynthesisError;
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
@ -114,7 +114,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
// Data type wrappers
|
// Data type wrappers
|
||||||
ConstrainedValue::Array(array) => {
|
ConstrainedValue::Array(array) => {
|
||||||
let array_type = array[0].to_type(span)?;
|
let array_type = array[0].to_type(span)?;
|
||||||
let mut dimensions = vec![array.len()];
|
let mut dimensions = ArrayDimensions::default();
|
||||||
|
dimensions.push_usize(array.len(), span.to_owned());
|
||||||
|
|
||||||
// Nested array type
|
// Nested array type
|
||||||
if let Type::Array(inner_type, inner_dimensions) = &array_type {
|
if let Type::Array(inner_type, inner_dimensions) = &array_type {
|
||||||
|
Loading…
Reference in New Issue
Block a user