mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 15:15:47 +03:00
fix array indexing assigning
This commit is contained in:
parent
5ebea328fb
commit
15402584c0
@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user