Merge pull request #855 from Zokrates/fix-constant-struct-member-mutation
Fix constant assignment to constant struct member panic
This commit is contained in:
commit
dab975b7f7
4 changed files with 38 additions and 9 deletions
1
changelogs/unreleased/855-schaeff
Normal file
1
changelogs/unreleased/855-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Fix crash when updating a constant struct member to another constant
|
|
@ -152,13 +152,16 @@ fn is_constant<T: Field>(e: &TypedExpression<T>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
||||
fn remove_spreads_aux<T: Field>(e: TypedExpressionOrSpread<T>) -> Vec<TypedExpression<T>> {
|
||||
// in the constant map, we only want canonical constants: [0; 3] -> [0, 0, 0], [...[1], 2] -> [1, 2], etc
|
||||
fn to_canonical_constant<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
||||
fn to_canonical_constant_aux<T: Field>(
|
||||
e: TypedExpressionOrSpread<T>,
|
||||
) -> Vec<TypedExpression<T>> {
|
||||
match e {
|
||||
TypedExpressionOrSpread::Expression(e) => vec![e],
|
||||
TypedExpressionOrSpread::Spread(s) => match s.array.into_inner() {
|
||||
ArrayExpressionInner::Value(v) => {
|
||||
v.into_iter().flat_map(remove_spreads_aux).collect()
|
||||
v.into_iter().flat_map(to_canonical_constant_aux).collect()
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
|
@ -172,7 +175,7 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
match a.into_inner() {
|
||||
ArrayExpressionInner::Value(v) => ArrayExpressionInner::Value(
|
||||
v.into_iter()
|
||||
.flat_map(remove_spreads_aux)
|
||||
.flat_map(to_canonical_constant_aux)
|
||||
.map(|e| e.into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
|
@ -197,7 +200,7 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
|
||||
ArrayExpressionInner::Value(
|
||||
v.into_iter()
|
||||
.flat_map(remove_spreads_aux)
|
||||
.flat_map(to_canonical_constant_aux)
|
||||
.map(|e| e.into())
|
||||
.enumerate()
|
||||
.filter(|(index, _)| index >= &from && index < &to)
|
||||
|
@ -214,7 +217,7 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
_ => unreachable!("should be a uint value"),
|
||||
};
|
||||
|
||||
let e = remove_spreads(e);
|
||||
let e = to_canonical_constant(e);
|
||||
|
||||
ArrayExpressionInner::Value(
|
||||
vec![TypedExpressionOrSpread::Expression(e); count].into(),
|
||||
|
@ -225,6 +228,18 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
TypedExpression::Struct(s) => {
|
||||
let struct_ty = s.ty().clone();
|
||||
|
||||
match s.into_inner() {
|
||||
StructExpressionInner::Value(expressions) => StructExpressionInner::Value(
|
||||
expressions.into_iter().map(to_canonical_constant).collect(),
|
||||
)
|
||||
.annotate(struct_ty)
|
||||
.into(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
e => e,
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +315,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
if is_constant(&expr) {
|
||||
match assignee {
|
||||
TypedAssignee::Identifier(var) => {
|
||||
let expr = remove_spreads(expr);
|
||||
let expr = to_canonical_constant(expr);
|
||||
|
||||
assert!(self.constants.insert(var.id, expr).is_none());
|
||||
|
||||
|
@ -308,7 +323,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
}
|
||||
assignee => match self.try_get_constant_mut(&assignee) {
|
||||
Ok((_, c)) => {
|
||||
*c = remove_spreads(expr);
|
||||
*c = to_canonical_constant(expr);
|
||||
Ok(vec![])
|
||||
}
|
||||
Err(v) => match self.constants.remove(&v.id) {
|
||||
|
@ -374,7 +389,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
|
||||
let argument = arguments.pop().unwrap();
|
||||
|
||||
let argument = remove_spreads(argument);
|
||||
let argument = to_canonical_constant(argument);
|
||||
|
||||
match ArrayExpression::try_from(argument)
|
||||
.unwrap()
|
||||
|
|
5
zokrates_core_test/tests/tests/structs/constant.json
Normal file
5
zokrates_core_test/tests/tests/structs/constant.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/structs/constant.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": []
|
||||
}
|
8
zokrates_core_test/tests/tests/structs/constant.zok
Normal file
8
zokrates_core_test/tests/tests/structs/constant.zok
Normal file
|
@ -0,0 +1,8 @@
|
|||
struct State {
|
||||
u32[16] memory
|
||||
}
|
||||
|
||||
def main():
|
||||
State s = State { memory: [0; 16] }
|
||||
s.memory[0] = 0x00000001
|
||||
return
|
Loading…
Reference in a new issue