fix array indexing assigning

This commit is contained in:
gluax 2021-06-26 20:44:48 -07:00
parent 5ebea328fb
commit 15402584c0
3 changed files with 107 additions and 73 deletions

View File

@ -19,7 +19,7 @@
use std::convert::TryInto;
use crate::{
errors::{ExpressionError, StatementError},
errors::{ExpressionError, IntegerError, StatementError},
program::ConstrainedProgram,
value::ConstrainedValue,
GroupType,
@ -40,85 +40,117 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
mut context: ResolverContext<'a, 'b, F, G>,
index: &'a Expression<'a>,
) -> Result<(), StatementError> {
if context.input.len() != 1 {
println!("RTAAI input len {}", context.input.len());
let input_len = context.input.len();
if input_len == 0 {
return Err(StatementError::array_assign_interior_index(&context.span));
}
let input = match context.input.remove(0) {
ConstrainedValue::Array(old) => old,
_ => return Err(StatementError::array_assign_index(&context.span)),
};
let index_resolved = self.enforce_index(cs, index, &context.span)?;
if let Some(index) = index_resolved.to_usize() {
if index >= input.len() {
Err(StatementError::array_assign_index_bounds(
index,
input.len(),
&context.span,
))
} else {
let target = input.get_mut(index).unwrap();
if context.remaining_accesses.is_empty() {
self.enforce_assign_context(cs, &context, target)
match (context.input.remove(0), input_len) {
(ConstrainedValue::Array(input), 1) => {
if let Some(index) = index_resolved.to_usize() {
if index >= input.len() {
Err(StatementError::array_assign_index_bounds(
index,
input.len(),
&context.span,
))
} else {
let target = input.get_mut(index).unwrap();
if context.remaining_accesses.is_empty() {
self.enforce_assign_context(cs, &context, target)
} else {
context.input = vec![target];
self.resolve_target_access(cs, context)
}
}
} else {
context.input = vec![target];
self.resolve_target_access(cs, context)
let span = index.span().cloned().unwrap_or_default();
{
let array_len: u32 = input
.len()
.try_into()
.map_err(|_| ExpressionError::array_length_out_of_bounds(&span))?;
self.array_bounds_check(cs, &&index_resolved, array_len, &span)?;
}
for (i, item) in input.iter_mut().enumerate() {
let namespace_string = format!(
"evaluate dyn array assignment eq {} {}:{}",
i, span.line_start, span.col_start
);
let eq_namespace = cs.ns(|| namespace_string);
let index_bounded = i
.try_into()
.map_err(|_| ExpressionError::array_index_out_of_legal_bounds(&span))?;
let const_index = ConstInt::U32(index_bounded).cast_to(&index_resolved.get_type());
let index_comparison = index_resolved
.evaluate_equal(eq_namespace, &Integer::new(&const_index))
.map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), &span))?;
let mut unique_namespace = cs.ns(|| {
format!(
"select array dyn assignment {} {}:{}",
i, span.line_start, span.col_start
)
});
let temp_item = {
let mut item = item.clone();
let mut new_context = ResolverContext {
input: vec![&mut item],
span: context.span.clone(),
target_value: context.target_value.clone(),
remaining_accesses: context.remaining_accesses,
indicator: context.indicator,
operation: context.operation,
};
if context.remaining_accesses.is_empty() {
let item = new_context.input.remove(0);
self.enforce_assign_context(&mut unique_namespace, &new_context, item)?;
} else {
self.resolve_target_access(&mut unique_namespace, new_context)?;
}
item
};
let value = ConstrainedValue::conditionally_select(
unique_namespace,
&index_comparison,
&temp_item,
&item,
)
.map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, &span))?;
*item = value;
}
Ok(())
}
}
} else {
let span = index.span().cloned().unwrap_or_default();
{
let array_len: u32 = input
.len()
.try_into()
.map_err(|_| ExpressionError::array_length_out_of_bounds(&span))?;
self.array_bounds_check(cs, &&index_resolved, array_len, &span)?;
}
for (i, item) in input.iter_mut().enumerate() {
let namespace_string = format!(
"evaluate dyn array assignment eq {} {}:{}",
i, span.line_start, span.col_start
);
let eq_namespace = cs.ns(|| namespace_string);
let index_bounded = i
.try_into()
.map_err(|_| ExpressionError::array_index_out_of_legal_bounds(&span))?;
let const_index = ConstInt::U32(index_bounded).cast_to(&index_resolved.get_type());
let index_comparison = index_resolved
.evaluate_equal(eq_namespace, &Integer::new(&const_index))
.map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), &span))?;
let mut unique_namespace = cs.ns(|| {
format!(
"select array dyn assignment {} {}:{}",
i, span.line_start, span.col_start
)
});
let temp_item = {
let mut item = item.clone();
let mut new_context = ResolverContext {
input: vec![&mut item],
span: context.span.clone(),
target_value: context.target_value.clone(),
remaining_accesses: context.remaining_accesses,
indicator: context.indicator,
operation: context.operation,
};
if context.remaining_accesses.is_empty() {
let item = new_context.input.remove(0);
self.enforce_assign_context(&mut unique_namespace, &new_context, item)?;
} else {
self.resolve_target_access(&mut unique_namespace, new_context)?;
(target, _) => {
// index of array range
if let Some(index) = index_resolved.to_usize() {
if index >= input_len {
return Err(StatementError::array_assign_index_bounds(
index,
input_len,
&context.span,
));
}
item
};
let value =
ConstrainedValue::conditionally_select(unique_namespace, &index_comparison, &temp_item, &item)
.map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, &span))?;
*item = value;
if context.remaining_accesses.is_empty() {
self.enforce_assign_context(cs, &context, target)
} else {
context.input = vec![target];
self.resolve_target_access(cs, context)
}
} else {
let span = index.span().cloned().unwrap_or_default();
Err(StatementError::from(IntegerError::invalid_integer(
index_resolved.to_string(),
&span,
)))
}
}
Ok(())
}
}
}

View File

@ -68,8 +68,10 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
self.enforce_assign_context(cs, &context, input)?;
return Ok(());
}
let access = context.remaining_accesses[context.remaining_accesses.len() - 1];
context.remaining_accesses = &context.remaining_accesses[..context.remaining_accesses.len() - 1];
match access {
AssignAccess::ArrayRange(start, stop) => {
self.resolve_target_access_array_range(cs, context, start.get(), stop.get())

View File

@ -308,7 +308,7 @@ mod cli_tests {
let path = Some(dir.path("new"));
assert!(run_cmd("leo new test", &path).is_ok());
assert!(run_cmd("leo new test", &path).is_err()); // 2nd time
assert!(run_cmd("leo new test", &path).is_err()); // 2nd time
assert!(run_cmd("leo new wrong_name", &path).is_err());
}