1
0
Fork 0
mirror of synced 2025-09-23 20:28:36 +00:00

add tests, add book entry, fix inference

This commit is contained in:
schaeff 2022-01-11 11:48:16 +01:00
parent e5184a236b
commit 1cd049ac93
16 changed files with 179 additions and 37 deletions

View file

@ -79,12 +79,18 @@ impl<T: Field> fmt::Display for Value<T> {
),
Value::Tuple(elements) => {
write!(f, "(")?;
for (i, e) in elements.iter().enumerate() {
write!(f, "{},", e)?;
if i < elements.len() - 1 {
write!(f, " ")?;
}
}
match elements.len() {
1 => write!(f, "{},", elements[0]),
_ => write!(
f,
"{}",
elements
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
),
}?;
write!(f, ")")
}
}

View file

@ -107,9 +107,18 @@ field[3] a = [1, 2, 3]
field[2] b = a[1..3] // initialize an array copying a slice from `a`
```
### Tuples
A tuple is a composite datatype representing a numbered collection of values.
The following code shows an example of how to use tuples.
```zokrates
{{#include ../../../zokrates_cli/examples/book/tuples.zok}}
```
In tuple types and values, the trailing comma is optional, unless the tuple contains a single element, in which case it is mandatory.
### Structs
A struct is a composite datatype representing a named collection of variables. Structs can be generic over constants, in order to wrap arrays of generic size. For more details on generic array sizes, see [constant generics](../language/generics.md)
The contained variables can be of any type.
A struct is a composite datatype representing a named collection of values. Structs can be generic over constants, in order to wrap arrays of generic size. For more details on generic array sizes, see [constant generics](../language/generics.md). The contained variables can be of any type.
The following code shows an example of how to use structs.

View file

@ -0,0 +1,4 @@
def main() -> bool:
(field[2], bool) v = ([1, 2], true)
v.0 = [42, 43]
return v.1

View file

@ -643,12 +643,18 @@ impl<'ast> fmt::Display for Expression<'ast> {
}
Expression::InlineTuple(ref exprs) => {
write!(f, "(")?;
for (i, e) in exprs.iter().enumerate() {
write!(f, "{},", e)?;
if i < exprs.len() - 1 {
write!(f, " ")?;
}
}
match exprs.len() {
1 => write!(f, "{},", exprs[0]),
_ => write!(
f,
"{}",
exprs
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
),
}?;
write!(f, ")")
}
Expression::ArrayInitializer(ref e, ref count) => write!(f, "[{}; {}]", e, count),

View file

@ -25,12 +25,18 @@ impl<'ast> fmt::Display for UnresolvedType<'ast> {
UnresolvedType::Array(ref ty, ref size) => write!(f, "{}[{}]", ty, size),
UnresolvedType::Tuple(ref elements) => {
write!(f, "(")?;
for (i, e) in elements.iter().enumerate() {
write!(f, "{},", e)?;
if i < elements.len() {
write!(f, " ")?;
}
}
match elements.len() {
1 => write!(f, "{},", elements[0]),
_ => write!(
f,
"{}",
elements
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
),
}?;
write!(f, ")")
}
UnresolvedType::User(ref id, ref generics) => {

View file

@ -2817,6 +2817,9 @@ impl<'ast, T: Field> Checker<'ast, T> {
(TypedExpression::Struct(e1), TypedExpression::Struct(e2)) => {
Ok(BooleanExpression::StructEq(box e1, box e2).into())
}
(TypedExpression::Tuple(e1), TypedExpression::Tuple(e2)) => {
Ok(BooleanExpression::TupleEq(box e1, box e2).into())
}
(TypedExpression::Uint(e1), TypedExpression::Uint(e2))
if e1.get_type() == e2.get_type() =>
{

View file

@ -1,7 +1,7 @@
use crate::typed_absy::types::{
ArrayType, DeclarationArrayType, DeclarationConstant, DeclarationStructMember,
DeclarationStructType, DeclarationType, GArrayType, GStructType, GTupleType, GType,
GenericIdentifier, StructType, TupleType, Type,
DeclarationStructType, DeclarationTupleType, DeclarationType, GArrayType, GStructType,
GTupleType, GType, GenericIdentifier, StructType, TupleType, Type,
};
use crate::typed_absy::UBitwidth;
use crate::typed_absy::{
@ -40,7 +40,7 @@ trait IntegerInference: Sized {
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)>;
}
impl<'ast, T> IntegerInference for Type<'ast, T> {
impl<'ast, T: Clone> IntegerInference for Type<'ast, T> {
type Pattern = DeclarationType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
@ -67,12 +67,16 @@ impl<'ast, T> IntegerInference for Type<'ast, T> {
t.get_common_pattern(u)
.map_err(|(t, u)| (Type::Struct(t), Type::Struct(u)))?,
)),
(Type::Tuple(t), Type::Tuple(u)) => Ok(DeclarationType::Tuple(
t.get_common_pattern(u)
.map_err(|(t, u)| (Type::Tuple(t), Type::Tuple(u)))?,
)),
(t, u) => Err((t, u)),
}
}
}
impl<'ast, T> IntegerInference for ArrayType<'ast, T> {
impl<'ast, T: Clone> IntegerInference for ArrayType<'ast, T> {
type Pattern = DeclarationArrayType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
@ -88,7 +92,7 @@ impl<'ast, T> IntegerInference for ArrayType<'ast, T> {
}
}
impl<'ast, T> IntegerInference for StructType<'ast, T> {
impl<'ast, T: Clone> IntegerInference for StructType<'ast, T> {
type Pattern = DeclarationStructType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
@ -120,6 +124,22 @@ impl<'ast, T> IntegerInference for StructType<'ast, T> {
}
}
impl<'ast, T: Clone> IntegerInference for TupleType<'ast, T> {
type Pattern = DeclarationTupleType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
Ok(DeclarationTupleType {
elements: self
.elements
.iter()
.zip(other.elements.iter())
.map(|(t, u)| t.clone().get_common_pattern(u.clone()))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| (self, other))?,
})
}
}
impl<'ast, T: Field> TypedExpression<'ast, T> {
// return two TypedExpression, replacing IntExpression by FieldElement or Uint to try to align the two types if possible.
// Post condition is that (lhs, rhs) cannot be made equal by further removing IntExpressions

View file

@ -1454,12 +1454,18 @@ impl<'ast, T: fmt::Display> fmt::Display for TupleExpression<'ast, T> {
TupleExpressionInner::Identifier(ref var) => write!(f, "{}", var),
TupleExpressionInner::Value(ref values) => {
write!(f, "(")?;
for (i, v) in values.iter().enumerate() {
write!(f, "{},", v)?;
if i < values.len() - 1 {
write!(f, " ")?;
}
}
match values.len() {
1 => write!(f, "{},", values[0]),
_ => write!(
f,
"{}",
values
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
),
}?;
write!(f, ")")
}
TupleExpressionInner::FunctionCall(ref function_call) => {

View file

@ -189,6 +189,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
match t {
Array(array_type) => Ok(Array(self.fold_array_type(array_type)?)),
Struct(struct_type) => Ok(Struct(self.fold_struct_type(struct_type)?)),
Tuple(tuple_type) => Ok(Tuple(self.fold_tuple_type(tuple_type)?)),
t => Ok(t),
}
}

View file

@ -425,12 +425,18 @@ impl<'ast, S, R: PartialEq<S>> PartialEq<GTupleType<S>> for GTupleType<R> {
impl<S: fmt::Display> fmt::Display for GTupleType<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
for (i, e) in self.elements.iter().enumerate() {
write!(f, "{},", e)?;
if i < self.elements.len() - 1 {
write!(f, " ")?;
}
}
match self.elements.len() {
1 => write!(f, "{},", self.elements[0]),
_ => write!(
f,
"{}",
self.elements
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
),
}?;
write!(f, ")")
}
}

View file

@ -0,0 +1,5 @@
{
"entry_point": "./tests/tests/structs/constant.zok",
"curves": ["Bn128"],
"tests": []
}

View file

@ -0,0 +1,4 @@
def main():
State s = ([0; 16],)
s.0[0] = 0x00000001
return

View file

@ -0,0 +1,40 @@
{
"entry_point": "./tests/tests/structs/identity.zok",
"curves": ["Bn128", "Bls12_381", "Bls12_377", "Bw6_761"],
"tests": [
{
"input": {
"values": ["42", "0"]
},
"output": {
"Ok": {
"values": ["42", "0"]
}
}
},
{
"input": {
"values": ["42", "1"]
},
"output": {
"Ok": {
"values": ["42", "1"]
}
}
},
{
"input": {
"values": ["42", "3"]
},
"output": {
"Err": {
"UnsatisfiedConstraint": {
"left": "9",
"right": "3",
"error": "ArgumentBitness"
}
}
}
}
]
}

View file

@ -0,0 +1,2 @@
def main((field, bool,) a) -> ((field, bool,)):
return a

View file

@ -0,0 +1,20 @@
{
"entry_point": "./tests/tests/structs/member_order.zok",
"curves": ["Bn128"],
"tests": [
{
"abi": true,
"input": {
"values": [{
"a":true,
"b": "3"
}]
},
"output": {
"Ok": {
"values": []
}
}
}
]
}

View file

@ -0,0 +1,4 @@
// this tests the abi, checking that the fields of a (field, bool) instance get encoded in the right order
// if the the encoder reverses `0` and `1`, the boolean check ends up being done on the field value, which would fail
def main((field, bool) f):
return